1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Author: Stig Sæther Bakken <ssb@php.net> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: versioning.c 272374 2008-12-31 11:17:49Z sebastian $ */
20 :
21 : #include <stdio.h>
22 : #include <sys/types.h>
23 : #include <ctype.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include "php.h"
27 : #include "php_versioning.h"
28 :
29 : #define sign(n) ((n)<0?-1:((n)>0?1:0))
30 :
31 : /* {{{ php_canonicalize_version() */
32 :
33 : PHPAPI char *
34 : php_canonicalize_version(const char *version)
35 46016 : {
36 46016 : int len = strlen(version);
37 46016 : char *buf = safe_emalloc(len, 2, 1), *q, lp, lq;
38 : const char *p;
39 :
40 46016 : if (len == 0) {
41 0 : *buf = '\0';
42 0 : return buf;
43 : }
44 :
45 46016 : p = version;
46 46016 : q = buf;
47 46016 : *q++ = lp = *p++;
48 46016 : lq = '\0';
49 541447 : while (*p) {
50 : /* s/[-_+]/./g;
51 : * s/([^\d\.])([^\D\.])/$1.$2/g;
52 : * s/([^\D\.])([^\d\.])/$1.$2/g;
53 : */
54 : #define isdig(x) (isdigit(x)&&(x)!='.')
55 : #define isndig(x) (!isdigit(x)&&(x)!='.')
56 : #define isspecialver(x) ((x)=='-'||(x)=='_'||(x)=='+')
57 :
58 449415 : lq = *(q - 1);
59 493838 : if (isspecialver(*p)) {
60 44423 : if (lq != '.') {
61 44423 : lq = *q++ = '.';
62 : }
63 451174 : } else if ((isndig(lp) && isdig(*p)) || (isdig(lp) && isndig(*p))) {
64 46182 : if (lq != '.') {
65 46182 : *q++ = '.';
66 : }
67 46182 : lq = *q++ = *p;
68 358810 : } else if (!isalnum(*p)) {
69 90337 : if (lq != '.') {
70 90337 : lq = *q++ = '.';
71 : }
72 : } else {
73 268473 : lq = *q++ = *p;
74 : }
75 449415 : lp = *p++;
76 : }
77 46016 : *q++ = '\0';
78 46016 : return buf;
79 : }
80 :
81 : /* }}} */
82 : /* {{{ compare_special_version_forms() */
83 :
84 : typedef struct {
85 : const char *name;
86 : int order;
87 : } special_forms_t;
88 :
89 : static int
90 : compare_special_version_forms(char *form1, char *form2)
91 720 : {
92 720 : int found1 = -1, found2 = -1;
93 : special_forms_t special_forms[11] = {
94 : {"dev", 0},
95 : {"alpha", 1},
96 : {"a", 1},
97 : {"beta", 2},
98 : {"b", 2},
99 : {"RC", 3},
100 : {"rc", 3},
101 : {"#", 4},
102 : {"pl", 5},
103 : {"p", 5},
104 : {NULL, 0},
105 720 : };
106 : special_forms_t *pp;
107 :
108 3975 : for (pp = special_forms; pp && pp->name; pp++) {
109 3975 : if (strncmp(form1, pp->name, strlen(pp->name)) == 0) {
110 720 : found1 = pp->order;
111 720 : break;
112 : }
113 : }
114 3975 : for (pp = special_forms; pp && pp->name; pp++) {
115 3975 : if (strncmp(form2, pp->name, strlen(pp->name)) == 0) {
116 720 : found2 = pp->order;
117 720 : break;
118 : }
119 : }
120 720 : return sign(found1 - found2);
121 : }
122 :
123 : /* }}} */
124 : /* {{{ php_version_compare() */
125 :
126 : PHPAPI int
127 : php_version_compare(const char *orig_ver1, const char *orig_ver2)
128 23098 : {
129 : char *ver1;
130 : char *ver2;
131 : char *p1, *p2, *n1, *n2;
132 : long l1, l2;
133 23098 : int compare = 0;
134 :
135 23098 : if (!*orig_ver1 || !*orig_ver2) {
136 0 : if (!*orig_ver1 && !*orig_ver2) {
137 0 : return 0;
138 : } else {
139 0 : return *orig_ver1 ? 1 : -1;
140 : }
141 : }
142 23098 : if (orig_ver1[0] == '#') {
143 90 : ver1 = estrdup(orig_ver1);
144 : } else {
145 23008 : ver1 = php_canonicalize_version(orig_ver1);
146 : }
147 23098 : if (orig_ver2[0] == '#') {
148 90 : ver2 = estrdup(orig_ver2);
149 : } else {
150 23008 : ver2 = php_canonicalize_version(orig_ver2);
151 : }
152 23098 : p1 = n1 = ver1;
153 23098 : p2 = n2 = ver2;
154 48034 : while (*p1 && *p2 && n1 && n2) {
155 24621 : if ((n1 = strchr(p1, '.')) != NULL) {
156 24211 : *n1 = '\0';
157 : }
158 24621 : if ((n2 = strchr(p2, '.')) != NULL) {
159 24209 : *n2 = '\0';
160 : }
161 48522 : if (isdigit(*p1) && isdigit(*p2)) {
162 : /* compare element numerically */
163 23901 : l1 = strtol(p1, NULL, 10);
164 23901 : l2 = strtol(p2, NULL, 10);
165 23901 : compare = sign(l1 - l2);
166 1440 : } else if (!isdigit(*p1) && !isdigit(*p2)) {
167 : /* compare element names */
168 720 : compare = compare_special_version_forms(p1, p2);
169 : } else {
170 : /* mix of names and numbers */
171 0 : if (isdigit(*p1)) {
172 0 : compare = compare_special_version_forms("#N#", p2);
173 : } else {
174 0 : compare = compare_special_version_forms(p1, "#N#");
175 : }
176 : }
177 24621 : if (compare != 0) {
178 22783 : break;
179 : }
180 1838 : if (n1 != NULL) {
181 1613 : p1 = n1 + 1;
182 : }
183 1838 : if (n2 != NULL) {
184 1613 : p2 = n2 + 1;
185 : }
186 : }
187 23098 : if (compare == 0) {
188 315 : if (n1 != NULL) {
189 90 : if (isdigit(*p1)) {
190 0 : compare = 1;
191 : } else {
192 90 : compare = php_version_compare(p1, "#N#");
193 : }
194 225 : } else if (n2 != NULL) {
195 90 : if (isdigit(*p2)) {
196 0 : compare = -1;
197 : } else {
198 90 : compare = php_version_compare("#N#", p2);
199 : }
200 : }
201 : }
202 23098 : efree(ver1);
203 23098 : efree(ver2);
204 23098 : return compare;
205 : }
206 :
207 : /* }}} */
208 : /* {{{ proto int version_compare(string ver1, string ver2 [, string oper])
209 : Compares two "PHP-standardized" version number strings */
210 :
211 : PHP_FUNCTION(version_compare)
212 22918 : {
213 : char *v1, *v2, *op;
214 : int v1_len, v2_len, op_len;
215 : int compare, argc;
216 :
217 22918 : argc = ZEND_NUM_ARGS();
218 22918 : if (zend_parse_parameters(argc TSRMLS_CC, "ss|s", &v1, &v1_len, &v2,
219 : &v2_len, &op, &op_len) == FAILURE) {
220 0 : return;
221 : }
222 22918 : compare = php_version_compare(v1, v2);
223 22918 : if (argc == 2) {
224 22089 : RETURN_LONG(compare);
225 : }
226 829 : if (!strncmp(op, "<", op_len) || !strncmp(op, "lt", op_len)) {
227 238 : RETURN_BOOL(compare == -1);
228 : }
229 591 : if (!strncmp(op, "<=", op_len) || !strncmp(op, "le", op_len)) {
230 98 : RETURN_BOOL(compare != 1);
231 : }
232 493 : if (!strncmp(op, ">", op_len) || !strncmp(op, "gt", op_len)) {
233 98 : RETURN_BOOL(compare == 1);
234 : }
235 395 : if (!strncmp(op, ">=", op_len) || !strncmp(op, "ge", op_len)) {
236 101 : RETURN_BOOL(compare != -1);
237 : }
238 294 : if (!strncmp(op, "==", op_len) || !strncmp(op, "=", op_len) || !strncmp(op, "eq", op_len)) {
239 147 : RETURN_BOOL(compare == 0);
240 : }
241 147 : if (!strncmp(op, "!=", op_len) || !strncmp(op, "<>", op_len) || !strncmp(op, "ne", op_len)) {
242 147 : RETURN_BOOL(compare != 0);
243 : }
244 0 : RETURN_NULL();
245 : }
246 :
247 : /* }}} */
248 :
249 : /*
250 : * Local variables:
251 : * tab-width: 4
252 : * c-basic-offset: 4
253 : * indent-tabs-mode: t
254 : * End:
255 : */
|