1570af302Sopenharmony_ci#include <stdlib.h> 2570af302Sopenharmony_ci#include <stdarg.h> 3570af302Sopenharmony_ci#include <ctype.h> 4570af302Sopenharmony_ci#include <wchar.h> 5570af302Sopenharmony_ci#include <wctype.h> 6570af302Sopenharmony_ci#include <limits.h> 7570af302Sopenharmony_ci#include <string.h> 8570af302Sopenharmony_ci#include <stdint.h> 9570af302Sopenharmony_ci 10570af302Sopenharmony_ci#include "stdio_impl.h" 11570af302Sopenharmony_ci#include "shgetc.h" 12570af302Sopenharmony_ci#include "intscan.h" 13570af302Sopenharmony_ci#include "floatscan.h" 14570af302Sopenharmony_ci 15570af302Sopenharmony_ci#define SIZE_hh -2 16570af302Sopenharmony_ci#define SIZE_h -1 17570af302Sopenharmony_ci#define SIZE_def 0 18570af302Sopenharmony_ci#define SIZE_l 1 19570af302Sopenharmony_ci#define SIZE_L 2 20570af302Sopenharmony_ci#define SIZE_ll 3 21570af302Sopenharmony_ci#define BUF_LEN 513 22570af302Sopenharmony_ci 23570af302Sopenharmony_ci#if (defined(MUSL_AARCH64_ARCH)) || (defined(MUSL_ARM_ARCH)) 24570af302Sopenharmony_ciextern int parsefloat(FILE *f, char *buf, char *end); 25570af302Sopenharmony_ci#endif 26570af302Sopenharmony_ci 27570af302Sopenharmony_cistatic void store_int(void *dest, int size, unsigned long long i) 28570af302Sopenharmony_ci{ 29570af302Sopenharmony_ci if (!dest) return; 30570af302Sopenharmony_ci switch (size) { 31570af302Sopenharmony_ci case SIZE_hh: 32570af302Sopenharmony_ci *(char *)dest = i; 33570af302Sopenharmony_ci break; 34570af302Sopenharmony_ci case SIZE_h: 35570af302Sopenharmony_ci *(short *)dest = i; 36570af302Sopenharmony_ci break; 37570af302Sopenharmony_ci case SIZE_def: 38570af302Sopenharmony_ci *(int *)dest = i; 39570af302Sopenharmony_ci break; 40570af302Sopenharmony_ci case SIZE_l: 41570af302Sopenharmony_ci *(long *)dest = i; 42570af302Sopenharmony_ci break; 43570af302Sopenharmony_ci case SIZE_ll: 44570af302Sopenharmony_ci *(long long *)dest = i; 45570af302Sopenharmony_ci break; 46570af302Sopenharmony_ci } 47570af302Sopenharmony_ci} 48570af302Sopenharmony_ci 49570af302Sopenharmony_cistatic void *arg_n(va_list ap, unsigned int n) 50570af302Sopenharmony_ci{ 51570af302Sopenharmony_ci void *p; 52570af302Sopenharmony_ci unsigned int i; 53570af302Sopenharmony_ci va_list ap2; 54570af302Sopenharmony_ci va_copy(ap2, ap); 55570af302Sopenharmony_ci for (i=n; i>1; i--) va_arg(ap2, void *); 56570af302Sopenharmony_ci p = va_arg(ap2, void *); 57570af302Sopenharmony_ci va_end(ap2); 58570af302Sopenharmony_ci return p; 59570af302Sopenharmony_ci} 60570af302Sopenharmony_ci 61570af302Sopenharmony_ciint vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) 62570af302Sopenharmony_ci{ 63570af302Sopenharmony_ci#if (defined(MUSL_AARCH64_ARCH)) || (defined(MUSL_ARM_ARCH)) 64570af302Sopenharmony_ci char buf[BUF_LEN]; 65570af302Sopenharmony_ci char *endptr; 66570af302Sopenharmony_ci#endif 67570af302Sopenharmony_ci int width; 68570af302Sopenharmony_ci int size; 69570af302Sopenharmony_ci int alloc = 0; 70570af302Sopenharmony_ci int base; 71570af302Sopenharmony_ci const unsigned char *p; 72570af302Sopenharmony_ci int c, t; 73570af302Sopenharmony_ci char *s; 74570af302Sopenharmony_ci wchar_t *wcs; 75570af302Sopenharmony_ci mbstate_t st; 76570af302Sopenharmony_ci void *dest=NULL; 77570af302Sopenharmony_ci int invert; 78570af302Sopenharmony_ci int matches=0; 79570af302Sopenharmony_ci unsigned long long x; 80570af302Sopenharmony_ci long double y; 81570af302Sopenharmony_ci off_t pos = 0; 82570af302Sopenharmony_ci unsigned char scanset[257]; 83570af302Sopenharmony_ci size_t i, k; 84570af302Sopenharmony_ci wchar_t wc; 85570af302Sopenharmony_ci 86570af302Sopenharmony_ci FLOCK(f); 87570af302Sopenharmony_ci 88570af302Sopenharmony_ci if (!f->rpos) __toread(f); 89570af302Sopenharmony_ci if (!f->rpos) goto input_fail; 90570af302Sopenharmony_ci 91570af302Sopenharmony_ci for (p=(const unsigned char *)fmt; *p; p++) { 92570af302Sopenharmony_ci 93570af302Sopenharmony_ci alloc = 0; 94570af302Sopenharmony_ci 95570af302Sopenharmony_ci if (isspace(*p)) { 96570af302Sopenharmony_ci while (isspace(p[1])) p++; 97570af302Sopenharmony_ci shlim(f, 0); 98570af302Sopenharmony_ci while (isspace(shgetc(f))); 99570af302Sopenharmony_ci shunget(f); 100570af302Sopenharmony_ci pos += shcnt(f); 101570af302Sopenharmony_ci continue; 102570af302Sopenharmony_ci } 103570af302Sopenharmony_ci if (*p != '%' || p[1] == '%') { 104570af302Sopenharmony_ci shlim(f, 0); 105570af302Sopenharmony_ci if (*p == '%') { 106570af302Sopenharmony_ci p++; 107570af302Sopenharmony_ci while (isspace((c=shgetc(f)))); 108570af302Sopenharmony_ci } else { 109570af302Sopenharmony_ci c = shgetc(f); 110570af302Sopenharmony_ci } 111570af302Sopenharmony_ci if (c!=*p) { 112570af302Sopenharmony_ci shunget(f); 113570af302Sopenharmony_ci if (c<0) goto input_fail; 114570af302Sopenharmony_ci goto match_fail; 115570af302Sopenharmony_ci } 116570af302Sopenharmony_ci pos += shcnt(f); 117570af302Sopenharmony_ci continue; 118570af302Sopenharmony_ci } 119570af302Sopenharmony_ci 120570af302Sopenharmony_ci p++; 121570af302Sopenharmony_ci if (*p=='*') { 122570af302Sopenharmony_ci dest = 0; p++; 123570af302Sopenharmony_ci } else if (isdigit(*p) && p[1]=='$') { 124570af302Sopenharmony_ci dest = arg_n(ap, *p-'0'); p+=2; 125570af302Sopenharmony_ci } else { 126570af302Sopenharmony_ci dest = va_arg(ap, void *); 127570af302Sopenharmony_ci } 128570af302Sopenharmony_ci 129570af302Sopenharmony_ci for (width=0; isdigit(*p); p++) { 130570af302Sopenharmony_ci width = 10*width + *p - '0'; 131570af302Sopenharmony_ci } 132570af302Sopenharmony_ci 133570af302Sopenharmony_ci if (*p=='m') { 134570af302Sopenharmony_ci wcs = 0; 135570af302Sopenharmony_ci s = 0; 136570af302Sopenharmony_ci alloc = !!dest; 137570af302Sopenharmony_ci p++; 138570af302Sopenharmony_ci } else { 139570af302Sopenharmony_ci alloc = 0; 140570af302Sopenharmony_ci } 141570af302Sopenharmony_ci 142570af302Sopenharmony_ci size = SIZE_def; 143570af302Sopenharmony_ci switch (*p++) { 144570af302Sopenharmony_ci case 'h': 145570af302Sopenharmony_ci if (*p == 'h') p++, size = SIZE_hh; 146570af302Sopenharmony_ci else size = SIZE_h; 147570af302Sopenharmony_ci break; 148570af302Sopenharmony_ci case 'l': 149570af302Sopenharmony_ci if (*p == 'l') p++, size = SIZE_ll; 150570af302Sopenharmony_ci else size = SIZE_l; 151570af302Sopenharmony_ci break; 152570af302Sopenharmony_ci case 'j': 153570af302Sopenharmony_ci size = SIZE_ll; 154570af302Sopenharmony_ci break; 155570af302Sopenharmony_ci case 'z': 156570af302Sopenharmony_ci case 't': 157570af302Sopenharmony_ci size = SIZE_l; 158570af302Sopenharmony_ci break; 159570af302Sopenharmony_ci case 'L': 160570af302Sopenharmony_ci size = SIZE_L; 161570af302Sopenharmony_ci break; 162570af302Sopenharmony_ci case 'd': case 'i': case 'o': case 'u': case 'x': 163570af302Sopenharmony_ci case 'a': case 'e': case 'f': case 'g': 164570af302Sopenharmony_ci case 'A': case 'E': case 'F': case 'G': case 'X': 165570af302Sopenharmony_ci case 's': case 'c': case '[': 166570af302Sopenharmony_ci case 'S': case 'C': 167570af302Sopenharmony_ci case 'p': case 'n': 168570af302Sopenharmony_ci p--; 169570af302Sopenharmony_ci break; 170570af302Sopenharmony_ci default: 171570af302Sopenharmony_ci goto fmt_fail; 172570af302Sopenharmony_ci } 173570af302Sopenharmony_ci 174570af302Sopenharmony_ci t = *p; 175570af302Sopenharmony_ci 176570af302Sopenharmony_ci /* C or S */ 177570af302Sopenharmony_ci if ((t&0x2f) == 3) { 178570af302Sopenharmony_ci t |= 32; 179570af302Sopenharmony_ci size = SIZE_l; 180570af302Sopenharmony_ci } 181570af302Sopenharmony_ci 182570af302Sopenharmony_ci switch (t) { 183570af302Sopenharmony_ci case 'c': 184570af302Sopenharmony_ci if (width < 1) width = 1; 185570af302Sopenharmony_ci case '[': 186570af302Sopenharmony_ci break; 187570af302Sopenharmony_ci case 'n': 188570af302Sopenharmony_ci store_int(dest, size, pos); 189570af302Sopenharmony_ci /* do not increment match count, etc! */ 190570af302Sopenharmony_ci continue; 191570af302Sopenharmony_ci default: 192570af302Sopenharmony_ci shlim(f, 0); 193570af302Sopenharmony_ci while (isspace(shgetc(f))); 194570af302Sopenharmony_ci shunget(f); 195570af302Sopenharmony_ci pos += shcnt(f); 196570af302Sopenharmony_ci } 197570af302Sopenharmony_ci 198570af302Sopenharmony_ci shlim(f, width); 199570af302Sopenharmony_ci if (shgetc(f) < 0) goto input_fail; 200570af302Sopenharmony_ci shunget(f); 201570af302Sopenharmony_ci 202570af302Sopenharmony_ci switch (t) { 203570af302Sopenharmony_ci case 's': 204570af302Sopenharmony_ci case 'c': 205570af302Sopenharmony_ci case '[': 206570af302Sopenharmony_ci if (t == 'c' || t == 's') { 207570af302Sopenharmony_ci memset(scanset, -1, sizeof scanset); 208570af302Sopenharmony_ci scanset[0] = 0; 209570af302Sopenharmony_ci if (t == 's') { 210570af302Sopenharmony_ci scanset[1+'\t'] = 0; 211570af302Sopenharmony_ci scanset[1+'\n'] = 0; 212570af302Sopenharmony_ci scanset[1+'\v'] = 0; 213570af302Sopenharmony_ci scanset[1+'\f'] = 0; 214570af302Sopenharmony_ci scanset[1+'\r'] = 0; 215570af302Sopenharmony_ci scanset[1+' '] = 0; 216570af302Sopenharmony_ci } 217570af302Sopenharmony_ci } else { 218570af302Sopenharmony_ci if (*++p == '^') p++, invert = 1; 219570af302Sopenharmony_ci else invert = 0; 220570af302Sopenharmony_ci memset(scanset, invert, sizeof scanset); 221570af302Sopenharmony_ci scanset[0] = 0; 222570af302Sopenharmony_ci if (*p == '-') p++, scanset[1+'-'] = 1-invert; 223570af302Sopenharmony_ci else if (*p == ']') p++, scanset[1+']'] = 1-invert; 224570af302Sopenharmony_ci for (; *p != ']'; p++) { 225570af302Sopenharmony_ci if (!*p) goto fmt_fail; 226570af302Sopenharmony_ci if (*p=='-' && p[1] && p[1] != ']') 227570af302Sopenharmony_ci for (c=p++[-1]; c<*p; c++) 228570af302Sopenharmony_ci scanset[1+c] = 1-invert; 229570af302Sopenharmony_ci scanset[1+*p] = 1-invert; 230570af302Sopenharmony_ci } 231570af302Sopenharmony_ci } 232570af302Sopenharmony_ci wcs = 0; 233570af302Sopenharmony_ci s = 0; 234570af302Sopenharmony_ci i = 0; 235570af302Sopenharmony_ci k = t=='c' ? width+1U : 31; 236570af302Sopenharmony_ci if (size == SIZE_l) { 237570af302Sopenharmony_ci if (alloc) { 238570af302Sopenharmony_ci wcs = malloc(k*sizeof(wchar_t)); 239570af302Sopenharmony_ci if (!wcs) goto alloc_fail; 240570af302Sopenharmony_ci } else { 241570af302Sopenharmony_ci wcs = dest; 242570af302Sopenharmony_ci } 243570af302Sopenharmony_ci st = (mbstate_t){0}; 244570af302Sopenharmony_ci while (scanset[(c=shgetc(f))+1]) { 245570af302Sopenharmony_ci switch (mbrtowc(&wc, &(char){c}, 1, &st)) { 246570af302Sopenharmony_ci case -1: 247570af302Sopenharmony_ci goto input_fail; 248570af302Sopenharmony_ci case -2: 249570af302Sopenharmony_ci continue; 250570af302Sopenharmony_ci } 251570af302Sopenharmony_ci if (wcs) wcs[i++] = wc; 252570af302Sopenharmony_ci if (alloc && i==k) { 253570af302Sopenharmony_ci k+=k+1; 254570af302Sopenharmony_ci wchar_t *tmp = realloc(wcs, k*sizeof(wchar_t)); 255570af302Sopenharmony_ci if (!tmp) goto alloc_fail; 256570af302Sopenharmony_ci wcs = tmp; 257570af302Sopenharmony_ci } 258570af302Sopenharmony_ci } 259570af302Sopenharmony_ci if (!mbsinit(&st)) goto input_fail; 260570af302Sopenharmony_ci } else if (alloc) { 261570af302Sopenharmony_ci s = malloc(k); 262570af302Sopenharmony_ci if (!s) goto alloc_fail; 263570af302Sopenharmony_ci while (scanset[(c=shgetc(f))+1]) { 264570af302Sopenharmony_ci s[i++] = c; 265570af302Sopenharmony_ci if (i==k) { 266570af302Sopenharmony_ci k+=k+1; 267570af302Sopenharmony_ci char *tmp = realloc(s, k); 268570af302Sopenharmony_ci if (!tmp) goto alloc_fail; 269570af302Sopenharmony_ci s = tmp; 270570af302Sopenharmony_ci } 271570af302Sopenharmony_ci } 272570af302Sopenharmony_ci } else if ((s = dest)) { 273570af302Sopenharmony_ci while (scanset[(c=shgetc(f))+1]) 274570af302Sopenharmony_ci s[i++] = c; 275570af302Sopenharmony_ci } else { 276570af302Sopenharmony_ci while (scanset[(c=shgetc(f))+1]); 277570af302Sopenharmony_ci } 278570af302Sopenharmony_ci shunget(f); 279570af302Sopenharmony_ci if (!shcnt(f)) goto match_fail; 280570af302Sopenharmony_ci if (t == 'c' && shcnt(f) != width) goto match_fail; 281570af302Sopenharmony_ci if (alloc) { 282570af302Sopenharmony_ci if (size == SIZE_l) *(wchar_t **)dest = wcs; 283570af302Sopenharmony_ci else *(char **)dest = s; 284570af302Sopenharmony_ci } 285570af302Sopenharmony_ci if (t != 'c') { 286570af302Sopenharmony_ci if (wcs) wcs[i] = 0; 287570af302Sopenharmony_ci if (s) s[i] = 0; 288570af302Sopenharmony_ci } 289570af302Sopenharmony_ci break; 290570af302Sopenharmony_ci case 'p': 291570af302Sopenharmony_ci case 'X': 292570af302Sopenharmony_ci case 'x': 293570af302Sopenharmony_ci base = 16; 294570af302Sopenharmony_ci goto int_common; 295570af302Sopenharmony_ci case 'o': 296570af302Sopenharmony_ci base = 8; 297570af302Sopenharmony_ci goto int_common; 298570af302Sopenharmony_ci case 'd': 299570af302Sopenharmony_ci case 'u': 300570af302Sopenharmony_ci base = 10; 301570af302Sopenharmony_ci goto int_common; 302570af302Sopenharmony_ci case 'i': 303570af302Sopenharmony_ci base = 0; 304570af302Sopenharmony_ci int_common: 305570af302Sopenharmony_ci x = __intscan(f, base, 0, ULLONG_MAX); 306570af302Sopenharmony_ci if (!shcnt(f)) goto match_fail; 307570af302Sopenharmony_ci if (t=='p' && dest) *(void **)dest = (void *)(uintptr_t)x; 308570af302Sopenharmony_ci else store_int(dest, size, x); 309570af302Sopenharmony_ci break; 310570af302Sopenharmony_ci case 'a': case 'A': 311570af302Sopenharmony_ci case 'e': case 'E': 312570af302Sopenharmony_ci case 'f': case 'F': 313570af302Sopenharmony_ci case 'g': case 'G': 314570af302Sopenharmony_ci#if (defined(MUSL_AARCH64_ARCH)) || (defined(MUSL_ARM_ARCH)) 315570af302Sopenharmony_ci if (width == 0 || width > sizeof(buf) - 1) 316570af302Sopenharmony_ci width = sizeof(buf) - 1; 317570af302Sopenharmony_ci int count = parsefloat(f, buf, buf + width); 318570af302Sopenharmony_ci if (count == 0) 319570af302Sopenharmony_ci goto match_fail; 320570af302Sopenharmony_ci if (dest) switch (size) { 321570af302Sopenharmony_ci case SIZE_def: 322570af302Sopenharmony_ci y = strtof(buf, &endptr); 323570af302Sopenharmony_ci *(float *)dest = y; 324570af302Sopenharmony_ci break; 325570af302Sopenharmony_ci case SIZE_l: 326570af302Sopenharmony_ci y = strtod(buf, &endptr); 327570af302Sopenharmony_ci *(double *)dest = y; 328570af302Sopenharmony_ci break; 329570af302Sopenharmony_ci case SIZE_L: 330570af302Sopenharmony_ci y = strtold(buf, &endptr); 331570af302Sopenharmony_ci *(long double *)dest = y; 332570af302Sopenharmony_ci break; 333570af302Sopenharmony_ci } 334570af302Sopenharmony_ci break; 335570af302Sopenharmony_ci } 336570af302Sopenharmony_ci#else 337570af302Sopenharmony_ci y = __floatscan(f, size, 0); 338570af302Sopenharmony_ci if (!shcnt(f)) goto match_fail; 339570af302Sopenharmony_ci if (dest) switch (size) { 340570af302Sopenharmony_ci case SIZE_def: 341570af302Sopenharmony_ci *(float *)dest = y; 342570af302Sopenharmony_ci break; 343570af302Sopenharmony_ci case SIZE_l: 344570af302Sopenharmony_ci *(double *)dest = y; 345570af302Sopenharmony_ci break; 346570af302Sopenharmony_ci case SIZE_L: 347570af302Sopenharmony_ci *(long double *)dest = y; 348570af302Sopenharmony_ci break; 349570af302Sopenharmony_ci } 350570af302Sopenharmony_ci break; 351570af302Sopenharmony_ci } 352570af302Sopenharmony_ci#endif 353570af302Sopenharmony_ci pos += shcnt(f); 354570af302Sopenharmony_ci if (dest) matches++; 355570af302Sopenharmony_ci } 356570af302Sopenharmony_ci if (0) { 357570af302Sopenharmony_cifmt_fail: 358570af302Sopenharmony_cialloc_fail: 359570af302Sopenharmony_ciinput_fail: 360570af302Sopenharmony_ci if (!matches) matches--; 361570af302Sopenharmony_cimatch_fail: 362570af302Sopenharmony_ci if (alloc) { 363570af302Sopenharmony_ci free(s); 364570af302Sopenharmony_ci free(wcs); 365570af302Sopenharmony_ci } 366570af302Sopenharmony_ci } 367570af302Sopenharmony_ci FUNLOCK(f); 368570af302Sopenharmony_ci return matches; 369570af302Sopenharmony_ci} 370570af302Sopenharmony_ci 371570af302Sopenharmony_ciweak_alias(vfscanf,__isoc99_vfscanf); 372