static int getint(struct tbl *vp, mksh_ari_u *nump, bool arith) { mksh_uari_t c, num = 0, base = 10; const char *s; bool have_base = false, neg = false; 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)) return (-1); if (vp->flag & INTEGER) { nump->i = vp->val.i; return (vp->type); } s = vp->val.s + vp->type; do { c = (unsigned char)*s++; } while (ksh_isspace(c)); switch (c) { case '-': neg = true; /* FALLTHROUGH */ case '+': c = (unsigned char)*s++; break; } if (c == '0' && arith) { if (ksh_eq(s[0], 'X', '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++; } } 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) wc = *(const unsigned char *)s; else if (utf_mbtowc(&wc, s) == (size_t)-1) /* OPTU-8 -> OPTU-16 */ /* * (with a twist: 1#\uEF80 converts * the same as 1#\x80 does, thus is * not round-tripping correctly XXX) */ wc = 0xEF00 + *(const unsigned char *)s; nump->u = (mksh_uari_t)wc; return (1); } else if (base > 36) base = 10; num = 0; have_base = true; continue; } if (ksh_isdigit(c)) c = ksh_numdig(c); else if (ksh_isupper(c)) c = ksh_numuc(c) + 10; else if (ksh_islower(c)) c = ksh_numlc(c) + 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; return (base); }
static int getint(struct tbl *vp, mksh_ari_t *nump, bool arith) { int c, base, neg; mksh_uari_t num; const char *s; bool have_base = false; if (vp->flag&SPECIAL) getspec(vp); /* XXX is it possible for ISSET to be set and val.s to be 0? */ if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL)) return (-1); if (vp->flag&INTEGER) { *nump = vp->val.i; return (vp->type); } s = vp->val.s + vp->type; base = 10; num = 0; neg = 0; if (arith && s[0] == '0' && (s[1] | 0x20) == 'x') { s += 2; base = 16; have_base = true; } #ifdef MKSH_LEGACY_MODE if (arith && s[0] == '0' && ksh_isdigit(s[1]) && !(vp->flag & ZEROFIL)) { /* interpret as octal (deprecated) */ base = 8; have_base = true; } #endif while ((c = *s++)) { if (c == '-') { neg++; continue; } else if (c == '#') { if (have_base || num < 1 || num > 36) return (-1); base = (int)num; if (base == 1) { unsigned int wc; if (!UTFMODE) wc = *(const unsigned char *)s; else if (utf_mbtowc(&wc, s) == (size_t)-1) /* OPTU-8 -> OPTU-16 */ /* * (with a twist: 1#\uEF80 converts * the same as 1#\x80 does, thus is * not round-tripping correctly XXX) */ wc = 0xEF00 + *(const unsigned char *)s; *nump = (mksh_ari_t)wc; return (1); } num = 0; have_base = true; continue; } else if (ksh_isdigit(c)) c -= '0'; else if (ksh_islower(c)) c -= 'a' - 10; else if (ksh_isupper(c)) c -= 'A' - 10; else return (-1); if (c < 0 || c >= base) return (-1); num = num * base + c; } *nump = neg ? -((mksh_ari_t)num) : (mksh_ari_t)num; return (base); }