X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/73c04bcfe1096173b00431f0cdc742894b15eef0..f59164e3d128c7675a4d3934206346a3384e53a5:/icuSources/io/uprntf_p.c diff --git a/icuSources/io/uprntf_p.c b/icuSources/io/uprntf_p.c index 08236762..fcb6ff80 100644 --- a/icuSources/io/uprntf_p.c +++ b/icuSources/io/uprntf_p.c @@ -1,7 +1,7 @@ /* ****************************************************************************** * -* Copyright (C) 1998-2006, International Business Machines +* Copyright (C) 1998-2016, International Business Machines * Corporation and others. All Rights Reserved. * ****************************************************************************** @@ -19,10 +19,10 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING +#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_CONVERSION #include "unicode/ustring.h" - +#include "unicode/utf16.h" #include "uprintf.h" #include "ufmt_cmn.h" #include "cmemory.h" @@ -143,7 +143,7 @@ u_printf_set_sign(UNumberFormat *format, symbolLen = unum_getSymbol(format, UNUM_PLUS_SIGN_SYMBOL, plusSymbol, - sizeof(plusSymbol)/sizeof(*plusSymbol), + UPRV_LENGTHOF(plusSymbol), status); unum_setTextAttribute(format, UNUM_POSITIVE_PREFIX, @@ -215,7 +215,7 @@ u_printf_string_handler(const u_printf_stream_handler *handler, } else { s = ufmt_defaultCPToUnicode(arg, argSize, buffer, - sizeof(buffer)/sizeof(UChar)); + UPRV_LENGTHOF(buffer)); } } else { @@ -246,12 +246,12 @@ u_printf_char_handler(const u_printf_stream_handler *handler, const u_printf_spec_info *info, const ufmt_args *args) { - UChar s[UTF_MAX_CHAR_LENGTH+1]; + UChar s[U16_MAX_LENGTH+1]; int32_t len = 1, written; unsigned char arg = (unsigned char)(args[0].int64Value); /* convert from default codepage to Unicode */ - ufmt_defaultCPToUnicode((const char *)&arg, 2, s, sizeof(s)/sizeof(UChar)); + ufmt_defaultCPToUnicode((const char *)&arg, 2, s, UPRV_LENGTHOF(s)); /* Remember that this may be an MBCS character */ if (arg != 0) { @@ -800,6 +800,8 @@ u_printf_scidbl_handler(const u_printf_stream_handler *handler, u_printf_spec_info scidbl_info; double num = args[0].doubleValue; int32_t retVal; + UNumberFormat *format; + int32_t maxSigDecimalDigits, significantDigits; memcpy(&scidbl_info, info, sizeof(u_printf_spec_info)); @@ -824,9 +826,13 @@ u_printf_scidbl_handler(const u_printf_stream_handler *handler, retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args); } else { - UNumberFormat *format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL); - int32_t maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS); - int32_t significantDigits = scidbl_info.fPrecision; + format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL); + /* Check for null pointer */ + if (format == NULL) { + return 0; + } + maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS); + significantDigits = scidbl_info.fPrecision; /* use 'f' notation */ scidbl_info.fSpec = 0x0066; @@ -1036,6 +1042,165 @@ static const u_printf_info g_u_printf_infos[UPRINTF_NUM_FMT_HANDLERS] = { #define ISMOD(s) (s) == MOD_H || \ (s) == MOD_LOWERL || \ (s) == MOD_L +/* Returns an array of the parsed argument type given in the format string. */ +static ufmt_args* parseArguments(const UChar *alias, va_list ap, UErrorCode *status) { + ufmt_args *arglist = NULL; + ufmt_type_info *typelist = NULL; + UBool *islonglong = NULL; + int32_t size = 0; + int32_t pos = 0; + UChar type; + uint16_t handlerNum; + const UChar *aliasStart = alias; + + /* get maximum number of arguments */ + for(;;) { + /* find % */ + while(*alias != UP_PERCENT && *alias != 0x0000) { + alias++; + } + + if(*alias == 0x0000) { + break; + } + + alias++; + + /* handle the pos number */ + if(ISDIGIT(*alias)) { + + /* handle positional parameters */ + if(ISDIGIT(*alias)) { + pos = (int) (*alias++ - DIGIT_ZERO); + + while(ISDIGIT(*alias)) { + pos *= 10; + pos += (int) (*alias++ - DIGIT_ZERO); + } + } + + /* if there is no '$', don't read anything */ + if(*alias != SPEC_DOLLARSIGN) { + return NULL; + } + } else { + return NULL; + } + + if (pos > size) { + size = pos; + } + } + + /* create the parsed argument list */ + typelist = (ufmt_type_info*)uprv_malloc(sizeof(ufmt_type_info) * size); + islonglong = (UBool*)uprv_malloc(sizeof(UBool) * size); + arglist = (ufmt_args*)uprv_malloc(sizeof(ufmt_args) * size); + + /* If malloc failed, return NULL */ + if (!typelist || !islonglong || !arglist) { + if (typelist) { + uprv_free(typelist); + } + + if (islonglong) { + uprv_free(islonglong); + } + + if (arglist) { + uprv_free(arglist); + } + + *status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + + /* reset alias back to the beginning */ + alias = aliasStart; + + for(;;) { + /* find % */ + while(*alias != UP_PERCENT && *alias != 0x0000) { + alias++; + } + + if(*alias == 0x0000) { + break; + } + + alias++; + + /* handle positional parameters */ + if(ISDIGIT(*alias)) { + pos = (int) (*alias++ - DIGIT_ZERO); + + while(ISDIGIT(*alias)) { + pos *= 10; + pos += (int) (*alias++ - DIGIT_ZERO); + } + } + /* offset position by 1 */ + pos--; + + /* skip over everything except for the type */ + while (ISMOD(*alias) || ISFLAG(*alias) || ISDIGIT(*alias) || + *alias == SPEC_ASTERISK || *alias == SPEC_PERIOD || *alias == SPEC_DOLLARSIGN) { + islonglong[pos] = FALSE; + if (ISMOD(*alias)) { + alias++; + if (*alias == MOD_LOWERL) { + islonglong[pos] = TRUE; + } + } + alias++; + } + type = *alias; + + /* store the argument type in the correct position of the parsed argument list */ + handlerNum = (uint16_t)(type - UPRINTF_BASE_FMT_HANDLERS); + if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) { + typelist[pos] = g_u_printf_infos[ handlerNum ].info; + } else { + typelist[pos] = ufmt_empty; + } + } + + /* store argument in arglist */ + for (pos = 0; pos < size; pos++) { + switch (typelist[pos]) { + case ufmt_string: + case ufmt_ustring: + case ufmt_pointer: + arglist[pos].ptrValue = va_arg(ap, void*); + break; + case ufmt_char: + case ufmt_uchar: + case ufmt_int: + if (islonglong[pos]) { + arglist[pos].int64Value = va_arg(ap, int64_t); + } + else { + arglist[pos].int64Value = va_arg(ap, int32_t); + } + break; + case ufmt_float: + arglist[pos].floatValue = (float) va_arg(ap, double); + break; + case ufmt_double: + arglist[pos].doubleValue = va_arg(ap, double); + break; + default: + /* else args is ignored */ + arglist[pos].ptrValue = NULL; + break; + } + } + + uprv_free(typelist); + uprv_free(islonglong); + + return arglist; +} /* We parse the argument list in Unicode */ U_CFUNC int32_t @@ -1057,9 +1222,22 @@ u_printf_parse(const u_printf_stream_handler *streamHandler, const UChar *alias = fmt; const UChar *backup; const UChar *lastAlias; - + const UChar *orgAlias = fmt; + /* parsed argument list */ + ufmt_args *arglist = NULL; /* initialized it to avoid compiler warnings */ + UErrorCode status = U_ZERO_ERROR; + if (!locStringContext || locStringContext->available >= 0) { + /* get the parsed list of argument types */ + arglist = parseArguments(orgAlias, ap, &status); + + /* Return error if parsing failed. */ + if (U_FAILURE(status)) { + return -1; + } + } + /* iterate through the pattern */ - while(!locStringContext || locStringContext->available > 0) { + while(!locStringContext || locStringContext->available >= 0) { /* find the next '%' */ lastAlias = alias; @@ -1320,36 +1498,71 @@ u_printf_parse(const u_printf_stream_handler *streamHandler, if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) { /* query the info function for argument information */ argType = g_u_printf_infos[ handlerNum ].info; - switch(argType) { - case ufmt_count: - /* set the spec's width to the # of chars written */ - info->fWidth = *written; - /* fall through to set the pointer */ - case ufmt_string: - case ufmt_ustring: - case ufmt_pointer: - args.ptrValue = va_arg(ap, void*); - break; - case ufmt_char: - case ufmt_uchar: - case ufmt_int: - if (info->fIsLongLong) { - args.int64Value = va_arg(ap, int64_t); + + /* goto the correct argument on arg_list if position is specified */ + if (spec.fArgPos > 0) { + /* offset position by 1 */ + spec.fArgPos--; + switch(argType) { + case ufmt_count: + /* set the spec's width to the # of chars written */ + info->fWidth = *written; + /* fall through to set the pointer */ + U_FALLTHROUGH; + case ufmt_string: + case ufmt_ustring: + case ufmt_pointer: + args.ptrValue = arglist[spec.fArgPos].ptrValue; + break; + case ufmt_char: + case ufmt_uchar: + case ufmt_int: + args.int64Value = arglist[spec.fArgPos].int64Value; + break; + case ufmt_float: + args.floatValue = arglist[spec.fArgPos].floatValue; + break; + case ufmt_double: + args.doubleValue = arglist[spec.fArgPos].doubleValue; + break; + default: + /* else args is ignored */ + args.ptrValue = NULL; + break; } - else { - args.int64Value = va_arg(ap, int32_t); + } else { /* no positional argument specified */ + switch(argType) { + case ufmt_count: + /* set the spec's width to the # of chars written */ + info->fWidth = *written; + /* fall through to set the pointer */ + U_FALLTHROUGH; + case ufmt_string: + case ufmt_ustring: + case ufmt_pointer: + args.ptrValue = va_arg(ap, void*); + break; + case ufmt_char: + case ufmt_uchar: + case ufmt_int: + if (info->fIsLongLong) { + args.int64Value = va_arg(ap, int64_t); + } + else { + args.int64Value = va_arg(ap, int32_t); + } + break; + case ufmt_float: + args.floatValue = (float) va_arg(ap, double); + break; + case ufmt_double: + args.doubleValue = va_arg(ap, double); + break; + default: + /* else args is ignored */ + args.ptrValue = NULL; + break; } - break; - case ufmt_float: - args.floatValue = (float) va_arg(ap, double); - break; - case ufmt_double: - args.doubleValue = va_arg(ap, double); - break; - default: - /* else args is ignored */ - args.ptrValue = NULL; - break; } /* call the handler function */ @@ -1367,6 +1580,10 @@ u_printf_parse(const u_printf_stream_handler *streamHandler, *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias)); } } + /* delete parsed argument list */ + if (arglist != NULL) { + uprv_free(arglist); + } /* return # of characters in this format that have been parsed. */ return (int32_t)(alias - fmt); }