1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
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 276986 2009-03-10 23:40:06Z helly $ */
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 59720 : {
36 59720 : int len = strlen(version);
37 59720 : char *buf = safe_emalloc(len, 2, 1), *q, lp, lq;
38 : const char *p;
39 :
40 59720 : if (len == 0) {
41 0 : *buf = '\0';
42 0 : return buf;
43 : }
44 :
45 59720 : p = version;
46 59720 : q = buf;
47 59720 : *q++ = lp = *p++;
48 :
49 572475 : 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 453035 : lq = *(q - 1);
59 506751 : if (isspecialver(*p)) {
60 53716 : if (lq != '.') {
61 53716 : *q++ = '.';
62 : }
63 401419 : } else if ((isndig(lp) && isdig(*p)) || (isdig(lp) && isndig(*p))) {
64 2100 : if (lq != '.') {
65 2100 : *q++ = '.';
66 : }
67 2100 : *q++ = *p;
68 397219 : } else if (!isalnum(*p)) {
69 117643 : if (lq != '.') {
70 117643 : *q++ = '.';
71 : }
72 : } else {
73 279576 : *q++ = *p;
74 : }
75 453035 : lp = *p++;
76 : }
77 59720 : *q++ = '\0';
78 59720 : return buf;
79 : }
80 :
81 : /* }}} */
82 :
83 : /* {{{ compare_special_version_forms() */
84 :
85 : typedef struct {
86 : const char *name;
87 : int order;
88 : } special_forms_t;
89 :
90 : static int
91 : compare_special_version_forms(char *form1, char *form2)
92 25065 : {
93 25065 : int found1 = -1, found2 = -1;
94 : special_forms_t special_forms[11] = {
95 : {"dev", 0},
96 : {"alpha", 1},
97 : {"a", 1},
98 : {"beta", 2},
99 : {"b", 2},
100 : {"RC", 3},
101 : {"rc", 3},
102 : {"#", 4},
103 : {"pl", 5},
104 : {"p", 5},
105 : {NULL, 0},
106 25065 : };
107 : special_forms_t *pp;
108 :
109 28320 : for (pp = special_forms; pp && pp->name; pp++) {
110 28320 : if (strncmp(form1, pp->name, strlen(pp->name)) == 0) {
111 25065 : found1 = pp->order;
112 25065 : break;
113 : }
114 : }
115 28320 : for (pp = special_forms; pp && pp->name; pp++) {
116 28320 : if (strncmp(form2, pp->name, strlen(pp->name)) == 0) {
117 25065 : found2 = pp->order;
118 25065 : break;
119 : }
120 : }
121 25065 : return sign(found1 - found2);
122 : }
123 :
124 : /* }}} */
125 :
126 : /* {{{ php_version_compare() */
127 :
128 : PHPAPI int
129 : php_version_compare(const char *orig_ver1, const char *orig_ver2)
130 29952 : {
131 : char *ver1;
132 : char *ver2;
133 : char *p1, *p2, *n1, *n2;
134 : long l1, l2;
135 29952 : int compare = 0;
136 :
137 29952 : if (!*orig_ver1 || !*orig_ver2) {
138 2 : if (!*orig_ver1 && !*orig_ver2) {
139 0 : return 0;
140 : } else {
141 2 : return *orig_ver1 ? 1 : -1;
142 : }
143 : }
144 29950 : if (orig_ver1[0] == '#') {
145 90 : ver1 = estrdup(orig_ver1);
146 : } else {
147 29860 : ver1 = php_canonicalize_version(orig_ver1);
148 : }
149 29950 : if (orig_ver2[0] == '#') {
150 90 : ver2 = estrdup(orig_ver2);
151 : } else {
152 29860 : ver2 = php_canonicalize_version(orig_ver2);
153 : }
154 29950 : p1 = n1 = ver1;
155 29950 : p2 = n2 = ver2;
156 159103 : while (*p1 && *p2 && n1 && n2) {
157 104431 : if ((n1 = strchr(p1, '.')) != NULL) {
158 79675 : *n1 = '\0';
159 : }
160 104431 : if ((n2 = strchr(p2, '.')) != NULL) {
161 79615 : *n2 = '\0';
162 : }
163 183797 : if (isdigit(*p1) && isdigit(*p2)) {
164 : /* compare element numerically */
165 79366 : l1 = strtol(p1, NULL, 10);
166 79366 : l2 = strtol(p2, NULL, 10);
167 79366 : compare = sign(l1 - l2);
168 50130 : } else if (!isdigit(*p1) && !isdigit(*p2)) {
169 : /* compare element names */
170 25065 : compare = compare_special_version_forms(p1, p2);
171 : } else {
172 : /* mix of names and numbers */
173 0 : if (isdigit(*p1)) {
174 0 : compare = compare_special_version_forms("#N#", p2);
175 : } else {
176 0 : compare = compare_special_version_forms(p1, "#N#");
177 : }
178 : }
179 104431 : if (compare != 0) {
180 5228 : break;
181 : }
182 99203 : if (n1 != NULL) {
183 74632 : p1 = n1 + 1;
184 : }
185 99203 : if (n2 != NULL) {
186 74571 : p2 = n2 + 1;
187 : }
188 : }
189 29950 : if (compare == 0) {
190 24722 : if (n1 != NULL) {
191 151 : if (isdigit(*p1)) {
192 61 : compare = 1;
193 : } else {
194 90 : compare = php_version_compare(p1, "#N#");
195 : }
196 24571 : } else if (n2 != NULL) {
197 90 : if (isdigit(*p2)) {
198 0 : compare = -1;
199 : } else {
200 90 : compare = php_version_compare("#N#", p2);
201 : }
202 : }
203 : }
204 29950 : efree(ver1);
205 29950 : efree(ver2);
206 29950 : return compare;
207 : }
208 :
209 : /* }}} */
210 :
211 : /* {{{ proto int version_compare(string ver1, string ver2 [, string oper]) U
212 : Compares two "PHP-standardized" version number strings */
213 :
214 : PHP_FUNCTION(version_compare)
215 29772 : {
216 29772 : char *v1, *v2, *op = NULL;
217 29772 : int v1_len, v2_len, op_len = 0;
218 : int compare, argc;
219 :
220 29772 : argc = ZEND_NUM_ARGS();
221 29772 : if (zend_parse_parameters(argc TSRMLS_CC, "ss|s", &v1, &v1_len, &v2,
222 : &v2_len, &op, &op_len) == FAILURE) {
223 0 : return;
224 : }
225 29772 : compare = php_version_compare(v1, v2);
226 29772 : if (argc == 2) {
227 24482 : RETURN_LONG(compare);
228 : }
229 5290 : if (!strncmp(op, "<", op_len) || !strncmp(op, "lt", op_len)) {
230 296 : RETURN_BOOL(compare == -1);
231 : }
232 4994 : if (!strncmp(op, "<=", op_len) || !strncmp(op, "le", op_len)) {
233 98 : RETURN_BOOL(compare != 1);
234 : }
235 4896 : if (!strncmp(op, ">", op_len) || !strncmp(op, "gt", op_len)) {
236 4499 : RETURN_BOOL(compare == 1);
237 : }
238 397 : if (!strncmp(op, ">=", op_len) || !strncmp(op, "ge", op_len)) {
239 103 : RETURN_BOOL(compare != -1);
240 : }
241 294 : if (!strncmp(op, "==", op_len) || !strncmp(op, "=", op_len) || !strncmp(op, "eq", op_len)) {
242 147 : RETURN_BOOL(compare == 0);
243 : }
244 147 : if (!strncmp(op, "!=", op_len) || !strncmp(op, "<>", op_len) || !strncmp(op, "ne", op_len)) {
245 147 : RETURN_BOOL(compare != 0);
246 : }
247 0 : RETURN_NULL();
248 : }
249 :
250 : /* }}} */
251 :
252 : /*
253 : * Local variables:
254 : * tab-width: 4
255 : * c-basic-offset: 4
256 : * indent-tabs-mode: t
257 : * End:
258 : */
|