#include #include #include static inline bool isspace(char c) { return (c == ' ') || (c == '\t') || (c == '\n'); } static inline bool isdigit(char c) { return (c >= '0') && (c <= '9'); } static inline bool isxdigit(char c) { return ((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F')); } static int parse_dec(int (*peek)(void *userp), void (*pop)(void *userp), void *userp, long *vp) { long v = 0; int n = 0; int minus = 0; char ch; if ((*peek)(userp) == '-') { (*pop)(userp); n++; minus = 1; } ch = (*peek)(userp); if (!isdigit(ch)) return -1; do { v = v * 10 + ch - '0'; (*pop)(userp); n++; ch = (*peek)(userp); } while (isdigit(ch)); *vp = minus ? -v : v; return n; } static int parse_hex(int (*peek)(void *userp), void (*pop)(void *userp), void *userp, unsigned long *vp) { unsigned long v = 0; int n = 0; char ch; ch = (*peek)(userp); if (!isxdigit(ch)) return -1; do { if (ch >= 'a') ch = ch - 'a' + 10; else if (ch >= 'A') ch = ch - 'A' + 10; else ch = ch - '0'; v = v * 16 + ch; (*pop)(userp); n++; ch = (*peek)(userp); } while (isxdigit(ch)); *vp = v; return n; } static int skip_spaces(int (*peek)(void *userp), void (*pop)(void *userp), void *userp) { int n = 0; while (isspace((*peek)(userp))) { n++; (*pop)(userp); } return n; } static int scan(int (*peek)(void *userp), void (*pop)(void *userp), void *userp, const char *fmt, va_list ap) { char ch; int n = 0; int n_chars = 0; int r; long lval; unsigned long ulval; while ((ch = *fmt++) != '\0') { bool literal = false; if (ch == '%') { ch = *fmt++; switch (ch) { case 'x': n_chars += skip_spaces(peek, pop, userp); if ((r = parse_hex(peek, pop, userp, &ulval)) >= 0) { *(va_arg(ap, unsigned int *)) = ulval; n++; n_chars += r; } else return n; break; case 'd': n_chars += skip_spaces(peek, pop, userp); if ((r = parse_dec(peek, pop, userp, &lval)) >= 0) { *(va_arg(ap, int *)) = lval; n++; n_chars += r; } else return n; break; case 'n': *(va_arg(ap, int *)) = n_chars; n++; break; case 'l': n_chars += skip_spaces(peek, pop, userp); ch = *fmt++; switch (ch) { case 'x': if ((r = parse_hex(peek, pop, userp, &ulval)) >= 0) { *(va_arg(ap, unsigned long *)) = ulval; n++; n_chars += r; } else return n; break; case 'd': if ((r = parse_dec(peek, pop, userp, &lval)) >= 0) { *(va_arg(ap, long *)) = lval; n++; n_chars += r; } else return n; break; case '\0': return n; default: literal = true; break; } break; case '\0': return n; default: literal = true; break; } } else literal = true; if (literal) { n_chars += skip_spaces(peek, pop, userp); if ((*peek)(userp) != ch) return n; else { (*pop)(userp); n_chars++; } } } return n; } static int sspeek(void *userp) { return **((char **)userp); } static void sspop(void *userp) { (*((char **)userp))++; } int sscanf(const char *s, const char *fmt, ...) { int r; va_list ap; const char *p; p = s; va_start(ap, fmt); r = scan(sspeek, sspop, &p, fmt, ap); va_end(ap); return r; }