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