master
  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
 22static 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
 44static 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
 56int 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) {
325fmt_fail:
326alloc_fail:
327input_fail:
328		if (!matches) matches--;
329match_fail:
330		if (alloc) {
331			free(s);
332			free(wcs);
333		}
334	}
335	FUNLOCK(f);
336	return matches;
337}
338
339weak_alias(vfscanf,__isoc99_vfscanf);