tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

uprntf_p.cpp (54019B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 ******************************************************************************
      5 *
      6 *   Copyright (C) 1998-2016, International Business Machines
      7 *   Corporation and others.  All Rights Reserved.
      8 *
      9 ******************************************************************************
     10 *
     11 * File uprntf_p.c
     12 *
     13 * Modification History:
     14 *
     15 *   Date        Name        Description
     16 *   11/23/98    stephen     Creation.
     17 *   03/12/99    stephen     Modified for new C API.
     18 *   08/07/2003  george      Reunify printf implementations
     19 ******************************************************************************
     20 */
     21 
     22 #include "unicode/utypes.h"
     23 
     24 #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_CONVERSION
     25 
     26 #include "unicode/ustring.h"
     27 #include "unicode/utf16.h"
     28 #include "uprintf.h"
     29 #include "ufmt_cmn.h"
     30 #include "cmemory.h"
     31 #include "putilimp.h"
     32 
     33 /* ANSI style formatting */
     34 /* Use US-ASCII characters only for formatting */
     35 
     36 /* % */
     37 #define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_printf_simple_percent_handler}
     38 /* s */
     39 #define UFMT_STRING         {ufmt_string, u_printf_string_handler}
     40 /* c */
     41 #define UFMT_CHAR           {ufmt_char, u_printf_char_handler}
     42 /* d, i */
     43 #define UFMT_INT            {ufmt_int, u_printf_integer_handler}
     44 /* u */
     45 #define UFMT_UINT           {ufmt_int, u_printf_uinteger_handler}
     46 /* o */
     47 #define UFMT_OCTAL          {ufmt_int, u_printf_octal_handler}
     48 /* x, X */
     49 #define UFMT_HEX            {ufmt_int, u_printf_hex_handler}
     50 /* f */
     51 #define UFMT_DOUBLE         {ufmt_double, u_printf_double_handler}
     52 /* e, E */
     53 #define UFMT_SCIENTIFIC     {ufmt_double, u_printf_scientific_handler}
     54 /* g, G */
     55 #define UFMT_SCIDBL         {ufmt_double, u_printf_scidbl_handler}
     56 /* n */
     57 #define UFMT_COUNT          {ufmt_count, u_printf_count_handler}
     58 
     59 /* non-ANSI extensions */
     60 /* Use US-ASCII characters only for formatting */
     61 
     62 /* p */
     63 #define UFMT_POINTER        {ufmt_pointer, u_printf_pointer_handler}
     64 /* V */
     65 #define UFMT_SPELLOUT       {ufmt_double, u_printf_spellout_handler}
     66 /* P */
     67 #define UFMT_PERCENT        {ufmt_double, u_printf_percent_handler}
     68 /* C  K is old format */
     69 #define UFMT_UCHAR          {ufmt_uchar, u_printf_uchar_handler}
     70 /* S  U is old format */
     71 #define UFMT_USTRING        {ufmt_ustring, u_printf_ustring_handler}
     72 
     73 
     74 #define UFMT_EMPTY {ufmt_empty, nullptr}
     75 
     76 /**
     77 * A u_printf handler function.  
     78 * A u_printf handler is responsible for handling a single u_printf 
     79 * format specification, for example 'd' or 's'.
     80 * @param stream The UFILE to which to write output.
     81 * @param info A pointer to a <TT>u_printf_spec_info</TT> struct containing
     82 * information on the format specification.
     83 * @param args A pointer to the argument data
     84 * @return The number of Unicode characters written to <TT>stream</TT>.
     85 */
     86 typedef int32_t U_EXPORT2
     87 u_printf_handler(const u_printf_stream_handler  *handler,
     88 
     89                 void                           *context,
     90                 ULocaleBundle                  *formatBundle,
     91                 const u_printf_spec_info       *info,
     92                 const ufmt_args                *args);
     93 
     94 typedef struct u_printf_info {
     95    ufmt_type_info info;
     96    u_printf_handler *handler;
     97 } u_printf_info;
     98 
     99 /**
    100 * Struct encapsulating a single uprintf format specification.
    101 */
    102 typedef struct u_printf_spec {
    103  u_printf_spec_info    fInfo;        /* Information on this spec */
    104  int32_t        fWidthPos;     /* Position of width in arg list */
    105  int32_t        fPrecisionPos;    /* Position of precision in arg list */
    106  int32_t        fArgPos;    /* Position of data in arg list */
    107 } u_printf_spec;
    108 
    109 #define UPRINTF_NUM_FMT_HANDLERS 108
    110 
    111 /* We do not use handlers for 0-0x1f */
    112 #define UPRINTF_BASE_FMT_HANDLERS 0x20
    113 
    114 /* buffer size for formatting */
    115 #define UPRINTF_BUFFER_SIZE 1024
    116 #define UPRINTF_SYMBOL_BUFFER_SIZE 8
    117 
    118 static const char16_t gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
    119 static const char16_t gSpaceStr[] = {0x20, 0}; /* " " */
    120 
    121 /* Sets the sign of a format based on u_printf_spec_info */
    122 /* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */
    123 static void
    124 u_printf_set_sign(UNumberFormat        *format,
    125                   const u_printf_spec_info     *info,
    126                   char16_t *prefixBuffer,
    127                   int32_t *prefixBufLen,
    128                   UErrorCode *status)
    129 {
    130    if(info->fShowSign) {
    131        *prefixBufLen = unum_getTextAttribute(format,
    132                                              UNUM_POSITIVE_PREFIX,
    133                                              prefixBuffer,
    134                                              *prefixBufLen,
    135                                              status);
    136        if (info->fSpace) {
    137            /* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */
    138            /* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */
    139            unum_setTextAttribute(format, UNUM_POSITIVE_PREFIX, gSpaceStr, 1, status);
    140        }
    141        else {
    142            char16_t plusSymbol[UPRINTF_SYMBOL_BUFFER_SIZE];
    143            int32_t symbolLen;
    144 
    145            symbolLen = unum_getSymbol(format,
    146                UNUM_PLUS_SIGN_SYMBOL,
    147                plusSymbol,
    148                UPRV_LENGTHOF(plusSymbol),
    149                status);
    150            unum_setTextAttribute(format,
    151                UNUM_POSITIVE_PREFIX,
    152                plusSymbol,
    153                symbolLen,
    154                status);
    155        }
    156    }
    157    else {
    158        *prefixBufLen = 0;
    159    }
    160 }
    161 
    162 static void
    163 u_printf_reset_sign(UNumberFormat        *format,
    164                   const u_printf_spec_info     *info,
    165                   char16_t *prefixBuffer,
    166                   int32_t *prefixBufLen,
    167                   UErrorCode *status)
    168 {
    169    if(info->fShowSign) {
    170        unum_setTextAttribute(format,
    171                              UNUM_POSITIVE_PREFIX,
    172                              prefixBuffer,
    173                              *prefixBufLen,
    174                              status);
    175    }
    176 }
    177 
    178 
    179 /* handle a '%' */
    180 static int32_t
    181 u_printf_simple_percent_handler(const u_printf_stream_handler  *handler,
    182                                void                           *context,
    183                                ULocaleBundle                  *formatBundle,
    184                                const u_printf_spec_info       *info,
    185                                const ufmt_args                *args)
    186 {
    187    (void)formatBundle;
    188    (void)info;
    189    (void)args;
    190    static const char16_t PERCENT[] = { UP_PERCENT };
    191 
    192    /* put a single '%' onto the output */
    193    return handler->write(context, PERCENT, 1);
    194 }
    195 
    196 /* handle 's' */
    197 static int32_t
    198 u_printf_string_handler(const u_printf_stream_handler  *handler,
    199                        void                           *context,
    200                        ULocaleBundle                  *formatBundle,
    201                        const u_printf_spec_info       *info,
    202                        const ufmt_args                *args)
    203 {
    204    (void)formatBundle;
    205    char16_t *s;
    206    char16_t buffer[UFMT_DEFAULT_BUFFER_SIZE];
    207    int32_t len, written;
    208    int32_t argSize;
    209    const char* arg = static_cast<const char*>(args[0].ptrValue);
    210 
    211    /* convert from the default codepage to Unicode */
    212    if (arg) {
    213        argSize = static_cast<int32_t>(strlen(arg)) + 1;
    214        if (argSize >= MAX_UCHAR_BUFFER_SIZE(buffer)) {
    215            s = ufmt_defaultCPToUnicode(arg, argSize,
    216                    static_cast<char16_t*>(uprv_malloc(MAX_UCHAR_BUFFER_NEEDED(argSize))),
    217                    MAX_UCHAR_BUFFER_NEEDED(argSize));
    218            if(s == nullptr) {
    219                return 0;
    220            }
    221        }
    222        else {
    223            s = ufmt_defaultCPToUnicode(arg, argSize, buffer,
    224                    UPRV_LENGTHOF(buffer));
    225        }
    226    }
    227    else {
    228        s = (char16_t *)gNullStr;
    229    }
    230    len = u_strlen(s);
    231 
    232    /* width = minimum # of characters to write */
    233    /* precision = maximum # of characters to write */
    234    if (info->fPrecision != -1 && info->fPrecision < len) {
    235        len = info->fPrecision;
    236    }
    237 
    238    written = handler->pad_and_justify(context, info, s, len);
    239 
    240    /* clean up */
    241    if (gNullStr != s && buffer != s) {
    242        uprv_free(s);
    243    }
    244 
    245    return written;
    246 }
    247 
    248 static int32_t
    249 u_printf_char_handler(const u_printf_stream_handler  *handler,
    250                      void                           *context,
    251                      ULocaleBundle                  *formatBundle,
    252                      const u_printf_spec_info       *info,
    253                      const ufmt_args                *args)
    254 {
    255    (void)formatBundle;
    256    char16_t s[U16_MAX_LENGTH+1];
    257    int32_t len = 1, written;
    258    unsigned char arg = static_cast<unsigned char>(args[0].int64Value);
    259 
    260    /* convert from default codepage to Unicode */
    261    ufmt_defaultCPToUnicode(reinterpret_cast<const char*>(&arg), 2, s, UPRV_LENGTHOF(s));
    262 
    263    /* Remember that this may be an MBCS character */
    264    if (arg != 0) {
    265        len = u_strlen(s);
    266    }
    267 
    268    /* width = minimum # of characters to write */
    269    /* precision = maximum # of characters to write */
    270    /* precision is ignored when handling a char */
    271 
    272    written = handler->pad_and_justify(context, info, s, len);
    273 
    274    return written;
    275 }
    276 
    277 static int32_t
    278 u_printf_double_handler(const u_printf_stream_handler  *handler,
    279                        void                           *context,
    280                        ULocaleBundle                  *formatBundle,
    281                        const u_printf_spec_info       *info,
    282                        const ufmt_args                *args)
    283 {
    284    double num = args[0].doubleValue;
    285    UNumberFormat  *format;
    286    char16_t       result[UPRINTF_BUFFER_SIZE];
    287    char16_t       prefixBuffer[UPRINTF_BUFFER_SIZE];
    288    int32_t        prefixBufferLen = sizeof(prefixBuffer);
    289    int32_t        minDecimalDigits;
    290    int32_t        maxDecimalDigits;
    291    int32_t        resultLen;
    292    UErrorCode     status        = U_ZERO_ERROR;
    293 
    294    prefixBuffer[0] = 0;
    295 
    296    /* mask off any necessary bits */
    297    /*  if(! info->fIsLongDouble)
    298    num &= DBL_MAX;*/
    299 
    300    /* get the formatter */
    301    format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
    302 
    303    /* handle error */
    304    if (format == nullptr)
    305        return 0;
    306 
    307    /* save the formatter's state */
    308    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
    309    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
    310 
    311    /* set the appropriate flags and number of decimal digits on the formatter */
    312    if(info->fPrecision != -1) {
    313        /* set the # of decimal digits */
    314        unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
    315    }
    316    else if(info->fAlt) {
    317        /* '#' means always show decimal point */
    318        /* copy of printf behavior on Solaris - '#' shows 6 digits */
    319        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    320    }
    321    else {
    322        /* # of decimal digits is 6 if precision not specified regardless of locale */
    323        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    324    }
    325 
    326    /* set whether to show the sign */
    327    if (info->fShowSign) {
    328        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    329    }
    330 
    331    /* format the number */
    332    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status);
    333 
    334    if (U_FAILURE(status)) {
    335        resultLen = 0;
    336    }
    337 
    338    /* restore the number format */
    339    /* TODO: Is this needed? */
    340    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
    341    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
    342 
    343    if (info->fShowSign) {
    344        /* Reset back to original value regardless of what the error was */
    345        UErrorCode localStatus = U_ZERO_ERROR;
    346        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    347    }
    348 
    349    return handler->pad_and_justify(context, info, result, resultLen);
    350 }
    351 
    352 /* HSYS */
    353 static int32_t
    354 u_printf_integer_handler(const u_printf_stream_handler  *handler,
    355                         void                           *context,
    356                         ULocaleBundle                  *formatBundle,
    357                         const u_printf_spec_info       *info,
    358                         const ufmt_args                *args)
    359 {
    360    int64_t         num        = args[0].int64Value;
    361    UNumberFormat   *format;
    362    char16_t        result[UPRINTF_BUFFER_SIZE];
    363    char16_t        prefixBuffer[UPRINTF_BUFFER_SIZE];
    364    int32_t         prefixBufferLen = sizeof(prefixBuffer);
    365    int32_t         minDigits     = -1;
    366    int32_t         resultLen;
    367    UErrorCode      status        = U_ZERO_ERROR;
    368 
    369    prefixBuffer[0] = 0;
    370 
    371    /* mask off any necessary bits */
    372    if (info->fIsShort)
    373        num = static_cast<int16_t>(num);
    374    else if (!info->fIsLongLong)
    375        num = static_cast<int32_t>(num);
    376 
    377    /* get the formatter */
    378    format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
    379 
    380    /* handle error */
    381    if (format == nullptr)
    382        return 0;
    383 
    384    /* set the appropriate flags on the formatter */
    385 
    386    /* set the minimum integer digits */
    387    if(info->fPrecision != -1) {
    388        /* set the minimum # of digits */
    389        minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
    390        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
    391    }
    392 
    393    /* set whether to show the sign */
    394    if(info->fShowSign) {
    395        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    396    }
    397 
    398    /* format the number */
    399    resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status);
    400 
    401    if (U_FAILURE(status)) {
    402        resultLen = 0;
    403    }
    404 
    405    /* restore the number format */
    406    if (minDigits != -1) {
    407        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
    408    }
    409 
    410    if (info->fShowSign) {
    411        /* Reset back to original value regardless of what the error was */
    412        UErrorCode localStatus = U_ZERO_ERROR;
    413        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    414    }
    415 
    416    return handler->pad_and_justify(context, info, result, resultLen);
    417 }
    418 
    419 static int32_t
    420 u_printf_hex_handler(const u_printf_stream_handler  *handler,
    421                     void                           *context,
    422                     ULocaleBundle                  *formatBundle,
    423                     const u_printf_spec_info       *info,
    424                     const ufmt_args                *args)
    425 {
    426    (void)formatBundle;
    427    int64_t         num        = args[0].int64Value;
    428    char16_t        result[UPRINTF_BUFFER_SIZE];
    429    int32_t         len        = UPRINTF_BUFFER_SIZE;
    430 
    431 
    432    /* mask off any necessary bits */
    433    if (info->fIsShort)
    434        num &= UINT16_MAX;
    435    else if (!info->fIsLongLong)
    436        num &= UINT32_MAX;
    437 
    438    /* format the number, preserving the minimum # of digits */
    439    ufmt_64tou(result, &len, num, 16,
    440        static_cast<UBool>(info->fSpec == 0x0078),
    441        (info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);
    442 
    443    /* convert to alt form, if desired */
    444    if(num != 0 && info->fAlt && len < UPRINTF_BUFFER_SIZE - 2) {
    445        /* shift the formatted string right by 2 chars */
    446        memmove(result + 2, result, len * sizeof(char16_t));
    447        result[0] = 0x0030;
    448        result[1] = info->fSpec;
    449        len += 2;
    450    }
    451 
    452    return handler->pad_and_justify(context, info, result, len);
    453 }
    454 
    455 static int32_t
    456 u_printf_octal_handler(const u_printf_stream_handler  *handler,
    457                       void                           *context,
    458                       ULocaleBundle                  *formatBundle,
    459                       const u_printf_spec_info       *info,
    460                       const ufmt_args                *args)
    461 {
    462    (void)formatBundle;
    463    int64_t         num        = args[0].int64Value;
    464    char16_t        result[UPRINTF_BUFFER_SIZE];
    465    int32_t         len        = UPRINTF_BUFFER_SIZE;
    466 
    467 
    468    /* mask off any necessary bits */
    469    if (info->fIsShort)
    470        num &= UINT16_MAX;
    471    else if (!info->fIsLongLong)
    472        num &= UINT32_MAX;
    473 
    474    /* format the number, preserving the minimum # of digits */
    475    ufmt_64tou(result, &len, num, 8,
    476        false, /* doesn't matter for octal */
    477        info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);
    478 
    479    /* convert to alt form, if desired */
    480    if(info->fAlt && result[0] != 0x0030 && len < UPRINTF_BUFFER_SIZE - 1) {
    481        /* shift the formatted string right by 1 char */
    482        memmove(result + 1, result, len * sizeof(char16_t));
    483        result[0] = 0x0030;
    484        len += 1;
    485    }
    486 
    487    return handler->pad_and_justify(context, info, result, len);
    488 }
    489 
    490 static int32_t
    491 u_printf_uinteger_handler(const u_printf_stream_handler *handler,
    492                          void                          *context,
    493                          ULocaleBundle                 *formatBundle,
    494                          const u_printf_spec_info      *info,
    495                          const ufmt_args               *args)
    496 {
    497    int64_t         num        = args[0].int64Value;
    498    UNumberFormat   *format;
    499    char16_t        result[UPRINTF_BUFFER_SIZE];
    500    int32_t         minDigits     = -1;
    501    int32_t         resultLen;
    502    UErrorCode      status        = U_ZERO_ERROR;
    503 
    504    /* TODO: Fix this once uint64_t can be formatted. */
    505    if (info->fIsShort)
    506        num &= UINT16_MAX;
    507    else if (!info->fIsLongLong)
    508        num &= UINT32_MAX;
    509 
    510    /* get the formatter */
    511    format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
    512 
    513    /* handle error */
    514    if (format == nullptr)
    515        return 0;
    516 
    517    /* set the appropriate flags on the formatter */
    518 
    519    /* set the minimum integer digits */
    520    if(info->fPrecision != -1) {
    521        /* set the minimum # of digits */
    522        minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
    523        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
    524    }
    525 
    526    /* To mirror other stdio implementations, we ignore the sign argument */
    527 
    528    /* format the number */
    529    resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status);
    530 
    531    if (U_FAILURE(status)) {
    532        resultLen = 0;
    533    }
    534 
    535    /* restore the number format */
    536    if (minDigits != -1) {
    537        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
    538    }
    539 
    540    return handler->pad_and_justify(context, info, result, resultLen);
    541 }
    542 
    543 static int32_t
    544 u_printf_pointer_handler(const u_printf_stream_handler  *handler,
    545                         void                           *context,
    546                         ULocaleBundle                  *formatBundle,
    547                         const u_printf_spec_info       *info,
    548                         const ufmt_args                *args)
    549 { 
    550    (void)formatBundle;
    551    char16_t        result[UPRINTF_BUFFER_SIZE];
    552    int32_t         len  = UPRINTF_BUFFER_SIZE;
    553 
    554    /* format the pointer in hex */
    555    ufmt_ptou(result, &len, args[0].ptrValue, true/*, info->fPrecision*/);
    556 
    557    return handler->pad_and_justify(context, info, result, len);
    558 }
    559 
    560 static int32_t
    561 u_printf_scientific_handler(const u_printf_stream_handler  *handler,
    562                            void                           *context,
    563                            ULocaleBundle                  *formatBundle,
    564                            const u_printf_spec_info       *info,
    565                            const ufmt_args                *args)
    566 {
    567    double num = args[0].doubleValue;
    568    UNumberFormat   *format;
    569    char16_t        result[UPRINTF_BUFFER_SIZE];
    570    char16_t        prefixBuffer[UPRINTF_BUFFER_SIZE];
    571    int32_t         prefixBufferLen = sizeof(prefixBuffer);
    572    int32_t         minDecimalDigits;
    573    int32_t         maxDecimalDigits;
    574    UErrorCode      status        = U_ZERO_ERROR;
    575    char16_t srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
    576    int32_t srcLen, expLen;
    577    int32_t resultLen;
    578    char16_t expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
    579 
    580    prefixBuffer[0] = 0;
    581 
    582    /* mask off any necessary bits */
    583    /*  if(! info->fIsLongDouble)
    584    num &= DBL_MAX;*/
    585 
    586    /* get the formatter */
    587    format = u_locbund_getNumberFormat(formatBundle, UNUM_SCIENTIFIC);
    588 
    589    /* handle error */
    590    if (format == nullptr)
    591        return 0;
    592 
    593    /* set the appropriate flags on the formatter */
    594 
    595    srcLen = unum_getSymbol(format,
    596        UNUM_EXPONENTIAL_SYMBOL,
    597        srcExpBuf,
    598        sizeof(srcExpBuf),
    599        &status);
    600 
    601    /* Upper/lower case the e */
    602    if (info->fSpec == static_cast<char16_t>(0x65) /* e */) {
    603        expLen = u_strToLower(expBuf, static_cast<int32_t>(sizeof(expBuf)),
    604            srcExpBuf, srcLen,
    605            formatBundle->fLocale,
    606            &status);
    607    }
    608    else {
    609        expLen = u_strToUpper(expBuf, static_cast<int32_t>(sizeof(expBuf)),
    610            srcExpBuf, srcLen,
    611            formatBundle->fLocale,
    612            &status);
    613    }
    614 
    615    unum_setSymbol(format,
    616        UNUM_EXPONENTIAL_SYMBOL,
    617        expBuf,
    618        expLen,
    619        &status);
    620 
    621    /* save the formatter's state */
    622    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
    623    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
    624 
    625    /* set the appropriate flags and number of decimal digits on the formatter */
    626    if(info->fPrecision != -1) {
    627        /* set the # of decimal digits */
    628        if (info->fOrigSpec == static_cast<char16_t>(0x65) /* e */ ||
    629            info->fOrigSpec == static_cast<char16_t>(0x45) /* E */) {
    630            unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
    631        }
    632        else {
    633            unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, 1);
    634            unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, info->fPrecision);
    635        }
    636    }
    637    else if(info->fAlt) {
    638        /* '#' means always show decimal point */
    639        /* copy of printf behavior on Solaris - '#' shows 6 digits */
    640        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    641    }
    642    else {
    643        /* # of decimal digits is 6 if precision not specified */
    644        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    645    }
    646 
    647    /* set whether to show the sign */
    648    if (info->fShowSign) {
    649        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    650    }
    651 
    652    /* format the number */
    653    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status);
    654 
    655    if (U_FAILURE(status)) {
    656        resultLen = 0;
    657    }
    658 
    659    /* restore the number format */
    660    /* TODO: Is this needed? */
    661    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
    662    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
    663 
    664    /* Since we're the only one using the scientific
    665       format, we don't need to save the old exponent value. */
    666    /*unum_setSymbol(format,
    667        UNUM_EXPONENTIAL_SYMBOL,
    668        srcExpBuf,
    669        srcLen,
    670        &status);*/
    671 
    672    if (info->fShowSign) {
    673        /* Reset back to original value regardless of what the error was */
    674        UErrorCode localStatus = U_ZERO_ERROR;
    675        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    676    }
    677 
    678    return handler->pad_and_justify(context, info, result, resultLen);
    679 }
    680 
    681 static int32_t
    682 u_printf_percent_handler(const u_printf_stream_handler  *handler,
    683                         void                           *context,
    684                         ULocaleBundle                  *formatBundle,
    685                         const u_printf_spec_info       *info,
    686                         const ufmt_args                *args)
    687 {
    688    double num = args[0].doubleValue;
    689    UNumberFormat   *format;
    690    char16_t        result[UPRINTF_BUFFER_SIZE];
    691    char16_t        prefixBuffer[UPRINTF_BUFFER_SIZE];
    692    int32_t         prefixBufferLen = sizeof(prefixBuffer);
    693    int32_t         minDecimalDigits;
    694    int32_t         maxDecimalDigits;
    695    int32_t         resultLen;
    696    UErrorCode      status        = U_ZERO_ERROR;
    697 
    698    prefixBuffer[0] = 0;
    699 
    700    /* mask off any necessary bits */
    701    /*  if(! info->fIsLongDouble)
    702    num &= DBL_MAX;*/
    703 
    704    /* get the formatter */
    705    format = u_locbund_getNumberFormat(formatBundle, UNUM_PERCENT);
    706 
    707    /* handle error */
    708    if (format == nullptr)
    709        return 0;
    710 
    711    /* save the formatter's state */
    712    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
    713    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
    714 
    715    /* set the appropriate flags and number of decimal digits on the formatter */
    716    if(info->fPrecision != -1) {
    717        /* set the # of decimal digits */
    718        unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
    719    }
    720    else if(info->fAlt) {
    721        /* '#' means always show decimal point */
    722        /* copy of printf behavior on Solaris - '#' shows 6 digits */
    723        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    724    }
    725    else {
    726        /* # of decimal digits is 6 if precision not specified */
    727        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    728    }
    729 
    730    /* set whether to show the sign */
    731    if (info->fShowSign) {
    732        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    733    }
    734 
    735    /* format the number */
    736    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status);
    737 
    738    if (U_FAILURE(status)) {
    739        resultLen = 0;
    740    }
    741 
    742    /* restore the number format */
    743    /* TODO: Is this needed? */
    744    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
    745    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
    746 
    747    if (info->fShowSign) {
    748        /* Reset back to original value regardless of what the error was */
    749        UErrorCode localStatus = U_ZERO_ERROR;
    750        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    751    }
    752 
    753    return handler->pad_and_justify(context, info, result, resultLen);
    754 }
    755 
    756 static int32_t
    757 u_printf_ustring_handler(const u_printf_stream_handler  *handler,
    758                         void                           *context,
    759                         ULocaleBundle                  *formatBundle,
    760                         const u_printf_spec_info       *info,
    761                         const ufmt_args                *args)
    762 {
    763    (void)formatBundle;
    764    int32_t len, written;
    765    const char16_t* arg = static_cast<const char16_t*>(args[0].ptrValue);
    766 
    767    /* allocate enough space for the buffer */
    768    if (arg == nullptr) {
    769        arg = gNullStr;
    770    }
    771    len = u_strlen(arg);
    772 
    773    /* width = minimum # of characters to write */
    774    /* precision = maximum # of characters to write */
    775    if (info->fPrecision != -1 && info->fPrecision < len) {
    776        len = info->fPrecision;
    777    }
    778 
    779    /* determine if the string should be padded */
    780    written = handler->pad_and_justify(context, info, arg, len);
    781 
    782    return written;
    783 }
    784 
    785 static int32_t
    786 u_printf_uchar_handler(const u_printf_stream_handler  *handler,
    787                       void                           *context,
    788                       ULocaleBundle                  *formatBundle,
    789                       const u_printf_spec_info       *info,
    790                       const ufmt_args                *args)
    791 {
    792    (void)formatBundle;
    793    int32_t written = 0;
    794    char16_t arg = static_cast<char16_t>(args[0].int64Value);
    795 
    796    /* width = minimum # of characters to write */
    797    /* precision = maximum # of characters to write */
    798    /* precision is ignored when handling a uchar */
    799 
    800    /* determine if the string should be padded */
    801    written = handler->pad_and_justify(context, info, &arg, 1);
    802 
    803    return written;
    804 }
    805 
    806 static int32_t
    807 u_printf_scidbl_handler(const u_printf_stream_handler  *handler,
    808                        void                           *context,
    809                        ULocaleBundle                  *formatBundle,
    810                        const u_printf_spec_info       *info,
    811                        const ufmt_args                *args)
    812 {
    813    u_printf_spec_info scidbl_info;
    814    double      num = args[0].doubleValue;
    815    int32_t     retVal;
    816    UNumberFormat *format;
    817    int32_t maxSigDecimalDigits, significantDigits;
    818 
    819    memcpy(&scidbl_info, info, sizeof(u_printf_spec_info));
    820 
    821    /* determine whether to use 'd', 'e' or 'f' notation */
    822    if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num))
    823    {
    824        /* use 'f' notation */
    825        scidbl_info.fSpec = 0x0066;
    826        scidbl_info.fPrecision = 0;
    827        /* call the double handler */
    828        retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
    829    }
    830    else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num)
    831        || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision)))
    832    {
    833        /* use 'e' or 'E' notation */
    834        scidbl_info.fSpec = scidbl_info.fSpec - 2;
    835        if (scidbl_info.fPrecision == -1) {
    836            scidbl_info.fPrecision = 5;
    837        }
    838        /* call the scientific handler */
    839        retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args);
    840    }
    841    else {
    842        format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
    843        /* Check for null pointer */
    844        if (format == nullptr) {
    845            return 0;
    846        }
    847        maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS);
    848        significantDigits = scidbl_info.fPrecision;
    849 
    850        /* use 'f' notation */
    851        scidbl_info.fSpec = 0x0066;
    852        if (significantDigits == -1) {
    853            significantDigits = 6;
    854        }
    855        unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, true);
    856        unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, significantDigits);
    857        /* call the double handler */
    858        retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
    859        unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, maxSigDecimalDigits);
    860        unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, false);
    861    }
    862    return retVal;
    863 }
    864 
    865 static int32_t
    866 u_printf_count_handler(const u_printf_stream_handler  *handler,
    867                       void                           *context,
    868                       ULocaleBundle                  *formatBundle,
    869                       const u_printf_spec_info       *info,
    870                       const ufmt_args                *args)
    871 {
    872    (void)handler;
    873    (void)context;
    874    (void)formatBundle;
    875    int32_t* count = static_cast<int32_t*>(args[0].ptrValue);
    876 
    877    /* in the special case of count, the u_printf_spec_info's width */
    878    /* will contain the # of chars written thus far */
    879    *count = info->fWidth;
    880 
    881    return 0;
    882 }
    883 
    884 static int32_t
    885 u_printf_spellout_handler(const u_printf_stream_handler *handler,
    886                          void                          *context,
    887                          ULocaleBundle                 *formatBundle,
    888                          const u_printf_spec_info      *info,
    889                          const ufmt_args               *args)
    890 {
    891    double num = args[0].doubleValue;
    892    UNumberFormat   *format;
    893    char16_t        result[UPRINTF_BUFFER_SIZE];
    894    char16_t        prefixBuffer[UPRINTF_BUFFER_SIZE];
    895    int32_t         prefixBufferLen = sizeof(prefixBuffer);
    896    int32_t         minDecimalDigits;
    897    int32_t         maxDecimalDigits;
    898    int32_t         resultLen;
    899    UErrorCode      status        = U_ZERO_ERROR;
    900 
    901    prefixBuffer[0] = 0;
    902 
    903    /* mask off any necessary bits */
    904    /*  if(! info->fIsLongDouble)
    905    num &= DBL_MAX;*/
    906 
    907    /* get the formatter */
    908    format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT);
    909 
    910    /* handle error */
    911    if (format == nullptr)
    912        return 0;
    913 
    914    /* save the formatter's state */
    915    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
    916    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
    917 
    918    /* set the appropriate flags and number of decimal digits on the formatter */
    919    if(info->fPrecision != -1) {
    920        /* set the # of decimal digits */
    921        unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
    922    }
    923    else if(info->fAlt) {
    924        /* '#' means always show decimal point */
    925        /* copy of printf behavior on Solaris - '#' shows 6 digits */
    926        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    927    }
    928    else {
    929        /* # of decimal digits is 6 if precision not specified */
    930        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    931    }
    932 
    933    /* set whether to show the sign */
    934    if (info->fShowSign) {
    935        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    936    }
    937 
    938    /* format the number */
    939    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status);
    940 
    941    if (U_FAILURE(status)) {
    942        resultLen = 0;
    943    }
    944 
    945    /* restore the number format */
    946    /* TODO: Is this needed? */
    947    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
    948    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
    949 
    950    if (info->fShowSign) {
    951        /* Reset back to original value regardless of what the error was */
    952        UErrorCode localStatus = U_ZERO_ERROR;
    953        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    954    }
    955 
    956    return handler->pad_and_justify(context, info, result, resultLen);
    957 }
    958 
    959 /* Use US-ASCII characters only for formatting. Most codepages have
    960 characters 20-7F from Unicode. Using any other codepage specific
    961 characters will make it very difficult to format the string on
    962 non-Unicode machines */
    963 static const u_printf_info g_u_printf_infos[UPRINTF_NUM_FMT_HANDLERS] = {
    964 /* 0x20 */
    965    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    966    UFMT_EMPTY,         UFMT_SIMPLE_PERCENT,UFMT_EMPTY,         UFMT_EMPTY,
    967    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    968    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    969 
    970 /* 0x30 */
    971    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    972    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    973    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    974    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    975 
    976 /* 0x40 */
    977    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR,
    978    UFMT_EMPTY,         UFMT_SCIENTIFIC,    UFMT_EMPTY,         UFMT_SCIDBL,
    979 #ifdef U_USE_OBSOLETE_IO_FORMATTING
    980    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR/*deprecated*/,
    981 #else
    982    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    983 #endif
    984    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    985 
    986 /* 0x50 */
    987    UFMT_PERCENT,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_USTRING,
    988 #ifdef U_USE_OBSOLETE_IO_FORMATTING
    989    UFMT_EMPTY,         UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT,      UFMT_EMPTY,
    990 #else
    991    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_SPELLOUT,      UFMT_EMPTY,
    992 #endif
    993    UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    994    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    995 
    996 /* 0x60 */
    997    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_CHAR,
    998    UFMT_INT,           UFMT_SCIENTIFIC,    UFMT_DOUBLE,        UFMT_SCIDBL,
    999    UFMT_EMPTY,         UFMT_INT,           UFMT_EMPTY,         UFMT_EMPTY,
   1000    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_COUNT,         UFMT_OCTAL,
   1001 
   1002 /* 0x70 */
   1003    UFMT_POINTER,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_STRING,
   1004    UFMT_EMPTY,         UFMT_UINT,          UFMT_EMPTY,         UFMT_EMPTY,
   1005    UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1006    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1007 };
   1008 
   1009 /* flag characters for uprintf */
   1010 #define FLAG_MINUS 0x002D
   1011 #define FLAG_PLUS 0x002B
   1012 #define FLAG_SPACE 0x0020
   1013 #define FLAG_POUND 0x0023
   1014 #define FLAG_ZERO  0x0030
   1015 #define FLAG_PAREN 0x0028
   1016 
   1017 #define ISFLAG(s)    (s) == FLAG_MINUS || \
   1018            (s) == FLAG_PLUS || \
   1019            (s) == FLAG_SPACE || \
   1020            (s) == FLAG_POUND || \
   1021            (s) == FLAG_ZERO || \
   1022            (s) == FLAG_PAREN
   1023 
   1024 /* special characters for uprintf */
   1025 #define SPEC_ASTERISK 0x002A
   1026 #define SPEC_DOLLARSIGN 0x0024
   1027 #define SPEC_PERIOD 0x002E
   1028 #define SPEC_PERCENT 0x0025
   1029 
   1030 /* unicode digits */
   1031 #define DIGIT_ZERO 0x0030
   1032 #define DIGIT_ONE 0x0031
   1033 #define DIGIT_TWO 0x0032
   1034 #define DIGIT_THREE 0x0033
   1035 #define DIGIT_FOUR 0x0034
   1036 #define DIGIT_FIVE 0x0035
   1037 #define DIGIT_SIX 0x0036
   1038 #define DIGIT_SEVEN 0x0037
   1039 #define DIGIT_EIGHT 0x0038
   1040 #define DIGIT_NINE 0x0039
   1041 
   1042 #define ISDIGIT(s)    (s) == DIGIT_ZERO || \
   1043            (s) == DIGIT_ONE || \
   1044            (s) == DIGIT_TWO || \
   1045            (s) == DIGIT_THREE || \
   1046            (s) == DIGIT_FOUR || \
   1047            (s) == DIGIT_FIVE || \
   1048            (s) == DIGIT_SIX || \
   1049            (s) == DIGIT_SEVEN || \
   1050            (s) == DIGIT_EIGHT || \
   1051            (s) == DIGIT_NINE
   1052 
   1053 /* u_printf modifiers */
   1054 #define MOD_H 0x0068
   1055 #define MOD_LOWERL 0x006C
   1056 #define MOD_L 0x004C
   1057 
   1058 #define ISMOD(s)    (s) == MOD_H || \
   1059            (s) == MOD_LOWERL || \
   1060            (s) == MOD_L
   1061 /* Returns an array of the parsed argument type given in the format string. */
   1062 static ufmt_args* parseArguments(const char16_t *alias, va_list ap, UErrorCode *status) {
   1063    ufmt_args *arglist = nullptr;
   1064    ufmt_type_info *typelist = nullptr;
   1065    UBool *islonglong = nullptr;
   1066    int32_t size = 0;
   1067    int32_t pos = 0;
   1068    char16_t type;
   1069    uint16_t handlerNum;
   1070    const char16_t *aliasStart = alias;
   1071 
   1072    /* get maximum number of arguments */
   1073    for(;;) {
   1074        /* find % */
   1075        while(*alias != UP_PERCENT && *alias != 0x0000) {
   1076            alias++;
   1077        }
   1078 
   1079        if(*alias == 0x0000) {
   1080            break;
   1081        }
   1082 
   1083        alias++;
   1084 
   1085        /* handle the pos number */
   1086        if(ISDIGIT(*alias)) {
   1087 
   1088            /* handle positional parameters */
   1089            if(ISDIGIT(*alias)) {
   1090                pos = *alias++ - DIGIT_ZERO;
   1091 
   1092                while(ISDIGIT(*alias)) {
   1093                    pos *= 10;
   1094                    pos += *alias++ - DIGIT_ZERO;
   1095                }
   1096            }
   1097 
   1098            /* if there is no '$', don't read anything */
   1099            if(*alias != SPEC_DOLLARSIGN) {
   1100                return nullptr;
   1101            }
   1102        } else {
   1103            return nullptr;
   1104        }
   1105 
   1106        if (pos > size) {
   1107            size = pos;
   1108        }
   1109    }
   1110 
   1111    /* create the parsed argument list */
   1112    typelist = static_cast<ufmt_type_info*>(uprv_malloc(sizeof(ufmt_type_info) * size));
   1113    islonglong = static_cast<UBool*>(uprv_malloc(sizeof(UBool) * size));
   1114    arglist = static_cast<ufmt_args*>(uprv_malloc(sizeof(ufmt_args) * size));
   1115 
   1116    /* If malloc failed, return nullptr */
   1117    if (!typelist || !islonglong || !arglist) {
   1118        if (typelist) {
   1119            uprv_free(typelist);
   1120        }
   1121 
   1122        if (islonglong) {
   1123            uprv_free(islonglong);
   1124        }
   1125 
   1126        if (arglist) {
   1127            uprv_free(arglist);
   1128        }
   1129 
   1130        *status = U_MEMORY_ALLOCATION_ERROR;
   1131        return nullptr;
   1132    }
   1133 
   1134    /* reset alias back to the beginning */
   1135    alias = aliasStart;
   1136 
   1137    for(;;) {
   1138        /* find % */
   1139        while(*alias != UP_PERCENT && *alias != 0x0000) {
   1140            alias++;
   1141        }
   1142 
   1143        if(*alias == 0x0000) {
   1144            break;
   1145        }
   1146 
   1147        alias++;
   1148 
   1149        /* handle positional parameters */
   1150        if(ISDIGIT(*alias)) {
   1151            pos = *alias++ - DIGIT_ZERO;
   1152 
   1153            while(ISDIGIT(*alias)) {
   1154                pos *= 10;
   1155                pos += *alias++ - DIGIT_ZERO;
   1156            }
   1157        }
   1158        /* offset position by 1 */
   1159        pos--;
   1160 
   1161        /* skip over everything except for the type */
   1162        while (ISMOD(*alias) || ISFLAG(*alias) || ISDIGIT(*alias) || 
   1163            *alias == SPEC_ASTERISK || *alias == SPEC_PERIOD || *alias == SPEC_DOLLARSIGN) {
   1164                islonglong[pos] = false;
   1165                if (ISMOD(*alias)) {
   1166                    alias++;
   1167                    if (*alias == MOD_LOWERL) {
   1168                        islonglong[pos] = true;
   1169                    } 
   1170                } 
   1171                alias++;
   1172        }
   1173        type = *alias;
   1174 
   1175        /* store the argument type in the correct position of the parsed argument list */
   1176        handlerNum = static_cast<uint16_t>(type - UPRINTF_BASE_FMT_HANDLERS);
   1177        if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
   1178            typelist[pos] = g_u_printf_infos[ handlerNum ].info;
   1179        } else {
   1180            typelist[pos] = ufmt_empty;
   1181        }
   1182    }
   1183 
   1184    /* store argument in arglist */
   1185    for (pos = 0; pos < size; pos++) {
   1186        switch (typelist[pos]) {
   1187        case ufmt_string:
   1188        case ufmt_ustring:
   1189        case ufmt_pointer:
   1190            arglist[pos].ptrValue = va_arg(ap, void*);
   1191            break;
   1192        case ufmt_char:
   1193        case ufmt_uchar:
   1194        case ufmt_int:
   1195            if (islonglong[pos]) {
   1196                arglist[pos].int64Value = va_arg(ap, int64_t);
   1197            }
   1198            else {
   1199                arglist[pos].int64Value = va_arg(ap, int32_t);
   1200            }
   1201            break;
   1202        case ufmt_float:
   1203            arglist[pos].floatValue = static_cast<float>(va_arg(ap, double));
   1204            break;
   1205        case ufmt_double:
   1206            arglist[pos].doubleValue = va_arg(ap, double);
   1207            break;
   1208        default:
   1209            /* else args is ignored */
   1210            arglist[pos].ptrValue = nullptr;
   1211            break;
   1212        }
   1213    }
   1214 
   1215    uprv_free(typelist);
   1216    uprv_free(islonglong);
   1217 
   1218    return arglist;
   1219 }
   1220 
   1221 /* We parse the argument list in Unicode */
   1222 U_CFUNC int32_t
   1223 u_printf_parse(const u_printf_stream_handler *streamHandler,
   1224               const char16_t  *fmt,
   1225               void            *context,
   1226               u_localized_print_string *locStringContext,
   1227               ULocaleBundle   *formatBundle,
   1228               int32_t         *written,
   1229               va_list         ap)
   1230 {
   1231    uint16_t         handlerNum;
   1232    ufmt_args        args;
   1233    ufmt_type_info   argType;
   1234    u_printf_handler *handler;
   1235    u_printf_spec    spec;
   1236    u_printf_spec_info *info = &(spec.fInfo);
   1237 
   1238    const char16_t *alias = fmt;
   1239    const char16_t *backup;
   1240    const char16_t *lastAlias;
   1241    const char16_t *orgAlias = fmt;
   1242    /* parsed argument list */
   1243    ufmt_args *arglist = nullptr; /* initialized it to avoid compiler warnings */
   1244    UErrorCode status = U_ZERO_ERROR;
   1245    if (!locStringContext || locStringContext->available >= 0) {
   1246        /* get the parsed list of argument types */
   1247        arglist = parseArguments(orgAlias, ap, &status);
   1248 
   1249        /* Return error if parsing failed. */
   1250        if (U_FAILURE(status)) {
   1251            return -1;
   1252        }
   1253    }
   1254    
   1255    /* iterate through the pattern */
   1256    while(!locStringContext || locStringContext->available >= 0) {
   1257 
   1258        /* find the next '%' */
   1259        lastAlias = alias;
   1260        while(*alias != UP_PERCENT && *alias != 0x0000) {
   1261            alias++;
   1262        }
   1263 
   1264        /* write any characters before the '%' */
   1265        if(alias > lastAlias) {
   1266            *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias));
   1267        }
   1268 
   1269        /* break if at end of string */
   1270        if(*alias == 0x0000) {
   1271            break;
   1272        }
   1273 
   1274        /* initialize spec to default values */
   1275        spec.fWidthPos     = -1;
   1276        spec.fPrecisionPos = -1;
   1277        spec.fArgPos       = -1;
   1278 
   1279        uprv_memset(info, 0, sizeof(*info));
   1280        info->fPrecision    = -1;
   1281        info->fWidth        = -1;
   1282        info->fPadChar      = 0x0020;
   1283 
   1284        /* skip over the initial '%' */
   1285        alias++;
   1286 
   1287        /* Check for positional argument */
   1288        if(ISDIGIT(*alias)) {
   1289 
   1290            /* Save the current position */
   1291            backup = alias;
   1292 
   1293            /* handle positional parameters */
   1294            if(ISDIGIT(*alias)) {
   1295                spec.fArgPos = *alias++ - DIGIT_ZERO;
   1296 
   1297                while(ISDIGIT(*alias)) {
   1298                    spec.fArgPos *= 10;
   1299                    spec.fArgPos += *alias++ - DIGIT_ZERO;
   1300                }
   1301            }
   1302 
   1303            /* if there is no '$', don't read anything */
   1304            if(*alias != SPEC_DOLLARSIGN) {
   1305                spec.fArgPos = -1;
   1306                alias = backup;
   1307            }
   1308            /* munge the '$' */
   1309            else
   1310                alias++;
   1311        }
   1312 
   1313        /* Get any format flags */
   1314        while(ISFLAG(*alias)) {
   1315            switch(*alias++) {
   1316 
   1317                /* left justify */
   1318            case FLAG_MINUS:
   1319                info->fLeft = true;
   1320                break;
   1321 
   1322                /* always show sign */
   1323            case FLAG_PLUS:
   1324                info->fShowSign = true;
   1325                break;
   1326 
   1327                /* use space if no sign present */
   1328            case FLAG_SPACE:
   1329                info->fShowSign = true;
   1330                info->fSpace = true;
   1331                break;
   1332 
   1333                /* use alternate form */
   1334            case FLAG_POUND:
   1335                info->fAlt = true;
   1336                break;
   1337 
   1338                /* pad with leading zeroes */
   1339            case FLAG_ZERO:
   1340                info->fZero = true;
   1341                info->fPadChar = 0x0030;
   1342                break;
   1343 
   1344                /* pad character specified */
   1345            case FLAG_PAREN:
   1346 
   1347                /* TODO test that all four are numbers */
   1348                /* first four characters are hex values for pad char */
   1349                info->fPadChar = (char16_t)ufmt_digitvalue(*alias++);
   1350                info->fPadChar = (char16_t)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
   1351                info->fPadChar = (char16_t)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
   1352                info->fPadChar = (char16_t)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
   1353 
   1354                /* final character is ignored */
   1355                alias++;
   1356 
   1357                break;
   1358            }
   1359        }
   1360 
   1361        /* Get the width */
   1362 
   1363        /* width is specified out of line */
   1364        if(*alias == SPEC_ASTERISK) {
   1365 
   1366            info->fWidth = -2;
   1367 
   1368            /* Skip the '*' */
   1369            alias++;
   1370 
   1371            /* Save the current position */
   1372            backup = alias;
   1373 
   1374            /* handle positional parameters */
   1375            if(ISDIGIT(*alias)) {
   1376                spec.fWidthPos = *alias++ - DIGIT_ZERO;
   1377 
   1378                while(ISDIGIT(*alias)) {
   1379                    spec.fWidthPos *= 10;
   1380                    spec.fWidthPos += *alias++ - DIGIT_ZERO;
   1381                }
   1382            }
   1383 
   1384            /* if there is no '$', don't read anything */
   1385            if(*alias != SPEC_DOLLARSIGN) {
   1386                spec.fWidthPos = -1;
   1387                alias = backup;
   1388            }
   1389            /* munge the '$' */
   1390            else
   1391                alias++;
   1392        }
   1393        /* read the width, if present */
   1394        else if(ISDIGIT(*alias)){
   1395            info->fWidth = *alias++ - DIGIT_ZERO;
   1396 
   1397            while(ISDIGIT(*alias)) {
   1398                info->fWidth *= 10;
   1399                info->fWidth += *alias++ - DIGIT_ZERO;
   1400            }
   1401        }
   1402 
   1403        /* Get the precision */
   1404 
   1405        if(*alias == SPEC_PERIOD) {
   1406 
   1407            /* eat up the '.' */
   1408            alias++;
   1409 
   1410            /* precision is specified out of line */
   1411            if(*alias == SPEC_ASTERISK) {
   1412 
   1413                info->fPrecision = -2;
   1414 
   1415                /* Skip the '*' */
   1416                alias++;
   1417 
   1418                /* save the current position */
   1419                backup = alias;
   1420 
   1421                /* handle positional parameters */
   1422                if(ISDIGIT(*alias)) {
   1423                    spec.fPrecisionPos = *alias++ - DIGIT_ZERO;
   1424 
   1425                    while(ISDIGIT(*alias)) {
   1426                        spec.fPrecisionPos *= 10;
   1427                        spec.fPrecisionPos += *alias++ - DIGIT_ZERO;
   1428                    }
   1429 
   1430                    /* if there is no '$', don't read anything */
   1431                    if(*alias != SPEC_DOLLARSIGN) {
   1432                        spec.fPrecisionPos = -1;
   1433                        alias = backup;
   1434                    }
   1435                    else {
   1436                        /* munge the '$' */
   1437                        alias++;
   1438                    }
   1439                }
   1440            }
   1441            /* read the precision */
   1442            else if(ISDIGIT(*alias)){
   1443                info->fPrecision = *alias++ - DIGIT_ZERO;
   1444 
   1445                while(ISDIGIT(*alias)) {
   1446                    info->fPrecision *= 10;
   1447                    info->fPrecision += *alias++ - DIGIT_ZERO;
   1448                }
   1449            }
   1450        }
   1451 
   1452        /* Get any modifiers */
   1453        if(ISMOD(*alias)) {
   1454            switch(*alias++) {
   1455 
   1456                /* short */
   1457            case MOD_H:
   1458                info->fIsShort = true;
   1459                break;
   1460 
   1461                /* long or long long */
   1462            case MOD_LOWERL:
   1463                if(*alias == MOD_LOWERL) {
   1464                    info->fIsLongLong = true;
   1465                    /* skip over the next 'l' */
   1466                    alias++;
   1467                }
   1468                else
   1469                    info->fIsLong = true;
   1470                break;
   1471 
   1472                /* long double */
   1473            case MOD_L:
   1474                info->fIsLongDouble = true;
   1475                break;
   1476            }
   1477        }
   1478 
   1479        /* finally, get the specifier letter */
   1480        info->fSpec = *alias++;
   1481        info->fOrigSpec = info->fSpec;
   1482 
   1483        /* fill in the precision and width, if specified out of line */
   1484 
   1485        /* width specified out of line */
   1486        if(spec.fInfo.fWidth == -2) {
   1487            if(spec.fWidthPos == -1) {
   1488                /* read the width from the argument list */
   1489                info->fWidth = va_arg(ap, int32_t);
   1490            }
   1491            /* else handle positional parameter */
   1492 
   1493            /* if it's negative, take the absolute value and set left alignment */
   1494            if(info->fWidth < 0) {
   1495                info->fWidth *= -1; /* Make positive */
   1496                info->fLeft = true;
   1497            }
   1498        }
   1499 
   1500        /* precision specified out of line */
   1501        if(info->fPrecision == -2) {
   1502            if(spec.fPrecisionPos == -1) {
   1503                /* read the precision from the argument list */
   1504                info->fPrecision = va_arg(ap, int32_t);
   1505            }
   1506            /* else handle positional parameter */
   1507 
   1508            /* if it's negative, set it to zero */
   1509            if(info->fPrecision < 0)
   1510                info->fPrecision = 0;
   1511        }
   1512 
   1513        handlerNum = (uint16_t)(info->fSpec - UPRINTF_BASE_FMT_HANDLERS);
   1514        if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
   1515            /* query the info function for argument information */
   1516            argType = g_u_printf_infos[ handlerNum ].info;
   1517 
   1518            /* goto the correct argument on arg_list if position is specified */
   1519            if (spec.fArgPos > 0) {
   1520                /* offset position by 1 */
   1521                spec.fArgPos--;
   1522                switch(argType) {
   1523                case ufmt_count:
   1524                    /* set the spec's width to the # of chars written */
   1525                    info->fWidth = *written;
   1526                    /* fall through to set the pointer */
   1527                    U_FALLTHROUGH;
   1528                case ufmt_string:
   1529                case ufmt_ustring:
   1530                case ufmt_pointer:
   1531                    args.ptrValue = arglist[spec.fArgPos].ptrValue;
   1532                    break;
   1533                case ufmt_char:
   1534                case ufmt_uchar:
   1535                case ufmt_int:
   1536                    args.int64Value = arglist[spec.fArgPos].int64Value;
   1537                    break;
   1538                case ufmt_float:
   1539                    args.floatValue = arglist[spec.fArgPos].floatValue;
   1540                    break;
   1541                case ufmt_double:
   1542                    args.doubleValue = arglist[spec.fArgPos].doubleValue;
   1543                    break;
   1544                default:
   1545                    /* else args is ignored */
   1546                    args.ptrValue = nullptr;
   1547                    break;
   1548                }
   1549            } else { /* no positional argument specified */
   1550                switch(argType) {
   1551                case ufmt_count:
   1552                    /* set the spec's width to the # of chars written */
   1553                    info->fWidth = *written;
   1554                    /* fall through to set the pointer */
   1555                    U_FALLTHROUGH;
   1556                case ufmt_string:
   1557                case ufmt_ustring:
   1558                case ufmt_pointer:
   1559                    args.ptrValue = va_arg(ap, void*);
   1560                    break;
   1561                case ufmt_char:
   1562                case ufmt_uchar:
   1563                case ufmt_int:
   1564                    if (info->fIsLongLong) {
   1565                        args.int64Value = va_arg(ap, int64_t);
   1566                    }
   1567                    else {
   1568                        args.int64Value = va_arg(ap, int32_t);
   1569                    }
   1570                    break;
   1571                case ufmt_float:
   1572                    args.floatValue = (float) va_arg(ap, double);
   1573                    break;
   1574                case ufmt_double:
   1575                    args.doubleValue = va_arg(ap, double);
   1576                    break;
   1577                default:
   1578                    /* else args is ignored */
   1579                    args.ptrValue = nullptr;
   1580                    break;
   1581                }
   1582            }
   1583 
   1584            /* call the handler function */
   1585            handler = g_u_printf_infos[ handlerNum ].handler;
   1586            if (handler != nullptr) {
   1587                *written += (*handler)(streamHandler, context, formatBundle, info, &args);
   1588            }
   1589            else {
   1590                /* just echo unknown tags */
   1591                *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
   1592            }
   1593        }
   1594        else {
   1595            /* just echo unknown tags */
   1596            *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
   1597        }
   1598    }
   1599    /* delete parsed argument list */
   1600    if (arglist != nullptr) {
   1601        uprv_free(arglist);
   1602    }
   1603    /* return # of characters in this format that have been parsed. */
   1604    return (int32_t)(alias - fmt);
   1605 }
   1606 
   1607 #endif /* #if !UCONFIG_NO_FORMATTING */