diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | Src/builtin.c | 5 | ||||
-rw-r--r-- | Src/utils.c | 61 |
3 files changed, 71 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog index ae20911f9..24df71d49 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2018-01-31 Peter Stephenson <p.stephenson@samsung.com> + + * 42332: Src/builtin.c, Src/utils.c: special case printf for + unsigned integers by looking for constansts, avoiding conversion + to unsigned. + 2018-01-24 Daniel Hahler <zsh@thequod.de> * 42323: Completion/Unix/Command/_git: _git: move "local" statement diff --git a/Src/builtin.c b/Src/builtin.c index 0211f2721..fb59738f3 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -5243,7 +5243,10 @@ bin_print(char *name, char **args, Options ops, int func) *d++ = 'l'; #endif *d++ = 'l', *d++ = *c, *d = '\0'; - zulongval = (curarg) ? mathevali(curarg) : 0; + if (!curarg) + zulongval = (zulong)0; + else if (!zstrtoul_underscore(curarg, &zulongval)) + zulongval = mathevali(curarg); if (errflag) { zulongval = 0; errflag &= ~ERRFLAG_ERROR; diff --git a/Src/utils.c b/Src/utils.c index 74fdac31f..3b589aa35 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -2455,6 +2455,67 @@ zstrtol_underscore(const char *s, char **t, int base, int underscore) return neg ? -(zlong)calc : (zlong)calc; } +/* + * If s represents a complete unsigned integer (and nothing else) + * return 1 and set retval to the value. Otherwise return 0. + * + * Underscores are always allowed. + * + * Sensitive to OCTAL_ZEROES. + */ + +/**/ +mod_export int +zstrtoul_underscore(const char *s, zulong *retval) +{ + zulong calc = 0, newcalc = 0, base; + + if (*s == '+') + s++; + + if (*s != '0') + base = 10; + else if (*++s == 'x' || *s == 'X') + base = 16, s++; + else if (*s == 'b' || *s == 'B') + base = 2, s++; + else + base = isset(OCTALZEROES) ? 8 : 10; + if (base < 2 || base > 36) { + return 0; + } else if (base <= 10) { + for (; (*s >= '0' && *s < ('0' + base)) || + *s == '_'; s++) { + if (*s == '_') + continue; + newcalc = calc * base + *s - '0'; + if (newcalc < calc) + { + return 0; + } + calc = newcalc; + } + } else { + for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10)) + || (*s >= 'A' && *s < ('A' + base - 10)) + || *s == '_'; s++) { + if (*s == '_') + continue; + newcalc = calc*base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9); + if (newcalc < calc) + { + return 0; + } + calc = newcalc; + } + } + + if (*s) + return 0; + *retval = calc; + return 1; +} + /**/ mod_export int setblock_fd(int turnonblocking, int fd, long *modep) |