#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#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"
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);
#define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_printf_simple_percent_handler}
#define UFMT_STRING {ufmt_string, u_printf_string_handler}
#define UFMT_CHAR {ufmt_char, u_printf_char_handler}
#define UFMT_INT {ufmt_int, u_printf_integer_handler}
#define UFMT_UINT {ufmt_int, u_printf_uinteger_handler}
#define UFMT_OCTAL {ufmt_int, u_printf_octal_handler}
#define UFMT_HEX {ufmt_int, u_printf_hex_handler}
#define UFMT_DOUBLE {ufmt_double, u_printf_double_handler}
#define UFMT_SCIENTIFIC {ufmt_double, u_printf_scientific_handler}
#define UFMT_SCIDBL {ufmt_double, u_printf_scidbl_handler}
#define UFMT_COUNT {ufmt_count, u_printf_count_handler}
#define UFMT_POINTER {ufmt_pointer, u_printf_pointer_handler}
#define UFMT_DATE {ufmt_date, u_printf_date_handler}
#define UFMT_TIME {ufmt_date, u_printf_time_handler}
#define UFMT_SPELLOUT {ufmt_double, u_printf_spellout_handler}
#define UFMT_PERCENT {ufmt_double, u_printf_percent_handler}
#define UFMT_CURRENCY {ufmt_double, u_printf_currency_handler}
#define UFMT_UCHAR {ufmt_uchar, u_printf_uchar_handler}
#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;
static const u_printf_info g_u_printf_infos[108] = {
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,
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,
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,
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,
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,
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)
#define UPRINTF_BASE_FMT_HANDLERS 0x20
#define UFPRINTF_BUFFER_SIZE 1024
#define UFPRINTF_SYMBOL_BUFFER_SIZE 8
static const UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0};
static const 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_vfprintf( UFILE *f,
const char *patternSpecification,
va_list ap)
{
int32_t count;
UChar *pattern;
UChar buffer[UFMT_DEFAULT_BUFFER_SIZE];
int32_t size = (int32_t)strlen(patternSpecification) + 1;
if (size >= MAX_UCHAR_BUFFER_SIZE(buffer)) {
pattern = (UChar *)uprv_malloc(size * sizeof(UChar));
if(pattern == 0) {
return 0;
}
}
else {
pattern = buffer;
}
ufmt_defaultCPToUnicode(patternSpecification, size, pattern, size);
count = u_vfprintf_u(f, pattern, ap);
if (pattern != buffer) {
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;
if(info->fWidth != -1 && resultLen < info->fWidth) {
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);
}
}
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);
}
}
else
written = u_file_write(result, resultLen, stream);
return written;
}
static void
u_printf_set_sign(UNumberFormat *format,
const u_printf_spec_info *info,
UErrorCode *status)
{
if(info->fShowSign) {
if (info->fSpace) {
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);
}
}
}
int32_t
u_printf_simple_percent_handler(UFILE *stream,
const u_printf_spec_info *info,
const ufmt_args *args)
{
u_fputc(0x0025, stream);
return 1;
}
int32_t
u_printf_string_handler(UFILE *stream,
const u_printf_spec_info *info,
const ufmt_args *args)
{
UChar *s;
UChar buffer[UFMT_DEFAULT_BUFFER_SIZE];
int32_t len, written;
int32_t argSize;
const char *arg = (const char*)(args[0].ptrValue);
if (arg) {
argSize = (int32_t)strlen(arg) + 1;
if (argSize >= MAX_UCHAR_BUFFER_SIZE(buffer)) {
s = ufmt_defaultCPToUnicode(arg, argSize,
(UChar *)uprv_malloc(MAX_UCHAR_BUFFER_NEEDED(argSize)),
MAX_UCHAR_BUFFER_NEEDED(argSize));
if(s == NULL) {
return 0;
}
}
else {
s = ufmt_defaultCPToUnicode(arg, argSize, buffer,
sizeof(buffer)/sizeof(UChar));
}
}
else {
s = (UChar *)gNullStr;
}
len = u_strlen(s);
if(info->fPrecision != -1 && len > info->fPrecision) {
written = u_file_write(s, info->fPrecision, stream);
}
else {
written = u_printf_pad_and_justify(stream, info, s, len);
}
if (gNullStr != s && buffer != s) {
uprv_free(s);
}
return written;
}
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;
if(info->fIsShort)
num &= UINT16_MAX;
else if(! info->fIsLong || ! info->fIsLongLong)
num &= UINT32_MAX;
format = u_locbund_getNumberFormat(stream->fBundle);
if(format == 0)
return 0;
if(info->fPrecision != -1) {
if(! stream->fOwnBundle) {
stream->fBundle = u_locbund_clone(stream->fBundle);
stream->fOwnBundle = TRUE;
format = u_locbund_getNumberFormat(stream->fBundle);
}
minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
}
if(info->fShowSign) {
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);
}
unum_format(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
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;
if(info->fIsShort)
num &= UINT16_MAX;
else if(! info->fIsLong || ! info->fIsLongLong)
num &= UINT32_MAX;
ufmt_ltou(result, &len, num, 16,
(UBool)(info->fSpec == 0x0078),
(info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);
if(num != 0 && info->fAlt && len < UFPRINTF_BUFFER_SIZE - 2) {
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;
if(info->fIsShort)
num &= UINT16_MAX;
else if(! info->fIsLong || ! info->fIsLongLong)
num &= UINT32_MAX;
ufmt_ltou(result, &len, num, 8,
FALSE,
info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);
if(info->fAlt && result[0] != 0x0030 && len < UFPRINTF_BUFFER_SIZE - 1) {
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;
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;
format = u_locbund_getNumberFormat(stream->fBundle);
if(format == 0)
return 0;
if(! stream->fOwnBundle) {
stream->fBundle = u_locbund_clone(stream->fBundle);
stream->fOwnBundle = TRUE;
format = u_locbund_getNumberFormat(stream->fBundle);
}
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
if(info->fPrecision != -1) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
}
else if(info->fPrecision == 0 && ! info->fAlt) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
}
else if(info->fAlt) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
}
else {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
}
u_printf_set_sign(format, info, &status);
unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
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[UTF_MAX_CHAR_LENGTH+1];
int32_t len = 1, written;
unsigned char arg = (unsigned char)(args[0].intValue);
ufmt_defaultCPToUnicode((const char *)&arg, 2, s, sizeof(s)/sizeof(UChar));
if (arg != 0) {
len = u_strlen(s);
}
if(info->fPrecision != -1 && len > info->fPrecision) {
written = u_file_write(s, info->fPrecision, stream);
}
else {
written = u_printf_pad_and_justify(stream, info, s, len);
}
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;
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];
format = u_locbund_getScientificFormat(stream->fBundle);
if(format == 0)
return 0;
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);
if (info->fSpec == (UChar)0x65 ) {
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);
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
if(info->fPrecision != -1) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
}
else if(info->fPrecision == 0 && ! info->fAlt) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
}
else if(info->fAlt) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
}
else {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
}
u_printf_set_sign(format, info, &status);
unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
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_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;
format = u_locbund_getDateFormat(stream->fBundle);
if(format == 0)
return 0;
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;
format = u_locbund_getTimeFormat(stream->fBundle);
if(format == 0)
return 0;
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;
format = u_locbund_getPercentFormat(stream->fBundle);
if(format == 0)
return 0;
if(! stream->fOwnBundle) {
stream->fBundle = u_locbund_clone(stream->fBundle);
stream->fOwnBundle = TRUE;
format = u_locbund_getPercentFormat(stream->fBundle);
}
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
if(info->fPrecision != -1) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
}
else if(info->fPrecision == 0 && ! info->fAlt) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
}
else if(info->fAlt) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
}
else {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
}
u_printf_set_sign(format, info, &status);
unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
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;
format = u_locbund_getCurrencyFormat(stream->fBundle);
if(format == 0)
return 0;
if(! stream->fOwnBundle) {
stream->fBundle = u_locbund_clone(stream->fBundle);
stream->fOwnBundle = TRUE;
format = u_locbund_getCurrencyFormat(stream->fBundle);
}
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
if(info->fPrecision != -1) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
}
else if(info->fPrecision == 0 && ! info->fAlt) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
}
else if(info->fAlt) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 2);
}
else {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 2);
}
u_printf_set_sign(format, info, &status);
unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
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);
if (arg == NULL) {
arg = gNullStr;
}
len = u_strlen(arg);
if(info->fPrecision != -1 && len > info->fPrecision) {
written = u_file_write(arg, info->fPrecision, stream);
}
else {
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);
if(info->fPrecision != -1 && info->fPrecision < 1) {
written = 0;
}
else {
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));
if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num))
{
scidbl_info.fSpec = 0x0066;
scidbl_info.fPrecision = 0;
return u_printf_double_handler(stream, &scidbl_info, args);
}
else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num)
|| (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision)))
{
scidbl_info.fSpec = scidbl_info.fSpec - 2;
return u_printf_scientific_handler(stream, &scidbl_info, args);
}
else {
scidbl_info.fSpec = 0x0066;
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);
*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;
format = u_locbund_getSpelloutFormat(stream->fBundle);
if(format == 0)
return 0;
if(! stream->fOwnBundle) {
stream->fBundle = u_locbund_clone(stream->fBundle);
stream->fOwnBundle = TRUE;
format = u_locbund_getSpelloutFormat(stream->fBundle);
}
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
if(info->fPrecision != -1) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
}
else if(info->fPrecision == 0 && ! info->fAlt) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
}
else if(info->fAlt) {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
}
else {
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
}
u_printf_set_sign(format, info, &status);
unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
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_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 = patternSpecification;
written = 0;
for(;;) {
patCount = 0;
while(*alias != UP_PERCENT && *alias != 0x0000) {
alias++;
++patCount;
}
if(patCount > 0)
written += u_file_write(alias - patCount, patCount, f);
if(*alias == 0x0000)
break;
patCount = u_printf_parse_spec(alias, &spec);
if(spec.fInfo.fWidth == -2) {
if(spec.fWidthPos == -1) {
spec.fInfo.fWidth = va_arg(ap, int);
}
else {
}
if(spec.fInfo.fWidth < 0) {
spec.fInfo.fWidth *= -1;
spec.fInfo.fLeft = TRUE;
}
}
if(spec.fInfo.fPrecision == -2) {
if(spec.fPrecisionPos == -1) {
spec.fInfo.fPrecision = va_arg(ap, int);
}
else {
}
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) {
info = g_u_printf_infos[ handlerNum ].info;
if(info > ufmt_simple_percent) {
switch(info) {
case ufmt_count:
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;
}
}
handler = g_u_printf_infos[ handlerNum ].handler;
if(handler != 0) {
written += (*handler)(f, &spec.fInfo, &args);
}
else {
written += u_file_write(alias, patCount, f);
}
}
else {
written += u_file_write(alias, patCount, f);
}
alias += patCount;
}
return written;
}
#endif