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