vfscanf.c - vx32 - Local 9vx git repository for patches.
(HTM) git clone git://r-36.net/vx32
(DIR) Log
(DIR) Files
(DIR) 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