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