1#include <stdlib.h> 2#include <stdarg.h> 3#include <ctype.h> 4#include <wchar.h> 5#include <wctype.h> 6#include <limits.h> 7#include <string.h> 8#include <stdint.h> 9 10#include "stdio_impl.h" 11#include "shgetc.h" 12#include "intscan.h" 13#include "floatscan.h" 14 15#define SIZE_hh -2 16#define SIZE_h -1 17#define SIZE_def 0 18#define SIZE_l 1 19#define SIZE_L 2 20#define SIZE_ll 3 21#define BUF_LEN 513 22 23#if (defined(MUSL_AARCH64_ARCH)) || (defined(MUSL_ARM_ARCH)) 24extern int parsefloat(FILE *f, char *buf, char *end); 25#endif 26 27static void store_int(void *dest, int size, unsigned long long i) 28{ 29 if (!dest) return; 30 switch (size) { 31 case SIZE_hh: 32 *(char *)dest = i; 33 break; 34 case SIZE_h: 35 *(short *)dest = i; 36 break; 37 case SIZE_def: 38 *(int *)dest = i; 39 break; 40 case SIZE_l: 41 *(long *)dest = i; 42 break; 43 case SIZE_ll: 44 *(long long *)dest = i; 45 break; 46 } 47} 48 49static void *arg_n(va_list ap, unsigned int n) 50{ 51 void *p; 52 unsigned int i; 53 va_list ap2; 54 va_copy(ap2, ap); 55 for (i=n; i>1; i--) va_arg(ap2, void *); 56 p = va_arg(ap2, void *); 57 va_end(ap2); 58 return p; 59} 60 61int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) 62{ 63#if (defined(MUSL_AARCH64_ARCH)) || (defined(MUSL_ARM_ARCH)) 64 char buf[BUF_LEN]; 65 char *endptr; 66#endif 67 int width; 68 int size; 69 int alloc = 0; 70 int base; 71 const unsigned char *p; 72 int c, t; 73 char *s; 74 wchar_t *wcs; 75 mbstate_t st; 76 void *dest=NULL; 77 int invert; 78 int matches=0; 79 unsigned long long x; 80 long double y; 81 off_t pos = 0; 82 unsigned char scanset[257]; 83 size_t i, k; 84 wchar_t wc; 85 86 FLOCK(f); 87 88 if (!f->rpos) __toread(f); 89 if (!f->rpos) goto input_fail; 90 91 for (p=(const unsigned char *)fmt; *p; p++) { 92 93 alloc = 0; 94 95 if (isspace(*p)) { 96 while (isspace(p[1])) p++; 97 shlim(f, 0); 98 while (isspace(shgetc(f))); 99 shunget(f); 100 pos += shcnt(f); 101 continue; 102 } 103 if (*p != '%' || p[1] == '%') { 104 shlim(f, 0); 105 if (*p == '%') { 106 p++; 107 while (isspace((c=shgetc(f)))); 108 } else { 109 c = shgetc(f); 110 } 111 if (c!=*p) { 112 shunget(f); 113 if (c<0) goto input_fail; 114 goto match_fail; 115 } 116 pos += shcnt(f); 117 continue; 118 } 119 120 p++; 121 if (*p=='*') { 122 dest = 0; p++; 123 } else if (isdigit(*p) && p[1]=='$') { 124 dest = arg_n(ap, *p-'0'); p+=2; 125 } else { 126 dest = va_arg(ap, void *); 127 } 128 129 for (width=0; isdigit(*p); p++) { 130 width = 10*width + *p - '0'; 131 } 132 133 if (*p=='m') { 134 wcs = 0; 135 s = 0; 136 alloc = !!dest; 137 p++; 138 } else { 139 alloc = 0; 140 } 141 142 size = SIZE_def; 143 switch (*p++) { 144 case 'h': 145 if (*p == 'h') p++, size = SIZE_hh; 146 else size = SIZE_h; 147 break; 148 case 'l': 149 if (*p == 'l') p++, size = SIZE_ll; 150 else size = SIZE_l; 151 break; 152 case 'j': 153 size = SIZE_ll; 154 break; 155 case 'z': 156 case 't': 157 size = SIZE_l; 158 break; 159 case 'L': 160 size = SIZE_L; 161 break; 162 case 'd': case 'i': case 'o': case 'u': case 'x': 163 case 'a': case 'e': case 'f': case 'g': 164 case 'A': case 'E': case 'F': case 'G': case 'X': 165 case 's': case 'c': case '[': 166 case 'S': case 'C': 167 case 'p': case 'n': 168 p--; 169 break; 170 default: 171 goto fmt_fail; 172 } 173 174 t = *p; 175 176 /* C or S */ 177 if ((t&0x2f) == 3) { 178 t |= 32; 179 size = SIZE_l; 180 } 181 182 switch (t) { 183 case 'c': 184 if (width < 1) width = 1; 185 case '[': 186 break; 187 case 'n': 188 store_int(dest, size, pos); 189 /* do not increment match count, etc! */ 190 continue; 191 default: 192 shlim(f, 0); 193 while (isspace(shgetc(f))); 194 shunget(f); 195 pos += shcnt(f); 196 } 197 198 shlim(f, width); 199 if (shgetc(f) < 0) goto input_fail; 200 shunget(f); 201 202 switch (t) { 203 case 's': 204 case 'c': 205 case '[': 206 if (t == 'c' || t == 's') { 207 memset(scanset, -1, sizeof scanset); 208 scanset[0] = 0; 209 if (t == 's') { 210 scanset[1+'\t'] = 0; 211 scanset[1+'\n'] = 0; 212 scanset[1+'\v'] = 0; 213 scanset[1+'\f'] = 0; 214 scanset[1+'\r'] = 0; 215 scanset[1+' '] = 0; 216 } 217 } else { 218 if (*++p == '^') p++, invert = 1; 219 else invert = 0; 220 memset(scanset, invert, sizeof scanset); 221 scanset[0] = 0; 222 if (*p == '-') p++, scanset[1+'-'] = 1-invert; 223 else if (*p == ']') p++, scanset[1+']'] = 1-invert; 224 for (; *p != ']'; p++) { 225 if (!*p) goto fmt_fail; 226 if (*p=='-' && p[1] && p[1] != ']') 227 for (c=p++[-1]; c<*p; c++) 228 scanset[1+c] = 1-invert; 229 scanset[1+*p] = 1-invert; 230 } 231 } 232 wcs = 0; 233 s = 0; 234 i = 0; 235 k = t=='c' ? width+1U : 31; 236 if (size == SIZE_l) { 237 if (alloc) { 238 wcs = malloc(k*sizeof(wchar_t)); 239 if (!wcs) goto alloc_fail; 240 } else { 241 wcs = dest; 242 } 243 st = (mbstate_t){0}; 244 while (scanset[(c=shgetc(f))+1]) { 245 switch (mbrtowc(&wc, &(char){c}, 1, &st)) { 246 case -1: 247 goto input_fail; 248 case -2: 249 continue; 250 } 251 if (wcs) wcs[i++] = wc; 252 if (alloc && i==k) { 253 k+=k+1; 254 wchar_t *tmp = realloc(wcs, k*sizeof(wchar_t)); 255 if (!tmp) goto alloc_fail; 256 wcs = tmp; 257 } 258 } 259 if (!mbsinit(&st)) goto input_fail; 260 } else if (alloc) { 261 s = malloc(k); 262 if (!s) goto alloc_fail; 263 while (scanset[(c=shgetc(f))+1]) { 264 s[i++] = c; 265 if (i==k) { 266 k+=k+1; 267 char *tmp = realloc(s, k); 268 if (!tmp) goto alloc_fail; 269 s = tmp; 270 } 271 } 272 } else if ((s = dest)) { 273 while (scanset[(c=shgetc(f))+1]) 274 s[i++] = c; 275 } else { 276 while (scanset[(c=shgetc(f))+1]); 277 } 278 shunget(f); 279 if (!shcnt(f)) goto match_fail; 280 if (t == 'c' && shcnt(f) != width) goto match_fail; 281 if (alloc) { 282 if (size == SIZE_l) *(wchar_t **)dest = wcs; 283 else *(char **)dest = s; 284 } 285 if (t != 'c') { 286 if (wcs) wcs[i] = 0; 287 if (s) s[i] = 0; 288 } 289 break; 290 case 'p': 291 case 'X': 292 case 'x': 293 base = 16; 294 goto int_common; 295 case 'o': 296 base = 8; 297 goto int_common; 298 case 'd': 299 case 'u': 300 base = 10; 301 goto int_common; 302 case 'i': 303 base = 0; 304 int_common: 305 x = __intscan(f, base, 0, ULLONG_MAX); 306 if (!shcnt(f)) goto match_fail; 307 if (t=='p' && dest) *(void **)dest = (void *)(uintptr_t)x; 308 else store_int(dest, size, x); 309 break; 310 case 'a': case 'A': 311 case 'e': case 'E': 312 case 'f': case 'F': 313 case 'g': case 'G': 314#if (defined(MUSL_AARCH64_ARCH)) || (defined(MUSL_ARM_ARCH)) 315 if (width == 0 || width > sizeof(buf) - 1) 316 width = sizeof(buf) - 1; 317 int count = parsefloat(f, buf, buf + width); 318 if (count == 0) 319 goto match_fail; 320 if (dest) switch (size) { 321 case SIZE_def: 322 y = strtof(buf, &endptr); 323 *(float *)dest = y; 324 break; 325 case SIZE_l: 326 y = strtod(buf, &endptr); 327 *(double *)dest = y; 328 break; 329 case SIZE_L: 330 y = strtold(buf, &endptr); 331 *(long double *)dest = y; 332 break; 333 } 334 break; 335 } 336#else 337 y = __floatscan(f, size, 0); 338 if (!shcnt(f)) goto match_fail; 339 if (dest) switch (size) { 340 case SIZE_def: 341 *(float *)dest = y; 342 break; 343 case SIZE_l: 344 *(double *)dest = y; 345 break; 346 case SIZE_L: 347 *(long double *)dest = y; 348 break; 349 } 350 break; 351 } 352#endif 353 pos += shcnt(f); 354 if (dest) matches++; 355 } 356 if (0) { 357fmt_fail: 358alloc_fail: 359input_fail: 360 if (!matches) matches--; 361match_fail: 362 if (alloc) { 363 free(s); 364 free(wcs); 365 } 366 } 367 FUNLOCK(f); 368 return matches; 369} 370 371weak_alias(vfscanf,__isoc99_vfscanf); 372