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