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); }
/* * print variable/alias value using necessary quotes * (POSIX says they should be suitable for re-entry...) * No trailing newline is printed. */ void print_value_quoted(struct shf *shf, const char *s) { unsigned char c; const unsigned char *p = (const unsigned char *)s; bool inquote = true; /* first, check whether any quotes are needed */ while ((c = *p++) >= 32) if (ctype(c, C_QUOTE)) inquote = false; p = (const unsigned char *)s; if (c == 0) { if (inquote) { /* nope, use the shortcut */ shf_puts(s, shf); return; } /* otherwise, quote nicely via state machine */ while ((c = *p++) != 0) { if (c == '\'') { /* * multiple single quotes or any of them * at the beginning of a string look nicer * this way than when simply substituting */ if (inquote) { shf_putc('\'', shf); inquote = false; } shf_putc('\\', shf); } else if (!inquote) { shf_putc('\'', shf); inquote = true; } shf_putc(c, shf); } } else { unsigned int wc; size_t n; /* use $'...' quote format */ shf_putc('$', shf); shf_putc('\'', shf); while ((c = *p) != 0) { if (c >= 0xC2) { n = utf_mbtowc(&wc, (const char *)p); if (n != (size_t)-1) { p += n; shf_fprintf(shf, "\\u%04X", wc); continue; } } ++p; switch (c) { /* see unbksl() in this file for comments */ case 7: c = 'a'; if (0) /* FALLTHROUGH */ case '\b': c = 'b'; if (0) /* FALLTHROUGH */ case '\f': c = 'f'; if (0) /* FALLTHROUGH */ case '\n': c = 'n'; if (0) /* FALLTHROUGH */ case '\r': c = 'r'; if (0) /* FALLTHROUGH */ case '\t': c = 't'; if (0) /* FALLTHROUGH */ case 11: c = 'v'; if (0) /* FALLTHROUGH */ case '\033': /* take E not e because \e is \ in *roff */ c = 'E'; /* FALLTHROUGH */ case '\\': shf_putc('\\', shf); if (0) /* FALLTHROUGH */ default: if (c < 32 || c > 0x7E) { /* FALLTHROUGH */ case '\'': shf_fprintf(shf, "\\%03o", c); break; } shf_putc(c, shf); break; } } inquote = true; } if (inquote) shf_putc('\'', shf); }
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); }