intl/icu/source/io/uprntf_p.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial