]> granicus.if.org Git - php/commitdiff
Implemented ++ and -- operations for unicode strings
authorDmitry Stogov <dmitry@php.net>
Wed, 27 Jun 2007 10:27:04 +0000 (10:27 +0000)
committerDmitry Stogov <dmitry@php.net>
Wed, 27 Jun 2007 10:27:04 +0000 (10:27 +0000)
Zend/tests/decrement_001.phpt
Zend/tests/decrement_001_64bit.phpt
Zend/tests/increment_001.phpt
Zend/zend_operators.c

index 6ade8ad1639d2c3df0986ee88384cf59b50783c2..6449187a34405900bec64ca428c02643e1ee3202 100644 (file)
@@ -58,3 +58,29 @@ array(0) {
 float(-2147483649)
 float(-2147483649)
 Done
+--UEXPECTF--   
+array(3) {
+  [0]=>
+  int(1)
+  [1]=>
+  int(2)
+  [2]=>
+  int(3)
+}
+int(-1)
+int(0)
+float(1.5)
+int(-1)
+unicode(6) "string"
+int(122)
+float(1.5)
+NULL
+bool(true)
+bool(false)
+object(stdClass)#%d (0) {
+}
+array(0) {
+}
+float(-2147483649)
+float(-2147483649)
+Done
index 7ad24b76f736949003e6ffb861c4a6fd0e3a9945..2e79d76c851c1863d7ee2f33c7c4508399f7a110 100644 (file)
@@ -58,3 +58,29 @@ array(0) {
 float(-9.2233720368548E+18)
 float(-9.2233720368548E+18)
 Done
+--UEXPECTF--   
+array(3) {
+  [0]=>
+  int(1)
+  [1]=>
+  int(2)
+  [2]=>
+  int(3)
+}
+int(-1)
+int(0)
+float(1.5)
+int(-1)
+unicode(6) "string"
+int(122)
+float(1.5)
+NULL
+bool(true)
+bool(false)
+object(stdClass)#%d (0) {
+}
+array(0) {
+}
+float(-9.2233720368548E+18)
+float(-9.2233720368548E+18)
+Done
index 3638474971a2d4de4284b2d33d5bcb07ee1d99ec..fa524664f36ab4dacd84837a3d1fc15b33f75a9e 100644 (file)
@@ -58,3 +58,29 @@ array(0) {
 float(2147483648)
 float(2147483648)
 Done
+--UEXPECTF--   
+array(3) {
+  [0]=>
+  int(1)
+  [1]=>
+  int(2)
+  [2]=>
+  int(3)
+}
+unicode(1) "1"
+int(2)
+float(3.5)
+int(1)
+unicode(6) "strinh"
+int(124)
+float(3.5)
+int(1)
+bool(true)
+bool(false)
+object(stdClass)#%d (0) {
+}
+array(0) {
+}
+float(2147483648)
+float(2147483648)
+Done
index acecc561097f7c35d0def1d44ffb91fd73ce2e21..e245150a624d8225eff9c3b42c8a7b2bb2ddeb12 100644 (file)
@@ -2274,6 +2274,80 @@ static void increment_string(zval *str)
     }
 }
 
