summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Src/builtin.c5
-rw-r--r--Src/utils.c61
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)