From a2a4e419752d5c50a3879019145caa0b91042941 Mon Sep 17 00:00:00 2001 From: tg Date: Sun, 19 Apr 2015 18:13:31 +0000 Subject: [PATCH] make var.c:getint() more like misc.c:getn(), except for the API differences: getn() parses a decimal 32-bit integer, getint() a POSIX- or ksh-style based integer with unsigned wraparound to 32 bit, then possible negation (so that, for example, -0xFFFFFFFF continues to work) --- var.c | 75 +++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/var.c b/var.c index caebb0e..0b2990f 100644 --- a/var.c +++ b/var.c @@ -28,7 +28,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/var.c,v 1.188 2015/04/19 14:22:09 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/var.c,v 1.189 2015/04/19 18:13:31 tg Exp $"); /*- * Variables @@ -481,41 +481,57 @@ setint(struct tbl *vq, mksh_ari_t n) static int getint(struct tbl *vp, mksh_ari_u *nump, bool arith) { - mksh_uari_t c, num, base; + mksh_uari_t c, num = 0, base = 10; const char *s; bool have_base = false, neg = false; - if (vp->flag&SPECIAL) + if (vp->flag & SPECIAL) getspec(vp); /* XXX is it possible for ISSET to be set and val.s to be NULL? */ - if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL)) + if (!(vp->flag & ISSET) || (!(vp->flag & INTEGER) && vp->val.s == NULL)) return (-1); - if (vp->flag&INTEGER) { + if (vp->flag & INTEGER) { nump->i = vp->val.i; return (vp->type); } s = vp->val.s + vp->type; - base = 10; - num = 0; - if (arith && s[0] == '0' && (s[1] | 0x20) == 'x') { - s += 2; - base = 16; - have_base = true; + + do { + c = (unsigned char)*s++; + } while (ksh_isspace(c)); + + switch (c) { + case '-': + neg = true; + /* FALLTHROUGH */ + case '+': + c = (unsigned char)*s++; + break; } - if (Flag(FPOSIX) && arith && s[0] == '0' && ksh_isdigit(s[1]) && - !(vp->flag & ZEROFIL)) { - /* interpret as octal (deprecated) */ - base = 8; - have_base = true; + + if (c == '0' && arith) { + if ((s[0] | 0x20) == 'x') { + /* interpret as hexadecimal */ + base = 16; + ++s; + goto getint_c_style_base; + } else if (Flag(FPOSIX) && ksh_isdigit(s[0]) && + !(vp->flag & ZEROFIL)) { + /* interpret as octal (deprecated) */ + base = 8; + getint_c_style_base: + have_base = true; + c = (unsigned char)*s++; + } } - while ((c = (unsigned char)*s++)) { - if (c == '-') { - neg = true; - continue; - } else if (c == '#') { + + do { + if (c == '#') { + /* ksh-style base determination */ if (have_base || num < 1) return (-1); if ((base = num) == 1) { + /* mksh-specific extension */ unsigned int wc; if (!UTFMODE) @@ -535,18 +551,21 @@ getint(struct tbl *vp, mksh_ari_u *nump, bool arith) num = 0; have_base = true; continue; - } else if (ksh_isdigit(c)) + } + if (ksh_isdigit(c)) c -= '0'; - else if (ksh_islower(c)) + else { + c |= 0x20; + if (!ksh_islower(c)) + return (-1); c -= 'a' - 10; - else if (ksh_isupper(c)) - c -= 'A' - 10; - else - return (-1); + } if (c >= base) return (-1); + /* handle overflow as truncation */ num = num * base + c; - } + } while ((c = (unsigned char)*s++)); + if (neg) num = -num; nump->u = num;