diff options
author | Peter Stephenson <pws@users.sourceforge.net> | 2004-08-16 09:52:56 +0000 |
---|---|---|
committer | Peter Stephenson <pws@users.sourceforge.net> | 2004-08-16 09:52:56 +0000 |
commit | 7d3220f2981c81dbd3cbde873c1bb4d540c92574 (patch) | |
tree | 42dc0190ace60c7558619a8a208612c5c4d03376 /Src/utils.c | |
parent | b8e6c82fab9d36e463fe32ed5b1a905c795919d5 (diff) | |
download | zsh-7d3220f2981c81dbd3cbde873c1bb4d540c92574.tar.gz zsh-7d3220f2981c81dbd3cbde873c1bb4d540c92574.tar.xz zsh-7d3220f2981c81dbd3cbde873c1bb4d540c92574.zip |
20251: integer conversion truncation
20258: save command status in prompt substitution update FAQ rename version to 4.2.1-dev-1
Diffstat (limited to 'Src/utils.c')
-rw-r--r-- | Src/utils.c | 51 |
1 files changed, 45 insertions, 6 deletions
diff --git a/Src/utils.c b/Src/utils.c index 678376eae..143855160 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1261,7 +1261,8 @@ skipparens(char inpar, char outpar, char **s) mod_export zlong zstrtol(const char *s, char **t, int base) { - zlong ret = 0; + const char *inp, *trunc = NULL; + zulong calc = 0, newcalc = 0; int neg; while (inblank(*s)) @@ -1280,16 +1281,54 @@ zstrtol(const char *s, char **t, int base) else base = 8; } + inp = s; if (base <= 10) - for (; *s >= '0' && *s < ('0' + base); s++) - ret = ret * base + *s - '0'; + for (; *s >= '0' && *s < ('0' + base); s++) { + if (trunc) + continue; + newcalc = calc * base + *s - '0'; + if (newcalc < calc) + { + trunc = s; + continue; + } + calc = newcalc; + } else for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10)) - || (*s >= 'A' && *s < ('A' + base - 10)); s++) - ret = ret * base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9); + || (*s >= 'A' && *s < ('A' + base - 10)); s++) { + if (trunc) + continue; + newcalc = calc*base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9); + if (newcalc < calc) + { + trunc = s; + continue; + } + calc = newcalc; + } + + /* + * Special case: check for a number that was just too long for + * signed notation. + * Extra special case: the lowest negative number would trigger + * the first test, but is actually representable correctly. + * This is a 1 in the top bit, all others zero, so test for + * that explicitly. + */ + if (!trunc && (zlong)calc < 0 && + (!neg || calc & ~((zulong)1 << (8*sizeof(zulong)-1)))) + { + trunc = s - 1; + calc /= base; + } + + if (trunc) + zwarn("number truncated after %d digits: %s", inp, trunc - inp); + if (t) *t = (char *)s; - return neg ? -ret : ret; + return neg ? -(zlong)calc : (zlong)calc; } /**/ |