1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 *
6 * Copyright (C) 1998-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
8 *
9 *******************************************************************************
10 *
11 * File uscnnf_p.c
12 *
13 * Modification History:
14 *
15 * Date Name Description
16 * 12/02/98 stephen Creation.
17 * 03/13/99 stephen Modified for new C API.
18 *******************************************************************************
19 */
20
21 #include "unicode/utypes.h"
22
23 #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_CONVERSION
24
25 #include "unicode/uchar.h"
26 #include "unicode/ustring.h"
27 #include "unicode/unum.h"
28 #include "unicode/udat.h"
29 #include "unicode/uset.h"
30 #include "uscanf.h"
31 #include "ufmt_cmn.h"
32 #include "ufile.h"
33 #include "locbund.h"
34
35 #include "cmemory.h"
36 #include "ustr_cnv.h"
37
38 /* flag characters for u_scanf */
39 #define FLAG_ASTERISK 0x002A
40 #define FLAG_PAREN 0x0028
41
42 #define ISFLAG(s) (s) == FLAG_ASTERISK || \
43 (s) == FLAG_PAREN
44
45 /* special characters for u_scanf */
46 #define SPEC_DOLLARSIGN 0x0024
47
48 /* unicode digits */
49 #define DIGIT_ZERO 0x0030
50 #define DIGIT_ONE 0x0031
51 #define DIGIT_TWO 0x0032
52 #define DIGIT_THREE 0x0033
53 #define DIGIT_FOUR 0x0034
54 #define DIGIT_FIVE 0x0035
55 #define DIGIT_SIX 0x0036
56 #define DIGIT_SEVEN 0x0037
57 #define DIGIT_EIGHT 0x0038
58 #define DIGIT_NINE 0x0039
59
60 #define ISDIGIT(s) (s) == DIGIT_ZERO || \
61 (s) == DIGIT_ONE || \
62 (s) == DIGIT_TWO || \
63 (s) == DIGIT_THREE || \
64 (s) == DIGIT_FOUR || \
65 (s) == DIGIT_FIVE || \
66 (s) == DIGIT_SIX || \
67 (s) == DIGIT_SEVEN || \
68 (s) == DIGIT_EIGHT || \
69 (s) == DIGIT_NINE
70
71 /* u_scanf modifiers */
72 #define MOD_H 0x0068
73 #define MOD_LOWERL 0x006C
74 #define MOD_L 0x004C
75
76 #define ISMOD(s) (s) == MOD_H || \
77 (s) == MOD_LOWERL || \
78 (s) == MOD_L
79
80 /**
81 * Struct encapsulating a single uscanf format specification.
82 */
83 typedef struct u_scanf_spec_info {
84 int32_t fWidth; /* Width */
85
86 UChar fSpec; /* Format specification */
87
88 UChar fPadChar; /* Padding character */
89
90 UBool fSkipArg; /* TRUE if arg should be skipped */
91 UBool fIsLongDouble; /* L flag */
92 UBool fIsShort; /* h flag */
93 UBool fIsLong; /* l flag */
94 UBool fIsLongLong; /* ll flag */
95 UBool fIsString; /* TRUE if this is a NULL-terminated string. */
96 } u_scanf_spec_info;
97
98
99 /**
100 * Struct encapsulating a single u_scanf format specification.
101 */
102 typedef struct u_scanf_spec {
103 u_scanf_spec_info fInfo; /* Information on this spec */
104 int32_t fArgPos; /* Position of data in arg list */
105 } u_scanf_spec;
106
107 /**
108 * Parse a single u_scanf format specifier in Unicode.
109 * @param fmt A pointer to a '%' character in a u_scanf format specification.
110 * @param spec A pointer to a <TT>u_scanf_spec</TT> to receive the parsed
111 * format specifier.
112 * @return The number of characters contained in this specifier.
113 */
114 static int32_t
u_scanf_parse_spec(const UChar * fmt,u_scanf_spec * spec)115 u_scanf_parse_spec (const UChar *fmt,
116 u_scanf_spec *spec)
117 {
118 const UChar *s = fmt;
119 const UChar *backup;
120 u_scanf_spec_info *info = &(spec->fInfo);
121
122 /* initialize spec to default values */
123 spec->fArgPos = -1;
124
125 info->fWidth = -1;
126 info->fSpec = 0x0000;
127 info->fPadChar = 0x0020;
128 info->fSkipArg = FALSE;
129 info->fIsLongDouble = FALSE;
130 info->fIsShort = FALSE;
131 info->fIsLong = FALSE;
132 info->fIsLongLong = FALSE;
133 info->fIsString = TRUE;
134
135
136 /* skip over the initial '%' */
137 s++;
138
139 /* Check for positional argument */
140 if(ISDIGIT(*s)) {
141
142 /* Save the current position */
143 backup = s;
144
145 /* handle positional parameters */
146 if(ISDIGIT(*s)) {
147 spec->fArgPos = (int) (*s++ - DIGIT_ZERO);
148
149 while(ISDIGIT(*s)) {
150 spec->fArgPos *= 10;
151 spec->fArgPos += (int) (*s++ - DIGIT_ZERO);
152 }
153 }
154
155 /* if there is no '$', don't read anything */
156 if(*s != SPEC_DOLLARSIGN) {
157 spec->fArgPos = -1;
158 s = backup;
159 }
160 /* munge the '$' */
161 else
162 s++;
163 }
164
165 /* Get any format flags */
166 while(ISFLAG(*s)) {
167 switch(*s++) {
168
169 /* skip argument */
170 case FLAG_ASTERISK:
171 info->fSkipArg = TRUE;
172 break;
173
174 /* pad character specified */
175 case FLAG_PAREN:
176
177 /* first four characters are hex values for pad char */
178 info->fPadChar = (UChar)ufmt_digitvalue(*s++);
179 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++));
180 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++));
181 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++));
182
183 /* final character is ignored */
184 s++;
185
186 break;
187 }
188 }
189
190 /* Get the width */
191 if(ISDIGIT(*s)){
192 info->fWidth = (int) (*s++ - DIGIT_ZERO);
193
194 while(ISDIGIT(*s)) {
195 info->fWidth *= 10;
196 info->fWidth += (int) (*s++ - DIGIT_ZERO);
197 }
198 }
199
200 /* Get any modifiers */
201 if(ISMOD(*s)) {
202 switch(*s++) {
203
204 /* short */
205 case MOD_H:
206 info->fIsShort = TRUE;
207 break;
208
209 /* long or long long */
210 case MOD_LOWERL:
211 if(*s == MOD_LOWERL) {
212 info->fIsLongLong = TRUE;
213 /* skip over the next 'l' */
214 s++;
215 }
216 else
217 info->fIsLong = TRUE;
218 break;
219
220 /* long double */
221 case MOD_L:
222 info->fIsLongDouble = TRUE;
223 break;
224 }
225 }
226
227 /* finally, get the specifier letter */
228 info->fSpec = *s++;
229
230 /* return # of characters in this specifier */
231 return (int32_t)(s - fmt);
232 }
233
234 #define UP_PERCENT 0x0025
235
236
237 /* ANSI style formatting */
238 /* Use US-ASCII characters only for formatting */
239
240 /* % */
241 #define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_scanf_simple_percent_handler}
242 /* s */
243 #define UFMT_STRING {ufmt_string, u_scanf_string_handler}
244 /* c */
245 #define UFMT_CHAR {ufmt_string, u_scanf_char_handler}
246 /* d, i */
247 #define UFMT_INT {ufmt_int, u_scanf_integer_handler}
248 /* u */
249 #define UFMT_UINT {ufmt_int, u_scanf_uinteger_handler}
250 /* o */
251 #define UFMT_OCTAL {ufmt_int, u_scanf_octal_handler}
252 /* x, X */
253 #define UFMT_HEX {ufmt_int, u_scanf_hex_handler}
254 /* f */
255 #define UFMT_DOUBLE {ufmt_double, u_scanf_double_handler}
256 /* e, E */
257 #define UFMT_SCIENTIFIC {ufmt_double, u_scanf_scientific_handler}
258 /* g, G */
259 #define UFMT_SCIDBL {ufmt_double, u_scanf_scidbl_handler}
260 /* n */
261 #define UFMT_COUNT {ufmt_count, u_scanf_count_handler}
262 /* [ */
263 #define UFMT_SCANSET {ufmt_string, u_scanf_scanset_handler}
264
265 /* non-ANSI extensions */
266 /* Use US-ASCII characters only for formatting */
267
268 /* p */
269 #define UFMT_POINTER {ufmt_pointer, u_scanf_pointer_handler}
270 /* V */
271 #define UFMT_SPELLOUT {ufmt_double, u_scanf_spellout_handler}
272 /* P */
273 #define UFMT_PERCENT {ufmt_double, u_scanf_percent_handler}
274 /* C K is old format */
275 #define UFMT_UCHAR {ufmt_uchar, u_scanf_uchar_handler}
276 /* S U is old format */
277 #define UFMT_USTRING {ufmt_ustring, u_scanf_ustring_handler}
278
279
280 #define UFMT_EMPTY {ufmt_empty, NULL}
281
282 /**
283 * A u_scanf handler function.
284 * A u_scanf handler is responsible for handling a single u_scanf
285 * format specification, for example 'd' or 's'.
286 * @param stream The UFILE to which to write output.
287 * @param info A pointer to a <TT>u_scanf_spec_info</TT> struct containing
288 * information on the format specification.
289 * @param args A pointer to the argument data
290 * @param fmt A pointer to the first character in the format string
291 * following the spec.
292 * @param fmtConsumed On output, set to the number of characters consumed
293 * in <TT>fmt</TT>. Do nothing, if the argument isn't variable width.
294 * @param argConverted The number of arguments converted and assigned, or -1 if an
295 * error occurred.
296 * @return The number of code points consumed during reading.
297 */
298 typedef int32_t (*u_scanf_handler) (UFILE *stream,
299 u_scanf_spec_info *info,
300 ufmt_args *args,
301 const UChar *fmt,
302 int32_t *fmtConsumed,
303 int32_t *argConverted);
304
305 typedef struct u_scanf_info {
306 ufmt_type_info info;
307 u_scanf_handler handler;
308 } u_scanf_info;
309
310 #define USCANF_NUM_FMT_HANDLERS 108
311 #define USCANF_SYMBOL_BUFFER_SIZE 8
312
313 /* We do not use handlers for 0-0x1f */
314 #define USCANF_BASE_FMT_HANDLERS 0x20
315
316
317 static int32_t
u_scanf_skip_leading_ws(UFILE * input,UChar pad)318 u_scanf_skip_leading_ws(UFILE *input,
319 UChar pad)
320 {
321 UChar c;
322 int32_t count = 0;
323 UBool isNotEOF;
324
325 /* skip all leading ws in the input */
326 while( (isNotEOF = ufile_getch(input, &c)) && (c == pad || u_isWhitespace(c)) )
327 {
328 count++;
329 }
330
331 /* put the final character back on the input */
332 if(isNotEOF)
333 u_fungetc(c, input);
334
335 return count;
336 }
337
338 /* TODO: Is always skipping the prefix symbol as a positive sign a good idea in all locales? */
339 static int32_t
u_scanf_skip_leading_positive_sign(UFILE * input,UNumberFormat * format,UErrorCode * status)340 u_scanf_skip_leading_positive_sign(UFILE *input,
341 UNumberFormat *format,
342 UErrorCode *status)
343 {
344 UChar c;
345 int32_t count = 0;
346 UBool isNotEOF;
347 UChar plusSymbol[USCANF_SYMBOL_BUFFER_SIZE];
348 int32_t symbolLen;
349 UErrorCode localStatus = U_ZERO_ERROR;
350
351 if (U_SUCCESS(*status)) {
352 symbolLen = unum_getSymbol(format,
353 UNUM_PLUS_SIGN_SYMBOL,
354 plusSymbol,
355 UPRV_LENGTHOF(plusSymbol),
356 &localStatus);
357
358 if (U_SUCCESS(localStatus)) {
359 /* skip all leading ws in the input */
360 while( (isNotEOF = ufile_getch(input, &c)) && (count < symbolLen && c == plusSymbol[count]) )
361 {
362 count++;
363 }
364
365 /* put the final character back on the input */
366 if(isNotEOF) {
367 u_fungetc(c, input);
368 }
369 }
370 }
371
372 return count;
373 }
374
375 static int32_t
u_scanf_simple_percent_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)376 u_scanf_simple_percent_handler(UFILE *input,
377 u_scanf_spec_info *info,
378 ufmt_args *args,
379 const UChar *fmt,
380 int32_t *fmtConsumed,
381 int32_t *argConverted)
382 {
383 /* make sure the next character in the input is a percent */
384 *argConverted = 0;
385 if(u_fgetc(input) != 0x0025) {
386 *argConverted = -1;
387 }
388 return 1;
389 }
390
391 static int32_t
u_scanf_count_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)392 u_scanf_count_handler(UFILE *input,
393 u_scanf_spec_info *info,
394 ufmt_args *args,
395 const UChar *fmt,
396 int32_t *fmtConsumed,
397 int32_t *argConverted)
398 {
399 /* in the special case of count, the u_scanf_spec_info's width */
400 /* will contain the # of items converted thus far */
401 if (!info->fSkipArg) {
402 if (info->fIsShort)
403 *(int16_t*)(args[0].ptrValue) = (int16_t)(UINT16_MAX & info->fWidth);
404 else if (info->fIsLongLong)
405 *(int64_t*)(args[0].ptrValue) = info->fWidth;
406 else
407 *(int32_t*)(args[0].ptrValue) = (int32_t)(UINT32_MAX & info->fWidth);
408 }
409 *argConverted = 0;
410
411 /* we converted 0 args */
412 return 0;
413 }
414
415 static int32_t
u_scanf_double_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)416 u_scanf_double_handler(UFILE *input,
417 u_scanf_spec_info *info,
418 ufmt_args *args,
419 const UChar *fmt,
420 int32_t *fmtConsumed,
421 int32_t *argConverted)
422 {
423 int32_t len;
424 double num;
425 UNumberFormat *format;
426 int32_t parsePos = 0;
427 int32_t skipped;
428 UErrorCode status = U_ZERO_ERROR;
429
430
431 /* skip all ws in the input */
432 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
433
434 /* fill the input's internal buffer */
435 ufile_fill_uchar_buffer(input);
436
437 /* determine the size of the input's buffer */
438 len = (int32_t)(input->str.fLimit - input->str.fPos);
439
440 /* truncate to the width, if specified */
441 if(info->fWidth != -1)
442 len = ufmt_min(len, info->fWidth);
443
444 /* get the formatter */
445 format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
446
447 /* handle error */
448 if(format == 0)
449 return 0;
450
451 /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
452 skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
453
454 /* parse the number */
455 num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
456
457 if (!info->fSkipArg) {
458 if (info->fIsLong)
459 *(double*)(args[0].ptrValue) = num;
460 else if (info->fIsLongDouble)
461 *(long double*)(args[0].ptrValue) = num;
462 else
463 *(float*)(args[0].ptrValue) = (float)num;
464 }
465
466 /* mask off any necessary bits */
467 /* if(! info->fIsLong_double)
468 num &= DBL_MAX;*/
469
470 /* update the input's position to reflect consumed data */
471 input->str.fPos += parsePos;
472
473 /* we converted 1 arg */
474 *argConverted = !info->fSkipArg;
475 return parsePos + skipped;
476 }
477
478 #define UPRINTF_SYMBOL_BUFFER_SIZE 8
479
480 static int32_t
u_scanf_scientific_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)481 u_scanf_scientific_handler(UFILE *input,
482 u_scanf_spec_info *info,
483 ufmt_args *args,
484 const UChar *fmt,
485 int32_t *fmtConsumed,
486 int32_t *argConverted)
487 {
488 int32_t len;
489 double num;
490 UNumberFormat *format;
491 int32_t parsePos = 0;
492 int32_t skipped;
493 UErrorCode status = U_ZERO_ERROR;
494 UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
495 int32_t srcLen, expLen;
496 UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
497
498
499 /* skip all ws in the input */
500 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
501
502 /* fill the input's internal buffer */
503 ufile_fill_uchar_buffer(input);
504
505 /* determine the size of the input's buffer */
506 len = (int32_t)(input->str.fLimit - input->str.fPos);
507
508 /* truncate to the width, if specified */
509 if(info->fWidth != -1)
510 len = ufmt_min(len, info->fWidth);
511
512 /* get the formatter */
513 format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SCIENTIFIC);
514
515 /* handle error */
516 if(format == 0)
517 return 0;
518
519 /* set the appropriate flags on the formatter */
520
521 srcLen = unum_getSymbol(format,
522 UNUM_EXPONENTIAL_SYMBOL,
523 srcExpBuf,
524 sizeof(srcExpBuf),
525 &status);
526
527 /* Upper/lower case the e */
528 if (info->fSpec == (UChar)0x65 /* e */) {
529 expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
530 srcExpBuf, srcLen,
531 input->str.fBundle.fLocale,
532 &status);
533 }
534 else {
535 expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
536 srcExpBuf, srcLen,
537 input->str.fBundle.fLocale,
538 &status);
539 }
540
541 unum_setSymbol(format,
542 UNUM_EXPONENTIAL_SYMBOL,
543 expBuf,
544 expLen,
545 &status);
546
547
548
549
550 /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
551 skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
552
553 /* parse the number */
554 num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
555
556 if (!info->fSkipArg) {
557 if (info->fIsLong)
558 *(double*)(args[0].ptrValue) = num;
559 else if (info->fIsLongDouble)
560 *(long double*)(args[0].ptrValue) = num;
561 else
562 *(float*)(args[0].ptrValue) = (float)num;
563 }
564
565 /* mask off any necessary bits */
566 /* if(! info->fIsLong_double)
567 num &= DBL_MAX;*/
568
569 /* update the input's position to reflect consumed data */
570 input->str.fPos += parsePos;
571
572 /* we converted 1 arg */
573 *argConverted = !info->fSkipArg;
574 return parsePos + skipped;
575 }
576
577 static int32_t
u_scanf_scidbl_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)578 u_scanf_scidbl_handler(UFILE *input,
579 u_scanf_spec_info *info,
580 ufmt_args *args,
581 const UChar *fmt,
582 int32_t *fmtConsumed,
583 int32_t *argConverted)
584 {
585 int32_t len;
586 double num;
587 UNumberFormat *scientificFormat, *genericFormat;
588 /*int32_t scientificResult, genericResult;*/
589 double scientificResult, genericResult;
590 int32_t scientificParsePos = 0, genericParsePos = 0, parsePos = 0;
591 int32_t skipped;
592 UErrorCode scientificStatus = U_ZERO_ERROR;
593 UErrorCode genericStatus = U_ZERO_ERROR;
594
595
596 /* since we can't determine by scanning the characters whether */
597 /* a number was formatted in the 'f' or 'g' styles, parse the */
598 /* string with both formatters, and assume whichever one */
599 /* parsed the most is the correct formatter to use */
600
601
602 /* skip all ws in the input */
603 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
604
605 /* fill the input's internal buffer */
606 ufile_fill_uchar_buffer(input);
607
608 /* determine the size of the input's buffer */
609 len = (int32_t)(input->str.fLimit - input->str.fPos);
610
611 /* truncate to the width, if specified */
612 if(info->fWidth != -1)
613 len = ufmt_min(len, info->fWidth);
614
615 /* get the formatters */
616 scientificFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SCIENTIFIC);
617 genericFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
618
619 /* handle error */
620 if(scientificFormat == 0 || genericFormat == 0)
621 return 0;
622
623 /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
624 skipped += u_scanf_skip_leading_positive_sign(input, genericFormat, &genericStatus);
625
626 /* parse the number using each format*/
627
628 scientificResult = unum_parseDouble(scientificFormat, input->str.fPos, len,
629 &scientificParsePos, &scientificStatus);
630
631 genericResult = unum_parseDouble(genericFormat, input->str.fPos, len,
632 &genericParsePos, &genericStatus);
633
634 /* determine which parse made it farther */
635 if(scientificParsePos > genericParsePos) {
636 /* stash the result in num */
637 num = scientificResult;
638 /* update the input's position to reflect consumed data */
639 parsePos += scientificParsePos;
640 }
641 else {
642 /* stash the result in num */
643 num = genericResult;
644 /* update the input's position to reflect consumed data */
645 parsePos += genericParsePos;
646 }
647 input->str.fPos += parsePos;
648
649 if (!info->fSkipArg) {
650 if (info->fIsLong)
651 *(double*)(args[0].ptrValue) = num;
652 else if (info->fIsLongDouble)
653 *(long double*)(args[0].ptrValue) = num;
654 else
655 *(float*)(args[0].ptrValue) = (float)num;
656 }
657
658 /* mask off any necessary bits */
659 /* if(! info->fIsLong_double)
660 num &= DBL_MAX;*/
661
662 /* we converted 1 arg */
663 *argConverted = !info->fSkipArg;
664 return parsePos + skipped;
665 }
666
667 static int32_t
u_scanf_integer_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)668 u_scanf_integer_handler(UFILE *input,
669 u_scanf_spec_info *info,
670 ufmt_args *args,
671 const UChar *fmt,
672 int32_t *fmtConsumed,
673 int32_t *argConverted)
674 {
675 int32_t len;
676 void *num = (void*) (args[0].ptrValue);
677 UNumberFormat *format;
678 int32_t parsePos = 0;
679 int32_t skipped;
680 UErrorCode status = U_ZERO_ERROR;
681 int64_t result;
682
683
684 /* skip all ws in the input */
685 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
686
687 /* fill the input's internal buffer */
688 ufile_fill_uchar_buffer(input);
689
690 /* determine the size of the input's buffer */
691 len = (int32_t)(input->str.fLimit - input->str.fPos);
692
693 /* truncate to the width, if specified */
694 if(info->fWidth != -1)
695 len = ufmt_min(len, info->fWidth);
696
697 /* get the formatter */
698 format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
699
700 /* handle error */
701 if(format == 0)
702 return 0;
703
704 /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
705 skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
706
707 /* parse the number */
708 result = unum_parseInt64(format, input->str.fPos, len, &parsePos, &status);
709
710 /* mask off any necessary bits */
711 if (!info->fSkipArg) {
712 if (info->fIsShort)
713 *(int16_t*)num = (int16_t)(UINT16_MAX & result);
714 else if (info->fIsLongLong)
715 *(int64_t*)num = result;
716 else
717 *(int32_t*)num = (int32_t)(UINT32_MAX & result);
718 }
719
720 /* update the input's position to reflect consumed data */
721 input->str.fPos += parsePos;
722
723 /* we converted 1 arg */
724 *argConverted = !info->fSkipArg;
725 return parsePos + skipped;
726 }
727
728 static int32_t
u_scanf_uinteger_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)729 u_scanf_uinteger_handler(UFILE *input,
730 u_scanf_spec_info *info,
731 ufmt_args *args,
732 const UChar *fmt,
733 int32_t *fmtConsumed,
734 int32_t *argConverted)
735 {
736 /* TODO Fix this when Numberformat handles uint64_t */
737 return u_scanf_integer_handler(input, info, args, fmt, fmtConsumed, argConverted);
738 }
739
740 static int32_t
u_scanf_percent_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)741 u_scanf_percent_handler(UFILE *input,
742 u_scanf_spec_info *info,
743 ufmt_args *args,
744 const UChar *fmt,
745 int32_t *fmtConsumed,
746 int32_t *argConverted)
747 {
748 int32_t len;
749 double num;
750 UNumberFormat *format;
751 int32_t parsePos = 0;
752 UErrorCode status = U_ZERO_ERROR;
753
754
755 /* skip all ws in the input */
756 u_scanf_skip_leading_ws(input, info->fPadChar);
757
758 /* fill the input's internal buffer */
759 ufile_fill_uchar_buffer(input);
760
761 /* determine the size of the input's buffer */
762 len = (int32_t)(input->str.fLimit - input->str.fPos);
763
764 /* truncate to the width, if specified */
765 if(info->fWidth != -1)
766 len = ufmt_min(len, info->fWidth);
767
768 /* get the formatter */
769 format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_PERCENT);
770
771 /* handle error */
772 if(format == 0)
773 return 0;
774
775 /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
776 u_scanf_skip_leading_positive_sign(input, format, &status);
777
778 /* parse the number */
779 num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
780
781 if (!info->fSkipArg) {
782 *(double*)(args[0].ptrValue) = num;
783 }
784
785 /* mask off any necessary bits */
786 /* if(! info->fIsLong_double)
787 num &= DBL_MAX;*/
788
789 /* update the input's position to reflect consumed data */
790 input->str.fPos += parsePos;
791
792 /* we converted 1 arg */
793 *argConverted = !info->fSkipArg;
794 return parsePos;
795 }
796
797 static int32_t
u_scanf_string_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)798 u_scanf_string_handler(UFILE *input,
799 u_scanf_spec_info *info,
800 ufmt_args *args,
801 const UChar *fmt,
802 int32_t *fmtConsumed,
803 int32_t *argConverted)
804 {
805 const UChar *source;
806 UConverter *conv;
807 char *arg = (char*)(args[0].ptrValue);
808 char *alias = arg;
809 char *limit;
810 UErrorCode status = U_ZERO_ERROR;
811 int32_t count;
812 int32_t skipped = 0;
813 UChar c;
814 UBool isNotEOF = FALSE;
815
816 /* skip all ws in the input */
817 if (info->fIsString) {
818 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
819 }
820
821 /* get the string one character at a time, truncating to the width */
822 count = 0;
823
824 /* open the default converter */
825 conv = u_getDefaultConverter(&status);
826
827 if(U_FAILURE(status))
828 return -1;
829
830 while( (info->fWidth == -1 || count < info->fWidth)
831 && (isNotEOF = ufile_getch(input, &c))
832 && (!info->fIsString || (c != info->fPadChar && !u_isWhitespace(c))))
833 {
834
835 if (!info->fSkipArg) {
836 /* put the character from the input onto the target */
837 source = &c;
838 /* Since we do this one character at a time, do it this way. */
839 if (info->fWidth > 0) {
840 limit = alias + info->fWidth - count;
841 }
842 else {
843 limit = alias + ucnv_getMaxCharSize(conv);
844 }
845
846 /* convert the character to the default codepage */
847 ucnv_fromUnicode(conv, &alias, limit, &source, source + 1,
848 NULL, TRUE, &status);
849
850 if(U_FAILURE(status)) {
851 /* clean up */
852 u_releaseDefaultConverter(conv);
853 return -1;
854 }
855 }
856
857 /* increment the count */
858 ++count;
859 }
860
861 /* put the final character we read back on the input */
862 if (!info->fSkipArg) {
863 if ((info->fWidth == -1 || count < info->fWidth) && isNotEOF)
864 u_fungetc(c, input);
865
866 /* add the terminator */
867 if (info->fIsString) {
868 *alias = 0x00;
869 }
870 }
871
872 /* clean up */
873 u_releaseDefaultConverter(conv);
874
875 /* we converted 1 arg */
876 *argConverted = !info->fSkipArg;
877 return count + skipped;
878 }
879
880 static int32_t
u_scanf_char_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)881 u_scanf_char_handler(UFILE *input,
882 u_scanf_spec_info *info,
883 ufmt_args *args,
884 const UChar *fmt,
885 int32_t *fmtConsumed,
886 int32_t *argConverted)
887 {
888 if (info->fWidth < 0) {
889 info->fWidth = 1;
890 }
891 info->fIsString = FALSE;
892 return u_scanf_string_handler(input, info, args, fmt, fmtConsumed, argConverted);
893 }
894
895 static int32_t
u_scanf_ustring_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)896 u_scanf_ustring_handler(UFILE *input,
897 u_scanf_spec_info *info,
898 ufmt_args *args,
899 const UChar *fmt,
900 int32_t *fmtConsumed,
901 int32_t *argConverted)
902 {
903 UChar *arg = (UChar*)(args[0].ptrValue);
904 UChar *alias = arg;
905 int32_t count;
906 int32_t skipped = 0;
907 UChar c;
908 UBool isNotEOF = FALSE;
909
910 /* skip all ws in the input */
911 if (info->fIsString) {
912 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
913 }
914
915 /* get the string one character at a time, truncating to the width */
916 count = 0;
917
918 while( (info->fWidth == -1 || count < info->fWidth)
919 && (isNotEOF = ufile_getch(input, &c))
920 && (!info->fIsString || (c != info->fPadChar && !u_isWhitespace(c))))
921 {
922
923 /* put the character from the input onto the target */
924 if (!info->fSkipArg) {
925 *alias++ = c;
926 }
927
928 /* increment the count */
929 ++count;
930 }
931
932 /* put the final character we read back on the input */
933 if (!info->fSkipArg) {
934 if((info->fWidth == -1 || count < info->fWidth) && isNotEOF) {
935 u_fungetc(c, input);
936 }
937
938 /* add the terminator */
939 if (info->fIsString) {
940 *alias = 0x0000;
941 }
942 }
943
944 /* we converted 1 arg */
945 *argConverted = !info->fSkipArg;
946 return count + skipped;
947 }
948
949 static int32_t
u_scanf_uchar_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)950 u_scanf_uchar_handler(UFILE *input,
951 u_scanf_spec_info *info,
952 ufmt_args *args,
953 const UChar *fmt,
954 int32_t *fmtConsumed,
955 int32_t *argConverted)
956 {
957 if (info->fWidth < 0) {
958 info->fWidth = 1;
959 }
960 info->fIsString = FALSE;
961 return u_scanf_ustring_handler(input, info, args, fmt, fmtConsumed, argConverted);
962 }
963
964 static int32_t
u_scanf_spellout_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)965 u_scanf_spellout_handler(UFILE *input,
966 u_scanf_spec_info *info,
967 ufmt_args *args,
968 const UChar *fmt,
969 int32_t *fmtConsumed,
970 int32_t *argConverted)
971 {
972 int32_t len;
973 double num;
974 UNumberFormat *format;
975 int32_t parsePos = 0;
976 int32_t skipped;
977 UErrorCode status = U_ZERO_ERROR;
978
979
980 /* skip all ws in the input */
981 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
982
983 /* fill the input's internal buffer */
984 ufile_fill_uchar_buffer(input);
985
986 /* determine the size of the input's buffer */
987 len = (int32_t)(input->str.fLimit - input->str.fPos);
988
989 /* truncate to the width, if specified */
990 if(info->fWidth != -1)
991 len = ufmt_min(len, info->fWidth);
992
993 /* get the formatter */
994 format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SPELLOUT);
995
996 /* handle error */
997 if(format == 0)
998 return 0;
999
1000 /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
1001 /* This is not applicable to RBNF. */
1002 /*skipped += u_scanf_skip_leading_positive_sign(input, format, &status);*/
1003
1004 /* parse the number */
1005 num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
1006
1007 if (!info->fSkipArg) {
1008 *(double*)(args[0].ptrValue) = num;
1009 }
1010
1011 /* mask off any necessary bits */
1012 /* if(! info->fIsLong_double)
1013 num &= DBL_MAX;*/
1014
1015 /* update the input's position to reflect consumed data */
1016 input->str.fPos += parsePos;
1017
1018 /* we converted 1 arg */
1019 *argConverted = !info->fSkipArg;
1020 return parsePos + skipped;
1021 }
1022
1023 static int32_t
u_scanf_hex_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)1024 u_scanf_hex_handler(UFILE *input,
1025 u_scanf_spec_info *info,
1026 ufmt_args *args,
1027 const UChar *fmt,
1028 int32_t *fmtConsumed,
1029 int32_t *argConverted)
1030 {
1031 int32_t len;
1032 int32_t skipped;
1033 void *num = (void*) (args[0].ptrValue);
1034 int64_t result;
1035
1036 /* skip all ws in the input */
1037 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
1038
1039 /* fill the input's internal buffer */
1040 ufile_fill_uchar_buffer(input);
1041
1042 /* determine the size of the input's buffer */
1043 len = (int32_t)(input->str.fLimit - input->str.fPos);
1044
1045 /* truncate to the width, if specified */
1046 if(info->fWidth != -1)
1047 len = ufmt_min(len, info->fWidth);
1048
1049 /* check for alternate form */
1050 if( *(input->str.fPos) == 0x0030 &&
1051 (*(input->str.fPos + 1) == 0x0078 || *(input->str.fPos + 1) == 0x0058) ) {
1052
1053 /* skip the '0' and 'x' or 'X' if present */
1054 input->str.fPos += 2;
1055 len -= 2;
1056 }
1057
1058 /* parse the number */
1059 result = ufmt_uto64(input->str.fPos, &len, 16);
1060
1061 /* update the input's position to reflect consumed data */
1062 input->str.fPos += len;
1063
1064 /* mask off any necessary bits */
1065 if (!info->fSkipArg) {
1066 if (info->fIsShort)
1067 *(int16_t*)num = (int16_t)(UINT16_MAX & result);
1068 else if (info->fIsLongLong)
1069 *(int64_t*)num = result;
1070 else
1071 *(int32_t*)num = (int32_t)(UINT32_MAX & result);
1072 }
1073
1074 /* we converted 1 arg */
1075 *argConverted = !info->fSkipArg;
1076 return len + skipped;
1077 }
1078
1079 static int32_t
u_scanf_octal_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)1080 u_scanf_octal_handler(UFILE *input,
1081 u_scanf_spec_info *info,
1082 ufmt_args *args,
1083 const UChar *fmt,
1084 int32_t *fmtConsumed,
1085 int32_t *argConverted)
1086 {
1087 int32_t len;
1088 int32_t skipped;
1089 void *num = (void*) (args[0].ptrValue);
1090 int64_t result;
1091
1092 /* skip all ws in the input */
1093 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
1094
1095 /* fill the input's internal buffer */
1096 ufile_fill_uchar_buffer(input);
1097
1098 /* determine the size of the input's buffer */
1099 len = (int32_t)(input->str.fLimit - input->str.fPos);
1100
1101 /* truncate to the width, if specified */
1102 if(info->fWidth != -1)
1103 len = ufmt_min(len, info->fWidth);
1104
1105 /* parse the number */
1106 result = ufmt_uto64(input->str.fPos, &len, 8);
1107
1108 /* update the input's position to reflect consumed data */
1109 input->str.fPos += len;
1110
1111 /* mask off any necessary bits */
1112 if (!info->fSkipArg) {
1113 if (info->fIsShort)
1114 *(int16_t*)num = (int16_t)(UINT16_MAX & result);
1115 else if (info->fIsLongLong)
1116 *(int64_t*)num = result;
1117 else
1118 *(int32_t*)num = (int32_t)(UINT32_MAX & result);
1119 }
1120
1121 /* we converted 1 arg */
1122 *argConverted = !info->fSkipArg;
1123 return len + skipped;
1124 }
1125
1126 static int32_t
u_scanf_pointer_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)1127 u_scanf_pointer_handler(UFILE *input,
1128 u_scanf_spec_info *info,
1129 ufmt_args *args,
1130 const UChar *fmt,
1131 int32_t *fmtConsumed,
1132 int32_t *argConverted)
1133 {
1134 int32_t len;
1135 int32_t skipped;
1136 void *result;
1137 void **p = (void**)(args[0].ptrValue);
1138
1139
1140 /* skip all ws in the input */
1141 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
1142
1143 /* fill the input's internal buffer */
1144 ufile_fill_uchar_buffer(input);
1145
1146 /* determine the size of the input's buffer */
1147 len = (int32_t)(input->str.fLimit - input->str.fPos);
1148
1149 /* truncate to the width, if specified */
1150 if(info->fWidth != -1) {
1151 len = ufmt_min(len, info->fWidth);
1152 }
1153
1154 /* Make sure that we don't consume too much */
1155 if (len > (int32_t)(sizeof(void*)*2)) {
1156 len = (int32_t)(sizeof(void*)*2);
1157 }
1158
1159 /* parse the pointer - assign to temporary value */
1160 result = ufmt_utop(input->str.fPos, &len);
1161
1162 if (!info->fSkipArg) {
1163 *p = result;
1164 }
1165
1166 /* update the input's position to reflect consumed data */
1167 input->str.fPos += len;
1168
1169 /* we converted 1 arg */
1170 *argConverted = !info->fSkipArg;
1171 return len + skipped;
1172 }
1173
1174 static int32_t
u_scanf_scanset_handler(UFILE * input,u_scanf_spec_info * info,ufmt_args * args,const UChar * fmt,int32_t * fmtConsumed,int32_t * argConverted)1175 u_scanf_scanset_handler(UFILE *input,
1176 u_scanf_spec_info *info,
1177 ufmt_args *args,
1178 const UChar *fmt,
1179 int32_t *fmtConsumed,
1180 int32_t *argConverted)
1181 {
1182 USet *scanset;
1183 UErrorCode status = U_ZERO_ERROR;
1184 int32_t chLeft = INT32_MAX;
1185 UChar32 c;
1186 UChar *alias = (UChar*) (args[0].ptrValue);
1187 UBool isNotEOF = FALSE;
1188 UBool readCharacter = FALSE;
1189
1190 /* Create an empty set */
1191 scanset = uset_open(0, -1);
1192
1193 /* Back up one to get the [ */
1194 fmt--;
1195
1196 /* truncate to the width, if specified and alias the target */
1197 if(info->fWidth >= 0) {
1198 chLeft = info->fWidth;
1199 }
1200
1201 /* parse the scanset from the fmt string */
1202 *fmtConsumed = uset_applyPattern(scanset, fmt, -1, 0, &status);
1203
1204 /* verify that the parse was successful */
1205 if (U_SUCCESS(status)) {
1206 c=0;
1207
1208 /* grab characters one at a time and make sure they are in the scanset */
1209 while(chLeft > 0) {
1210 if ((isNotEOF = ufile_getch32(input, &c)) && uset_contains(scanset, c)) {
1211 readCharacter = TRUE;
1212 if (!info->fSkipArg) {
1213 int32_t idx = 0;
1214 UBool isError = FALSE;
1215
1216 U16_APPEND(alias, idx, chLeft, c, isError);
1217 if (isError) {
1218 break;
1219 }
1220 alias += idx;
1221 }
1222 chLeft -= (1 + U_IS_SUPPLEMENTARY(c));
1223 }
1224 else {
1225 /* if the character's not in the scanset, break out */
1226 break;
1227 }
1228 }
1229
1230 /* put the final character we read back on the input */
1231 if(isNotEOF && chLeft > 0) {
1232 u_fungetc(c, input);
1233 }
1234 }
1235
1236 uset_close(scanset);
1237
1238 /* if we didn't match at least 1 character, fail */
1239 if(!readCharacter)
1240 return -1;
1241 /* otherwise, add the terminator */
1242 else if (!info->fSkipArg) {
1243 *alias = 0x00;
1244 }
1245
1246 /* we converted 1 arg */
1247 *argConverted = !info->fSkipArg;
1248 return (info->fWidth >= 0 ? info->fWidth : INT32_MAX) - chLeft;
1249 }
1250
1251 /* Use US-ASCII characters only for formatting. Most codepages have
1252 characters 20-7F from Unicode. Using any other codepage specific
1253 characters will make it very difficult to format the string on
1254 non-Unicode machines */
1255 static const u_scanf_info g_u_scanf_infos[USCANF_NUM_FMT_HANDLERS] = {
1256 /* 0x20 */
1257 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1258 UFMT_EMPTY, UFMT_SIMPLE_PERCENT,UFMT_EMPTY, UFMT_EMPTY,
1259 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1260 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1261
1262 /* 0x30 */
1263 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1264 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1265 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1266 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1267
1268 /* 0x40 */
1269 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR,
1270 UFMT_EMPTY, UFMT_SCIENTIFIC, UFMT_EMPTY, UFMT_SCIDBL,
1271 #ifdef U_USE_OBSOLETE_IO_FORMATTING
1272 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR/*deprecated*/,
1273 #else
1274 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1275 #endif
1276 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1277
1278 /* 0x50 */
1279 UFMT_PERCENT, UFMT_EMPTY, UFMT_EMPTY, UFMT_USTRING,
1280 #ifdef U_USE_OBSOLETE_IO_FORMATTING
1281 UFMT_EMPTY, UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT, UFMT_EMPTY,
1282 #else
1283 UFMT_EMPTY, UFMT_EMPTY, UFMT_SPELLOUT, UFMT_EMPTY,
1284 #endif
1285 UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_SCANSET,
1286 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1287
1288 /* 0x60 */
1289 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_CHAR,
1290 UFMT_INT, UFMT_SCIENTIFIC, UFMT_DOUBLE, UFMT_SCIDBL,
1291 UFMT_EMPTY, UFMT_INT, UFMT_EMPTY, UFMT_EMPTY,
1292 UFMT_EMPTY, UFMT_EMPTY, UFMT_COUNT, UFMT_OCTAL,
1293
1294 /* 0x70 */
1295 UFMT_POINTER, UFMT_EMPTY, UFMT_EMPTY, UFMT_STRING,
1296 UFMT_EMPTY, UFMT_UINT, UFMT_EMPTY, UFMT_EMPTY,
1297 UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1298 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1299 };
1300
1301 U_CFUNC int32_t
u_scanf_parse(UFILE * f,const UChar * patternSpecification,va_list ap)1302 u_scanf_parse(UFILE *f,
1303 const UChar *patternSpecification,
1304 va_list ap)
1305 {
1306 const UChar *alias;
1307 int32_t count, converted, argConsumed, cpConsumed;
1308 uint16_t handlerNum;
1309
1310 ufmt_args args;
1311 u_scanf_spec spec;
1312 ufmt_type_info info;
1313 u_scanf_handler handler;
1314
1315 /* alias the pattern */
1316 alias = patternSpecification;
1317
1318 /* haven't converted anything yet */
1319 argConsumed = 0;
1320 converted = 0;
1321 cpConsumed = 0;
1322
1323 /* iterate through the pattern */
1324 for(;;) {
1325
1326 /* match any characters up to the next '%' */
1327 while(*alias != UP_PERCENT && *alias != 0x0000 && u_fgetc(f) == *alias) {
1328 alias++;
1329 }
1330
1331 /* if we aren't at a '%', or if we're at end of string, break*/
1332 if(*alias != UP_PERCENT || *alias == 0x0000)
1333 break;
1334
1335 /* parse the specifier */
1336 count = u_scanf_parse_spec(alias, &spec);
1337
1338 /* update the pointer in pattern */
1339 alias += count;
1340
1341 handlerNum = (uint16_t)(spec.fInfo.fSpec - USCANF_BASE_FMT_HANDLERS);
1342 if (handlerNum < USCANF_NUM_FMT_HANDLERS) {
1343 /* skip the argument, if necessary */
1344 /* query the info function for argument information */
1345 info = g_u_scanf_infos[ handlerNum ].info;
1346 if (info != ufmt_count && u_feof(f)) {
1347 break;
1348 }
1349 else if(spec.fInfo.fSkipArg) {
1350 args.ptrValue = NULL;
1351 }
1352 else {
1353 switch(info) {
1354 case ufmt_count:
1355 /* set the spec's width to the # of items converted */
1356 spec.fInfo.fWidth = cpConsumed;
1357 U_FALLTHROUGH;
1358 case ufmt_char:
1359 case ufmt_uchar:
1360 case ufmt_int:
1361 case ufmt_string:
1362 case ufmt_ustring:
1363 case ufmt_pointer:
1364 case ufmt_float:
1365 case ufmt_double:
1366 args.ptrValue = va_arg(ap, void*);
1367 break;
1368
1369 default:
1370 /* else args is ignored */
1371 args.ptrValue = NULL;
1372 break;
1373 }
1374 }
1375
1376 /* call the handler function */
1377 handler = g_u_scanf_infos[ handlerNum ].handler;
1378 if(handler != 0) {
1379
1380 /* reset count to 1 so that += for alias works. */
1381 count = 1;
1382
1383 cpConsumed += (*handler)(f, &spec.fInfo, &args, alias, &count, &argConsumed);
1384
1385 /* if the handler encountered an error condition, break */
1386 if(argConsumed < 0) {
1387 converted = -1;
1388 break;
1389 }
1390
1391 /* add to the # of items converted */
1392 converted += argConsumed;
1393
1394 /* update the pointer in pattern */
1395 alias += count-1;
1396 }
1397 /* else do nothing */
1398 }
1399 /* else do nothing */
1400
1401 /* just ignore unknown tags */
1402 }
1403
1404 /* return # of items converted */
1405 return converted;
1406 }
1407
1408 #endif /* #if !UCONFIG_NO_FORMATTING */
1409