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