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