intl/icu/source/io/uscanf_p.c

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /*
     2 *******************************************************************************
     3 *
     4 *   Copyright (C) 1998-2011, 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 */
    19 #include "unicode/utypes.h"
    21 #if !UCONFIG_NO_FORMATTING
    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"
    33 #include "cmemory.h"
    34 #include "ustr_cnv.h"
    36 /* flag characters for u_scanf */
    37 #define FLAG_ASTERISK 0x002A
    38 #define FLAG_PAREN 0x0028
    40 #define ISFLAG(s)    (s) == FLAG_ASTERISK || \
    41             (s) == FLAG_PAREN
    43 /* special characters for u_scanf */
    44 #define SPEC_DOLLARSIGN 0x0024
    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
    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
    69 /* u_scanf modifiers */
    70 #define MOD_H 0x0068
    71 #define MOD_LOWERL 0x006C
    72 #define MOD_L 0x004C
    74 #define ISMOD(s)    (s) == MOD_H || \
    75             (s) == MOD_LOWERL || \
    76             (s) == MOD_L
    78 /**
    79  * Struct encapsulating a single uscanf format specification.
    80  */
    81 typedef struct u_scanf_spec_info {
    82     int32_t fWidth;         /* Width  */
    84     UChar   fSpec;          /* Format specification  */
    86     UChar   fPadChar;       /* Padding character  */
    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;
    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;
   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
   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);
   120     /* initialize spec to default values */
   121     spec->fArgPos             = -1;
   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;
   134     /* skip over the initial '%' */
   135     s++;
   137     /* Check for positional argument */
   138     if(ISDIGIT(*s)) {
   140         /* Save the current position */
   141         backup = s;
   143         /* handle positional parameters */
   144         if(ISDIGIT(*s)) {
   145             spec->fArgPos = (int) (*s++ - DIGIT_ZERO);
   147             while(ISDIGIT(*s)) {
   148                 spec->fArgPos *= 10;
   149                 spec->fArgPos += (int) (*s++ - DIGIT_ZERO);
   150             }
   151         }
   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     }
   163     /* Get any format flags */
   164     while(ISFLAG(*s)) {
   165         switch(*s++) {
   167             /* skip argument */
   168         case FLAG_ASTERISK:
   169             info->fSkipArg = TRUE;
   170             break;
   172             /* pad character specified */
   173         case FLAG_PAREN:
   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++));
   181             /* final character is ignored */
   182             s++;
   184             break;
   185         }
   186     }
   188     /* Get the width */
   189     if(ISDIGIT(*s)){
   190         info->fWidth = (int) (*s++ - DIGIT_ZERO);
   192         while(ISDIGIT(*s)) {
   193             info->fWidth *= 10;
   194             info->fWidth += (int) (*s++ - DIGIT_ZERO);
   195         }
   196     }
   198     /* Get any modifiers */
   199     if(ISMOD(*s)) {
   200         switch(*s++) {
   202             /* short */
   203         case MOD_H:
   204             info->fIsShort = TRUE;
   205             break;
   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;
   218             /* long double */
   219         case MOD_L:
   220             info->fIsLongDouble = TRUE;
   221             break;
   222         }
   223     }
   225     /* finally, get the specifier letter */
   226     info->fSpec = *s++;
   228     /* return # of characters in this specifier */
   229     return (int32_t)(s - fmt);
   230 }
   232 #define UP_PERCENT 0x0025
   235 /* ANSI style formatting */
   236 /* Use US-ASCII characters only for formatting */
   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}
   263 /* non-ANSI extensions */
   264 /* Use US-ASCII characters only for formatting */
   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}
   278 #define UFMT_EMPTY {ufmt_empty, NULL}
   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);
   303 typedef struct u_scanf_info {
   304     ufmt_type_info info;
   305     u_scanf_handler handler;
   306 } u_scanf_info;
   308 #define USCANF_NUM_FMT_HANDLERS 108
   309 #define USCANF_SYMBOL_BUFFER_SIZE 8
   311 /* We do not use handlers for 0-0x1f */
   312 #define USCANF_BASE_FMT_HANDLERS 0x20
   315 static int32_t
   316 u_scanf_skip_leading_ws(UFILE   *input,
   317                         UChar   pad)
   318 {
   319     UChar   c;
   320     int32_t count = 0;
   321     UBool isNotEOF;
   323     /* skip all leading ws in the input */
   324     while( (isNotEOF = ufile_getch(input, &c)) && (c == pad || u_isWhitespace(c)) )
   325     {
   326         count++;
   327     }
   329     /* put the final character back on the input */
   330     if(isNotEOF)
   331         u_fungetc(c, input);
   333     return count;
   334 }
   336 /* TODO: Is always skipping the prefix symbol as a positive sign a good idea in all locales? */
   337 static int32_t
   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;
   349     if (U_SUCCESS(*status)) {
   350         symbolLen = unum_getSymbol(format,
   351             UNUM_PLUS_SIGN_SYMBOL,
   352             plusSymbol,
   353             sizeof(plusSymbol)/sizeof(*plusSymbol),
   354             &localStatus);
   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             }
   363             /* put the final character back on the input */
   364             if(isNotEOF) {
   365                 u_fungetc(c, input);
   366             }
   367         }
   368     }
   370     return count;
   371 }
   373 static int32_t 
   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 }
   389 static int32_t
   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;
   409     /* we converted 0 args */
   410     return 0;
   411 }
   413 static int32_t
   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;
   429     /* skip all ws in the input */
   430     skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
   432     /* fill the input's internal buffer */
   433     ufile_fill_uchar_buffer(input);
   435     /* determine the size of the input's buffer */
   436     len = (int32_t)(input->str.fLimit - input->str.fPos);
   438     /* truncate to the width, if specified */
   439     if(info->fWidth != -1)
   440         len = ufmt_min(len, info->fWidth);
   442     /* get the formatter */
   443     format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
   445     /* handle error */
   446     if(format == 0)
   447         return 0;
   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);
   452     /* parse the number */
   453     num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
   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     }
   464     /* mask off any necessary bits */
   465     /*  if(! info->fIsLong_double)
   466     num &= DBL_MAX;*/
   468     /* update the input's position to reflect consumed data */
   469     input->str.fPos += parsePos;
   471     /* we converted 1 arg */
   472     *argConverted = !info->fSkipArg;
   473     return parsePos + skipped;
   474 }
   476 #define UPRINTF_SYMBOL_BUFFER_SIZE 8
   478 static int32_t
   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];
   497     /* skip all ws in the input */
   498     skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
   500     /* fill the input's internal buffer */
   501     ufile_fill_uchar_buffer(input);
   503     /* determine the size of the input's buffer */
   504     len = (int32_t)(input->str.fLimit - input->str.fPos);
   506     /* truncate to the width, if specified */
   507     if(info->fWidth != -1)
   508         len = ufmt_min(len, info->fWidth);
   510     /* get the formatter */
   511     format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SCIENTIFIC);
   513     /* handle error */
   514     if(format == 0)
   515         return 0;
   517     /* set the appropriate flags on the formatter */
   519     srcLen = unum_getSymbol(format,
   520         UNUM_EXPONENTIAL_SYMBOL,
   521         srcExpBuf,
   522         sizeof(srcExpBuf),
   523         &status);
   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     }
   539     unum_setSymbol(format,
   540         UNUM_EXPONENTIAL_SYMBOL,
   541         expBuf,
   542         expLen,
   543         &status);
   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);
   551     /* parse the number */
   552     num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
   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     }
   563     /* mask off any necessary bits */
   564     /*  if(! info->fIsLong_double)
   565     num &= DBL_MAX;*/
   567     /* update the input's position to reflect consumed data */
   568     input->str.fPos += parsePos;
   570     /* we converted 1 arg */
   571     *argConverted = !info->fSkipArg;
   572     return parsePos + skipped;
   573 }
   575 static int32_t
   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;
   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 */
   600     /* skip all ws in the input */
   601     skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
   603     /* fill the input's internal buffer */
   604     ufile_fill_uchar_buffer(input);
   606     /* determine the size of the input's buffer */
   607     len = (int32_t)(input->str.fLimit - input->str.fPos);
   609     /* truncate to the width, if specified */
   610     if(info->fWidth != -1)
   611         len = ufmt_min(len, info->fWidth);
   613     /* get the formatters */
   614     scientificFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SCIENTIFIC);
   615     genericFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
   617     /* handle error */
   618     if(scientificFormat == 0 || genericFormat == 0)
   619         return 0;
   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);
   624     /* parse the number using each format*/
   626     scientificResult = unum_parseDouble(scientificFormat, input->str.fPos, len,
   627         &scientificParsePos, &scientificStatus);
   629     genericResult = unum_parseDouble(genericFormat, input->str.fPos, len,
   630         &genericParsePos, &genericStatus);
   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;
   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     }
   656     /* mask off any necessary bits */
   657     /*  if(! info->fIsLong_double)
   658     num &= DBL_MAX;*/
   660     /* we converted 1 arg */
   661     *argConverted = !info->fSkipArg;
   662     return parsePos + skipped;
   663 }
   665 static int32_t
   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;
   682     /* skip all ws in the input */
   683     skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
   685     /* fill the input's internal buffer */
   686     ufile_fill_uchar_buffer(input);
   688     /* determine the size of the input's buffer */
   689     len = (int32_t)(input->str.fLimit - input->str.fPos);
   691     /* truncate to the width, if specified */
   692     if(info->fWidth != -1)
   693         len = ufmt_min(len, info->fWidth);
   695     /* get the formatter */
   696     format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
   698     /* handle error */
   699     if(format == 0)
   700         return 0;
   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);
   705     /* parse the number */
   706     result = unum_parseInt64(format, input->str.fPos, len, &parsePos, &status);
   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     }
   718     /* update the input's position to reflect consumed data */
   719     input->str.fPos += parsePos;
   721     /* we converted 1 arg */
   722     *argConverted = !info->fSkipArg;
   723     return parsePos + skipped;
   724 }
   726 static int32_t
   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 }
   738 static int32_t
   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;
   753     /* skip all ws in the input */
   754     u_scanf_skip_leading_ws(input, info->fPadChar);
   756     /* fill the input's internal buffer */
   757     ufile_fill_uchar_buffer(input);
   759     /* determine the size of the input's buffer */
   760     len = (int32_t)(input->str.fLimit - input->str.fPos);
   762     /* truncate to the width, if specified */
   763     if(info->fWidth != -1)
   764         len = ufmt_min(len, info->fWidth);
   766     /* get the formatter */
   767     format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_PERCENT);
   769     /* handle error */
   770     if(format == 0)
   771         return 0;
   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);
   776     /* parse the number */
   777     num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
   779     if (!info->fSkipArg) {
   780         *(double*)(args[0].ptrValue) = num;
   781     }
   783     /* mask off any necessary bits */
   784     /*  if(! info->fIsLong_double)
   785     num &= DBL_MAX;*/
   787     /* update the input's position to reflect consumed data */
   788     input->str.fPos += parsePos;
   790     /* we converted 1 arg */
   791     *argConverted = !info->fSkipArg;
   792     return parsePos;
   793 }
   795 static int32_t
   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;
   814     /* skip all ws in the input */
   815     if (info->fIsString) {
   816         skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
   817     }
   819     /* get the string one character at a time, truncating to the width */
   820     count = 0;
   822     /* open the default converter */
   823     conv = u_getDefaultConverter(&status);
   825     if(U_FAILURE(status))
   826         return -1;
   828     while( (info->fWidth == -1 || count < info->fWidth) 
   829         && (isNotEOF = ufile_getch(input, &c))
   830         && (!info->fIsString || (c != info->fPadChar && !u_isWhitespace(c))))
   831     {
   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             }
   844             /* convert the character to the default codepage */
   845             ucnv_fromUnicode(conv, &alias, limit, &source, source + 1,
   846                 NULL, TRUE, &status);
   848             if(U_FAILURE(status)) {
   849                 /* clean up */
   850                 u_releaseDefaultConverter(conv);
   851                 return -1;
   852             }
   853         }
   855         /* increment the count */
   856         ++count;
   857     }
   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);
   864         /* add the terminator */
   865         if (info->fIsString) {
   866             *alias = 0x00;
   867         }
   868     }
   870     /* clean up */
   871     u_releaseDefaultConverter(conv);
   873     /* we converted 1 arg */
   874     *argConverted = !info->fSkipArg;
   875     return count + skipped;
   876 }
   878 static int32_t
   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 }
   893 static int32_t
   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;
   908     /* skip all ws in the input */
   909     if (info->fIsString) {
   910         skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
   911     }
   913     /* get the string one character at a time, truncating to the width */
   914     count = 0;
   916     while( (info->fWidth == -1 || count < info->fWidth)
   917         && (isNotEOF = ufile_getch(input, &c))
   918         && (!info->fIsString || (c != info->fPadChar && !u_isWhitespace(c))))
   919     {
   921         /* put the character from the input onto the target */
   922         if (!info->fSkipArg) {
   923             *alias++ = c;
   924         }
   926         /* increment the count */
   927         ++count;
   928     }
   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         }
   936         /* add the terminator */
   937         if (info->fIsString) {
   938             *alias = 0x0000;
   939         }
   940     }
   942     /* we converted 1 arg */
   943     *argConverted = !info->fSkipArg;
   944     return count + skipped;
   945 }
   947 static int32_t
   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 }
   962 static int32_t
   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;
   978     /* skip all ws in the input */
   979     skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
   981     /* fill the input's internal buffer */
   982     ufile_fill_uchar_buffer(input);
   984     /* determine the size of the input's buffer */
   985     len = (int32_t)(input->str.fLimit - input->str.fPos);
   987     /* truncate to the width, if specified */
   988     if(info->fWidth != -1)
   989         len = ufmt_min(len, info->fWidth);
   991     /* get the formatter */
   992     format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SPELLOUT);
   994     /* handle error */
   995     if(format == 0)
   996         return 0;
   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);*/
  1002     /* parse the number */
  1003     num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
  1005     if (!info->fSkipArg) {
  1006         *(double*)(args[0].ptrValue) = num;
  1009     /* mask off any necessary bits */
  1010     /*  if(! info->fIsLong_double)
  1011     num &= DBL_MAX;*/
  1013     /* update the input's position to reflect consumed data */
  1014     input->str.fPos += parsePos;
  1016     /* we converted 1 arg */
  1017     *argConverted = !info->fSkipArg;
  1018     return parsePos + skipped;
  1021 static int32_t
  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)
  1029     int32_t     len;
  1030     int32_t     skipped;
  1031     void        *num    = (void*) (args[0].ptrValue);
  1032     int64_t     result;
  1034     /* skip all ws in the input */
  1035     skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
  1037     /* fill the input's internal buffer */
  1038     ufile_fill_uchar_buffer(input);
  1040     /* determine the size of the input's buffer */
  1041     len = (int32_t)(input->str.fLimit - input->str.fPos);
  1043     /* truncate to the width, if specified */
  1044     if(info->fWidth != -1)
  1045         len = ufmt_min(len, info->fWidth);
  1047     /* check for alternate form */
  1048     if( *(input->str.fPos) == 0x0030 &&
  1049         (*(input->str.fPos + 1) == 0x0078 || *(input->str.fPos + 1) == 0x0058) ) {
  1051         /* skip the '0' and 'x' or 'X' if present */
  1052         input->str.fPos += 2;
  1053         len -= 2;
  1056     /* parse the number */
  1057     result = ufmt_uto64(input->str.fPos, &len, 16);
  1059     /* update the input's position to reflect consumed data */
  1060     input->str.fPos += len;
  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);
  1072     /* we converted 1 arg */
  1073     *argConverted = !info->fSkipArg;
  1074     return len + skipped;
  1077 static int32_t
  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)
  1085     int32_t     len;
  1086     int32_t     skipped;
  1087     void        *num         = (void*) (args[0].ptrValue);
  1088     int64_t     result;
  1090     /* skip all ws in the input */
  1091     skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
  1093     /* fill the input's internal buffer */
  1094     ufile_fill_uchar_buffer(input);
  1096     /* determine the size of the input's buffer */
  1097     len = (int32_t)(input->str.fLimit - input->str.fPos);
  1099     /* truncate to the width, if specified */
  1100     if(info->fWidth != -1)
  1101         len = ufmt_min(len, info->fWidth);
  1103     /* parse the number */
  1104     result = ufmt_uto64(input->str.fPos, &len, 8);
  1106     /* update the input's position to reflect consumed data */
  1107     input->str.fPos += len;
  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);
  1119     /* we converted 1 arg */
  1120     *argConverted = !info->fSkipArg;
  1121     return len + skipped;
  1124 static int32_t
  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)
  1132     int32_t len;
  1133     int32_t skipped;
  1134     void    *result;
  1135     void    **p     = (void**)(args[0].ptrValue);
  1138     /* skip all ws in the input */
  1139     skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
  1141     /* fill the input's internal buffer */
  1142     ufile_fill_uchar_buffer(input);
  1144     /* determine the size of the input's buffer */
  1145     len = (int32_t)(input->str.fLimit - input->str.fPos);
  1147     /* truncate to the width, if specified */
  1148     if(info->fWidth != -1) {
  1149         len = ufmt_min(len, info->fWidth);
  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);
  1157     /* parse the pointer - assign to temporary value */
  1158     result = ufmt_utop(input->str.fPos, &len);
  1160     if (!info->fSkipArg) {
  1161         *p = result;
  1164     /* update the input's position to reflect consumed data */
  1165     input->str.fPos += len;
  1167     /* we converted 1 arg */
  1168     *argConverted = !info->fSkipArg;
  1169     return len + skipped;
  1172 static int32_t
  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)
  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;
  1188     /* Create an empty set */
  1189     scanset = uset_open(0, -1);
  1191     /* Back up one to get the [ */
  1192     fmt--;
  1194     /* truncate to the width, if specified and alias the target */
  1195     if(info->fWidth >= 0) {
  1196         chLeft = info->fWidth;
  1199     /* parse the scanset from the fmt string */
  1200     *fmtConsumed = uset_applyPattern(scanset, fmt, -1, 0, &status);
  1202     /* verify that the parse was successful */
  1203     if (U_SUCCESS(status)) {
  1204         c=0;
  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;
  1214                     U16_APPEND(alias, idx, chLeft, c, isError);
  1215                     if (isError) {
  1216                         break;
  1218                     alias += idx;
  1220                 chLeft -= (1 + U_IS_SUPPLEMENTARY(c));
  1222             else {
  1223                 /* if the character's not in the scanset, break out */
  1224                 break;
  1228         /* put the final character we read back on the input */
  1229         if(isNotEOF && chLeft > 0) {
  1230             u_fungetc(c, input);
  1234     uset_close(scanset);
  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;
  1244     /* we converted 1 arg */
  1245     *argConverted = !info->fSkipArg;
  1246     return (info->fWidth >= 0 ? info->fWidth : INT32_MAX) - chLeft;
  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,
  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,
  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,
  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,
  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,
  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 };
  1299 U_CFUNC int32_t
  1300 u_scanf_parse(UFILE     *f,
  1301             const UChar *patternSpecification,
  1302             va_list     ap)
  1304     const UChar     *alias;
  1305     int32_t         count, converted, argConsumed, cpConsumed;
  1306     uint16_t        handlerNum;
  1308     ufmt_args       args;
  1309     u_scanf_spec    spec;
  1310     ufmt_type_info  info;
  1311     u_scanf_handler handler;
  1313     /* alias the pattern */
  1314     alias = patternSpecification;
  1316     /* haven't converted anything yet */
  1317     argConsumed = 0;
  1318     converted = 0;
  1319     cpConsumed = 0;
  1321     /* iterate through the pattern */
  1322     for(;;) {
  1324         /* match any characters up to the next '%' */
  1325         while(*alias != UP_PERCENT && *alias != 0x0000 && u_fgetc(f) == *alias) {
  1326             alias++;
  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;
  1333         /* parse the specifier */
  1334         count = u_scanf_parse_spec(alias, &spec);
  1336         /* update the pointer in pattern */
  1337         alias += count;
  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;
  1347             else if(spec.fInfo.fSkipArg) {
  1348                 args.ptrValue = NULL;
  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;
  1367                 default:
  1368                     /* else args is ignored */
  1369                     args.ptrValue = NULL;
  1370                     break;
  1374             /* call the handler function */
  1375             handler = g_u_scanf_infos[ handlerNum ].handler;
  1376             if(handler != 0) {
  1378                 /* reset count to 1 so that += for alias works. */
  1379                 count = 1;
  1381                 cpConsumed += (*handler)(f, &spec.fInfo, &args, alias, &count, &argConsumed);
  1383                 /* if the handler encountered an error condition, break */
  1384                 if(argConsumed < 0) {
  1385                     converted = -1;
  1386                     break;
  1389                 /* add to the # of items converted */
  1390                 converted += argConsumed;
  1392                 /* update the pointer in pattern */
  1393                 alias += count-1;
  1395             /* else do nothing */
  1397         /* else do nothing */
  1399         /* just ignore unknown tags */
  1402     /* return # of items converted */
  1403     return converted;
  1406 #endif /* #if !UCONFIG_NO_FORMATTING */

mercurial