| /* | 
 | ****************************************************************************** | 
 | * | 
 | *   Copyright (C) 1998-2001, International Business Machines | 
 | *   Corporation and others.  All Rights Reserved. | 
 | * | 
 | ****************************************************************************** | 
 | * | 
 | * File uprintf.c | 
 | * | 
 | * Modification History: | 
 | * | 
 | *   Date        Name        Description | 
 | *   11/19/98    stephen        Creation. | 
 | *   03/12/99    stephen     Modified for new C API. | 
 | *                           Added conversion from default codepage. | 
 | ****************************************************************************** | 
 | */ | 
 |  | 
 | #include "unicode/utypes.h" | 
 | #include "uprintf.h" | 
 | #include "uprntf_p.h" | 
 | #include "unicode/ustdio.h" | 
 | #include "ufile.h" | 
 | #include "unicode/ustring.h" | 
 | #include "locbund.h" | 
 | #include "unicode/unum.h" | 
 | #include "unicode/udat.h" | 
 |  | 
 | #include "cmemory.h" | 
 |  | 
 |  | 
 | /* --- Prototypes ---------------------------- */ | 
 |  | 
 | int32_t | 
 | u_printf_simple_percent_handler(UFILE                 *stream, | 
 |                 const u_printf_spec_info     *info, | 
 |                 const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_string_handler(UFILE                 *stream, | 
 |             const u_printf_spec_info     *info, | 
 |             const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_date_handler(UFILE             *stream, | 
 |               const u_printf_spec_info     *info, | 
 |               const ufmt_args         *args); | 
 |  | 
 | int32_t | 
 | u_printf_scientific_handler(UFILE             *stream, | 
 |                 const u_printf_spec_info     *info, | 
 |                 const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_scidbl_handler(UFILE                 *stream, | 
 |             const u_printf_spec_info     *info, | 
 |             const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_uchar_handler(UFILE                 *stream, | 
 |                const u_printf_spec_info     *info, | 
 |                const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_currency_handler(UFILE             *stream, | 
 |               const u_printf_spec_info     *info, | 
 |               const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_ustring_handler(UFILE                 *stream, | 
 |              const u_printf_spec_info     *info, | 
 |              const ufmt_args         *args); | 
 |  | 
 | int32_t | 
 | u_printf_percent_handler(UFILE                 *stream, | 
 |              const u_printf_spec_info     *info, | 
 |              const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_time_handler(UFILE             *stream, | 
 |               const u_printf_spec_info     *info, | 
 |               const ufmt_args         *args); | 
 |  | 
 | int32_t | 
 | u_printf_spellout_handler(UFILE             *stream, | 
 |               const u_printf_spec_info     *info, | 
 |               const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_hex_handler(UFILE             *stream, | 
 |              const u_printf_spec_info     *info, | 
 |              const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_char_handler(UFILE                 *stream, | 
 |               const u_printf_spec_info         *info, | 
 |               const ufmt_args              *args); | 
 |  | 
 | int32_t | 
 | u_printf_integer_handler(UFILE                 *stream, | 
 |              const u_printf_spec_info     *info, | 
 |              const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_uinteger_handler(UFILE                 *stream, | 
 |              const u_printf_spec_info     *info, | 
 |              const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_double_handler(UFILE                 *stream, | 
 |             const u_printf_spec_info     *info, | 
 |             const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_count_handler(UFILE                 *stream, | 
 |             const u_printf_spec_info     *info, | 
 |             const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_octal_handler(UFILE                 *stream, | 
 |             const u_printf_spec_info     *info, | 
 |             const ufmt_args            *args); | 
 |  | 
 | int32_t | 
 | u_printf_pointer_handler(UFILE                 *stream, | 
 |             const u_printf_spec_info     *info, | 
 |             const ufmt_args            *args); | 
 |  | 
 | /* ANSI style formatting */ | 
 | /* Use US-ASCII characters only for formatting */ | 
 |  | 
 | /* % */ | 
 | #define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_printf_simple_percent_handler} | 
 | /* s */ | 
 | #define UFMT_STRING         {ufmt_string, u_printf_string_handler} | 
 | /* c */ | 
 | #define UFMT_CHAR           {ufmt_char, u_printf_char_handler} | 
 | /* d, i */ | 
 | #define UFMT_INT            {ufmt_int, u_printf_integer_handler} | 
 | /* u */ | 
 | #define UFMT_UINT           {ufmt_int, u_printf_uinteger_handler} | 
 | /* o */ | 
 | #define UFMT_OCTAL          {ufmt_int, u_printf_octal_handler} | 
 | /* x, X */ | 
 | #define UFMT_HEX            {ufmt_int, u_printf_hex_handler} | 
 | /* f */ | 
 | #define UFMT_DOUBLE         {ufmt_double, u_printf_double_handler} | 
 | /* e, E */ | 
 | #define UFMT_SCIENTIFIC     {ufmt_double, u_printf_scientific_handler} | 
 | /* g, G */ | 
 | #define UFMT_SCIDBL         {ufmt_double, u_printf_scidbl_handler} | 
 | /* n */ | 
 | #define UFMT_COUNT          {ufmt_count, u_printf_count_handler} | 
 |  | 
 | /* non-ANSI extensions */ | 
 | /* Use US-ASCII characters only for formatting */ | 
 |  | 
 | /* p */ | 
 | #define UFMT_POINTER        {ufmt_pointer, u_printf_pointer_handler} | 
 | /* D */ | 
 | #define UFMT_DATE           {ufmt_date, u_printf_date_handler} | 
 | /* T */ | 
 | #define UFMT_TIME           {ufmt_date, u_printf_time_handler} | 
 | /* V */ | 
 | #define UFMT_SPELLOUT       {ufmt_double, u_printf_spellout_handler} | 
 | /* P */ | 
 | #define UFMT_PERCENT        {ufmt_double, u_printf_percent_handler} | 
 | /* M */ | 
 | #define UFMT_CURRENCY       {ufmt_double, u_printf_currency_handler} | 
 | /* K */ | 
 | #define UFMT_UCHAR          {ufmt_uchar, u_printf_uchar_handler} | 
 | /* U */ | 
 | #define UFMT_USTRING        {ufmt_ustring, u_printf_ustring_handler} | 
 |  | 
 |  | 
 | #define UFMT_EMPTY {ufmt_empty, NULL} | 
 |  | 
 | struct u_printf_info { | 
 |     ufmt_type_info info; | 
 |     u_printf_handler handler; | 
 | }; | 
 | typedef struct u_printf_info u_printf_info; | 
 |  | 
 | /* Use US-ASCII characters only for formatting. Most codepages have | 
 |  characters 20-7F from Unicode. Using any other codepage specific | 
 |  characters will make it very difficult to format the string on | 
 |  non-Unicode machines */ | 
 | static const u_printf_info g_u_printf_infos[108] = { | 
 | /* 0x20 */ | 
 |     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY, | 
 |     UFMT_EMPTY,         UFMT_SIMPLE_PERCENT,UFMT_EMPTY,         UFMT_EMPTY, | 
 |     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY, | 
 |     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY, | 
 |  | 
 | /* 0x30 */ | 
 |     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY, | 
 |     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY, | 
 |     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY, | 
 |     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY, | 
 |  | 
 | /* 0x40 */ | 
 |     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY, | 
 |     UFMT_DATE,          UFMT_SCIENTIFIC,    UFMT_EMPTY,         UFMT_SCIDBL, | 
 |     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR, | 
 |     UFMT_EMPTY,         UFMT_CURRENCY,      UFMT_EMPTY,         UFMT_EMPTY, | 
 |  | 
 | /* 0x50 */ | 
 |     UFMT_PERCENT,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY, | 
 |     UFMT_TIME,          UFMT_USTRING,       UFMT_SPELLOUT,      UFMT_EMPTY, | 
 |     UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY, | 
 |     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY, | 
 |  | 
 | /* 0x60 */ | 
 |     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_CHAR, | 
 |     UFMT_INT,           UFMT_SCIENTIFIC,    UFMT_DOUBLE,        UFMT_SCIDBL, | 
 |     UFMT_EMPTY,         UFMT_INT,           UFMT_EMPTY,         UFMT_EMPTY, | 
 |     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_COUNT,         UFMT_OCTAL, | 
 |  | 
 | /* 0x70 */ | 
 |     UFMT_POINTER,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_STRING, | 
 |     UFMT_EMPTY,         UFMT_UINT,          UFMT_EMPTY,         UFMT_EMPTY, | 
 |     UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY, | 
 |     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY, | 
 | }; | 
 |  | 
 | #define UPRINTF_NUM_FMT_HANDLERS sizeof(g_u_printf_infos) | 
 |  | 
 | /* We do not use handlers for 0-0x1f */ | 
 | #define UPRINTF_BASE_FMT_HANDLERS 0x20 | 
 |  | 
 | /* buffer size for formatting */ | 
 | #define UFPRINTF_BUFFER_SIZE 1024 | 
 | #define UFPRINTF_SYMBOL_BUFFER_SIZE 8 | 
 |  | 
 | static UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */ | 
 | static UChar gSpaceStr[] = {0x20, 0}; /* " " */ | 
 |  | 
 | int32_t | 
 | u_fprintf(    UFILE        *f, | 
 |           const char    *patternSpecification, | 
 |           ... ) | 
 | { | 
 |     va_list ap; | 
 |     int32_t count; | 
 |  | 
 |     va_start(ap, patternSpecification); | 
 |     count = u_vfprintf(f, patternSpecification, ap); | 
 |     va_end(ap); | 
 |  | 
 |     return count; | 
 | } | 
 |  | 
 | int32_t | 
 | u_fprintf_u(    UFILE        *f, | 
 |             const UChar    *patternSpecification, | 
 |             ... ) | 
 | { | 
 |     va_list ap; | 
 |     int32_t count; | 
 |  | 
 |     va_start(ap, patternSpecification); | 
 |     count = u_vfprintf_u(f, patternSpecification, ap); | 
 |     va_end(ap); | 
 |  | 
 |     return count; | 
 | } | 
 |  | 
 | U_CAPI int32_t  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ | 
 | u_vfprintf(    UFILE        *f, | 
 |            const char    *patternSpecification, | 
 |            va_list        ap) | 
 | { | 
 |     int32_t count; | 
 |     UChar *pattern; | 
 |  | 
 |     /* convert from the default codepage to Unicode */ | 
 |     pattern = ufmt_defaultCPToUnicode(patternSpecification, | 
 |         (int32_t)strlen(patternSpecification)); | 
 |     if(pattern == 0) { | 
 |         return 0; | 
 |     } | 
 |  | 
 |     /* do the work */ | 
 |     count = u_vfprintf_u(f, pattern, ap); | 
 |  | 
 |     /* clean up */ | 
 |     uprv_free(pattern); | 
 |  | 
 |     return count; | 
 | } | 
 |  | 
 | static int32_t | 
 | u_printf_pad_and_justify(UFILE              *stream, | 
 |                          const u_printf_spec_info    *info, | 
 |                          const UChar                 *result, | 
 |                          int32_t                     resultLen) | 
 | { | 
 |     int32_t written, i; | 
 |  | 
 |     /* pad and justify, if needed */ | 
 |     if(info->fWidth != -1 && resultLen < info->fWidth) { | 
 |         /* left justify */ | 
 |         if(info->fLeft) { | 
 |             written = u_file_write(result, resultLen, stream); | 
 |             for(i = 0; i < info->fWidth - resultLen; ++i) { | 
 |                 written += u_file_write(&info->fPadChar, 1, stream); | 
 |             } | 
 |         } | 
 |         /* right justify */ | 
 |         else { | 
 |             written = 0; | 
 |             for(i = 0; i < info->fWidth - resultLen; ++i) { | 
 |                 written += u_file_write(&info->fPadChar, 1, stream); | 
 |             } | 
 |             written += u_file_write(result, resultLen, stream); | 
 |         } | 
 |     } | 
 |     /* just write the formatted output */ | 
 |     else | 
 |         written = u_file_write(result, resultLen, stream); | 
 |  | 
 |     return written; | 
 | } | 
 |  | 
 | /* Sets the sign of a format based on u_sprintf_spec_info */ | 
 | /* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */ | 
 | static void | 
 | u_printf_set_sign(UNumberFormat        *format, | 
 |                    const u_printf_spec_info     *info, | 
 |                    UErrorCode *status) | 
 | { | 
 |     if(info->fShowSign) { | 
 |         if (info->fSpace) { | 
 |             /* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */ | 
 |             /* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */ | 
 |             unum_setTextAttribute(format, UNUM_POSITIVE_PREFIX, gSpaceStr, 1, status); | 
 |         } | 
 |         else { | 
 |             UChar plusSymbol[UFPRINTF_SYMBOL_BUFFER_SIZE]; | 
 |             int32_t symbolLen; | 
 |  | 
 |             symbolLen = unum_getSymbol(format, | 
 |                 UNUM_PLUS_SIGN_SYMBOL, | 
 |                 plusSymbol, | 
 |                 sizeof(plusSymbol)/sizeof(*plusSymbol), | 
 |                 status); | 
 |             unum_setTextAttribute(format, | 
 |                 UNUM_POSITIVE_PREFIX, | 
 |                 plusSymbol, | 
 |                 symbolLen, | 
 |                 status); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /* handle a '%' */ | 
 |  | 
 | int32_t | 
 | u_printf_simple_percent_handler(UFILE                 *stream, | 
 |                                 const u_printf_spec_info     *info, | 
 |                                 const ufmt_args            *args) | 
 | { | 
 |     /* put a single '%' on the stream */ | 
 |     u_fputc(0x0025, stream); | 
 |     /* we wrote one character */ | 
 |     return 1; | 
 | } | 
 |  | 
 | /* handle 's' */ | 
 |  | 
 | int32_t | 
 | u_printf_string_handler(UFILE                 *stream, | 
 |                         const u_printf_spec_info     *info, | 
 |                         const ufmt_args            *args) | 
 | { | 
 |     UChar *s = NULL; | 
 |     int32_t len, written; | 
 |     const char *arg = (const char*)(args[0].ptrValue); | 
 |  | 
 |     /* convert from the default codepage to Unicode */ | 
 |     if (arg) { | 
 |         s = ufmt_defaultCPToUnicode(arg, (int32_t)strlen(arg)); | 
 |     } | 
 |     else { | 
 |         s = gNullStr; | 
 |     } | 
 |     if(s == NULL) { | 
 |         return 0; | 
 |     } | 
 |     len = u_strlen(s); | 
 |  | 
 |     /* width = minimum # of characters to write */ | 
 |     /* precision = maximum # of characters to write */ | 
 |  | 
 |     /* precision takes precedence over width */ | 
 |     /* determine if the string should be truncated */ | 
 |     if(info->fPrecision != -1 && len > info->fPrecision) { | 
 |         written = u_file_write(s, info->fPrecision, stream); | 
 |     } | 
 |     /* determine if the string should be padded */ | 
 |     else { | 
 |         written = u_printf_pad_and_justify(stream, info, s, len); | 
 |     } | 
 |  | 
 |     /* clean up */ | 
 |     if (gNullStr != s) { | 
 |         uprv_free(s); | 
 |     } | 
 |  | 
 |     return written; | 
 | } | 
 |  | 
 | /* HSYS */ | 
 | int32_t | 
 | u_printf_integer_handler(UFILE                 *stream, | 
 |                          const u_printf_spec_info     *info, | 
 |                          const ufmt_args            *args) | 
 | { | 
 |     long            num         = (long) (args[0].intValue); | 
 |     UNumberFormat        *format; | 
 |     UChar            result        [UFPRINTF_BUFFER_SIZE]; | 
 |     int32_t        minDigits     = -1; | 
 |     UErrorCode        status        = U_ZERO_ERROR; | 
 |  | 
 |     /* mask off any necessary bits */ | 
 |     if(info->fIsShort) | 
 |         num &= UINT16_MAX; | 
 |     else if(! info->fIsLong || ! info->fIsLongLong) | 
 |         num &= UINT32_MAX; | 
 |  | 
 |     /* get the formatter */ | 
 |     format = u_locbund_getNumberFormat(stream->fBundle); | 
 |  | 
 |     /* handle error */ | 
 |     if(format == 0) | 
 |         return 0; | 
 |  | 
 |     /* set the appropriate flags on the formatter */ | 
 |  | 
 |     /* set the minimum integer digits */ | 
 |     if(info->fPrecision != -1) { | 
 |         /* clone the stream's bundle if it isn't owned */ | 
 |         if(! stream->fOwnBundle) { | 
 |             stream->fBundle     = u_locbund_clone(stream->fBundle); | 
 |             stream->fOwnBundle = TRUE; | 
 |             format           = u_locbund_getNumberFormat(stream->fBundle); | 
 |         } | 
 |  | 
 |         /* set the minimum # of digits */ | 
 |         minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS); | 
 |         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision); | 
 |     } | 
 |  | 
 |     /* set whether to show the sign */ | 
 |     if(info->fShowSign) { | 
 |         /* clone the stream's bundle if it isn't owned */ | 
 |         if(! stream->fOwnBundle) { | 
 |             stream->fBundle     = u_locbund_clone(stream->fBundle); | 
 |             stream->fOwnBundle = TRUE; | 
 |             format           = u_locbund_getNumberFormat(stream->fBundle); | 
 |         } | 
 |  | 
 |         u_printf_set_sign(format, info, &status); | 
 |     } | 
 |  | 
 |     /* format the number */ | 
 |     unum_format(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status); | 
 |  | 
 |     /* restore the number format */ | 
 |     if(minDigits != -1) | 
 |         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits); | 
 |  | 
 |     return u_printf_pad_and_justify(stream, info, result, u_strlen(result)); | 
 | } | 
 |  | 
 | int32_t | 
 | u_printf_hex_handler(UFILE             *stream, | 
 |                      const u_printf_spec_info     *info, | 
 |                      const ufmt_args            *args) | 
 | { | 
 |     long            num         = (long) (args[0].intValue); | 
 |     UChar           result[UFPRINTF_BUFFER_SIZE]; | 
 |     int32_t         len        = UFPRINTF_BUFFER_SIZE; | 
 |  | 
 |  | 
 |     /* mask off any necessary bits */ | 
 |     if(info->fIsShort) | 
 |         num &= UINT16_MAX; | 
 |     else if(! info->fIsLong || ! info->fIsLongLong) | 
 |         num &= UINT32_MAX; | 
 |  | 
 |     /* format the number, preserving the minimum # of digits */ | 
 |     ufmt_ltou(result, &len, num, 16, | 
 |         (UBool)(info->fSpec == 0x0078), | 
 |         (info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision); | 
 |  | 
 |     /* convert to alt form, if desired */ | 
 |     if(num != 0 && info->fAlt && len < UFPRINTF_BUFFER_SIZE - 2) { | 
 |         /* shift the formatted string right by 2 chars */ | 
 |         memmove(result + 2, result, len * sizeof(UChar)); | 
 |         result[0] = 0x0030; | 
 |         result[1] = info->fSpec; | 
 |         len += 2; | 
 |     } | 
 |  | 
 |     return u_printf_pad_and_justify(stream, info, result, len); | 
 | } | 
 |  | 
 | int32_t | 
 | u_printf_octal_handler(UFILE                 *stream, | 
 |                        const u_printf_spec_info     *info, | 
 |                        const ufmt_args            *args) | 
 | { | 
 |     long            num         = (long) (args[0].intValue); | 
 |     UChar           result[UFPRINTF_BUFFER_SIZE]; | 
 |     int32_t         len        = UFPRINTF_BUFFER_SIZE; | 
 |  | 
 |  | 
 |     /* mask off any necessary bits */ | 
 |     if(info->fIsShort) | 
 |         num &= UINT16_MAX; | 
 |     else if(! info->fIsLong || ! info->fIsLongLong) | 
 |         num &= UINT32_MAX; | 
 |  | 
 |     /* format the number, preserving the minimum # of digits */ | 
 |     ufmt_ltou(result, &len, num, 8, | 
 |         FALSE, /* doesn't matter for octal */ | 
 |         info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision); | 
 |  | 
 |     /* convert to alt form, if desired */ | 
 |     if(info->fAlt && result[0] != 0x0030 && len < UFPRINTF_BUFFER_SIZE - 1) { | 
 |         /* shift the formatted string right by 1 char */ | 
 |         memmove(result + 1, result, len * sizeof(UChar)); | 
 |         result[0] = 0x0030; | 
 |         len += 1; | 
 |     } | 
 |  | 
 |     return u_printf_pad_and_justify(stream, info, result, len); | 
 | } | 
 |  | 
 |  | 
 | int32_t | 
 | u_printf_uinteger_handler(UFILE                 *stream, | 
 |                           const u_printf_spec_info     *info, | 
 |                           const ufmt_args            *args) | 
 | { | 
 |     u_printf_spec_info uint_info; | 
 |     ufmt_args uint_args; | 
 |  | 
 |     memcpy(&uint_info, info, sizeof(u_printf_spec_info)); | 
 |     memcpy(&uint_args, args, sizeof(ufmt_args)); | 
 |  | 
 |     uint_info.fPrecision = 0; | 
 |     uint_info.fAlt  = FALSE; | 
 |  | 
 |     /* Get around int32_t limitations */ | 
 |     uint_args.doubleValue = ((double) ((uint32_t) (uint_args.intValue))); | 
 |  | 
 |     return u_printf_double_handler(stream, &uint_info, &uint_args); | 
 | } | 
 |  | 
 | int32_t | 
 | u_printf_double_handler(UFILE                 *stream, | 
 |                         const u_printf_spec_info     *info, | 
 |                         const ufmt_args            *args) | 
 | { | 
 |     double        num         = (double) (args[0].doubleValue); | 
 |     UNumberFormat        *format; | 
 |     UChar            result        [UFPRINTF_BUFFER_SIZE]; | 
 |     int32_t        minDecimalDigits; | 
 |     int32_t        maxDecimalDigits; | 
 |     UErrorCode        status        = U_ZERO_ERROR; | 
 |  | 
 |     /* mask off any necessary bits */ | 
 |     /*  if(! info->fIsLongDouble) | 
 |     num &= DBL_MAX;*/ | 
 |  | 
 |     /* get the formatter */ | 
 |     format = u_locbund_getNumberFormat(stream->fBundle); | 
 |  | 
 |     /* handle error */ | 
 |     if(format == 0) | 
 |         return 0; | 
 |  | 
 |     /* set the appropriate flags on the formatter */ | 
 |  | 
 |     /* clone the stream's bundle if it isn't owned */ | 
 |     if(! stream->fOwnBundle) { | 
 |         stream->fBundle     = u_locbund_clone(stream->fBundle); | 
 |         stream->fOwnBundle     = TRUE; | 
 |         format           = u_locbund_getNumberFormat(stream->fBundle); | 
 |     } | 
 |  | 
 |     /* set the number of decimal digits */ | 
 |  | 
 |     /* save the formatter's state */ | 
 |     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); | 
 |     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); | 
 |  | 
 |     if(info->fPrecision != -1) { | 
 |         /* set the # of decimal digits */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); | 
 |     } | 
 |     else if(info->fPrecision == 0 && ! info->fAlt) { | 
 |         /* no decimal point in this case */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0); | 
 |     } | 
 |     else if(info->fAlt) { | 
 |         /* '#' means always show decimal point */ | 
 |         /* copy of printf behavior on Solaris - '#' shows 6 digits */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); | 
 |     } | 
 |     else { | 
 |         /* # of decimal digits is 6 if precision not specified */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); | 
 |     } | 
 |  | 
 |     /* set whether to show the sign */ | 
 |     u_printf_set_sign(format, info, &status); | 
 |  | 
 |     /* format the number */ | 
 |     unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status); | 
 |  | 
 |     /* restore the number format */ | 
 |     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); | 
 |     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); | 
 |  | 
 |     return u_printf_pad_and_justify(stream, info, result, u_strlen(result)); | 
 | } | 
 |  | 
 |  | 
 | int32_t | 
 | u_printf_char_handler(UFILE                 *stream, | 
 |                       const u_printf_spec_info         *info, | 
 |                       const ufmt_args              *args) | 
 | { | 
 |     UChar *s; | 
 |     int32_t len = 1, written; | 
 |     unsigned char arg = (unsigned char)(args[0].intValue); | 
 |  | 
 |     /* convert from default codepage to Unicode */ | 
 |     s = ufmt_defaultCPToUnicode((const char *)&arg, 1); | 
 |     if(s == 0) { | 
 |         return 0; | 
 |     } | 
 |     if (arg != 0) { | 
 |         len = u_strlen(s); | 
 |     } | 
 |  | 
 |     /* width = minimum # of characters to write */ | 
 |     /* precision = maximum # of characters to write */ | 
 |  | 
 |     /* precision takes precedence over width */ | 
 |     /* determine if the string should be truncated */ | 
 |     if(info->fPrecision != -1 && len > info->fPrecision) { | 
 |         written = u_file_write(s, info->fPrecision, stream); | 
 |     } | 
 |     else { | 
 |         /* determine if the string should be padded */ | 
 |         written = u_printf_pad_and_justify(stream, info, s, len); | 
 |     } | 
 |  | 
 |     /* clean up */ | 
 |     uprv_free(s); | 
 |  | 
 |     return written; | 
 | } | 
 |  | 
 |  | 
 | int32_t | 
 | u_printf_pointer_handler(UFILE                 *stream, | 
 |                          const u_printf_spec_info     *info, | 
 |                          const ufmt_args            *args) | 
 | { | 
 |     long            num         = (long) (args[0].intValue); | 
 |     UChar           result[UFPRINTF_BUFFER_SIZE]; | 
 |     int32_t         len        = UFPRINTF_BUFFER_SIZE; | 
 |  | 
 |  | 
 |     /* format the pointer in hex */ | 
 |     ufmt_ltou(result, &len, num, 16, TRUE, info->fPrecision); | 
 |  | 
 |     return u_printf_pad_and_justify(stream, info, result, len); | 
 | } | 
 |  | 
 |  | 
 | int32_t | 
 | u_printf_scientific_handler(UFILE             *stream, | 
 |                             const u_printf_spec_info     *info, | 
 |                             const ufmt_args            *args) | 
 | { | 
 |     double        num         = (double) (args[0].doubleValue); | 
 |     UNumberFormat        *format; | 
 |     UChar            result        [UFPRINTF_BUFFER_SIZE]; | 
 |     int32_t        minDecimalDigits; | 
 |     int32_t        maxDecimalDigits; | 
 |     UErrorCode        status        = U_ZERO_ERROR; | 
 |     UChar srcExpBuf[UFPRINTF_SYMBOL_BUFFER_SIZE]; | 
 |     int32_t srcLen, expLen; | 
 |     UChar expBuf[UFPRINTF_SYMBOL_BUFFER_SIZE]; | 
 |  | 
 |  | 
 |     /* mask off any necessary bits */ | 
 |     /*  if(! info->fIsLongDouble) | 
 |     num &= DBL_MAX;*/ | 
 |  | 
 |     /* get the formatter */ | 
 |     format = u_locbund_getScientificFormat(stream->fBundle); | 
 |  | 
 |     /* handle error */ | 
 |     if(format == 0) | 
 |         return 0; | 
 |  | 
 |     /* set the appropriate flags on the formatter */ | 
 |  | 
 |     /* clone the stream's bundle if it isn't owned */ | 
 |     if(! stream->fOwnBundle) { | 
 |         stream->fBundle     = u_locbund_clone(stream->fBundle); | 
 |         stream->fOwnBundle     = TRUE; | 
 |         format           = u_locbund_getScientificFormat(stream->fBundle); | 
 |     } | 
 |  | 
 |     srcLen = unum_getSymbol(format, | 
 |         UNUM_EXPONENTIAL_SYMBOL, | 
 |         srcExpBuf, | 
 |         sizeof(srcExpBuf), | 
 |         &status); | 
 |  | 
 |     /* Upper/lower case the e */ | 
 |     if (info->fSpec == (UChar)0x65 /* e */) { | 
 |         expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf), | 
 |             srcExpBuf, srcLen, | 
 |             stream->fBundle->fLocale, | 
 |             &status); | 
 |     } | 
 |     else { | 
 |         expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf), | 
 |             srcExpBuf, srcLen, | 
 |             stream->fBundle->fLocale, | 
 |             &status); | 
 |     } | 
 |  | 
 |     unum_setSymbol(format, | 
 |         UNUM_EXPONENTIAL_SYMBOL, | 
 |         expBuf, | 
 |         expLen, | 
 |         &status); | 
 |  | 
 |     /* set the number of decimal digits */ | 
 |  | 
 |     /* save the formatter's state */ | 
 |     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); | 
 |     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); | 
 |  | 
 |     if(info->fPrecision != -1) { | 
 |         /* set the # of decimal digits */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); | 
 |     } | 
 |     else if(info->fPrecision == 0 && ! info->fAlt) { | 
 |         /* no decimal point in this case */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0); | 
 |     } | 
 |     else if(info->fAlt) { | 
 |         /* '#' means always show decimal point */ | 
 |         /* copy of printf behavior on Solaris - '#' shows 6 digits */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); | 
 |     } | 
 |     else { | 
 |         /* # of decimal digits is 6 if precision not specified */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); | 
 |     } | 
 |  | 
 |     /* set whether to show the sign */ | 
 |     u_printf_set_sign(format, info, &status); | 
 |  | 
 |     /* format the number */ | 
 |     unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status); | 
 |  | 
 |     /* restore the number format */ | 
 |     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); | 
 |     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); | 
 |  | 
 |     unum_setSymbol(format, | 
 |         UNUM_EXPONENTIAL_SYMBOL, | 
 |         srcExpBuf, | 
 |         srcLen, | 
 |         &status); | 
 |  | 
 |     return u_printf_pad_and_justify(stream, info, result, u_strlen(result)); | 
 | } | 
 |  | 
 | int32_t | 
 | u_printf_date_handler(UFILE             *stream, | 
 |                       const u_printf_spec_info     *info, | 
 |                       const ufmt_args         *args) | 
 | { | 
 |     UDate            num         = (UDate) (args[0].dateValue); | 
 |     UDateFormat        *format; | 
 |     UChar            result        [UFPRINTF_BUFFER_SIZE]; | 
 |     UErrorCode        status        = U_ZERO_ERROR; | 
 |  | 
 |  | 
 |     /* get the formatter */ | 
 |     format = u_locbund_getDateFormat(stream->fBundle); | 
 |  | 
 |     /* handle error */ | 
 |     if(format == 0) | 
 |         return 0; | 
 |  | 
 |     /* format the date */ | 
 |     udat_format(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status); | 
 |  | 
 |     return u_printf_pad_and_justify(stream, info, result, u_strlen(result)); | 
 | } | 
 |  | 
 | int32_t | 
 | u_printf_time_handler(UFILE             *stream, | 
 |                       const u_printf_spec_info     *info, | 
 |                       const ufmt_args         *args) | 
 | { | 
 |     UDate            num         = (UDate) (args[0].dateValue); | 
 |     UDateFormat        *format; | 
 |     UChar            result        [UFPRINTF_BUFFER_SIZE]; | 
 |     UErrorCode        status        = U_ZERO_ERROR; | 
 |  | 
 |  | 
 |     /* get the formatter */ | 
 |     format = u_locbund_getTimeFormat(stream->fBundle); | 
 |  | 
 |     /* handle error */ | 
 |     if(format == 0) | 
 |         return 0; | 
 |  | 
 |     /* format the time */ | 
 |     udat_format(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status); | 
 |  | 
 |     return u_printf_pad_and_justify(stream, info, result, u_strlen(result)); | 
 | } | 
 |  | 
 |  | 
 | int32_t | 
 | u_printf_percent_handler(UFILE                 *stream, | 
 |                          const u_printf_spec_info     *info, | 
 |                          const ufmt_args            *args) | 
 | { | 
 |     double        num         = (double) (args[0].doubleValue); | 
 |     UNumberFormat        *format; | 
 |     UChar            result        [UFPRINTF_BUFFER_SIZE]; | 
 |     int32_t        minDecimalDigits; | 
 |     int32_t        maxDecimalDigits; | 
 |     UErrorCode        status        = U_ZERO_ERROR; | 
 |  | 
 |  | 
 |     /* mask off any necessary bits */ | 
 |     /*  if(! info->fIsLongDouble) | 
 |     num &= DBL_MAX;*/ | 
 |  | 
 |     /* get the formatter */ | 
 |     format = u_locbund_getPercentFormat(stream->fBundle); | 
 |  | 
 |     /* handle error */ | 
 |     if(format == 0) | 
 |         return 0; | 
 |  | 
 |     /* set the appropriate flags on the formatter */ | 
 |  | 
 |     /* clone the stream's bundle if it isn't owned */ | 
 |     if(! stream->fOwnBundle) { | 
 |         stream->fBundle     = u_locbund_clone(stream->fBundle); | 
 |         stream->fOwnBundle     = TRUE; | 
 |         format           = u_locbund_getPercentFormat(stream->fBundle); | 
 |     } | 
 |  | 
 |     /* set the number of decimal digits */ | 
 |  | 
 |     /* save the formatter's state */ | 
 |     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); | 
 |     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); | 
 |  | 
 |     if(info->fPrecision != -1) { | 
 |         /* set the # of decimal digits */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); | 
 |     } | 
 |     else if(info->fPrecision == 0 && ! info->fAlt) { | 
 |         /* no decimal point in this case */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0); | 
 |     } | 
 |     else if(info->fAlt) { | 
 |         /* '#' means always show decimal point */ | 
 |         /* copy of printf behavior on Solaris - '#' shows 6 digits */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); | 
 |     } | 
 |     else { | 
 |         /* # of decimal digits is 6 if precision not specified */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); | 
 |     } | 
 |  | 
 |     /* set whether to show the sign */ | 
 |     u_printf_set_sign(format, info, &status); | 
 |  | 
 |     /* format the number */ | 
 |     unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status); | 
 |  | 
 |     /* restore the number format */ | 
 |     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); | 
 |     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); | 
 |  | 
 |     return u_printf_pad_and_justify(stream, info, result, u_strlen(result)); | 
 | } | 
 |  | 
 |  | 
 | int32_t | 
 | u_printf_currency_handler(UFILE             *stream, | 
 |                           const u_printf_spec_info     *info, | 
 |                           const ufmt_args            *args) | 
 | { | 
 |     double        num         = (double) (args[0].doubleValue); | 
 |     UNumberFormat        *format; | 
 |     UChar            result        [UFPRINTF_BUFFER_SIZE]; | 
 |     int32_t        minDecimalDigits; | 
 |     int32_t        maxDecimalDigits; | 
 |     UErrorCode        status        = U_ZERO_ERROR; | 
 |  | 
 |  | 
 |     /* mask off any necessary bits */ | 
 |     /*  if(! info->fIsLongDouble) | 
 |     num &= DBL_MAX;*/ | 
 |  | 
 |     /* get the formatter */ | 
 |     format = u_locbund_getCurrencyFormat(stream->fBundle); | 
 |  | 
 |     /* handle error */ | 
 |     if(format == 0) | 
 |         return 0; | 
 |  | 
 |     /* set the appropriate flags on the formatter */ | 
 |  | 
 |     /* clone the stream's bundle if it isn't owned */ | 
 |     if(! stream->fOwnBundle) { | 
 |         stream->fBundle     = u_locbund_clone(stream->fBundle); | 
 |         stream->fOwnBundle     = TRUE; | 
 |         format           = u_locbund_getCurrencyFormat(stream->fBundle); | 
 |     } | 
 |  | 
 |     /* set the number of decimal digits */ | 
 |  | 
 |     /* save the formatter's state */ | 
 |     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); | 
 |     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); | 
 |  | 
 |     if(info->fPrecision != -1) { | 
 |         /* set the # of decimal digits */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); | 
 |     } | 
 |     else if(info->fPrecision == 0 && ! info->fAlt) { | 
 |         /* no decimal point in this case */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0); | 
 |     } | 
 |     else if(info->fAlt) { | 
 |         /* '#' means always show decimal point */ | 
 |         /* copy of printf behavior on Solaris - '#' shows 6 digits */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); | 
 |     } | 
 |     else { | 
 |         /* # of decimal digits is 6 if precision not specified */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); | 
 |     } | 
 |  | 
 |     /* set whether to show the sign */ | 
 |     u_printf_set_sign(format, info, &status); | 
 |  | 
 |     /* format the number */ | 
 |     unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status); | 
 |  | 
 |     /* restore the number format */ | 
 |     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); | 
 |     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); | 
 |  | 
 |     return u_printf_pad_and_justify(stream, info, result, u_strlen(result)); | 
 | } | 
 |  | 
 | int32_t | 
 | u_printf_ustring_handler(UFILE                 *stream, | 
 |                          const u_printf_spec_info     *info, | 
 |                          const ufmt_args         *args) | 
 | { | 
 |     int32_t len = 0, written; | 
 |     const UChar *arg = (const UChar*)(args[0].ptrValue); | 
 |  | 
 |     /* allocate enough space for the buffer */ | 
 |     if (arg == NULL) { | 
 |         arg = gNullStr; | 
 |     } | 
 |     len = u_strlen(arg); | 
 |  | 
 |     /* width = minimum # of characters to write */ | 
 |     /* precision = maximum # of characters to write */ | 
 |  | 
 |     /* precision takes precedence over width */ | 
 |     /* determine if the string should be truncated */ | 
 |     if(info->fPrecision != -1 && len > info->fPrecision) { | 
 |         written = u_file_write(arg, info->fPrecision, stream); | 
 |     } | 
 |     else { | 
 |         /* determine if the string should be padded */ | 
 |         written = u_printf_pad_and_justify(stream, info, arg, len); | 
 |     } | 
 |  | 
 |     return written; | 
 | } | 
 |  | 
 |  | 
 |  | 
 | int32_t | 
 | u_printf_uchar_handler(UFILE                 *stream, | 
 |                        const u_printf_spec_info     *info, | 
 |                        const ufmt_args            *args) | 
 | { | 
 |     int32_t written = 0; | 
 |     UChar arg = (UChar)(args[0].intValue); | 
 |  | 
 |  | 
 |     /* width = minimum # of characters to write */ | 
 |     /* precision = maximum # of characters to write */ | 
 |  | 
 |     /* precision takes precedence over width */ | 
 |     /* determine if the char should be printed */ | 
 |     if(info->fPrecision != -1 && info->fPrecision < 1) { | 
 |         /* write nothing */ | 
 |         written = 0; | 
 |     } | 
 |     else { | 
 |         /* determine if the string should be padded */ | 
 |         written = u_printf_pad_and_justify(stream, info, &arg, 1); | 
 |     } | 
 |  | 
 |     return written; | 
 | } | 
 |  | 
 | int32_t | 
 | u_printf_scidbl_handler(UFILE                 *stream, | 
 |                         const u_printf_spec_info     *info, | 
 |                         const ufmt_args            *args) | 
 | { | 
 |     u_printf_spec_info scidbl_info; | 
 |     double      num = args[0].doubleValue; | 
 |  | 
 |     memcpy(&scidbl_info, info, sizeof(u_printf_spec_info)); | 
 |  | 
 |     /* determine whether to use 'd', 'e' or 'f' notation */ | 
 |     if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num)) | 
 |     { | 
 |         /* use 'f' notation */ | 
 |         scidbl_info.fSpec = 0x0066; | 
 |         scidbl_info.fPrecision = 0; | 
 |         /* call the double handler */ | 
 |         return u_printf_double_handler(stream, &scidbl_info, args); | 
 |     } | 
 |     else if(num < 0.0001 | 
 |         || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision))) | 
 |     { | 
 |         /* use 'e' or 'E' notation */ | 
 |         scidbl_info.fSpec = scidbl_info.fSpec - 1; | 
 |         /* call the scientific handler */ | 
 |         return u_printf_scientific_handler(stream, &scidbl_info, args); | 
 |     } | 
 |     else { | 
 |         /* use 'f' notation */ | 
 |         scidbl_info.fSpec = 0x0066; | 
 |         /* call the double handler */ | 
 |         return u_printf_double_handler(stream, &scidbl_info, args); | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | int32_t | 
 | u_printf_count_handler(UFILE                 *stream, | 
 |                        const u_printf_spec_info     *info, | 
 |                        const ufmt_args            *args) | 
 | { | 
 |     int *count = (int*)(args[0].ptrValue); | 
 |  | 
 |     /* in the special case of count, the u_printf_spec_info's width */ | 
 |     /* will contain the # of chars written thus far */ | 
 |     *count = info->fWidth; | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 |  | 
 | int32_t | 
 | u_printf_spellout_handler(UFILE             *stream, | 
 |                           const u_printf_spec_info     *info, | 
 |                           const ufmt_args            *args) | 
 | { | 
 |     double        num         = (double) (args[0].doubleValue); | 
 |     UNumberFormat        *format; | 
 |     UChar            result        [UFPRINTF_BUFFER_SIZE]; | 
 |     int32_t        minDecimalDigits; | 
 |     int32_t        maxDecimalDigits; | 
 |     UErrorCode        status        = U_ZERO_ERROR; | 
 |  | 
 |  | 
 |     /* mask off any necessary bits */ | 
 |     /*  if(! info->fIsLongDouble) | 
 |     num &= DBL_MAX;*/ | 
 |  | 
 |     /* get the formatter */ | 
 |     format = u_locbund_getSpelloutFormat(stream->fBundle); | 
 |  | 
 |     /* handle error */ | 
 |     if(format == 0) | 
 |         return 0; | 
 |  | 
 |     /* set the appropriate flags on the formatter */ | 
 |  | 
 |     /* clone the stream's bundle if it isn't owned */ | 
 |     if(! stream->fOwnBundle) { | 
 |         stream->fBundle     = u_locbund_clone(stream->fBundle); | 
 |         stream->fOwnBundle     = TRUE; | 
 |         format           = u_locbund_getSpelloutFormat(stream->fBundle); | 
 |     } | 
 |  | 
 |     /* set the number of decimal digits */ | 
 |  | 
 |     /* save the formatter's state */ | 
 |     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); | 
 |     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); | 
 |  | 
 |     if(info->fPrecision != -1) { | 
 |         /* set the # of decimal digits */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); | 
 |     } | 
 |     else if(info->fPrecision == 0 && ! info->fAlt) { | 
 |         /* no decimal point in this case */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0); | 
 |     } | 
 |     else if(info->fAlt) { | 
 |         /* '#' means always show decimal point */ | 
 |         /* copy of printf behavior on Solaris - '#' shows 6 digits */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); | 
 |     } | 
 |     else { | 
 |         /* # of decimal digits is 6 if precision not specified */ | 
 |         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); | 
 |     } | 
 |  | 
 |     /* set whether to show the sign */ | 
 |     u_printf_set_sign(format, info, &status); | 
 |  | 
 |     /* format the number */ | 
 |     unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status); | 
 |  | 
 |     /* restore the number format */ | 
 |     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); | 
 |     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); | 
 |  | 
 |     return u_printf_pad_and_justify(stream, info, result, u_strlen(result)); | 
 | } | 
 |  | 
 | #define UP_PERCENT 0x0025 | 
 |  | 
 | U_CAPI int32_t  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ | 
 | u_vfprintf_u(    UFILE        *f, | 
 |              const UChar    *patternSpecification, | 
 |              va_list        ap) | 
 | { | 
 |     u_printf_spec   spec; | 
 |     const UChar     *alias; | 
 |     int32_t         patCount, written; | 
 |     uint16_t      handlerNum; | 
 |  | 
 |     ufmt_args       args; | 
 |  | 
 |     ufmt_type_info    info; | 
 |     u_printf_handler handler; | 
 |  | 
 |     /* alias the pattern */ | 
 |     alias = patternSpecification; | 
 |  | 
 |     /* haven't written anything yet */ | 
 |     written = 0; | 
 |  | 
 |     /* iterate through the pattern */ | 
 |     for(;;) { | 
 |  | 
 |         /* find the next '%' */ | 
 |         patCount = 0; | 
 |         while(*alias != UP_PERCENT && *alias != 0x0000) { | 
 |             alias++; | 
 |             ++patCount; | 
 |         } | 
 |  | 
 |         /* write any characters before the '%' */ | 
 |         if(patCount > 0) | 
 |             written += u_file_write(alias - patCount, patCount, f); | 
 |  | 
 |         /* break if at end of string */ | 
 |         if(*alias == 0x0000) | 
 |             break; | 
 |  | 
 |         /* parse the specifier */ | 
 |         patCount = u_printf_parse_spec(alias, &spec); | 
 |  | 
 |         /* fill in the precision and width, if specified out of line */ | 
 |  | 
 |         /* width specified out of line */ | 
 |         if(spec.fInfo.fWidth == -2) { | 
 |             if(spec.fWidthPos == -1) { | 
 |                 /* read the width from the argument list */ | 
 |                 spec.fInfo.fWidth = va_arg(ap, int); | 
 |             } | 
 |             else { | 
 |                 /* handle positional parameter */ | 
 |             } | 
 |  | 
 |             /* if it's negative, take the absolute value and set left alignment */ | 
 |             if(spec.fInfo.fWidth < 0) { | 
 |                 spec.fInfo.fWidth     *= -1; | 
 |                 spec.fInfo.fLeft     = TRUE; | 
 |             } | 
 |         } | 
 |  | 
 |         /* precision specified out of line */ | 
 |         if(spec.fInfo.fPrecision == -2) { | 
 |             if(spec.fPrecisionPos == -1) { | 
 |                 /* read the precision from the argument list */ | 
 |                 spec.fInfo.fPrecision = va_arg(ap, int); | 
 |             } | 
 |             else { | 
 |                 /* handle positional parameter */ | 
 |             } | 
 |  | 
 |             /* if it's negative, set it to zero */ | 
 |             if(spec.fInfo.fPrecision < 0) | 
 |                 spec.fInfo.fPrecision = 0; | 
 |         } | 
 |  | 
 |         handlerNum = (uint16_t)(spec.fInfo.fSpec - UPRINTF_BASE_FMT_HANDLERS); | 
 |         if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) { | 
 |             /* query the info function for argument information */ | 
 |             info = g_u_printf_infos[ handlerNum ].info; | 
 |             if(info > ufmt_simple_percent) { | 
 |                 switch(info) { | 
 |  | 
 |                 case ufmt_count: | 
 |                     /* set the spec's width to the # of chars written */ | 
 |                     spec.fInfo.fWidth = written; | 
 |  | 
 |                 case ufmt_char: | 
 |                 case ufmt_uchar: | 
 |                 case ufmt_int: | 
 |                     args.intValue = va_arg(ap, int); | 
 |                     break; | 
 |  | 
 |                 case ufmt_wchar: | 
 |                     args.wcharValue = va_arg(ap, wchar_t); | 
 |                     break; | 
 |  | 
 |                 case ufmt_string: | 
 |                     args.ptrValue = va_arg(ap, char*); | 
 |                     break; | 
 |  | 
 |                 case ufmt_wstring: | 
 |                     args.ptrValue = va_arg(ap, wchar_t*); | 
 |                     break; | 
 |  | 
 |                 case ufmt_ustring: | 
 |                     args.ptrValue = va_arg(ap, UChar*); | 
 |                     break; | 
 |  | 
 |                 case ufmt_pointer: | 
 |                     args.ptrValue = va_arg(ap, void*); | 
 |                     break; | 
 |  | 
 |                 case ufmt_float: | 
 |                     args.floatValue = (float) va_arg(ap, double); | 
 |                     break; | 
 |  | 
 |                 case ufmt_double: | 
 |                     args.doubleValue = va_arg(ap, double); | 
 |                     break; | 
 |  | 
 |                 case ufmt_date: | 
 |                     args.dateValue = va_arg(ap, UDate); | 
 |                     break; | 
 |  | 
 |                 default: | 
 |                     break;  /* Should never get here */ | 
 |                 } | 
 |             } | 
 |  | 
 |             /* call the handler function */ | 
 |             handler = g_u_printf_infos[ handlerNum ].handler; | 
 |             if(handler != 0) { | 
 |                 written += (*handler)(f, &spec.fInfo, &args); | 
 |             } | 
 |             else { | 
 |                 /* just echo unknown tags */ | 
 |                 written += u_file_write(alias, patCount, f); | 
 |             } | 
 |         } | 
 |         else { | 
 |             /* just echo unknown tags */ | 
 |             written += u_file_write(alias, patCount, f); | 
 |         } | 
 |  | 
 |         /* update the pointer in pattern and continue */ | 
 |         alias += patCount; | 
 |     } | 
 |  | 
 |     /* return # of UChars written */ | 
 |     return written; | 
 | } | 
 |  |