php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
versioning.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Stig Sæther Bakken <ssb@php.net> |
14 +----------------------------------------------------------------------+
15 */
16
17#include <stdio.h>
18#include <sys/types.h>
19#include <ctype.h>
20#include <stdlib.h>
21#include <string.h>
22#include "php.h"
23#include "php_versioning.h"
24
25/* {{{ php_canonicalize_version() */
26
27PHPAPI char *
28php_canonicalize_version(const char *version)
29{
30 size_t len = strlen(version);
31 char *buf = safe_emalloc(len, 2, 1), *q, lp, lq;
32 const char *p;
33
34 if (len == 0) {
35 *buf = '\0';
36 return buf;
37 }
38
39 p = version;
40 q = buf;
41 *q++ = lp = *p++;
42
43 while (*p) {
44/* s/[-_+]/./g;
45 * s/([^\d\.])([^\D\.])/$1.$2/g;
46 * s/([^\D\.])([^\d\.])/$1.$2/g;
47 */
48#define isdig(x) (isdigit(x)&&(x)!='.')
49#define isndig(x) (!isdigit(x)&&(x)!='.')
50#define isspecialver(x) ((x)=='-'||(x)=='_'||(x)=='+')
51
52 lq = *(q - 1);
53 if (isspecialver(*p)) {
54 if (lq != '.') {
55 *q++ = '.';
56 }
57 } else if ((isndig(lp) && isdig(*p)) || (isdig(lp) && isndig(*p))) {
58 if (lq != '.') {
59 *q++ = '.';
60 }
61 *q++ = *p;
62 } else if (!isalnum(*p)) {
63 if (lq != '.') {
64 *q++ = '.';
65 }
66 } else {
67 *q++ = *p;
68 }
69 lp = *p++;
70 }
71 *q++ = '\0';
72 return buf;
73}
74
75/* }}} */
76/* {{{ compare_special_version_forms() */
77
78typedef struct {
79 const char *name;
80 uint8_t name_len;
81 int order;
83
84static int compare_special_version_forms(char *form1, char *form2)
85{
86 int found1 = -1, found2 = -1;
87 special_forms_t special_forms[11] = {
88 {ZEND_STRL("dev"), 0},
89 {ZEND_STRL("alpha"), 1},
90 {ZEND_STRL("a"), 1},
91 {ZEND_STRL("beta"), 2},
92 {ZEND_STRL("b"), 2},
93 {ZEND_STRL("RC"), 3},
94 {ZEND_STRL("rc"), 3},
95 {ZEND_STRL("#"), 4},
96 {ZEND_STRL("pl"), 5},
97 {ZEND_STRL("p"), 5},
98 {NULL, 0, 0},
99 };
100 special_forms_t *pp;
101
102 for (pp = special_forms; pp && pp->name; pp++) {
103 if (strncmp(form1, pp->name, pp->name_len) == 0) {
104 found1 = pp->order;
105 break;
106 }
107 }
108 for (pp = special_forms; pp && pp->name; pp++) {
109 if (strncmp(form2, pp->name, pp->name_len) == 0) {
110 found2 = pp->order;
111 break;
112 }
113 }
114 return ZEND_NORMALIZE_BOOL(found1 - found2);
115}
116
117/* }}} */
118/* {{{ php_version_compare() */
119
120PHPAPI int
121php_version_compare(const char *orig_ver1, const char *orig_ver2)
122{
123 char *ver1;
124 char *ver2;
125 char *p1, *p2, *n1, *n2;
126 long l1, l2;
127 int compare = 0;
128
129 if (!*orig_ver1 || !*orig_ver2) {
130 if (!*orig_ver1 && !*orig_ver2) {
131 return 0;
132 } else {
133 return *orig_ver1 ? 1 : -1;
134 }
135 }
136 if (orig_ver1[0] == '#') {
137 ver1 = estrdup(orig_ver1);
138 } else {
139 ver1 = php_canonicalize_version(orig_ver1);
140 }
141 if (orig_ver2[0] == '#') {
142 ver2 = estrdup(orig_ver2);
143 } else {
144 ver2 = php_canonicalize_version(orig_ver2);
145 }
146 p1 = n1 = ver1;
147 p2 = n2 = ver2;
148 while (*p1 && *p2 && n1 && n2) {
149 if ((n1 = strchr(p1, '.')) != NULL) {
150 *n1 = '\0';
151 }
152 if ((n2 = strchr(p2, '.')) != NULL) {
153 *n2 = '\0';
154 }
155 if (isdigit(*p1) && isdigit(*p2)) {
156 /* compare element numerically */
157 l1 = strtol(p1, NULL, 10);
158 l2 = strtol(p2, NULL, 10);
159 compare = ZEND_NORMALIZE_BOOL(l1 - l2);
160 } else if (!isdigit(*p1) && !isdigit(*p2)) {
161 /* compare element names */
162 compare = compare_special_version_forms(p1, p2);
163 } else {
164 /* mix of names and numbers */
165 if (isdigit(*p1)) {
166 compare = compare_special_version_forms("#N#", p2);
167 } else {
168 compare = compare_special_version_forms(p1, "#N#");
169 }
170 }
171 if (compare != 0) {
172 break;
173 }
174 if (n1 != NULL) {
175 p1 = n1 + 1;
176 }
177 if (n2 != NULL) {
178 p2 = n2 + 1;
179 }
180 }
181 if (compare == 0) {
182 if (n1 != NULL) {
183 if (isdigit(*p1)) {
184 compare = 1;
185 } else {
186 compare = php_version_compare(p1, "#N#");
187 }
188 } else if (n2 != NULL) {
189 if (isdigit(*p2)) {
190 compare = -1;
191 } else {
192 compare = php_version_compare("#N#", p2);
193 }
194 }
195 }
196 efree(ver1);
197 efree(ver2);
198 return compare;
199}
200
201/* }}} */
202/* {{{ Compares two "PHP-standardized" version number strings */
203
205{
206 char *v1, *v2;
207 zend_string *op = NULL;
208 size_t v1_len, v2_len;
209 int compare;
210
212 Z_PARAM_STRING(v1, v1_len)
213 Z_PARAM_STRING(v2, v2_len)
217
218 compare = php_version_compare(v1, v2);
219 if (!op) {
220 RETURN_LONG(compare);
221 }
222 if (zend_string_equals_literal(op, "<") || zend_string_equals_literal(op, "lt")) {
223 RETURN_BOOL(compare == -1);
224 }
225 if (zend_string_equals_literal(op, "<=") || zend_string_equals_literal(op, "le")) {
226 RETURN_BOOL(compare != 1);
227 }
228 if (zend_string_equals_literal(op, ">") || zend_string_equals_literal(op, "gt")) {
229 RETURN_BOOL(compare == 1);
230 }
231 if (zend_string_equals_literal(op, ">=") || zend_string_equals_literal(op, "ge")) {
232 RETURN_BOOL(compare != -1);
233 }
235 RETURN_BOOL(compare == 0);
236 }
238 RETURN_BOOL(compare != 0);
239 }
240
241 zend_argument_value_error(3, "must be a valid comparison operator");
242}
243
244/* }}} */
size_t len
Definition apprentice.c:174
version_compare(string $version1, string $version2, ?string $operator=null)
strchr(string $haystack, string $needle, bool $before_needle=false)
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
#define NULL
Definition gdcache.h:45
#define PHP_FUNCTION
Definition php.h:364
#define PHPAPI
Definition php.h:71
p
Definition session.c:1105
uint8_t name_len
Definition versioning.c:80
const char * name
Definition versioning.c:79
#define isndig(x)
#define isdig(x)
PHPAPI int php_version_compare(const char *orig_ver1, const char *orig_ver2)
Definition versioning.c:121
PHPAPI char * php_canonicalize_version(const char *version)
Definition versioning.c:28
#define isspecialver(x)
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:433
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define Z_PARAM_STR_OR_NULL(dest)
Definition zend_API.h:2089
#define Z_PARAM_OPTIONAL
Definition zend_API.h:1667
#define Z_PARAM_STRING(dest, dest_len)
Definition zend_API.h:2071
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define RETURN_BOOL(b)
Definition zend_API.h:1035
#define efree(ptr)
Definition zend_alloc.h:155
#define estrdup(s)
Definition zend_alloc.h:164
#define safe_emalloc(nmemb, size, offset)
Definition zend_alloc.h:154
strlen(string $string)
strncmp(string $string1, string $string2, int $length)
struct _zend_string zend_string
#define ZEND_NORMALIZE_BOOL(n)
#define ZEND_STRL(str)
#define zend_string_equals_literal(str, literal)