/* parse a decimal number: returns 0 if string isn't a number, 1 otherwise */ int getn(const char *s, int *ai) { int i, c, rv = 0; bool neg = false; do { c = *s++; } while (ksh_isspace(c)); if (c == '-') { neg = true; c = *s++; } else if (c == '+') c = *s++; *ai = i = 0; do { if (!ksh_isdigit(c)) goto getn_out; i *= 10; if (i < *ai) /* overflow */ goto getn_out; i += c - '0'; *ai = i; } while ((c = *s++)); rv = 1; getn_out: if (neg) *ai = -*ai; return (rv); }
/* parse a decimal number: returns 0 if string isn't a number, 1 otherwise */ int getn(const char *s, int *ai) { char c; mksh_ari_u num; bool neg = false; num.u = 0; do { c = *s++; } while (ksh_isspace(c)); switch (c) { case '-': neg = true; /* FALLTHROUGH */ case '+': c = *s++; break; } do { if (!ksh_isdigit(c)) /* not numeric */ return (0); if (num.u > 214748364U) /* overflow on multiplication */ return (0); num.u = num.u * 10U + (unsigned int)ksh_numdig(c); /* now: num.u <= 2147483649U */ } while ((c = *s++)); if (num.u > (neg ? 2147483648U : 2147483647U)) /* overflow for signed 32-bit int */ return (0); if (neg) num.u = -num.u; *ai = num.i; return (1); }
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 char * formatstr(struct tbl *vp, const char *s) { int olen, nlen; char *p, *q; size_t psiz; olen = (int)utf_mbswidth(s); if (vp->flag & (RJUST|LJUST)) { if (!vp->u2.field) /* default field width */ vp->u2.field = olen; nlen = vp->u2.field; } else nlen = olen; p = alloc((psiz = nlen * /* MB_LEN_MAX */ 3 + 1), ATEMP); if (vp->flag & (RJUST|LJUST)) { int slen = olen, i = 0; if (vp->flag & RJUST) { const char *qq = s; int n = 0; while (i < slen) i += utf_widthadj(qq, &qq); /* strip trailing spaces (AT&T uses qq[-1] == ' ') */ while (qq > s && ksh_isspace(qq[-1])) { --qq; --slen; } if (vp->flag & ZEROFIL && vp->flag & INTEGER) { if (!s[0] || !s[1]) goto uhm_no; if (s[1] == '#') n = 2; else if (s[2] == '#') n = 3; uhm_no: if (vp->u2.field <= n) n = 0; } if (n) { memcpy(p, s, n); s += n; } while (slen > vp->u2.field) slen -= utf_widthadj(s, &s); if (vp->u2.field - slen) memset(p + n, (vp->flag & ZEROFIL) ? '0' : ' ', vp->u2.field - slen); slen -= n; shf_snprintf(p + vp->u2.field - slen, psiz - (vp->u2.field - slen), "%.*s", slen, s); } else { /* strip leading spaces/zeros */ while (ksh_isspace(*s)) s++; if (vp->flag & ZEROFIL) while (*s == '0') s++; shf_snprintf(p, nlen + 1, "%-*.*s", vp->u2.field, vp->u2.field, s); } } else memcpy(p, s, strlen(s) + 1); if (vp->flag & UCASEV_AL) { for (q = p; *q; q++) *q = ksh_toupper(*q); } else if (vp->flag & LCASEV) { for (q = p; *q; q++) *q = ksh_tolower(*q); } return (p); }
static int getsc_uu(void) { Source *s = source; int c; while ((c = *s->str++) == 0) { /* return 0 for EOF by default */ s->str = NULL; switch (s->type) { case SEOF: s->str = null; return (0); case SSTDIN: case SFILE: getsc_line(s); break; case SWSTR: break; case SSTRING: case SSTRINGCMDLINE: break; case SWORDS: s->start = s->str = *s->u.strv++; s->type = SWORDSEP; break; case SWORDSEP: if (*s->u.strv == NULL) { s->start = s->str = "\n"; s->type = SEOF; } else { s->start = s->str = " "; s->type = SWORDS; } break; case SALIAS: if (s->flags & SF_ALIASEND) { /* pass on an unused SF_ALIAS flag */ source = s->next; source->flags |= s->flags & SF_ALIAS; s = source; } else if (*s->u.tblp->val.s && (c = strnul(s->u.tblp->val.s)[-1], ksh_isspace(c))) { /* pop source stack */ source = s = s->next; /* * Note that this alias ended with a * space, enabling alias expansion on * the following word. */ s->flags |= SF_ALIAS; } else { /* * At this point, we need to keep the current * alias in the source list so recursive * aliases can be detected and we also need to * return the next character. Do this by * temporarily popping the alias to get the * next character and then put it back in the * source list with the SF_ALIASEND flag set. */ /* pop source stack */ source = s->next; source->flags |= s->flags & SF_ALIAS; c = getsc_uu(); if (c) { s->flags |= SF_ALIASEND; s->ugbuf[0] = c; s->ugbuf[1] = '\0'; s->start = s->str = s->ugbuf; s->next = source; source = s; } else { s = source; /* avoid reading EOF twice */ s->str = NULL; break; } } continue; case SREREAD: if (s->start != s->ugbuf) /* yuck */ afree(s->u.freeme, ATEMP); source = s = s->next; continue; } if (s->str == NULL) { s->type = SEOF; s->start = s->str = null; return ('\0'); } if (s->flags & SF_ECHO) { shf_puts(s->str, shl_out); shf_flush(shl_out); } } return (c); }