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);