github.com/afumu/libc@v0.0.6/musl/src/stdio/vfwscanf.c (about) 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <stdarg.h> 4 #include <ctype.h> 5 #include <wchar.h> 6 #include <wctype.h> 7 #include <limits.h> 8 #include <string.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 static int in_set(const wchar_t *set, int c) 57 { 58 int j; 59 const wchar_t *p = set; 60 if (*p == '-') { 61 if (c=='-') return 1; 62 p++; 63 } else if (*p == ']') { 64 if (c==']') return 1; 65 p++; 66 } 67 for (; *p && *p != ']'; p++) { 68 if (*p=='-' && p[1] && p[1] != ']') 69 for (j=p++[-1]; j<*p; j++) 70 if (c==j) return 1; 71 if (c==*p) return 1; 72 } 73 return 0; 74 } 75 76 #if 1 77 #undef getwc 78 #define getwc(f) \ 79 ((f)->rpos != (f)->rend && *(f)->rpos < 128 ? *(f)->rpos++ : (getwc)(f)) 80 81 #undef ungetwc 82 #define ungetwc(c,f) \ 83 ((f)->rend && (c)<128U ? *--(f)->rpos : ungetwc((c),(f))) 84 #endif 85 86 int vfwscanf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap) 87 { 88 int width; 89 int size; 90 int alloc; 91 const wchar_t *p; 92 int c, t; 93 char *s; 94 wchar_t *wcs; 95 void *dest=NULL; 96 int invert; 97 int matches=0; 98 off_t pos = 0, cnt; 99 static const char size_pfx[][3] = { "hh", "h", "", "l", "L", "ll" }; 100 char tmp[3*sizeof(int)+10]; 101 const wchar_t *set; 102 size_t i, k; 103 104 FLOCK(f); 105 106 fwide(f, 1); 107 108 for (p=fmt; *p; p++) { 109 110 alloc = 0; 111 112 if (iswspace(*p)) { 113 while (iswspace(p[1])) p++; 114 while (iswspace((c=getwc(f)))) pos++; 115 ungetwc(c, f); 116 continue; 117 } 118 if (*p != '%' || p[1] == '%') { 119 if (*p == '%') { 120 p++; 121 while (iswspace((c=getwc(f)))) pos++; 122 } else { 123 c = getwc(f); 124 } 125 if (c!=*p) { 126 ungetwc(c, f); 127 if (c<0) goto input_fail; 128 goto match_fail; 129 } 130 pos++; 131 continue; 132 } 133 134 p++; 135 if (*p=='*') { 136 dest = 0; p++; 137 } else if (iswdigit(*p) && p[1]=='$') { 138 dest = arg_n(ap, *p-'0'); p+=2; 139 } else { 140 dest = va_arg(ap, void *); 141 } 142 143 for (width=0; iswdigit(*p); p++) { 144 width = 10*width + *p - '0'; 145 } 146 147 if (*p=='m') { 148 wcs = 0; 149 s = 0; 150 alloc = !!dest; 151 p++; 152 } else { 153 alloc = 0; 154 } 155 156 size = SIZE_def; 157 switch (*p++) { 158 case 'h': 159 if (*p == 'h') p++, size = SIZE_hh; 160 else size = SIZE_h; 161 break; 162 case 'l': 163 if (*p == 'l') p++, size = SIZE_ll; 164 else size = SIZE_l; 165 break; 166 case 'j': 167 size = SIZE_ll; 168 break; 169 case 'z': 170 case 't': 171 size = SIZE_l; 172 break; 173 case 'L': 174 size = SIZE_L; 175 break; 176 case 'd': case 'i': case 'o': case 'u': case 'x': 177 case 'a': case 'e': case 'f': case 'g': 178 case 'A': case 'E': case 'F': case 'G': case 'X': 179 case 's': case 'c': case '[': 180 case 'S': case 'C': 181 case 'p': case 'n': 182 p--; 183 break; 184 default: 185 goto fmt_fail; 186 } 187 188 t = *p; 189 190 /* Transform S,C -> ls,lc */ 191 if ((t&0x2f)==3) { 192 size = SIZE_l; 193 t |= 32; 194 } 195 196 if (t != 'n') { 197 if (t != '[' && (t|32) != 'c') 198 while (iswspace((c=getwc(f)))) pos++; 199 else 200 c=getwc(f); 201 if (c < 0) goto input_fail; 202 ungetwc(c, f); 203 } 204 205 switch (t) { 206 case 'n': 207 store_int(dest, size, pos); 208 /* do not increment match count, etc! */ 209 continue; 210 211 case 's': 212 case 'c': 213 case '[': 214 if (t == 'c') { 215 if (width<1) width = 1; 216 invert = 1; 217 set = L""; 218 } else if (t == 's') { 219 invert = 1; 220 static const wchar_t spaces[] = { 221 ' ', '\t', '\n', '\r', 11, 12, 0x0085, 222 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 223 0x2006, 0x2008, 0x2009, 0x200a, 224 0x2028, 0x2029, 0x205f, 0x3000, 0 }; 225 set = spaces; 226 } else { 227 if (*++p == '^') p++, invert = 1; 228 else invert = 0; 229 set = p; 230 if (*p==']') p++; 231 while (*p!=']') { 232 if (!*p) goto fmt_fail; 233 p++; 234 } 235 } 236 237 s = (size == SIZE_def) ? dest : 0; 238 wcs = (size == SIZE_l) ? dest : 0; 239 240 int gotmatch = 0; 241 242 if (width < 1) width = -1; 243 244 i = 0; 245 if (alloc) { 246 k = t=='c' ? width+1U : 31; 247 if (size == SIZE_l) { 248 wcs = malloc(k*sizeof(wchar_t)); 249 if (!wcs) goto alloc_fail; 250 } else { 251 s = malloc(k); 252 if (!s) goto alloc_fail; 253 } 254 } 255 while (width) { 256 if ((c=getwc(f))<0) break; 257 if (in_set(set, c) == invert) 258 break; 259 if (wcs) { 260 wcs[i++] = c; 261 if (alloc && i==k) { 262 k += k+1; 263 wchar_t *tmp = realloc(wcs, k*sizeof(wchar_t)); 264 if (!tmp) goto alloc_fail; 265 wcs = tmp; 266 } 267 } else if (size != SIZE_l) { 268 int l = wctomb(s?s+i:tmp, c); 269 if (l<0) goto input_fail; 270 i += l; 271 if (alloc && i > k-4) { 272 k += k+1; 273 char *tmp = realloc(s, k); 274 if (!tmp) goto alloc_fail; 275 s = tmp; 276 } 277 } 278 pos++; 279 width-=(width>0); 280 gotmatch=1; 281 } 282 if (width) { 283 ungetwc(c, f); 284 if (t == 'c' || !gotmatch) goto match_fail; 285 } 286 287 if (alloc) { 288 if (size == SIZE_l) *(wchar_t **)dest = wcs; 289 else *(char **)dest = s; 290 } 291 if (t != 'c') { 292 if (wcs) wcs[i] = 0; 293 if (s) s[i] = 0; 294 } 295 break; 296 297 case 'd': case 'i': case 'o': case 'u': case 'x': 298 case 'a': case 'e': case 'f': case 'g': 299 case 'A': case 'E': case 'F': case 'G': case 'X': 300 case 'p': 301 if (width < 1) width = 0; 302 snprintf(tmp, sizeof tmp, "%.*s%.0d%s%c%%lln", 303 1+!dest, "%*", width, size_pfx[size+2], t); 304 cnt = 0; 305 if (fscanf(f, tmp, dest?dest:&cnt, &cnt) == -1) 306 goto input_fail; 307 else if (!cnt) 308 goto match_fail; 309 pos += cnt; 310 break; 311 default: 312 goto fmt_fail; 313 } 314 315 if (dest) matches++; 316 } 317 if (0) { 318 fmt_fail: 319 alloc_fail: 320 input_fail: 321 if (!matches) matches--; 322 match_fail: 323 if (alloc) { 324 free(s); 325 free(wcs); 326 } 327 } 328 FUNLOCK(f); 329 return matches; 330 } 331 332 weak_alias(vfwscanf,__isoc99_vfwscanf);