vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

vfscanf.c (4229B)


      1 #include <stdio.h>
      2 #include <stdarg.h>
      3 #include <inttypes.h>
      4 #include <stdlib.h>
      5 
      6 #include "ioprivate.h"
      7 
      8 typedef unsigned char		uchar;
      9 
     10 static void skipspace(FILE *fin)
     11 {
     12 	int c;
     13 	
     14 	while ((c = fgetc(fin)) != EOF) {
     15 		if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
     16 			continue;
     17 		ungetc(c, fin);
     18 		break;
     19 	}
     20 }
     21 
     22 // Main function to format and print a string.
     23 int vfscanf(FILE *fin, const char *fmt, va_list ap)
     24 {
     25 	char *p;
     26 	int ch, c;
     27 	int nout = 0;
     28 	int off0;
     29 	int sign;
     30 
     31 	off0 = ftell(fin);
     32 	unsigned long long ull;
     33 
     34 	for (;;) {
     35 		while ((ch = *(uchar *) fmt++) != '%') {
     36 			if (ch == '\0')
     37 				return nout;
     38 			if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') {
     39 				skipspace(fin);
     40 				continue;
     41 			}
     42 			if ((c = fgetc(fin)) != ch) {
     43 				ungetc(c, fin);
     44 				break;
     45 			}
     46 		}
     47 
     48 		// Process a %-escape sequence
     49 		int flag[256];
     50 		int width = 0;
     51 
     52 	reswitch:
     53 		switch (ch = *(uchar *) fmt++) {
     54 		case '*':
     55 		case 'h':
     56 		case 'l':
     57 		case 'L':
     58 		case 'j':
     59 		case 't':
     60 		case 'z':
     61 		case 'q':
     62 			flag[ch]++;
     63 			goto reswitch;
     64 
     65 		// width field
     66 		case '1':
     67 		case '2':
     68 		case '3':
     69 		case '4':
     70 		case '5':
     71 		case '6':
     72 		case '7':
     73 		case '8':
     74 		case '9':
     75 		case '0':
     76 			for (width = 0;; ++fmt) {
     77 				width = width * 10 + ch - '0';
     78 				ch = *fmt;
     79 				if (ch < '0' || ch > '9')
     80 					break;
     81 			}
     82 			goto reswitch;
     83 
     84 		// character
     85 		case '%':
     86 			skipspace(fin);
     87 			if ((c = fgetc(fin)) != '%') {
     88 				ungetc(c, fin);
     89 				return nout;
     90 			}
     91 			break;
     92 		
     93 		case 'n':
     94 			*va_arg(ap, int*) = ftell(fin) - off0;
     95 			nout++;
     96 			break;
     97 			
     98 		case 'd':
     99 		case 'u':
    100 			// optionally signed decimal
    101 			sign = 1;
    102 			c = fgetc(fin);
    103 			if (c == '-'){
    104 				sign = -1;
    105 				c = fgetc(fin);
    106 			}else if (c == '+'){
    107 				sign = 1;
    108 				c = fgetc(fin);
    109 			}
    110 			if (c < '0' || '9' < c) {
    111 				ungetc(c, fin);
    112 				return nout;
    113 			}
    114 		decimal:
    115 			ull = 0;
    116 			while ('0' <= c && c <= '9') {
    117 				ull = 10 * ull + c - '0';
    118 				c = fgetc(fin);
    119 			}
    120 			ungetc(c, fin);
    121 		assign:
    122 			if(sign < 0)
    123 				ull = -ull;
    124 			if(flag['h'] == 2)
    125 				*va_arg(ap, char*) = ull;
    126 			else if(flag['h'] == 1)
    127 				*va_arg(ap, short*) = ull;
    128 			else if(flag['l'] == 1)
    129 				*va_arg(ap, long*) = ull;
    130 			else if(flag['l'] == 2)
    131 				*va_arg(ap, long long*) = ull;
    132 			else
    133 				*va_arg(ap, int*) = ull;
    134 			nout++;
    135 			break;
    136 		
    137 		case 'i':
    138 			// optionally signed integer
    139 			c = fgetc(fin);
    140 			sign = 1;
    141 			if (c == '-'){
    142 				sign = -1;
    143 				c = fgetc(fin);
    144 			}else if (c == '+'){
    145 				sign = 1;
    146 				c = fgetc(fin);
    147 			}
    148 			if (c < '0' || '9' < c) {
    149 				ungetc(c, fin);
    150 				return nout;
    151 			}
    152 			if (c == '0') {
    153 				c = fgetc(fin);
    154 				if (c == 'x') {
    155 					c = fgetc(fin);
    156 					if (('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'))
    157 						goto hex;
    158 					return nout;
    159 				}
    160 				if ('0' <= c && c <= '7')
    161 					goto octal;
    162 			}
    163 			goto decimal;
    164 		
    165 		case 'o':
    166 			// octal
    167 			sign = 1;
    168 			c = fgetc(fin);
    169 			if (c < '0' || '7' < c) {
    170 				ungetc(c, fin);
    171 				return nout;
    172 			}
    173 		octal:
    174 			ull = 0;
    175 			while ('0' <= c && c <= '7') {
    176 				ull = 8 * ull + c - '0';
    177 				c = fgetc(fin);
    178 			}
    179 			ungetc(c, fin);
    180 			goto assign;
    181 
    182 		case 'x':
    183 		case 'X':
    184 			// optionally signed integer
    185 		case 'p':
    186 			// pointer value
    187 			sign = 1;
    188 			c = fgetc(fin);
    189 			if (c == '-'){
    190 				sign = -1;
    191 				c = fgetc(fin);
    192 			}else if (c == '+'){
    193 				sign = 1;
    194 				c = fgetc(fin);
    195 			}
    196 			if ((c < '0' || '9' < c) && (c < 'a' || 'z' < c) && (c < 'A' || 'Z' < c)) {
    197 				ungetc(c, fin);
    198 				return nout;
    199 			}
    200 		hex:
    201 			ull = 0;
    202 			for (;; c = fgetc(fin)) {
    203 				if ('0' <= c && c <= '9')
    204 					ull = 16 * ull + c - '0';
    205 				else if ('a' <= c && c <= 'f')
    206 					ull = 16 * ull + c - 'a' + 10;
    207 				else if ('A' <= c && c <= 'F')
    208 					ull = 16 * ull + c - 'A' + 10;
    209 				else
    210 					break;
    211 			}
    212 			ungetc(c, fin);
    213 			goto assign;
    214 			
    215 		case 'a':
    216 		case 'A':
    217 		case 'e':
    218 		case 'E':
    219 		case 'f':
    220 		case 'F':
    221 		case 'g':
    222 		case 'G':
    223 			// float in style of strtod
    224 
    225 		case 's':
    226 			// string
    227 
    228 		case 'S':
    229 			// long string
    230 		
    231 		case 'c':
    232 			// fixed # chars
    233 		
    234 		case 'C':
    235 			// same as lc
    236 		
    237 		case '[':
    238 			// nonempty sequence of chars from specified char set
    239 			
    240 			printf("sscanf only partially implemented\n");
    241 			abort();
    242 		
    243 		default:
    244 			printf("unrecognized verb %c (%d)\n", ch, ch);
    245 			abort();
    246 		}
    247 	}
    248 }
    249