Back to index

php5  5.3.10
versioning.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Stig Sæther Bakken <ssb@php.net>                             |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: versioning.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #include <stdio.h>
00022 #include <sys/types.h>
00023 #include <ctype.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include "php.h"
00027 #include "php_versioning.h"
00028 
00029 #define sign(n) ((n)<0?-1:((n)>0?1:0))
00030 
00031 /* {{{ php_canonicalize_version() */
00032 
00033 PHPAPI char *
00034 php_canonicalize_version(const char *version)
00035 {
00036     int len = strlen(version);
00037     char *buf = safe_emalloc(len, 2, 1), *q, lp, lq;
00038     const char *p;
00039 
00040     if (len == 0) {
00041         *buf = '\0';
00042         return buf;
00043     }
00044 
00045     p = version;
00046     q = buf;
00047     *q++ = lp = *p++;
00048 
00049     while (*p) {
00050 /*  s/[-_+]/./g;
00051  *  s/([^\d\.])([^\D\.])/$1.$2/g;
00052  *  s/([^\D\.])([^\d\.])/$1.$2/g;
00053  */
00054 #define isdig(x) (isdigit(x)&&(x)!='.')
00055 #define isndig(x) (!isdigit(x)&&(x)!='.')
00056 #define isspecialver(x) ((x)=='-'||(x)=='_'||(x)=='+')
00057 
00058               lq = *(q - 1);
00059               if (isspecialver(*p)) {
00060                      if (lq != '.') {
00061                             *q++ = '.';
00062                      }
00063               } else if ((isndig(lp) && isdig(*p)) || (isdig(lp) && isndig(*p))) {
00064                      if (lq != '.') {
00065                             *q++ = '.';
00066                      }
00067                      *q++ = *p;
00068               } else if (!isalnum(*p)) {
00069                      if (lq != '.') {
00070                             *q++ = '.';
00071                      }
00072               } else {
00073                      *q++ = *p;
00074               }
00075               lp = *p++;
00076     }
00077     *q++ = '\0';
00078     return buf;
00079 }
00080 
00081 /* }}} */
00082 /* {{{ compare_special_version_forms() */
00083 
00084 typedef struct {
00085        const char *name;
00086        int order;
00087 } special_forms_t;
00088 
00089 static int
00090 compare_special_version_forms(char *form1, char *form2)
00091 {
00092        int found1 = -1, found2 = -1;
00093        special_forms_t special_forms[11] = {
00094               {"dev", 0},
00095               {"alpha", 1},
00096               {"a", 1},
00097               {"beta", 2},
00098               {"b", 2},
00099               {"RC", 3},
00100               {"rc", 3},
00101               {"#", 4},
00102               {"pl", 5},
00103               {"p", 5},
00104               {NULL, 0},
00105        };
00106        special_forms_t *pp;
00107 
00108        for (pp = special_forms; pp && pp->name; pp++) {
00109               if (strncmp(form1, pp->name, strlen(pp->name)) == 0) {
00110                      found1 = pp->order;
00111                      break;
00112               }
00113        }
00114        for (pp = special_forms; pp && pp->name; pp++) {
00115               if (strncmp(form2, pp->name, strlen(pp->name)) == 0) {
00116                      found2 = pp->order;
00117                      break;
00118               }
00119        }
00120        return sign(found1 - found2);
00121 }
00122 
00123 /* }}} */
00124 /* {{{ php_version_compare() */
00125 
00126 PHPAPI int
00127 php_version_compare(const char *orig_ver1, const char *orig_ver2)
00128 {
00129        char *ver1;
00130        char *ver2;
00131        char *p1, *p2, *n1, *n2;
00132        long l1, l2;
00133        int compare = 0;
00134 
00135        if (!*orig_ver1 || !*orig_ver2) {
00136               if (!*orig_ver1 && !*orig_ver2) {
00137                      return 0;
00138               } else {
00139                      return *orig_ver1 ? 1 : -1;
00140               }
00141        }
00142        if (orig_ver1[0] == '#') {
00143               ver1 = estrdup(orig_ver1);
00144        } else {
00145               ver1 = php_canonicalize_version(orig_ver1);
00146        }
00147        if (orig_ver2[0] == '#') {
00148               ver2 = estrdup(orig_ver2);
00149        } else {
00150               ver2 = php_canonicalize_version(orig_ver2);
00151        }
00152        p1 = n1 = ver1;
00153        p2 = n2 = ver2;
00154        while (*p1 && *p2 && n1 && n2) {
00155               if ((n1 = strchr(p1, '.')) != NULL) {
00156                      *n1 = '\0';
00157               }
00158               if ((n2 = strchr(p2, '.')) != NULL) {
00159                      *n2 = '\0';
00160               }
00161               if (isdigit(*p1) && isdigit(*p2)) {
00162                      /* compare element numerically */
00163                      l1 = strtol(p1, NULL, 10);
00164                      l2 = strtol(p2, NULL, 10);
00165                      compare = sign(l1 - l2);
00166               } else if (!isdigit(*p1) && !isdigit(*p2)) {
00167                      /* compare element names */
00168                      compare = compare_special_version_forms(p1, p2);
00169               } else {
00170                      /* mix of names and numbers */
00171                      if (isdigit(*p1)) {
00172                             compare = compare_special_version_forms("#N#", p2);
00173                      } else {
00174                             compare = compare_special_version_forms(p1, "#N#");
00175                      }
00176               }
00177               if (compare != 0) {
00178                      break;
00179               }
00180               if (n1 != NULL) {
00181                      p1 = n1 + 1;
00182               }
00183               if (n2 != NULL) {
00184                      p2 = n2 + 1;
00185               }
00186        }
00187        if (compare == 0) {
00188               if (n1 != NULL) {
00189                      if (isdigit(*p1)) {
00190                             compare = 1;
00191                      } else {
00192                             compare = php_version_compare(p1, "#N#");
00193                      }
00194               } else if (n2 != NULL) {
00195                      if (isdigit(*p2)) {
00196                             compare = -1;
00197                      } else {
00198                             compare = php_version_compare("#N#", p2);
00199                      }
00200               }
00201        }
00202        efree(ver1);
00203        efree(ver2);
00204        return compare;
00205 }
00206 
00207 /* }}} */
00208 /* {{{ proto int version_compare(string ver1, string ver2 [, string oper])
00209   Compares two "PHP-standardized" version number strings */
00210 
00211 PHP_FUNCTION(version_compare)
00212 {
00213        char *v1, *v2, *op = NULL;
00214        int v1_len, v2_len, op_len = 0;
00215        int compare, argc;
00216 
00217        argc = ZEND_NUM_ARGS();
00218        if (zend_parse_parameters(argc TSRMLS_CC, "ss|s", &v1, &v1_len, &v2,
00219                                                    &v2_len, &op, &op_len) == FAILURE) {
00220               return;
00221        }
00222        compare = php_version_compare(v1, v2);
00223        if (argc == 2) {
00224               RETURN_LONG(compare);
00225        }
00226        if (!strncmp(op, "<", op_len) || !strncmp(op, "lt", op_len)) {
00227               RETURN_BOOL(compare == -1);
00228        }
00229        if (!strncmp(op, "<=", op_len) || !strncmp(op, "le", op_len)) {
00230               RETURN_BOOL(compare != 1);
00231        }
00232        if (!strncmp(op, ">", op_len) || !strncmp(op, "gt", op_len)) {
00233               RETURN_BOOL(compare == 1);
00234        }
00235        if (!strncmp(op, ">=", op_len) || !strncmp(op, "ge", op_len)) {
00236               RETURN_BOOL(compare != -1);
00237        }
00238        if (!strncmp(op, "==", op_len) || !strncmp(op, "=", op_len) || !strncmp(op, "eq", op_len)) {
00239               RETURN_BOOL(compare == 0);
00240        }
00241        if (!strncmp(op, "!=", op_len) || !strncmp(op, "<>", op_len) || !strncmp(op, "ne", op_len)) {
00242               RETURN_BOOL(compare != 0);
00243        }
00244        RETURN_NULL();
00245 }
00246 
00247 /* }}} */
00248 
00249 /*
00250  * Local variables:
00251  * tab-width: 4
00252  * c-basic-offset: 4
00253  * indent-tabs-mode: t
00254  * End:
00255  */