int vsscanf(const char * buf, const char * fmt, va_list ap) { const char * p = fmt; char ch; unsigned char uc; const char *q = buf; const char *qq; uintmax_t val = 0; int rank = rank_int; unsigned int width = INT_MAX; int base; enum flags flags = 0; enum { st_normal, /* Ground state */ st_flags, /* Special flags */ st_width, /* Field width */ st_modifiers, /* Length or conversion modifiers */ st_match_init, /* Initial state of %[ sequence */ st_match, /* Main state of %[ sequence */ st_match_range, /* After - in a %[ sequence */ } state = st_normal; char *sarg = NULL; /* %s %c or %[ string argument */ enum bail bail = bail_none; int converted = 0; /* Successful conversions */ unsigned long matchmap[((1 << 8) + ((8 * sizeof(long)) - 1)) / (8 * sizeof(long))]; int matchinv = 0; /* Is match map inverted? */ unsigned char range_start = 0; while ((ch = *p++) && !bail) { switch (state) { case st_normal: if (ch == '%') { state = st_flags; flags = 0; rank = rank_int; width = INT_MAX; } else if (isspace((unsigned char) ch)) { q = skipspace(q); } else { if (*q == ch) q++; else bail = bail_err; } break; case st_flags: switch (ch) { case '*': flags |= FL_SPLAT; break; case '0' ... '9': width = (ch - '0'); state = st_width; flags |= FL_WIDTH; break; default: state = st_modifiers; p--; /* Process this character again */ break; } break; case st_width: if (ch >= '0' && ch <= '9') { width = width * 10 + (ch - '0'); } else { state = st_modifiers; p--; /* Process this character again */ } break; case st_modifiers: switch (ch) { /* Length modifiers - nonterminal sequences */ case 'h': rank--; /* Shorter rank */ break; case 'l': rank++; /* Longer rank */ break; case 'j': rank = INTMAX_RANK; break; case 'z': rank = SIZE_T_RANK; break; case 't': rank = PTRDIFF_T_RANK; break; case 'L': case 'q': rank = rank_longlong; /* long double/long long */ break; default: /* Output modifiers - terminal sequences */ /* Next state will be normal */ state = st_normal; /* Canonicalize rank */ if (rank < MIN_RANK) rank = MIN_RANK; else if (rank > MAX_RANK) rank = MAX_RANK; switch (ch) { case 'P': /* Upper case pointer */ case 'p': /* Pointer */ rank = rank_ptr; base = 0; goto scan_int; case 'i': /* Base-independent integer */ base = 0; goto scan_int; case 'd': /* Decimal integer */ base = 10; goto scan_int; case 'o': /* Octal integer */ base = 8; goto scan_int; case 'u': /* Unsigned decimal integer */ base = 10; goto scan_int; case 'x': /* Hexadecimal integer */ case 'X': base = 16; goto scan_int; case 'n': /* # of characters consumed */ val = (q - buf); goto set_integer; scan_int: q = skipspace(q); if (!*q) { bail = bail_eof; break; } val = strntoumax(q, (char **)&qq, base, width); if (qq == q) { bail = bail_err; break; } q = qq; if (!(flags & FL_SPLAT)) converted++; set_integer: if (!(flags & FL_SPLAT)) { switch (rank) { case rank_char: *va_arg(ap, unsigned char *) = val; break; case rank_short: *va_arg(ap, unsigned short *) = val; break; case rank_int: *va_arg(ap, unsigned int *) = val; break; case rank_long: *va_arg(ap, unsigned long *) = val; break; case rank_longlong: *va_arg(ap, unsigned long long *) = val; break; case rank_ptr: *va_arg(ap, void **) = (void *) (uintptr_t) val; break; } } break; case 'c': /* Character */ width = (flags & FL_WIDTH) ? width : 1; if (flags & FL_SPLAT) { while (width--) { if (!*q) { bail = bail_eof; break; } } } else { sarg = va_arg(ap, char *); while (width--) { if (!*q) { bail = bail_eof; break; } *sarg++ = *q++; } if (!bail) converted++; } break; case 's': /* String */ uc = 1; /* Anything nonzero */ if (flags & FL_SPLAT) { while (width-- && (uc = *q) && !isspace(uc)) { q++; } } else { char *sp; sp = sarg = va_arg(ap, char *); while (width-- && (uc = *q) && !isspace(uc)) { *sp++ = uc; q++; } if (sarg != sp) { /* * Terminate output */ *sp = '\0'; converted++; } } if (!uc) bail = bail_eof; break; case '[': /* Character range */ sarg = (flags & FL_SPLAT) ? NULL : va_arg(ap, char *); state = st_match_init; matchinv = 0; memset(matchmap, 0, sizeof matchmap); break; case '%': /* %% sequence */ if (*q == '%') q++; else bail = bail_err; break; default: /* Anything else */ /* Unknown sequence */ bail = bail_err; break; } break; } break; case st_match_init: /* Initial state for %[ match */ if (ch == '^' && !(flags & FL_INV)) { matchinv = 1; } else { set_bit(matchmap, (unsigned char) ch); state = st_match; } break; case st_match: /* Main state for %[ match */ if (ch == ']') { goto match_run; } else if (ch == '-') { range_start = (unsigned char) ch; state = st_match_range; } else { set_bit(matchmap, (unsigned char) ch); } break; case st_match_range: /* %[ match after - */ if (ch == ']') { /* - was last character */ set_bit(matchmap, (unsigned char) '-'); goto match_run; } else { int i; for (i = range_start; i < (unsigned char) ch; i++) set_bit(matchmap, i); state = st_match; } break; match_run: /* Match expression finished */ qq = q; uc = 1; /* Anything nonzero */ while (width && (uc = *q) && (test_bit(matchmap, uc) ^ matchinv)) { if (sarg) *sarg++ = uc; q++; } if (q != qq && sarg) { *sarg = '\0'; converted++; } else { bail = bail_err; } if (!uc) bail = bail_eof; break; } } if (bail == bail_eof && !converted) converted = -1; return converted; }
TYPE NAME(const char *nptr, char **endptr, int base) { return (TYPE) strntoumax(nptr, endptr, base, ~(size_t) 0); }
intmax_t strtoimax(const char *nptr,char **endptr,int base) { return (intmax_t)strntoumax(nptr,endptr,base,~(size_t)0); }
intmax_t strntoimax(const char *nptr, char **endptr, int base, size_t n) { return (intmax_t) strntoumax(nptr, endptr, base, n); }
TYPE NAME(const char *nptr) { return (TYPE) strntoumax(nptr, (char **)NULL, 10, ~(size_t) 0); }