Rev 9862 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 9862 | Rev 9863 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | function for format read from any source |
2 | function for format read from any source |
3 | 3 | ||
4 | Siemargl formats as http://www.cplusplus.com/reference/cstdio/scanf/, no wchar though |
4 | Siemargl formats as http://www.cplusplus.com/reference/cstdio/scanf/, no wchar though |
5 | http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap05.html is used too |
5 | http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap05.html is used too |
6 | 6 | ||
7 | todo: |
7 | todo: |
8 | [characters], [^characters] |
8 | [characters], [^characters] |
9 | -%n nothing scanned, filled only if good result |
9 | -%n nothing scanned, filled only if good result |
10 | -%d, i, u, o, x, p read similar - detect base by prefix 0 or 0x |
10 | -%d, i, u, o, x, p read similar - detect base by prefix 0 or 0x |
11 | -%a |
11 | -%a |
12 | -can overflow unsigned as signed |
12 | -can overflow unsigned as signed |
13 | -radix point always '.', no LOCALEs |
13 | -radix point always '.', no LOCALEs |
14 | */ |
14 | */ |
15 | 15 | ||
16 | 16 | ||
17 | #include |
17 | #include |
18 | #include |
18 | #include |
19 | #include |
19 | #include |
20 | #include |
20 | #include |
21 | 21 | ||
22 | typedef int (*virtual_getc)(void *sp, const void *obj); |
22 | typedef int (*virtual_getc)(void *sp, const void *obj); |
23 | typedef void (*virtual_ungetc)(void *sp, int c, const void *obj); |
23 | typedef void (*virtual_ungetc)(void *sp, int c, const void *obj); |
24 | 24 | ||
25 | enum flags_t |
25 | enum flags_t |
26 | { |
26 | { |
27 | flag_unsigned = 0x02, |
27 | flag_unsigned = 0x02, |
28 | flag_register = 0x04, |
28 | flag_register = 0x04, |
29 | flag_plus = 0x08, |
29 | flag_plus = 0x08, |
30 | flag_left_just = 0x10, |
30 | flag_left_just = 0x10, |
31 | flag_lead_zeros = 0x20, |
31 | flag_lead_zeros = 0x20, |
32 | flag_space_plus = 0x40, |
32 | flag_space_plus = 0x40, |
33 | flag_hash_sign = 0x80, |
33 | flag_hash_sign = 0x80, |
34 | flag_point = 0x100 |
34 | flag_point = 0x100 |
35 | }; |
35 | }; |
36 | 36 | ||
37 | int try_parse_real(long double *real, int ch, const void *src, void *save, virtual_getc vgetc, virtual_ungetc vungetc) |
37 | int try_parse_real(long double *real, int ch, const void *src, void *save, virtual_getc vgetc, virtual_ungetc vungetc) |
38 | // returns 1 if OK, -1 == EOF, -2 parse broken |
38 | // returns 1 if OK, -1 == EOF, -2 parse broken |
39 | { |
39 | { |
40 | int sign = 1, have_digits = 0; |
40 | int sign = 1, have_digits = 0; |
41 | long long div; |
41 | long long div; |
42 | 42 | ||
43 | if (ch == '+') |
43 | if (ch == '+') |
44 | { |
44 | { |
45 | ch = vgetc(save, src); |
45 | ch = vgetc(save, src); |
46 | if (ch == EOF) return EOF; |
46 | if (ch == EOF) return EOF; |
47 | } else |
47 | } else |
48 | if (ch == '-') |
48 | if (ch == '-') |
49 | { |
49 | { |
50 | sign = -1; |
50 | sign = -1; |
51 | ch = vgetc(save, src); |
51 | ch = vgetc(save, src); |
52 | if (ch == EOF) return EOF; |
52 | if (ch == EOF) return EOF; |
53 | }; |
53 | }; |
54 | *real = 0.0; |
54 | *real = 0.0; |
55 | for (;;) // mantissa before point |
55 | for (;;) // mantissa before point |
56 | { |
56 | { |
57 | // test ch is valid |
57 | // test ch is valid |
58 | if (isdigit(ch)) |
58 | if (isdigit(ch)) |
59 | { |
59 | { |
60 | *real = *real * 10 + ch - '0'; |
60 | *real = *real * 10 + ch - '0'; |
61 | have_digits++; |
61 | have_digits++; |
62 | ch = vgetc(save, src); |
62 | ch = vgetc(save, src); |
63 | if (ch == EOF || isspace(ch)) break; // ok, just finish num |
63 | if (ch == EOF || isspace(ch)) break; // ok, just finish num |
64 | } else |
64 | } else |
65 | if (ch == '.' || ch == 'E' || ch == 'e') |
65 | if (ch == '.' || ch == 'E' || ch == 'e') |
66 | { |
66 | { |
67 | break; // ok |
67 | break; // ok |
68 | } |
68 | } |
69 | else |
69 | else |
70 | { |
70 | { |
71 | vungetc(save, ch, src); |
71 | vungetc(save, ch, src); |
72 | break; |
72 | break; |
73 | } |
73 | } |
74 | } |
74 | } |
75 | if (ch != '.' && ch != 'E' && ch != 'e') // ok, just integer part |
75 | if (ch != '.' && ch != 'E' && ch != 'e') // ok, just integer part |
76 | { |
76 | { |
77 | *real *= sign; |
77 | *real *= sign; |
78 | if (have_digits) |
78 | if (have_digits) |
79 | return 1; |
79 | return 1; |
80 | else |
80 | else |
81 | return -2; |
81 | return -2; |
82 | } |
82 | } |
83 | 83 | ||
84 | if(ch == '.') |
84 | if(ch == '.') |
85 | { |
85 | { |
86 | ch = vgetc(save, src); |
86 | ch = vgetc(save, src); |
87 | div = 10; // use as divisor |
87 | div = 10; // use as divisor |
88 | for (;;) // mantissa after point |
88 | for (;;) // mantissa after point |
89 | { |
89 | { |
90 | // test ch is valid |
90 | // test ch is valid |
91 | if (isdigit(ch)) |
91 | if (isdigit(ch)) |
92 | { |
92 | { |
93 | *real += (double)(ch - '0') / div; |
93 | *real += (double)(ch - '0') / div; |
94 | div *= 10; |
94 | div *= 10; |
95 | have_digits++; |
95 | have_digits++; |
96 | ch = vgetc(save, src); |
96 | ch = vgetc(save, src); |
97 | if (ch == EOF || isspace(ch)) break; // ok, just finish num |
97 | if (ch == EOF || isspace(ch)) break; // ok, just finish num |
98 | } else |
98 | } else |
99 | if (ch == 'E' || ch == 'e') |
99 | if (ch == 'E' || ch == 'e') |
100 | { |
100 | { |
101 | break; // ok |
101 | break; // ok |
102 | } |
102 | } |
103 | else |
103 | else |
104 | { |
104 | { |
105 | vungetc(save, ch, src); |
105 | vungetc(save, ch, src); |
106 | break; |
106 | break; |
107 | } |
107 | } |
108 | } |
108 | } |
109 | if (ch != 'E' && ch != 'e') // ok, real as XX.YY |
109 | if (ch != 'E' && ch != 'e') // ok, real as XX.YY |
110 | { |
110 | { |
111 | *real *= sign; |
111 | *real *= sign; |
112 | if (have_digits) |
112 | if (have_digits) |
113 | return 1; |
113 | return 1; |
114 | else |
114 | else |
115 | return -2; |
115 | return -2; |
116 | } |
116 | } |
117 | } |
117 | } |
118 | 118 | ||
119 | ch = vgetc(save, src); |
119 | ch = vgetc(save, src); |
120 | *real *= sign; |
120 | *real *= sign; |
121 | // exponent |
121 | // exponent |
122 | sign = 1; |
122 | sign = 1; |
123 | if (ch == '+') |
123 | if (ch == '+') |
124 | { |
124 | { |
125 | ch = vgetc(save, src); |
125 | ch = vgetc(save, src); |
126 | if (ch == EOF) return EOF; |
126 | if (ch == EOF) return EOF; |
127 | } else |
127 | } else |
128 | if (ch == '-') |
128 | if (ch == '-') |
129 | { |
129 | { |
130 | sign = -1; |
130 | sign = -1; |
131 | ch = vgetc(save, src); |
131 | ch = vgetc(save, src); |
132 | if (ch == EOF) return EOF; |
132 | if (ch == EOF) return EOF; |
133 | }; |
133 | }; |
134 | div = 0; |
134 | div = 0; |
135 | for (;;) |
135 | for (;;) |
136 | { |
136 | { |
137 | // test ch is valid |
137 | // test ch is valid |
138 | if (isdigit(ch)) |
138 | if (isdigit(ch)) |
139 | { |
139 | { |
140 | div = div * 10 + ch - '0'; |
140 | div = div * 10 + ch - '0'; |
141 | ch = vgetc(save, src); |
141 | ch = vgetc(save, src); |
142 | if (ch == EOF || isspace(ch)) break; // ok, just finish num |
142 | if (ch == EOF || isspace(ch)) break; // ok, just finish num |
143 | } |
143 | } |
144 | else |
144 | else |
145 | { |
145 | { |
146 | vungetc(save, ch, src); |
146 | vungetc(save, ch, src); |
147 | break; |
147 | break; |
148 | } |
148 | } |
149 | } |
149 | } |
150 | div *= sign; |
150 | div *= sign; |
151 | *real *= pow(10, div); |
151 | *real *= pow(10, div); |
152 | 152 | ||
153 | return 1; |
153 | return 1; |
154 | } |
154 | } |
155 | 155 | ||
156 | int try_parse_int(long long *digit, int ch, const void *src, void *save, virtual_getc vgetc, virtual_ungetc vungetc) |
156 | int try_parse_int(long long *digit, int ch, const void *src, void *save, virtual_getc vgetc, virtual_ungetc vungetc) |
157 | { |
157 | { |
158 | int sign = 1, base = 10, have_digits = 0; |
158 | int sign = 1, base = 10, have_digits = 0; |
159 | 159 | ||
160 | if (ch == '+') |
160 | if (ch == '+') |
161 | { |
161 | { |
162 | ch = vgetc(save, src); |
162 | ch = vgetc(save, src); |
163 | if (ch == EOF) return EOF; |
163 | if (ch == EOF) return EOF; |
164 | } else |
164 | } else |
165 | if (ch == '-') |
165 | if (ch == '-') |
166 | { |
166 | { |
167 | sign = -1; |
167 | sign = -1; |
168 | ch = vgetc(save, src); |
168 | ch = vgetc(save, src); |
169 | if (ch == EOF) return EOF; |
169 | if (ch == EOF) return EOF; |
170 | }; |
170 | }; |
171 | 171 | ||
172 | if (ch == '0') // octal or hex, read next |
172 | if (ch == '0') // octal or hex, read next |
173 | { |
173 | { |
174 | ch = vgetc(save, src); |
174 | ch = vgetc(save, src); |
175 | if (ch == 'o') |
175 | if (ch == 'c' || ch == 'C') |
176 | base = 8; |
176 | base = 8; |
177 | else if (ch == 'x' || ch == 'X') |
177 | else if (ch == 'x' || ch == 'X') |
178 | base = 16; |
178 | base = 16; |
179 | if (base == 10) |
179 | if (base == 10) |
180 | have_digits++; |
180 | have_digits++; |
181 | else |
181 | else |
182 | { |
182 | { |
183 | char tch = vgetc(save, src); |
183 | char tch = vgetc(save, src); |
184 | if ((base == 8 && isdigit(tch) && tch < '8') || |
184 | if ((base == 8 && isdigit(tch) && tch < '8') || |
185 | (base == 16 && isxdigit(tch))) |
185 | (base == 16 && isxdigit(tch))) |
186 | ch = tch; |
186 | ch = tch; |
187 | else |
187 | else |
188 | { |
188 | { |
189 | have_digits++; |
189 | have_digits++; |
190 | //base = 10; // not required: zero is zero with any (base > 1) |
190 | //base = 10; // not required: zero is zero with any (base > 1) |
191 | vungetc(save, tch, src); |
191 | vungetc(save, tch, src); |
192 | } |
192 | } |
193 | } |
193 | } |
194 | } |
194 | } |
195 | *digit = 0; |
195 | *digit = 0; |
196 | for (;;) |
196 | for (;;) |
197 | { |
197 | { |
198 | // test ch is valid |
198 | // test ch is valid |
199 | if ((isdigit(ch) && base == 10) || |
199 | if ((isdigit(ch) && base == 10) || |
200 | (isdigit(ch) && base == 8 && ch < '8') || |
200 | (isdigit(ch) && base == 8 && ch < '8') || |
201 | (isxdigit(ch) && base == 16)) |
201 | (isxdigit(ch) && base == 16)) |
202 | { |
202 | { |
203 | if (base == 16) |
203 | if (base == 16) |
204 | { |
204 | { |
205 | if (ch <= '9') ch -= '0'; |
205 | if (ch <= '9') ch -= '0'; |
206 | else |
206 | else |
207 | if (ch <= 'F') ch = 10 + ch - 'A'; |
207 | if (ch <= 'F') ch = 10 + ch - 'A'; |
208 | else |
208 | else |
209 | ch = 10 + ch - 'a'; |
209 | ch = 10 + ch - 'a'; |
210 | } |
210 | } |
211 | else |
211 | else |
212 | ch -= '0'; |
212 | ch -= '0'; |
213 | *digit = *digit * base + ch; |
213 | *digit = *digit * base + ch; |
214 | have_digits++; |
214 | have_digits++; |
215 | ch = vgetc(save, src); |
215 | ch = vgetc(save, src); |
216 | if (ch == EOF || isspace(ch)) break; // ok, just finish num |
216 | if (ch == EOF || isspace(ch)) break; // ok, just finish num |
217 | } |
217 | } |
218 | else if (ch == EOF || isspace(ch)) |
218 | else if (ch == EOF || isspace(ch)) |
219 | break; |
219 | break; |
220 | else |
220 | else |
221 | { |
221 | { |
222 | vungetc(save, ch, src); |
222 | vungetc(save, ch, src); |
223 | break; |
223 | break; |
224 | } |
224 | } |
225 | } |
225 | } |
226 | *digit *= sign; |
226 | *digit *= sign; |
227 | if (have_digits) |
227 | if (have_digits) |
228 | return 1; |
228 | return 1; |
229 | else |
229 | else |
230 | return -2; |
230 | return -2; |
231 | } |
231 | } |
232 | 232 | ||
233 | 233 | ||
234 | 234 | ||
235 | int format_scan(const void *src, const char *fmt, va_list argp, virtual_getc vgetc, virtual_ungetc vungetc) |
235 | int format_scan(const void *src, const char *fmt, va_list argp, virtual_getc vgetc, virtual_ungetc vungetc) |
236 | { |
236 | { |
237 | int i; |
237 | int i; |
238 | int length; |
238 | int length; |
239 | int fmt1, fmt2; // width, precision |
239 | int fmt1, fmt2; // width, precision |
240 | size_t pos, posc; |
240 | size_t pos, posc; |
241 | const char *fmtc; // first point to %, fmtc points to specifier |
241 | const char *fmtc; // first point to %, fmtc points to specifier |
242 | int ch; |
242 | int ch; |
243 | int format_flag; |
243 | int format_flag; |
244 | int flag_long; // 2 = long double or long long int or wchar |
244 | int flag_long; // 2 = long double or long long int or wchar |
245 | int *point_to_n = NULL, nread = 0; |
245 | int *point_to_n = NULL, nread = 0; |
246 | int flags; // parsed flags |
246 | int flags; // parsed flags |
247 | int save = 0; |
247 | int save = 0; |
248 | char *arg_str; |
248 | char *arg_str; |
249 | int *arg_int; |
249 | int *arg_int; |
250 | long *arg_long; |
250 | long *arg_long; |
251 | long long *arg_longlong; |
251 | long long *arg_longlong; |
252 | float *arg_float; |
252 | float *arg_float; |
253 | double *arg_double; |
253 | double *arg_double; |
254 | long double *arg_longdouble; |
254 | long double *arg_longdouble; |
255 | long long digit; |
255 | long long digit; |
256 | long double real; |
256 | long double real; |
257 | int skip_next; // skip arguments with * char format |
257 | int skip_next; // skip arguments with * char format |
258 | 258 | ||
259 | pos = 0; |
259 | pos = 0; |
260 | while(*fmt) |
260 | while(*fmt) |
261 | { |
261 | { |
262 | while (*fmt && isspace(*fmt)) fmt++; // skip spaces in format str |
262 | while (*fmt && isspace(*fmt)) fmt++; // skip spaces in format str |
263 | 263 | ||
264 | if (*fmt != '%') // usual char |
264 | if (*fmt != '%') // usual char |
265 | { |
265 | { |
266 | ch = vgetc(&save, src); |
266 | ch = vgetc(&save, src); |
267 | if (ch != *fmt++) // char not match format |
267 | if (ch != *fmt++) // char not match format |
268 | { |
268 | { |
269 | vungetc(&save, ch, src); |
269 | vungetc(&save, ch, src); |
270 | break; |
270 | break; |
271 | } |
271 | } |
272 | pos++; |
272 | pos++; |
273 | continue; |
273 | continue; |
274 | } |
274 | } |
275 | 275 | ||
276 | if (*(fmt + 1) == '%') // %% |
276 | if (*(fmt + 1) == '%') // %% |
277 | { |
277 | { |
278 | ch = vgetc(&save, src); |
278 | ch = vgetc(&save, src); |
279 | if (ch != '%') // char not match format |
279 | if (ch != '%') // char not match format |
280 | { |
280 | { |
281 | vungetc(&save, ch, src); |
281 | vungetc(&save, ch, src); |
282 | break; |
282 | break; |
283 | } |
283 | } |
284 | pos++; |
284 | pos++; |
285 | fmt += 2; |
285 | fmt += 2; |
286 | continue; |
286 | continue; |
287 | } |
287 | } |
288 | //checking to containg format in the string |
288 | //checking to containg format in the string |
289 | fmtc = fmt; |
289 | fmtc = fmt; |
290 | posc = pos; |
290 | posc = pos; |
291 | 291 | ||
292 | skip_next = 0; |
292 | skip_next = 0; |
293 | flags = 0; |
293 | flags = 0; |
294 | format_flag = 0; |
294 | format_flag = 0; |
295 | flag_long = 0; // 2 = long double or long long int or wchar |
295 | flag_long = 0; // 2 = long double or long long int or wchar |
296 | 296 | ||
297 | while(*fmtc != '\0' && !format_flag) // searching end of format |
297 | while(*fmtc != '\0' && !format_flag) // searching end of format |
298 | { |
298 | { |
299 | fmtc++; posc++; |
299 | fmtc++; posc++; |
300 | switch( *fmtc ) |
300 | switch( *fmtc ) |
301 | { |
301 | { |
302 | case 'a': |
302 | case 'a': |
303 | format_flag = 1; |
303 | format_flag = 1; |
304 | flags |= flag_unsigned; |
304 | flags |= flag_unsigned; |
305 | break; |
305 | break; |
306 | case 'c': case 'd': case 'i': case 'e': case 'f': case 'g': case 's': case 'n': |
306 | case 'c': case 'd': case 'i': case 'e': case 'f': case 'g': case 's': case 'n': |
307 | format_flag = 1; |
307 | format_flag = 1; |
308 | break; |
308 | break; |
309 | case 'l': |
309 | case 'l': |
310 | flag_long = flag_long ? 2 : 1; // ll.eq.L |
310 | flag_long = flag_long ? 2 : 1; // ll.eq.L |
311 | break; |
311 | break; |
312 | case 'L': |
312 | case 'L': |
313 | flag_long = 2; |
313 | flag_long = 2; |
314 | break; |
314 | break; |
315 | case 'o': case 'u': case 'x': case 'p': |
315 | case 'o': case 'u': case 'x': case 'p': |
316 | format_flag = 1; |
316 | format_flag = 1; |
317 | flags |= flag_unsigned; |
317 | flags |= flag_unsigned; |
318 | break; |
318 | break; |
319 | case '*': |
319 | case '*': |
320 | skip_next = 1; |
320 | skip_next = 1; |
321 | break; |
321 | break; |
322 | case '.': // just skip |
322 | case '.': // just skip |
323 | break; |
323 | break; |
324 | default: |
324 | default: |
325 | if(isdigit(*fmtc)) break; |
325 | if(isdigit(*fmtc)) break; |
326 | goto exit_me; // non format char found - user error |
326 | goto exit_me; // non format char found - user error |
327 | } |
327 | } |
328 | } |
328 | } |
329 | 329 | ||
330 | if (format_flag == 0) |
330 | if (format_flag == 0) |
331 | { |
331 | { |
332 | goto exit_me; // format char not found - user error |
332 | goto exit_me; // format char not found - user error |
333 | } |
333 | } |
334 | 334 | ||
335 | fmt1 = 0; |
335 | fmt1 = 0; |
336 | fmt2 = 0; |
336 | fmt2 = 0; |
337 | if (posc - pos > 1) // try to read width, precision |
337 | if (posc - pos > 1) // try to read width, precision |
338 | { |
338 | { |
339 | fmt++; |
339 | fmt++; |
340 | for(i = pos + 1; i < posc; i++) |
340 | for(i = pos + 1; i < posc; i++) |
341 | { |
341 | { |
342 | switch(*fmt) |
342 | switch(*fmt) |
343 | { |
343 | { |
344 | case '0': |
344 | case '0': |
345 | if(fmt1 == 0 && (flags & flag_point) == 0) flags |= flag_lead_zeros; |
345 | if(fmt1 == 0 && (flags & flag_point) == 0) flags |= flag_lead_zeros; |
346 | case '1': case '2': case '3': case '4': |
346 | case '1': case '2': case '3': case '4': |
347 | case '5': case '6': case '7': case '8': case '9': |
347 | case '5': case '6': case '7': case '8': case '9': |
348 | if ((flags & flag_point) == 0) |
348 | if ((flags & flag_point) == 0) |
349 | fmt1 = fmt1 * 10 + (*fmt -'0'); |
349 | fmt1 = fmt1 * 10 + (*fmt -'0'); |
350 | else |
350 | else |
351 | fmt2 = fmt2 * 10 + (*fmt -'0'); |
351 | fmt2 = fmt2 * 10 + (*fmt -'0'); |
352 | break; |
352 | break; |
353 | case '*': // ignoring |
353 | case '*': // ignoring |
354 | break; |
354 | break; |
355 | case '.': |
355 | case '.': |
356 | flags |= flag_point; |
356 | flags |= flag_point; |
357 | break; |
357 | break; |
358 | case 'l': case 'L': // valid chars - skip |
358 | case 'l': case 'L': // valid chars - skip |
359 | break; |
359 | break; |
360 | default: // must be error |
360 | default: // must be error |
361 | goto exit_me; // format char not found - user error |
361 | goto exit_me; // format char not found - user error |
362 | } |
362 | } |
363 | fmt++; |
363 | fmt++; |
364 | } |
364 | } |
365 | } |
365 | } |
366 | 366 | ||
367 | // do real work - format arguments values |
367 | // do real work - format arguments values |
368 | // skip input spaces |
368 | // skip input spaces |
369 | do { |
369 | do { |
370 | ch = vgetc(&save, src); |
370 | ch = vgetc(&save, src); |
371 | if (ch == EOF) goto exit_me; |
371 | if (ch == EOF) goto exit_me; |
372 | } while (isspace(ch)); |
372 | } while (isspace(ch)); |
373 | 373 | ||
374 | switch(*fmtc) |
374 | switch(*fmtc) |
375 | { |
375 | { |
376 | case 'n': |
376 | case 'n': |
377 | point_to_n = va_arg(argp, int*); |
377 | point_to_n = va_arg(argp, int*); |
378 | vungetc(&save, ch, src); |
378 | vungetc(&save, ch, src); |
379 | break; |
379 | break; |
380 | case 'c': // read width chars, ever spaces |
380 | case 'c': // read width chars, ever spaces |
381 | if (!skip_next) arg_str = va_arg(argp, char*); |
381 | if (!skip_next) arg_str = va_arg(argp, char*); |
382 | if (fmt1 == 0) length = 1; |
382 | if (fmt1 == 0) length = 1; |
383 | else length = fmt1; |
383 | else length = fmt1; |
384 | for (i = 0; i < length;) |
384 | for (i = 0; i < length;) |
385 | { |
385 | { |
386 | if (!skip_next) *arg_str++ = ch; |
386 | if (!skip_next) *arg_str++ = ch; |
387 | i++; |
387 | i++; |
388 | ch = vgetc(&save, src); |
388 | ch = vgetc(&save, src); |
389 | if (ch == EOF) break; |
389 | if (ch == EOF) break; |
390 | } |
390 | } |
391 | if (i < length) goto exit_me; // not enough chars |
391 | if (i < length) goto exit_me; // not enough chars |
392 | break; |
392 | break; |
393 | case 's': |
393 | case 's': |
394 | if (!skip_next) arg_str = va_arg(argp, char*); |
394 | if (!skip_next) arg_str = va_arg(argp, char*); |
395 | if (fmt1 == 0) length = 4095; // max string scan 4096 |
395 | if (fmt1 == 0) length = 4095; // max string scan 4096 |
396 | else length = fmt1; |
396 | else length = fmt1; |
397 | for (i = 0; i < length; i++) |
397 | for (i = 0; i < length; i++) |
398 | { |
398 | { |
399 | if (!skip_next) *arg_str++ = ch; |
399 | if (!skip_next) *arg_str++ = ch; |
400 | 400 | ||
401 | ch = vgetc(&save, src); |
401 | ch = vgetc(&save, src); |
402 | if (ch == EOF || isspace(ch)) break; // ok, just finish string |
402 | if (ch == EOF || isspace(ch)) break; // ok, just finish string |
403 | } |
403 | } |
404 | if (!skip_next) *arg_str++ = '\0'; |
404 | if (!skip_next) *arg_str++ = '\0'; |
405 | break; |
405 | break; |
406 | case 'd': case 'i': case 'u': |
406 | case 'd': case 'i': case 'u': |
407 | case 'o': case 'p': case 'x': |
407 | case 'o': case 'p': case 'x': |
408 | i = try_parse_int(&digit, ch, src, &save, vgetc, vungetc); |
408 | i = try_parse_int(&digit, ch, src, &save, vgetc, vungetc); |
409 | if (i < 0) goto exit_me; |
409 | if (i < 0) goto exit_me; |
410 | 410 | ||
411 | if (!skip_next) |
411 | if (!skip_next) |
412 | if (flag_long == 0) { arg_int = va_arg(argp, int*); *arg_int = (int)digit; } else |
412 | if (flag_long == 0) { arg_int = va_arg(argp, int*); *arg_int = (int)digit; } else |
413 | if (flag_long == 1) { arg_long = va_arg(argp, long*); *arg_long = (long)digit; } else |
413 | if (flag_long == 1) { arg_long = va_arg(argp, long*); *arg_long = (long)digit; } else |
414 | if (flag_long == 2) { arg_longlong = va_arg(argp, long long*); *arg_longlong = digit; } |
414 | if (flag_long == 2) { arg_longlong = va_arg(argp, long long*); *arg_longlong = digit; } |
415 | break; |
415 | break; |
416 | case 'a': case 'A': case 'f': case 'F': |
416 | case 'a': case 'A': case 'f': case 'F': |
417 | case 'e': case 'E': |
417 | case 'e': case 'E': |
418 | case 'g': case 'G': |
418 | case 'g': case 'G': |
419 | i = try_parse_real(&real, ch, src, &save, vgetc, vungetc); |
419 | i = try_parse_real(&real, ch, src, &save, vgetc, vungetc); |
420 | if (i < 0) goto exit_me; |
420 | if (i < 0) goto exit_me; |
421 | 421 | ||
422 | if (!skip_next) |
422 | if (!skip_next) |
423 | if (flag_long == 0) { arg_float = va_arg(argp, float*); *arg_float = (float)real; } else |
423 | if (flag_long == 0) { arg_float = va_arg(argp, float*); *arg_float = (float)real; } else |
424 | if (flag_long == 1) { arg_double = va_arg(argp, double*); *arg_double = (double)real; } else |
424 | if (flag_long == 1) { arg_double = va_arg(argp, double*); *arg_double = (double)real; } else |
425 | if (flag_long == 2) { arg_longdouble = va_arg(argp, long double*); *arg_longdouble = real; } |
425 | if (flag_long == 2) { arg_longdouble = va_arg(argp, long double*); *arg_longdouble = real; } |
426 | break; |
426 | break; |
427 | } |
427 | } |
428 | 428 | ||
429 | fmt = fmtc + 1; |
429 | fmt = fmtc + 1; |
430 | if (!skip_next) nread++; |
430 | if (!skip_next) nread++; |
431 | } |
431 | } |
432 | exit_me: |
432 | exit_me: |
433 | if (point_to_n) *point_to_n = nread; |
433 | if (point_to_n) *point_to_n = nread; |
434 | return nread; |
434 | return nread; |
435 | }>>>>>>=>=>>> |
435 | }>>>>>>=>=>>> |