about summary refs log tree commit diff
path: root/Src/utils.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2012-09-11 16:02:41 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2012-09-11 16:02:41 +0000
commite550c98d69a270a9c6623fe1fd602b5081f4b46c (patch)
tree40facf8ba2d330dc9e6c5a2a101ddac398563818 /Src/utils.c
parentd88365d964cb521097f70efb21935a776659a7ed (diff)
downloadzsh-e550c98d69a270a9c6623fe1fd602b5081f4b46c.tar.gz
zsh-e550c98d69a270a9c6623fe1fd602b5081f4b46c.tar.xz
zsh-e550c98d69a270a9c6623fe1fd602b5081f4b46c.zip
30647, 30649: allow underscores in numeric constants
Diffstat (limited to 'Src/utils.c')
-rw-r--r--Src/utils.c28
1 files changed, 19 insertions, 9 deletions
diff --git a/Src/utils.c b/Src/utils.c
index d35ca1dfd..cadb06f61 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -2030,13 +2030,20 @@ skipparens(char inpar, char outpar, char **s)
    return level;
 }
 
+/**/
+mod_export zlong
+zstrtol(const char *s, char **t, int base)
+{
+    return zstrtol_underscore(s, t, base, 0);
+}
+
 /* Convert string to zlong (see zsh.h).  This function (without the z) *
  * is contained in the ANSI standard C library, but a lot of them seem *
  * to be broken.                                                       */
 
 /**/
 mod_export zlong
-zstrtol(const char *s, char **t, int base)
+zstrtol_underscore(const char *s, char **t, int base, int underscore)
 {
     const char *inp, *trunc = NULL;
     zulong calc = 0, newcalc = 0;
@@ -2062,22 +2069,24 @@ zstrtol(const char *s, char **t, int base)
     if (base < 2 || base > 36) {
 	zerr("invalid base (must be 2 to 36 inclusive): %d", base);
 	return (zlong)0;
-    } else if (base <= 10)
-	for (; *s >= '0' && *s < ('0' + base); s++) {
-	    if (trunc)
+    } else if (base <= 10) {
+	for (; (*s >= '0' && *s < ('0' + base)) ||
+		 (underscore && *s == '_'); s++) {
+	    if (trunc || *s == '_')
 		continue;
 	    newcalc = calc * base + *s - '0';
 	    if (newcalc < calc)
 	    {
-	      trunc = s;
-	      continue;
+		trunc = s;
+		continue;
 	    }
 	    calc = newcalc;
 	}
-    else
+    } else {
 	for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10))
-	     || (*s >= 'A' && *s < ('A' + base - 10)); s++) {
-	    if (trunc)
+	     || (*s >= 'A' && *s < ('A' + base - 10))
+	     || (underscore && *s == '_'); s++) {
+	    if (trunc || *s == '_')
 		continue;
 	    newcalc = calc*base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9);
 	    if (newcalc < calc)
@@ -2087,6 +2096,7 @@ zstrtol(const char *s, char **t, int base)
 	    }
 	    calc = newcalc;
 	}
+    }
 
     /*
      * Special case: check for a number that was just too long for