| /* |
| ******************************************************************************* |
| * |
| * Copyright (C) 1998-1999, International Business Machines |
| * Corporation and others. All Rights Reserved. |
| * |
| ******************************************************************************* |
| * |
| * File sprintf.c |
| * |
| * Modification History: |
| * |
| * Date Name Description |
| * 02/08/2000 george Creation. Copied from uprintf.c |
| * 03/27/2002 Mark Schneckloth Many fixes regarding alignment, null termination |
| * (mschneckloth@atomz.com) and other various problems. |
| ******************************************************************************* |
| */ |
| |
| #include "unicode/utypes.h" |
| #include "sprintf.h" |
| #include "sprntf_p.h" |
| #include "unicode/ustdio.h" |
| #include "unicode/ustring.h" |
| #include "locbund.h" |
| #include "loccache.h" |
| #include "unicode/unum.h" |
| #include "unicode/udat.h" |
| #include "unicode/uloc.h" |
| |
| #include "cmemory.h" |
| #include <ctype.h> |
| |
| |
| /* --- Prototypes ---------------------------- */ |
| |
| int32_t |
| u_sprintf_simple_percent_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_string_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_date_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_scientific_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_scidbl_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_uchar_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_currency_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_ustring_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_percent_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_time_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_spellout_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_hex_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_char_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_integer_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_uinteger_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_double_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_count_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_octal_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args); |
| |
| int32_t |
| u_sprintf_pointer_handler(u_localized_string *output, |
| const u_sprintf_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_sprintf_simple_percent_handler} |
| /* s */ |
| #define UFMT_STRING {ufmt_string, u_sprintf_string_handler} |
| /* c */ |
| #define UFMT_CHAR {ufmt_char, u_sprintf_char_handler} |
| /* d, i */ |
| #define UFMT_INT {ufmt_int, u_sprintf_integer_handler} |
| /* u */ |
| #define UFMT_UINT {ufmt_int, u_sprintf_uinteger_handler} |
| /* o */ |
| #define UFMT_OCTAL {ufmt_int, u_sprintf_octal_handler} |
| /* x, X */ |
| #define UFMT_HEX {ufmt_int, u_sprintf_hex_handler} |
| /* f */ |
| #define UFMT_DOUBLE {ufmt_double, u_sprintf_double_handler} |
| /* e, E */ |
| #define UFMT_SCIENTIFIC {ufmt_double, u_sprintf_scientific_handler} |
| /* g, G */ |
| #define UFMT_SCIDBL {ufmt_double, u_sprintf_scidbl_handler} |
| /* n */ |
| #define UFMT_COUNT {ufmt_count, u_sprintf_count_handler} |
| |
| /* non-ANSI extensions */ |
| /* Use US-ASCII characters only for formatting */ |
| |
| /* p */ |
| #define UFMT_POINTER {ufmt_pointer, u_sprintf_pointer_handler} |
| /* D */ |
| #define UFMT_DATE {ufmt_date, u_sprintf_date_handler} |
| /* T */ |
| #define UFMT_TIME {ufmt_date, u_sprintf_time_handler} |
| /* V */ |
| #define UFMT_SPELLOUT {ufmt_double, u_sprintf_spellout_handler} |
| /* P */ |
| #define UFMT_PERCENT {ufmt_double, u_sprintf_percent_handler} |
| /* M */ |
| #define UFMT_CURRENCY {ufmt_double, u_sprintf_currency_handler} |
| /* K */ |
| #define UFMT_UCHAR {ufmt_uchar, u_sprintf_uchar_handler} |
| /* U */ |
| #define UFMT_USTRING {ufmt_ustring, u_sprintf_ustring_handler} |
| |
| |
| #define UFMT_EMPTY {ufmt_empty, NULL} |
| |
| struct u_sprintf_info { |
| enum ufmt_type_info info; |
| u_sprintf_handler handler; |
| }; |
| typedef struct u_sprintf_info u_sprintf_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_sprintf_info g_u_sprintf_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 USPRINTF_NUM_FMT_HANDLERS sizeof(g_u_sprintf_infos) |
| |
| /* We do not use handlers for 0-0x1f */ |
| #define USPRINTF_BASE_FMT_HANDLERS 0x20 |
| |
| /* buffer size for formatting */ |
| #define USPRINTF_BUFFER_SIZE 1024 |
| #define USPRINTF_SYMBOL_BUFFER_SIZE 8 |
| |
| static UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */ |
| static UChar gSpaceStr[] = {0x20, 0}; /* " " */ |
| |
| U_CAPI int32_t U_EXPORT2 |
| u_sprintf(UChar *buffer, |
| const char *locale, |
| const char *patternSpecification, |
| ... ) |
| { |
| va_list ap; |
| int32_t written; |
| |
| va_start(ap, patternSpecification); |
| written = u_vsnprintf(buffer, INT32_MAX, locale, patternSpecification, ap); |
| va_end(ap); |
| |
| return written; |
| } |
| |
| U_CAPI int32_t U_EXPORT2 |
| u_sprintf_u(UChar *buffer, |
| const char *locale, |
| const UChar *patternSpecification, |
| ... ) |
| { |
| va_list ap; |
| int32_t written; |
| |
| va_start(ap, patternSpecification); |
| written = u_vsnprintf_u(buffer, INT32_MAX, locale, patternSpecification, ap); |
| va_end(ap); |
| |
| return written; |
| } |
| |
| U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ |
| u_vsprintf(UChar *buffer, |
| const char *locale, |
| const char *patternSpecification, |
| va_list ap) |
| { |
| return u_vsnprintf(buffer, INT32_MAX, locale, patternSpecification, ap); |
| } |
| |
| U_CAPI int32_t U_EXPORT2 |
| u_snprintf(UChar *buffer, |
| int32_t count, |
| const char *locale, |
| const char *patternSpecification, |
| ... ) |
| { |
| va_list ap; |
| int32_t written; |
| |
| va_start(ap, patternSpecification); |
| written = u_vsnprintf(buffer, count, locale, patternSpecification, ap); |
| va_end(ap); |
| |
| return written; |
| } |
| |
| U_CAPI int32_t U_EXPORT2 |
| u_snprintf_u(UChar *buffer, |
| int32_t count, |
| const char *locale, |
| const UChar *patternSpecification, |
| ... ) |
| { |
| va_list ap; |
| int32_t written; |
| |
| va_start(ap, patternSpecification); |
| written = u_vsnprintf_u(buffer, count, locale, patternSpecification, ap); |
| va_end(ap); |
| |
| return written; |
| } |
| |
| U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ |
| u_vsnprintf(UChar *buffer, |
| int32_t count, |
| const char *locale, |
| const char *patternSpecification, |
| va_list ap) |
| { |
| int32_t written; |
| 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 */ |
| written = u_vsnprintf_u(buffer, count, locale, pattern, ap); |
| |
| /* clean up */ |
| uprv_free(pattern); |
| |
| return written; |
| } |
| |
| U_CAPI int32_t U_EXPORT2 |
| u_vsprintf_u(UChar *buffer, |
| const char *locale, |
| const UChar *patternSpecification, |
| va_list ap) |
| { |
| return u_vsnprintf_u(buffer, INT32_MAX, locale, patternSpecification, ap); |
| } |
| |
| |
| static UChar * |
| u_strset(UChar *str, int32_t count, UChar c) { |
| int32_t idx; |
| for(idx = 0; idx < count; ++idx) { |
| str[idx] = c; |
| } |
| return str; |
| } |
| |
| /* copies the minimum number of code units of (count or output->available) */ |
| static int32_t |
| u_minstrncpy(u_localized_string *output, const UChar *str, int32_t count) { |
| int32_t size = ufmt_min(count, output->available); |
| |
| u_strncpy(output->str + (output->len - output->available), str, size); |
| output->available -= size; |
| return size; |
| } |
| |
| static int32_t |
| u_sprintf_pad_and_justify(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const UChar *result, |
| int32_t resultLen) |
| { |
| int32_t written = 0; |
| |
| resultLen = ufmt_min(resultLen, output->available); |
| |
| /* pad and justify, if needed */ |
| if(info->fWidth != -1 && resultLen < info->fWidth) { |
| int32_t paddingLeft = info->fWidth - resultLen; |
| int32_t outputPos = output->len - output->available; |
| |
| if (paddingLeft + resultLen > output->available) { |
| paddingLeft = output->available - resultLen; |
| if (paddingLeft < 0) { |
| paddingLeft = 0; |
| } |
| /* paddingLeft = output->available - resultLen;*/ |
| } |
| written += paddingLeft; |
| |
| /* left justify */ |
| if(info->fLeft) { |
| written += u_minstrncpy(output, result, resultLen); |
| u_strset(&output->str[outputPos + resultLen], paddingLeft, info->fPadChar); |
| output->available -= paddingLeft; |
| } |
| /* right justify */ |
| else { |
| u_strset(&output->str[outputPos], paddingLeft, info->fPadChar); |
| output->available -= paddingLeft; |
| written += u_minstrncpy(output, result, resultLen); |
| } |
| } |
| /* just write the formatted output */ |
| else { |
| written = u_minstrncpy(output, result, resultLen); |
| } |
| |
| 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_sprintf_set_sign(UNumberFormat *format, |
| const u_sprintf_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[USPRINTF_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_sprintf_simple_percent_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| /* put a single '%' on the stream */ |
| if (output->available >= 1) { |
| output->str[output->len - output->available--] = 0x0025; |
| /* we wrote one character */ |
| return 1; |
| } |
| return 0; |
| } |
| |
| /* handle 's' */ |
| |
| int32_t |
| u_sprintf_string_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| UChar *s; |
| 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 == 0) { |
| 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_minstrncpy(output, s, info->fPrecision); |
| } |
| /* determine if the string should be padded */ |
| else { |
| written = u_sprintf_pad_and_justify(output, info, s, len); |
| } |
| |
| /* clean up */ |
| if (gNullStr != s) { |
| uprv_free(s); |
| } |
| |
| return written; |
| } |
| |
| /* HSYS */ |
| int32_t |
| u_sprintf_integer_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| long num = (long) (args[0].intValue); |
| UNumberFormat *format; |
| UChar result [USPRINTF_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(output->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(! output->fOwnBundle) { |
| output->fBundle = u_locbund_clone(output->fBundle); |
| output->fOwnBundle = TRUE; |
| format = u_locbund_getNumberFormat(output->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(! output->fOwnBundle) { |
| output->fBundle = u_locbund_clone(output->fBundle); |
| output->fOwnBundle = TRUE; |
| format = u_locbund_getNumberFormat(output->fBundle); |
| } |
| |
| u_sprintf_set_sign(format, info, &status); |
| } |
| |
| /* format the number */ |
| unum_format(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status); |
| |
| /* restore the number format */ |
| if(minDigits != -1) { |
| unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits); |
| } |
| |
| return u_sprintf_pad_and_justify(output, info, result, u_strlen(result)); |
| } |
| |
| int32_t |
| u_sprintf_hex_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| long num = (long) (args[0].intValue); |
| UChar result [USPRINTF_BUFFER_SIZE]; |
| int32_t len = USPRINTF_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 < USPRINTF_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_sprintf_pad_and_justify(output, info, result, len); |
| } |
| |
| int32_t |
| u_sprintf_octal_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| long num = (long) (args[0].intValue); |
| UChar result [USPRINTF_BUFFER_SIZE]; |
| int32_t len = USPRINTF_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 < USPRINTF_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_sprintf_pad_and_justify(output, info, result, len); |
| } |
| |
| |
| int32_t |
| u_sprintf_uinteger_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| u_sprintf_spec_info uint_info; |
| ufmt_args uint_args; |
| |
| memcpy(&uint_info, info, sizeof(u_sprintf_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_sprintf_double_handler(output, &uint_info, &uint_args); |
| } |
| |
| int32_t |
| u_sprintf_double_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| double num = (double) (args[0].doubleValue); |
| UNumberFormat *format; |
| UChar result [USPRINTF_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(output->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(! output->fOwnBundle) { |
| output->fBundle = u_locbund_clone(output->fBundle); |
| output->fOwnBundle = TRUE; |
| format = u_locbund_getNumberFormat(output->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 regardless of locale */ |
| unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); |
| } |
| |
| /* set whether to show the sign */ |
| u_sprintf_set_sign(format, info, &status); |
| |
| /* format the number */ |
| unum_formatDouble(format, num, result, USPRINTF_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_sprintf_pad_and_justify(output, info, result, u_strlen(result)); |
| } |
| |
| |
| int32_t |
| u_sprintf_char_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| UChar *s; |
| int32_t len, 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; |
| } |
| |
| /* Remember that this may be a surrogate pair */ |
| 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_minstrncpy(output, s, info->fPrecision); |
| } |
| else { |
| /* determine if the string should be padded */ |
| written = u_sprintf_pad_and_justify(output, info, s, len); |
| } |
| |
| /* clean up */ |
| uprv_free(s); |
| |
| return written; |
| } |
| |
| |
| int32_t |
| u_sprintf_pointer_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| long num = (long) (args[0].intValue); |
| UChar result [USPRINTF_BUFFER_SIZE]; |
| int32_t len = USPRINTF_BUFFER_SIZE; |
| |
| |
| /* format the pointer in hex */ |
| ufmt_ltou(result, &len, num, 16, TRUE, info->fPrecision); |
| |
| return u_sprintf_pad_and_justify(output, info, result, len); |
| } |
| |
| int32_t |
| u_sprintf_scientific_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| double num = (double) (args[0].doubleValue); |
| UNumberFormat *format; |
| UChar result [USPRINTF_BUFFER_SIZE]; |
| int32_t minDecimalDigits; |
| int32_t maxDecimalDigits; |
| UErrorCode status = U_ZERO_ERROR; |
| UChar srcExpBuf[USPRINTF_SYMBOL_BUFFER_SIZE]; |
| int32_t srcLen, expLen; |
| UChar expBuf[USPRINTF_SYMBOL_BUFFER_SIZE]; |
| |
| |
| /* mask off any necessary bits */ |
| /* if(! info->fIsLongDouble) |
| num &= DBL_MAX;*/ |
| |
| /* get the formatter */ |
| format = u_locbund_getScientificFormat(output->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(! output->fOwnBundle) { |
| output->fBundle = u_locbund_clone(output->fBundle); |
| output->fOwnBundle = TRUE; |
| format = u_locbund_getScientificFormat(output->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, |
| output->fBundle->fLocale, |
| &status); |
| } |
| else { |
| expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf), |
| srcExpBuf, srcLen, |
| output->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_sprintf_set_sign(format, info, &status); |
| |
| /* format the number */ |
| unum_formatDouble(format, num, result, USPRINTF_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_sprintf_pad_and_justify(output, info, result, u_strlen(result)); |
| } |
| |
| int32_t |
| u_sprintf_date_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| UDate num = (UDate) (args[0].dateValue); |
| UDateFormat *format; |
| UChar result [USPRINTF_BUFFER_SIZE]; |
| UErrorCode status = U_ZERO_ERROR; |
| |
| |
| /* get the formatter */ |
| format = u_locbund_getDateFormat(output->fBundle); |
| |
| /* handle error */ |
| if(format == 0) |
| return 0; |
| |
| /* format the date */ |
| udat_format(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status); |
| |
| return u_sprintf_pad_and_justify(output, info, result, u_strlen(result)); |
| } |
| |
| int32_t |
| u_sprintf_time_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| UDate num = (UDate) (args[0].dateValue); |
| UDateFormat *format; |
| UChar result [USPRINTF_BUFFER_SIZE]; |
| UErrorCode status = U_ZERO_ERROR; |
| |
| |
| /* get the formatter */ |
| format = u_locbund_getTimeFormat(output->fBundle); |
| |
| /* handle error */ |
| if(format == 0) |
| return 0; |
| |
| /* format the time */ |
| udat_format(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status); |
| |
| return u_sprintf_pad_and_justify(output, info, result, u_strlen(result)); |
| } |
| |
| |
| int32_t |
| u_sprintf_percent_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| double num = (double) (args[0].doubleValue); |
| UNumberFormat *format; |
| UChar result [USPRINTF_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(output->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(! output->fOwnBundle) { |
| output->fBundle = u_locbund_clone(output->fBundle); |
| output->fOwnBundle = TRUE; |
| format = u_locbund_getPercentFormat(output->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_sprintf_set_sign(format, info, &status); |
| |
| /* format the number */ |
| unum_formatDouble(format, num, result, USPRINTF_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_sprintf_pad_and_justify(output, info, result, u_strlen(result)); |
| } |
| |
| |
| int32_t |
| u_sprintf_currency_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| double num = (double) (args[0].doubleValue); |
| UNumberFormat *format; |
| UChar result [USPRINTF_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(output->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(! output->fOwnBundle) { |
| output->fBundle = u_locbund_clone(output->fBundle); |
| output->fOwnBundle = TRUE; |
| format = u_locbund_getCurrencyFormat(output->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_sprintf_set_sign(format, info, &status); |
| |
| /* format the number */ |
| unum_formatDouble(format, num, result, USPRINTF_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_sprintf_pad_and_justify(output, info, result, u_strlen(result)); |
| } |
| |
| int32_t |
| u_sprintf_ustring_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| int32_t len, written; |
| const UChar *arg = (const UChar*)(args[0].ptrValue); |
| |
| /* allocate enough space for the buffer */ |
| if (!arg) { |
| 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_minstrncpy(output, arg, info->fPrecision); |
| } |
| else { |
| /* determine if the string should be padded */ |
| written = u_sprintf_pad_and_justify(output, info, arg, len); |
| } |
| |
| return written; |
| } |
| |
| |
| |
| int32_t |
| u_sprintf_uchar_handler(u_localized_string *output, |
| const u_sprintf_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_sprintf_pad_and_justify(output, info, &arg, 1); |
| } |
| |
| return written; |
| } |
| |
| int32_t |
| u_sprintf_scidbl_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| u_sprintf_spec_info scidbl_info; |
| double num = args[0].doubleValue; |
| |
| memcpy(&scidbl_info, info, sizeof(u_sprintf_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_sprintf_double_handler(output, &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_sprintf_scientific_handler(output, &scidbl_info, args); |
| } |
| else { |
| /* use 'f' notation */ |
| scidbl_info.fSpec = 0x0066; |
| /* call the double handler */ |
| return u_sprintf_double_handler(output, &scidbl_info, args); |
| } |
| } |
| |
| |
| int32_t |
| u_sprintf_count_handler(u_localized_string *output, |
| const u_sprintf_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_sprintf_spellout_handler(u_localized_string *output, |
| const u_sprintf_spec_info *info, |
| const ufmt_args *args) |
| { |
| double num = (double) (args[0].doubleValue); |
| UNumberFormat *format; |
| UChar result [USPRINTF_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(output->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(! output->fOwnBundle) { |
| output->fBundle = u_locbund_clone(output->fBundle); |
| output->fOwnBundle = TRUE; |
| format = u_locbund_getSpelloutFormat(output->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_sprintf_set_sign(format, info, &status); |
| |
| /* format the number */ |
| unum_formatDouble(format, num, result, USPRINTF_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_sprintf_pad_and_justify(output, 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_vsnprintf_u(UChar *buffer, |
| int32_t count, |
| const char *locale, |
| const UChar *patternSpecification, |
| va_list ap) |
| { |
| const UChar *alias = patternSpecification; |
| const UChar *lastAlias; |
| int32_t patCount; |
| int32_t written = 0; |
| uint16_t handlerNum; |
| |
| ufmt_args args; |
| u_localized_string outStr; |
| u_sprintf_spec spec; |
| ufmt_type_info info; |
| u_sprintf_handler handler; |
| |
| if (count < 0) { |
| count = INT32_MAX; |
| } |
| |
| outStr.str = buffer; |
| outStr.len = count; |
| outStr.available = count; |
| |
| /* if locale is 0, use the default */ |
| if(locale == 0) { |
| locale = uloc_getDefault(); |
| } |
| outStr.fBundle = u_loccache_get(locale); |
| |
| if(outStr.fBundle == 0) { |
| return 0; |
| } |
| outStr.fOwnBundle = FALSE; |
| |
| /* iterate through the pattern */ |
| while(outStr.available > 0) { |
| |
| /* find the next '%' */ |
| lastAlias = alias; |
| while(*alias != UP_PERCENT && *alias != 0x0000) { |
| alias++; |
| } |
| |
| /* write any characters before the '%' */ |
| if(alias > lastAlias) { |
| written += u_minstrncpy(&outStr, lastAlias, (int32_t)(alias - lastAlias)); |
| } |
| |
| /* break if at end of string */ |
| if(*alias == 0x0000) { |
| break; |
| } |
| |
| /* parse the specifier */ |
| patCount = u_sprintf_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 - USPRINTF_BASE_FMT_HANDLERS); |
| if (handlerNum < USPRINTF_NUM_FMT_HANDLERS) { |
| /* query the info function for argument information */ |
| info = g_u_sprintf_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_sprintf_infos[ handlerNum ].handler; |
| if(handler != 0) { |
| written += (*handler)(&outStr, &spec.fInfo, &args); |
| } |
| else { |
| /* just echo unknown tags */ |
| written += u_minstrncpy(&outStr, lastAlias, (int32_t)(alias - lastAlias)); |
| } |
| } |
| else { |
| /* just echo unknown tags */ |
| written += u_minstrncpy(&outStr, lastAlias, (int32_t)(alias - lastAlias)); |
| } |
| |
| /* update the pointer in pattern and continue */ |
| alias += patCount; |
| } |
| |
| /* Terminate the buffer, if there's room. */ |
| if (outStr.available > 0) { |
| buffer[outStr.len - outStr.available] = 0x0000; |
| } |
| |
| /* Release the cloned bundle, if we cloned it. */ |
| if(outStr.fOwnBundle) { |
| u_locbund_delete(outStr.fBundle); |
| outStr.fBundle = NULL; |
| outStr.fOwnBundle = FALSE; |
| } |
| |
| /* return # of UChars written */ |
| return written; |
| } |
| |