+static void increment_unicode(zval *str)
+{
+    int carry=0;
+    int pos=Z_USTRLEN_P(str)-1;
+    UChar *s=Z_USTRVAL_P(str);
+    UChar *t;
+    int last=0; /* Shut up the compiler warning */
+    int ch;
+
+       if (Z_USTRLEN_P(str) == 0) {
+               USTR_FREE(Z_USTRVAL_P(str));
+               ZVAL_ASCII_STRINGL(str, "1", sizeof("1")-1, 1);
+               return;
+       }
+
+       while (pos >= 0) {
+        ch = s[pos];
+        if (ch >= 'a' && ch <= 'z') {
+            if (ch == 'z') {
+                s[pos] = 'a';
+                carry=1;
+            } else {
+                s[pos]++;
+                carry=0;
+            }
+            last=LOWER_CASE;
+        } else if (ch >= 'A' && ch <= 'Z') {
+            if (ch == 'Z') {
+                s[pos] = 'A';
+                carry=1;
+            } else {
+                s[pos]++;
+                carry=0;
+            }
+            last=UPPER_CASE;
+        } else if (ch >= '0' && ch <= '9') {
+            if (ch == '9') {
+                s[pos] = '0';
+                carry=1;
+            } else {
+                s[pos]++;
+                carry=0;
+            }
+            last = NUMERIC;
+        } else {
+            carry=0;
+            break;
+        }
+        if (carry == 0) {
+            break;
+        }
+        pos--;
+    }
+
+    if (carry) {
+        t = (UChar *) eumalloc(Z_USTRLEN_P(str)+1+1);
+        memcpy(t+1, Z_USTRVAL_P(str), UBYTES(Z_USTRLEN_P(str)));
+        Z_USTRLEN_P(str)++;
+        t[Z_USTRLEN_P(str)] = 0;
+        switch (last) {
+            case NUMERIC:
+               t[0] = '1';
+               break;
+            case UPPER_CASE:
+               t[0] = 'A';
+               break;
+            case LOWER_CASE:
+               t[0] = 'a';
+               break;
+        }
+        USTR_FREE(Z_USTRVAL_P(str));
+        Z_USTRVAL_P(str) = t;
+    }
+}
 
 ZEND_API int increment_function(zval *op1)
 {
@@ -2323,8 +2397,34 @@ ZEND_API int increment_function(zval *op1)
                                }
                        }
                        break;
-               case IS_UNICODE:
-                       zend_error(E_ERROR, "Unsupported operand type");
+               case IS_UNICODE: {
+                               long lval;
+                               double dval;
+                               UChar *ustrval = Z_USTRVAL_P(op1);
+
+                               switch (is_numeric_unicode(ustrval, Z_USTRLEN_P(op1), &lval, &dval, 0)) {
+                                       case IS_LONG:
+                                               if (lval == LONG_MAX) {
+                                                       /* switch to double */
+                                                       double d = (double)lval;
+                                                       ZVAL_DOUBLE(op1, d+1);
+                                               } else {
+                                               Z_LVAL_P(op1) = lval+1;
+                                               Z_TYPE_P(op1) = IS_LONG;
+                                               }
+                                               efree(ustrval); /* should never be empty_string */
+                                               break;
+                                       case IS_DOUBLE:
+                                               Z_DVAL_P(op1) = dval+1;
+                                               Z_TYPE_P(op1) = IS_DOUBLE;
+                                               efree(ustrval); /* should never be empty_string */
+                                               break;
+                                       default:
+                                               /* Perl style string increment */
+                                               increment_unicode(op1);
+                                               break;
+                               }
+                       }
                        break;
                default:
                        return FAILURE;
@@ -2376,7 +2476,29 @@ ZEND_API int decrement_function(zval *op1)
                        }
                        break;
                case IS_UNICODE:
-                       zend_error(E_ERROR, "Unsupported operand type");
+                       if (Z_USTRLEN_P(op1) == 0) { /* consider as 0 */
+                               USTR_FREE(Z_USTRVAL_P(op1));
+                               Z_LVAL_P(op1) = -1;
+                               Z_TYPE_P(op1) = IS_LONG;
+                               break;
+                       }
+                       switch (is_numeric_unicode(Z_USTRVAL_P(op1), Z_USTRLEN_P(op1), &lval, &dval, 0)) {
+                               case IS_LONG:
+                                       USTR_FREE(Z_USTRVAL_P(op1));
+                                       if (lval == LONG_MIN) {
+                                               double d = (double)lval;
+                                               ZVAL_DOUBLE(op1, d-1);
+                                       } else {
+                                               Z_LVAL_P(op1) = lval-1;
+                                               Z_TYPE_P(op1) = IS_LONG;
+                                       }
+                                       break;
+                               case IS_DOUBLE:
+                                       USTR_FREE(Z_USTRVAL_P(op1));
+                                       Z_DVAL_P(op1) = dval - 1;
+                                       Z_TYPE_P(op1) = IS_DOUBLE;
+                                       break;
+                       }
                        break;
                default:
                        return FAILURE;