Annotation of embedaddon/php/ext/standard/versioning.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 1997-2012 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 321634 2012-01-01 13:15:04Z felipe $ */
! 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: {
! 36: int len = strlen(version);
! 37: char *buf = safe_emalloc(len, 2, 1), *q, lp, lq;
! 38: const char *p;
! 39:
! 40: if (len == 0) {
! 41: *buf = '\0';
! 42: return buf;
! 43: }
! 44:
! 45: p = version;
! 46: q = buf;
! 47: *q++ = lp = *p++;
! 48:
! 49: 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: lq = *(q - 1);
! 59: if (isspecialver(*p)) {
! 60: if (lq != '.') {
! 61: *q++ = '.';
! 62: }
! 63: } else if ((isndig(lp) && isdig(*p)) || (isdig(lp) && isndig(*p))) {
! 64: if (lq != '.') {
! 65: *q++ = '.';
! 66: }
! 67: *q++ = *p;
! 68: } else if (!isalnum(*p)) {
! 69: if (lq != '.') {
! 70: *q++ = '.';
! 71: }
! 72: } else {
! 73: *q++ = *p;
! 74: }
! 75: lp = *p++;
! 76: }
! 77: *q++ = '\0';
! 78: 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: {
! 92: 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: };
! 106: special_forms_t *pp;
! 107:
! 108: for (pp = special_forms; pp && pp->name; pp++) {
! 109: if (strncmp(form1, pp->name, strlen(pp->name)) == 0) {
! 110: found1 = pp->order;
! 111: break;
! 112: }
! 113: }
! 114: for (pp = special_forms; pp && pp->name; pp++) {
! 115: if (strncmp(form2, pp->name, strlen(pp->name)) == 0) {
! 116: found2 = pp->order;
! 117: break;
! 118: }
! 119: }
! 120: 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: {
! 129: char *ver1;
! 130: char *ver2;
! 131: char *p1, *p2, *n1, *n2;
! 132: long l1, l2;
! 133: int compare = 0;
! 134:
! 135: if (!*orig_ver1 || !*orig_ver2) {
! 136: if (!*orig_ver1 && !*orig_ver2) {
! 137: return 0;
! 138: } else {
! 139: return *orig_ver1 ? 1 : -1;
! 140: }
! 141: }
! 142: if (orig_ver1[0] == '#') {
! 143: ver1 = estrdup(orig_ver1);
! 144: } else {
! 145: ver1 = php_canonicalize_version(orig_ver1);
! 146: }
! 147: if (orig_ver2[0] == '#') {
! 148: ver2 = estrdup(orig_ver2);
! 149: } else {
! 150: ver2 = php_canonicalize_version(orig_ver2);
! 151: }
! 152: p1 = n1 = ver1;
! 153: p2 = n2 = ver2;
! 154: while (*p1 && *p2 && n1 && n2) {
! 155: if ((n1 = strchr(p1, '.')) != NULL) {
! 156: *n1 = '\0';
! 157: }
! 158: if ((n2 = strchr(p2, '.')) != NULL) {
! 159: *n2 = '\0';
! 160: }
! 161: if (isdigit(*p1) && isdigit(*p2)) {
! 162: /* compare element numerically */
! 163: l1 = strtol(p1, NULL, 10);
! 164: l2 = strtol(p2, NULL, 10);
! 165: compare = sign(l1 - l2);
! 166: } else if (!isdigit(*p1) && !isdigit(*p2)) {
! 167: /* compare element names */
! 168: compare = compare_special_version_forms(p1, p2);
! 169: } else {
! 170: /* mix of names and numbers */
! 171: if (isdigit(*p1)) {
! 172: compare = compare_special_version_forms("#N#", p2);
! 173: } else {
! 174: compare = compare_special_version_forms(p1, "#N#");
! 175: }
! 176: }
! 177: if (compare != 0) {
! 178: break;
! 179: }
! 180: if (n1 != NULL) {
! 181: p1 = n1 + 1;
! 182: }
! 183: if (n2 != NULL) {
! 184: p2 = n2 + 1;
! 185: }
! 186: }
! 187: if (compare == 0) {
! 188: if (n1 != NULL) {
! 189: if (isdigit(*p1)) {
! 190: compare = 1;
! 191: } else {
! 192: compare = php_version_compare(p1, "#N#");
! 193: }
! 194: } else if (n2 != NULL) {
! 195: if (isdigit(*p2)) {
! 196: compare = -1;
! 197: } else {
! 198: compare = php_version_compare("#N#", p2);
! 199: }
! 200: }
! 201: }
! 202: efree(ver1);
! 203: efree(ver2);
! 204: 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: {
! 213: char *v1, *v2, *op = NULL;
! 214: int v1_len, v2_len, op_len = 0;
! 215: int compare, argc;
! 216:
! 217: argc = ZEND_NUM_ARGS();
! 218: if (zend_parse_parameters(argc TSRMLS_CC, "ss|s", &v1, &v1_len, &v2,
! 219: &v2_len, &op, &op_len) == FAILURE) {
! 220: return;
! 221: }
! 222: compare = php_version_compare(v1, v2);
! 223: if (argc == 2) {
! 224: RETURN_LONG(compare);
! 225: }
! 226: if (!strncmp(op, "<", op_len) || !strncmp(op, "lt", op_len)) {
! 227: RETURN_BOOL(compare == -1);
! 228: }
! 229: if (!strncmp(op, "<=", op_len) || !strncmp(op, "le", op_len)) {
! 230: RETURN_BOOL(compare != 1);
! 231: }
! 232: if (!strncmp(op, ">", op_len) || !strncmp(op, "gt", op_len)) {
! 233: RETURN_BOOL(compare == 1);
! 234: }
! 235: if (!strncmp(op, ">=", op_len) || !strncmp(op, "ge", op_len)) {
! 236: RETURN_BOOL(compare != -1);
! 237: }
! 238: if (!strncmp(op, "==", op_len) || !strncmp(op, "=", op_len) || !strncmp(op, "eq", op_len)) {
! 239: RETURN_BOOL(compare == 0);
! 240: }
! 241: if (!strncmp(op, "!=", op_len) || !strncmp(op, "<>", op_len) || !strncmp(op, "ne", op_len)) {
! 242: RETURN_BOOL(compare != 0);
! 243: }
! 244: 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: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>