Index: fusl/src/stdio/vfscanf.c |
diff --git a/fusl/src/stdio/vfscanf.c b/fusl/src/stdio/vfscanf.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d4d2454b08417de91621a40939c1970f9e42950a |
--- /dev/null |
+++ b/fusl/src/stdio/vfscanf.c |
@@ -0,0 +1,332 @@ |
+#include <stdlib.h> |
+#include <stdarg.h> |
+#include <ctype.h> |
+#include <wchar.h> |
+#include <wctype.h> |
+#include <limits.h> |
+#include <string.h> |
+#include <stdint.h> |
+ |
+#include "stdio_impl.h" |
+#include "shgetc.h" |
+#include "intscan.h" |
+#include "floatscan.h" |
+ |
+#define SIZE_hh -2 |
+#define SIZE_h -1 |
+#define SIZE_def 0 |
+#define SIZE_l 1 |
+#define SIZE_L 2 |
+#define SIZE_ll 3 |
+ |
+static void store_int(void *dest, int size, unsigned long long i) |
+{ |
+ if (!dest) return; |
+ switch (size) { |
+ case SIZE_hh: |
+ *(char *)dest = i; |
+ break; |
+ case SIZE_h: |
+ *(short *)dest = i; |
+ break; |
+ case SIZE_def: |
+ *(int *)dest = i; |
+ break; |
+ case SIZE_l: |
+ *(long *)dest = i; |
+ break; |
+ case SIZE_ll: |
+ *(long long *)dest = i; |
+ break; |
+ } |
+} |
+ |
+static void *arg_n(va_list ap, unsigned int n) |
+{ |
+ void *p; |
+ unsigned int i; |
+ va_list ap2; |
+ va_copy(ap2, ap); |
+ for (i=n; i>1; i--) va_arg(ap2, void *); |
+ p = va_arg(ap2, void *); |
+ va_end(ap2); |
+ return p; |
+} |
+ |
+int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) |
+{ |
+ int width; |
+ int size; |
+ int alloc; |
+ int base; |
+ const unsigned char *p; |
+ int c, t; |
+ char *s; |
+ wchar_t *wcs; |
+ mbstate_t st; |
+ void *dest=NULL; |
+ int invert; |
+ int matches=0; |
+ unsigned long long x; |
+ long double y; |
+ off_t pos = 0; |
+ unsigned char scanset[257]; |
+ size_t i, k; |
+ wchar_t wc; |
+ |
+ FLOCK(f); |
+ |
+ for (p=(const unsigned char *)fmt; *p; p++) { |
+ |
+ alloc = 0; |
+ |
+ if (isspace(*p)) { |
+ while (isspace(p[1])) p++; |
+ shlim(f, 0); |
+ while (isspace(shgetc(f))); |
+ shunget(f); |
+ pos += shcnt(f); |
+ continue; |
+ } |
+ if (*p != '%' || p[1] == '%') { |
+ p += *p=='%'; |
+ shlim(f, 0); |
+ c = shgetc(f); |
+ if (c!=*p) { |
+ shunget(f); |
+ if (c<0) goto input_fail; |
+ goto match_fail; |
+ } |
+ pos++; |
+ continue; |
+ } |
+ |
+ p++; |
+ if (*p=='*') { |
+ dest = 0; p++; |
+ } else if (isdigit(*p) && p[1]=='$') { |
+ dest = arg_n(ap, *p-'0'); p+=2; |
+ } else { |
+ dest = va_arg(ap, void *); |
+ } |
+ |
+ for (width=0; isdigit(*p); p++) { |
+ width = 10*width + *p - '0'; |
+ } |
+ |
+ if (*p=='m') { |
+ wcs = 0; |
+ s = 0; |
+ alloc = !!dest; |
+ p++; |
+ } else { |
+ alloc = 0; |
+ } |
+ |
+ size = SIZE_def; |
+ switch (*p++) { |
+ case 'h': |
+ if (*p == 'h') p++, size = SIZE_hh; |
+ else size = SIZE_h; |
+ break; |
+ case 'l': |
+ if (*p == 'l') p++, size = SIZE_ll; |
+ else size = SIZE_l; |
+ break; |
+ case 'j': |
+ size = SIZE_ll; |
+ break; |
+ case 'z': |
+ case 't': |
+ size = SIZE_l; |
+ break; |
+ case 'L': |
+ size = SIZE_L; |
+ break; |
+ case 'd': case 'i': case 'o': case 'u': case 'x': |
+ case 'a': case 'e': case 'f': case 'g': |
+ case 'A': case 'E': case 'F': case 'G': case 'X': |
+ case 's': case 'c': case '[': |
+ case 'S': case 'C': |
+ case 'p': case 'n': |
+ p--; |
+ break; |
+ default: |
+ goto fmt_fail; |
+ } |
+ |
+ t = *p; |
+ |
+ /* C or S */ |
+ if ((t&0x2f) == 3) { |
+ t |= 32; |
+ size = SIZE_l; |
+ } |
+ |
+ switch (t) { |
+ case 'c': |
+ if (width < 1) width = 1; |
+ case '[': |
+ break; |
+ case 'n': |
+ store_int(dest, size, pos); |
+ /* do not increment match count, etc! */ |
+ continue; |
+ default: |
+ shlim(f, 0); |
+ while (isspace(shgetc(f))); |
+ shunget(f); |
+ pos += shcnt(f); |
+ } |
+ |
+ shlim(f, width); |
+ if (shgetc(f) < 0) goto input_fail; |
+ shunget(f); |
+ |
+ switch (t) { |
+ case 's': |
+ case 'c': |
+ case '[': |
+ if (t == 'c' || t == 's') { |
+ memset(scanset, -1, sizeof scanset); |
+ scanset[0] = 0; |
+ if (t == 's') { |
+ scanset[1+'\t'] = 0; |
+ scanset[1+'\n'] = 0; |
+ scanset[1+'\v'] = 0; |
+ scanset[1+'\f'] = 0; |
+ scanset[1+'\r'] = 0; |
+ scanset[1+' '] = 0; |
+ } |
+ } else { |
+ if (*++p == '^') p++, invert = 1; |
+ else invert = 0; |
+ memset(scanset, invert, sizeof scanset); |
+ scanset[0] = 0; |
+ if (*p == '-') p++, scanset[1+'-'] = 1-invert; |
+ else if (*p == ']') p++, scanset[1+']'] = 1-invert; |
+ for (; *p != ']'; p++) { |
+ if (!*p) goto fmt_fail; |
+ if (*p=='-' && p[1] && p[1] != ']') |
+ for (c=p++[-1]; c<*p; c++) |
+ scanset[1+c] = 1-invert; |
+ scanset[1+*p] = 1-invert; |
+ } |
+ } |
+ wcs = 0; |
+ s = 0; |
+ i = 0; |
+ k = t=='c' ? width+1U : 31; |
+ if (size == SIZE_l) { |
+ if (alloc) { |
+ wcs = malloc(k*sizeof(wchar_t)); |
+ if (!wcs) goto alloc_fail; |
+ } else { |
+ wcs = dest; |
+ } |
+ st = (mbstate_t){0}; |
+ while (scanset[(c=shgetc(f))+1]) { |
+ switch (mbrtowc(&wc, &(char){c}, 1, &st)) { |
+ case -1: |
+ goto input_fail; |
+ case -2: |
+ continue; |
+ } |
+ if (wcs) wcs[i++] = wc; |
+ if (alloc && i==k) { |
+ k+=k+1; |
+ wchar_t *tmp = realloc(wcs, k*sizeof(wchar_t)); |
+ if (!tmp) goto alloc_fail; |
+ wcs = tmp; |
+ } |
+ } |
+ if (!mbsinit(&st)) goto input_fail; |
+ } else if (alloc) { |
+ s = malloc(k); |
+ if (!s) goto alloc_fail; |
+ while (scanset[(c=shgetc(f))+1]) { |
+ s[i++] = c; |
+ if (i==k) { |
+ k+=k+1; |
+ char *tmp = realloc(s, k); |
+ if (!tmp) goto alloc_fail; |
+ s = tmp; |
+ } |
+ } |
+ } else if ((s = dest)) { |
+ while (scanset[(c=shgetc(f))+1]) |
+ s[i++] = c; |
+ } else { |
+ while (scanset[(c=shgetc(f))+1]); |
+ } |
+ shunget(f); |
+ if (!shcnt(f)) goto match_fail; |
+ if (t == 'c' && shcnt(f) != width) goto match_fail; |
+ if (alloc) { |
+ if (size == SIZE_l) *(wchar_t **)dest = wcs; |
+ else *(char **)dest = s; |
+ } |
+ if (t != 'c') { |
+ if (wcs) wcs[i] = 0; |
+ if (s) s[i] = 0; |
+ } |
+ break; |
+ case 'p': |
+ case 'X': |
+ case 'x': |
+ base = 16; |
+ goto int_common; |
+ case 'o': |
+ base = 8; |
+ goto int_common; |
+ case 'd': |
+ case 'u': |
+ base = 10; |
+ goto int_common; |
+ case 'i': |
+ base = 0; |
+ int_common: |
+ x = __intscan(f, base, 0, ULLONG_MAX); |
+ if (!shcnt(f)) goto match_fail; |
+ if (t=='p' && dest) *(void **)dest = (void *)(uintptr_t)x; |
+ else store_int(dest, size, x); |
+ break; |
+ case 'a': case 'A': |
+ case 'e': case 'E': |
+ case 'f': case 'F': |
+ case 'g': case 'G': |
+ y = __floatscan(f, size, 0); |
+ if (!shcnt(f)) goto match_fail; |
+ if (dest) switch (size) { |
+ case SIZE_def: |
+ *(float *)dest = y; |
+ break; |
+ case SIZE_l: |
+ *(double *)dest = y; |
+ break; |
+ case SIZE_L: |
+ *(long double *)dest = y; |
+ break; |
+ } |
+ break; |
+ } |
+ |
+ pos += shcnt(f); |
+ if (dest) matches++; |
+ } |
+ if (0) { |
+fmt_fail: |
+alloc_fail: |
+input_fail: |
+ if (!matches) matches--; |
+match_fail: |
+ if (alloc) { |
+ free(s); |
+ free(wcs); |
+ } |
+ } |
+ FUNLOCK(f); |
+ return matches; |
+} |
+ |
+weak_alias(vfscanf,__isoc99_vfscanf); |