2
*******************************************************************************
4
* Copyright (C) 1998-1999, International Business Machines
5
* Corporation and others. All Rights Reserved.
7
*******************************************************************************
11
* Modification History:
13
* Date Name Description
14
* 02/08/00 george Creation. Copied from uprintf.c
15
*******************************************************************************
18
#include "unicode/utypes.h"
21
#include "unicode/ustdio.h"
22
#include "unicode/ustring.h"
25
#include "unicode/unum.h"
26
#include "unicode/udat.h"
27
#include "unicode/uloc.h"
33
/* --- Prototypes ---------------------------- */
36
u_sprintf_simple_percent_handler(u_localized_string *output,
37
const u_sprintf_spec_info *info,
38
const ufmt_args *args);
41
u_sprintf_string_handler(u_localized_string *output,
42
const u_sprintf_spec_info *info,
43
const ufmt_args *args);
46
u_sprintf_date_handler(u_localized_string *output,
47
const u_sprintf_spec_info *info,
48
const ufmt_args *args);
51
u_sprintf_scientific_handler(u_localized_string *output,
52
const u_sprintf_spec_info *info,
53
const ufmt_args *args);
56
u_sprintf_scidbl_handler(u_localized_string *output,
57
const u_sprintf_spec_info *info,
58
const ufmt_args *args);
61
u_sprintf_uchar_handler(u_localized_string *output,
62
const u_sprintf_spec_info *info,
63
const ufmt_args *args);
66
u_sprintf_currency_handler(u_localized_string *output,
67
const u_sprintf_spec_info *info,
68
const ufmt_args *args);
71
u_sprintf_ustring_handler(u_localized_string *output,
72
const u_sprintf_spec_info *info,
73
const ufmt_args *args);
76
u_sprintf_percent_handler(u_localized_string *output,
77
const u_sprintf_spec_info *info,
78
const ufmt_args *args);
81
u_sprintf_time_handler(u_localized_string *output,
82
const u_sprintf_spec_info *info,
83
const ufmt_args *args);
86
u_sprintf_spellout_handler(u_localized_string *output,
87
const u_sprintf_spec_info *info,
88
const ufmt_args *args);
91
u_sprintf_hex_handler(u_localized_string *output,
92
const u_sprintf_spec_info *info,
93
const ufmt_args *args);
96
u_sprintf_char_handler(u_localized_string *output,
97
const u_sprintf_spec_info *info,
98
const ufmt_args *args);
101
u_sprintf_integer_handler(u_localized_string *output,
102
const u_sprintf_spec_info *info,
103
const ufmt_args *args);
106
u_sprintf_uinteger_handler(u_localized_string *output,
107
const u_sprintf_spec_info *info,
108
const ufmt_args *args);
111
u_sprintf_double_handler(u_localized_string *output,
112
const u_sprintf_spec_info *info,
113
const ufmt_args *args);
116
u_sprintf_count_handler(u_localized_string *output,
117
const u_sprintf_spec_info *info,
118
const ufmt_args *args);
121
u_sprintf_octal_handler(u_localized_string *output,
122
const u_sprintf_spec_info *info,
123
const ufmt_args *args);
126
u_sprintf_pointer_handler(u_localized_string *output,
127
const u_sprintf_spec_info *info,
128
const ufmt_args *args);
130
/* ANSI style formatting */
131
/* Use US-ASCII characters only for formatting */
134
#define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_sprintf_simple_percent_handler}
136
#define UFMT_STRING {ufmt_string, u_sprintf_string_handler}
138
#define UFMT_CHAR {ufmt_char, u_sprintf_char_handler}
140
#define UFMT_INT {ufmt_int, u_sprintf_integer_handler}
142
#define UFMT_UINT {ufmt_int, u_sprintf_uinteger_handler}
144
#define UFMT_OCTAL {ufmt_int, u_sprintf_octal_handler}
146
#define UFMT_HEX {ufmt_int, u_sprintf_hex_handler}
148
#define UFMT_DOUBLE {ufmt_double, u_sprintf_double_handler}
150
#define UFMT_SCIENTIFIC {ufmt_double, u_sprintf_scientific_handler}
152
#define UFMT_SCIDBL {ufmt_double, u_sprintf_scidbl_handler}
154
#define UFMT_COUNT {ufmt_count, u_sprintf_count_handler}
156
/* non-ANSI extensions */
157
/* Use US-ASCII characters only for formatting */
160
#define UFMT_POINTER {ufmt_pointer, u_sprintf_pointer_handler}
162
#define UFMT_DATE {ufmt_date, u_sprintf_date_handler}
164
#define UFMT_TIME {ufmt_date, u_sprintf_time_handler}
166
#define UFMT_SPELLOUT {ufmt_double, u_sprintf_spellout_handler}
168
#define UFMT_PERCENT {ufmt_double, u_sprintf_percent_handler}
170
#define UFMT_CURRENCY {ufmt_double, u_sprintf_currency_handler}
172
#define UFMT_UCHAR {ufmt_uchar, u_sprintf_uchar_handler}
174
#define UFMT_USTRING {ufmt_ustring, u_sprintf_ustring_handler}
177
#define UFMT_EMPTY {ufmt_empty, NULL}
179
struct u_sprintf_info {
180
enum ufmt_type_info info;
181
u_sprintf_handler handler;
183
typedef struct u_sprintf_info u_sprintf_info;
185
/* Use US-ASCII characters only for formatting. Most codepages have
186
characters 20-7F from Unicode. Using any other codepage specific
187
characters will make it very difficult to format the string on
188
non-Unicode machines */
189
static const u_sprintf_info g_u_sprintf_infos[108] = {
191
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
192
UFMT_EMPTY, UFMT_SIMPLE_PERCENT,UFMT_EMPTY, UFMT_EMPTY,
193
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
194
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
197
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
198
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
199
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
200
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
203
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
204
UFMT_DATE, UFMT_SCIENTIFIC, UFMT_EMPTY, UFMT_SCIDBL,
205
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR,
206
UFMT_EMPTY, UFMT_CURRENCY, UFMT_EMPTY, UFMT_EMPTY,
209
UFMT_PERCENT, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
210
UFMT_TIME, UFMT_USTRING, UFMT_SPELLOUT, UFMT_EMPTY,
211
UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
212
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
215
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_CHAR,
216
UFMT_INT, UFMT_SCIENTIFIC, UFMT_DOUBLE, UFMT_SCIDBL,
217
UFMT_EMPTY, UFMT_INT, UFMT_EMPTY, UFMT_EMPTY,
218
UFMT_EMPTY, UFMT_EMPTY, UFMT_COUNT, UFMT_OCTAL,
221
UFMT_POINTER, UFMT_EMPTY, UFMT_EMPTY, UFMT_STRING,
222
UFMT_EMPTY, UFMT_UINT, UFMT_EMPTY, UFMT_EMPTY,
223
UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
224
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
227
#define USPRINTF_NUM_FMT_HANDLERS sizeof(g_u_sprintf_infos)
229
/* We do not use handlers for 0-0x1f */
230
#define USPRINTF_BASE_FMT_HANDLERS 0x20
232
/* buffer size for formatting */
233
#define USPRINTF_BUFFER_SIZE 1024
234
#define USPRINTF_EXP_BUFFER_SIZE 8
237
u_sprintf(UChar *buffer,
239
const char *patternSpecification,
245
va_start(ap, patternSpecification);
246
written = u_vsnprintf(buffer, INT32_MAX, locale, patternSpecification, ap);
253
u_sprintf_u(UChar *buffer,
255
const UChar *patternSpecification,
261
va_start(ap, patternSpecification);
262
written = u_vsnprintf_u(buffer, INT32_MAX, locale, patternSpecification, ap);
268
U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
269
u_vsprintf(UChar *buffer,
271
const char *patternSpecification,
274
return u_vsnprintf(buffer, INT32_MAX, locale, patternSpecification, ap);
278
u_snprintf(UChar *buffer,
281
const char *patternSpecification,
287
va_start(ap, patternSpecification);
288
written = u_vsnprintf(buffer, count, locale, patternSpecification, ap);
295
u_snprintf_u(UChar *buffer,
298
const UChar *patternSpecification,
304
va_start(ap, patternSpecification);
305
written = u_vsnprintf_u(buffer, count, locale, patternSpecification, ap);
311
U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
312
u_vsnprintf(UChar *buffer,
315
const char *patternSpecification,
321
/* convert from the default codepage to Unicode */
322
pattern = ufmt_defaultCPToUnicode(patternSpecification,
323
strlen(patternSpecification));
329
written = u_vsnprintf_u(buffer, count, locale, pattern, ap);
338
u_strset(UChar *str, int32_t count, UChar c) {
340
for(idx = 0; idx < count; ++idx) {
346
/* copies the minimum number of code units of (count or output->available) */
348
u_minstrncpy(u_localized_string *output, const UChar *str, int32_t count) {
349
int32_t size = ufmt_min(count, output->available);
351
u_strncpy(output->str + (output->len - output->available), str, size);
352
output->available -= size;
357
u_sprintf_pad_and_justify(u_localized_string *output,
358
const u_sprintf_spec_info *info,
364
resultLen = ufmt_min(resultLen, output->available);
367
/* pad and justify, if needed */
368
if(info->fWidth != -1 && resultLen < info->fWidth) {
369
int32_t paddingLeft = info->fWidth - resultLen;
370
int32_t outputPos = output->len - output->available;
372
if (paddingLeft + resultLen > output->available) {
373
paddingLeft = output->available - resultLen;
375
written += paddingLeft;
379
written += u_minstrncpy(output, result, resultLen);
380
u_strset(&output->str[outputPos + resultLen], paddingLeft, info->fPadChar);
384
u_strset(&output->str[outputPos + resultLen], paddingLeft, info->fPadChar);
385
written += u_minstrncpy(output, result, resultLen);
388
/* just write the formatted output */
390
written = u_minstrncpy(output, result, resultLen);
399
u_sprintf_simple_percent_handler(u_localized_string *output,
400
const u_sprintf_spec_info *info,
401
const ufmt_args *args)
403
/* put a single '%' on the stream */
404
if (output->available >= 1) {
405
output->str[output->len - output->available--] = 0x0025;
406
/* we wrote one character */
415
u_sprintf_string_handler(u_localized_string *output,
416
const u_sprintf_spec_info *info,
417
const ufmt_args *args)
420
int32_t len, written;
421
const char *arg = (const char*)(args[0].ptrValue);
423
/* convert from the default codepage to Unicode */
424
s = ufmt_defaultCPToUnicode(arg, strlen(arg));
430
/* width = minimum # of characters to write */
431
/* precision = maximum # of characters to write */
433
/* precision takes precedence over width */
434
/* determine if the string should be truncated */
435
if(info->fPrecision != -1 && len > info->fPrecision) {
436
written = u_minstrncpy(output, s, info->fPrecision);
438
/* determine if the string should be padded */
440
written = u_sprintf_pad_and_justify(output, info, s, len);
451
u_sprintf_integer_handler(u_localized_string *output,
452
const u_sprintf_spec_info *info,
453
const ufmt_args *args)
455
long num = (long) (args[0].intValue);
456
UNumberFormat *format;
457
UChar result [USPRINTF_BUFFER_SIZE];
458
int32_t minDigits = -1;
459
UErrorCode status = U_ZERO_ERROR;
462
/* mask off any necessary bits */
465
else if(! info->fIsLong || ! info->fIsLongLong)
468
/* get the formatter */
469
format = u_locbund_getNumberFormat(output->fBundle);
475
/* set the appropriate flags on the formatter */
477
/* set the minimum integer digits */
478
if(info->fPrecision != -1) {
479
/* clone the stream's bundle if it isn't owned */
480
if(! output->fOwnBundle) {
481
output->fBundle = u_locbund_clone(output->fBundle);
482
output->fOwnBundle = TRUE;
483
format = u_locbund_getNumberFormat(output->fBundle);
486
/* set the minimum # of digits */
487
minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
488
unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
491
/* set whether to show the sign */
492
if(info->fShowSign) {
493
/* clone the stream's bundle if it isn't owned */
494
if(! output->fOwnBundle) {
495
output->fBundle = u_locbund_clone(output->fBundle);
496
output->fOwnBundle = TRUE;
497
format = u_locbund_getNumberFormat(output->fBundle);
500
/* set whether to show the sign*/
504
/* format the number */
505
unum_format(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
507
/* restore the number format */
509
unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
511
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
515
u_sprintf_hex_handler(u_localized_string *output,
516
const u_sprintf_spec_info *info,
517
const ufmt_args *args)
519
long num = (long) (args[0].intValue);
520
UChar result [USPRINTF_BUFFER_SIZE];
521
int32_t len = USPRINTF_BUFFER_SIZE;
524
/* mask off any necessary bits */
527
else if(! info->fIsLong || ! info->fIsLongLong)
530
/* format the number, preserving the minimum # of digits */
531
ufmt_ltou(result, &len, num, 16,
532
(UBool)(info->fSpec == 0x0078),
533
(info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);
535
/* convert to alt form, if desired */
536
if(num != 0 && info->fAlt && len < USPRINTF_BUFFER_SIZE - 2) {
537
/* shift the formatted string right by 2 chars */
538
memmove(result + 2, result, len * sizeof(UChar));
540
result[1] = info->fSpec;
544
return u_sprintf_pad_and_justify(output, info, result, len);
548
u_sprintf_octal_handler(u_localized_string *output,
549
const u_sprintf_spec_info *info,
550
const ufmt_args *args)
552
long num = (long) (args[0].intValue);
553
UChar result [USPRINTF_BUFFER_SIZE];
554
int32_t len = USPRINTF_BUFFER_SIZE;
557
/* mask off any necessary bits */
560
else if(! info->fIsLong || ! info->fIsLongLong)
563
/* format the number, preserving the minimum # of digits */
564
ufmt_ltou(result, &len, num, 8,
565
FALSE, /* doesn't matter for octal */
566
info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);
568
/* convert to alt form, if desired */
569
if(info->fAlt && result[0] != 0x0030 && len < USPRINTF_BUFFER_SIZE - 1) {
570
/* shift the formatted string right by 1 char */
571
memmove(result + 1, result, len * sizeof(UChar));
576
return u_sprintf_pad_and_justify(output, info, result, len);
581
u_sprintf_uinteger_handler(u_localized_string *output,
582
const u_sprintf_spec_info *info,
583
const ufmt_args *args)
585
u_sprintf_spec_info uint_info;
588
memcpy(&uint_info, info, sizeof(u_sprintf_spec_info));
589
memcpy(&uint_args, args, sizeof(ufmt_args));
591
uint_info.fPrecision = 0;
592
uint_info.fAlt = FALSE;
594
/* Get around int32_t limitations */
595
uint_args.doubleValue = ((double) ((uint32_t) (uint_args.intValue)));
597
return u_sprintf_double_handler(output, &uint_info, &uint_args);
601
u_sprintf_double_handler(u_localized_string *output,
602
const u_sprintf_spec_info *info,
603
const ufmt_args *args)
605
double num = (double) (args[0].doubleValue);
606
UNumberFormat *format;
607
UChar result [USPRINTF_BUFFER_SIZE];
608
int32_t minDecimalDigits;
609
int32_t maxDecimalDigits;
610
UErrorCode status = U_ZERO_ERROR;
612
/* mask off any necessary bits */
613
/* if(! info->fIsLongDouble)
616
/* get the formatter */
617
format = u_locbund_getNumberFormat(output->fBundle);
623
/* set the appropriate flags on the formatter */
625
/* clone the stream's bundle if it isn't owned */
626
if(! output->fOwnBundle) {
627
output->fBundle = u_locbund_clone(output->fBundle);
628
output->fOwnBundle = TRUE;
629
format = u_locbund_getNumberFormat(output->fBundle);
632
/* set the number of decimal digits */
634
/* save the formatter's state */
635
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
636
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
638
if(info->fPrecision != -1) {
639
/* set the # of decimal digits */
640
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
642
else if(info->fPrecision == 0 && ! info->fAlt) {
643
/* no decimal point in this case */
644
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
646
else if(info->fAlt) {
647
/* '#' means always show decimal point */
648
/* copy of printf behavior on Solaris - '#' shows 6 digits */
649
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
652
/* # of decimal digits is 6 if precision not specified regardless of locale */
653
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
656
/* set whether to show the sign */
657
if(info->fShowSign) {
658
/* set whether to show the sign*/
662
/* format the number */
663
unum_formatDouble(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
665
/* restore the number format */
666
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
667
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
669
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
674
u_sprintf_char_handler(u_localized_string *output,
675
const u_sprintf_spec_info *info,
676
const ufmt_args *args)
679
int32_t len, written;
680
unsigned char arg = (unsigned char)(args[0].intValue);
682
/* convert from default codepage to Unicode */
683
s = ufmt_defaultCPToUnicode((const char *)&arg, 1);
688
/* Remember that this may be a surrogate pair */
691
/* width = minimum # of characters to write */
692
/* precision = maximum # of characters to write */
694
/* precision takes precedence over width */
695
/* determine if the string should be truncated */
696
if(info->fPrecision != -1 && len > info->fPrecision) {
697
written = u_minstrncpy(output, s, info->fPrecision);
700
/* determine if the string should be padded */
701
written = u_sprintf_pad_and_justify(output, info, s, len);
712
u_sprintf_pointer_handler(u_localized_string *output,
713
const u_sprintf_spec_info *info,
714
const ufmt_args *args)
716
long num = (long) (args[0].intValue);
717
UChar result [USPRINTF_BUFFER_SIZE];
718
int32_t len = USPRINTF_BUFFER_SIZE;
721
/* format the pointer in hex */
722
ufmt_ltou(result, &len, num, 16, TRUE, info->fPrecision);
724
return u_sprintf_pad_and_justify(output, info, result, len);
729
u_sprintf_scientific_handler(u_localized_string *output,
730
const u_sprintf_spec_info *info,
731
const ufmt_args *args)
733
double num = (double) (args[0].doubleValue);
734
UNumberFormat *format;
735
UChar result [USPRINTF_BUFFER_SIZE];
736
int32_t minDecimalDigits;
737
int32_t maxDecimalDigits;
738
UErrorCode status = U_ZERO_ERROR;
739
UChar srcExpBuf[USPRINTF_EXP_BUFFER_SIZE];
740
int32_t srcLen, expLen;
741
UChar expBuf[USPRINTF_EXP_BUFFER_SIZE];
744
/* mask off any necessary bits */
745
/* if(! info->fIsLongDouble)
748
/* get the formatter */
749
format = u_locbund_getScientificFormat(output->fBundle);
755
/* set the appropriate flags on the formatter */
757
/* clone the stream's bundle if it isn't owned */
758
if(! output->fOwnBundle) {
759
output->fBundle = u_locbund_clone(output->fBundle);
760
output->fOwnBundle = TRUE;
761
format = u_locbund_getScientificFormat(output->fBundle);
764
srcLen = unum_getSymbol(format,
765
UNUM_EXPONENTIAL_SYMBOL,
770
/* Upper/lower case the e */
771
if (info->fSpec == (UChar)0x65 /* e */) {
772
expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
774
output->fBundle->fLocale,
778
expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
780
output->fBundle->fLocale,
784
unum_setSymbol(format,
785
UNUM_EXPONENTIAL_SYMBOL,
790
/* set the number of decimal digits */
792
/* save the formatter's state */
793
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
794
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
796
if(info->fPrecision != -1) {
797
/* set the # of decimal digits */
798
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
800
else if(info->fPrecision == 0 && ! info->fAlt) {
801
/* no decimal point in this case */
802
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
804
else if(info->fAlt) {
805
/* '#' means always show decimal point */
806
/* copy of printf behavior on Solaris - '#' shows 6 digits */
807
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
810
/* # of decimal digits is 6 if precision not specified */
811
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
814
/* set whether to show the sign */
815
if(info->fShowSign) {
816
/* set whether to show the sign*/
820
/* format the number */
821
unum_formatDouble(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
823
/* restore the number format */
824
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
825
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
827
unum_setSymbol(format,
828
UNUM_EXPONENTIAL_SYMBOL,
833
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
837
u_sprintf_date_handler(u_localized_string *output,
838
const u_sprintf_spec_info *info,
839
const ufmt_args *args)
841
UDate num = (UDate) (args[0].dateValue);
843
UChar result [USPRINTF_BUFFER_SIZE];
844
UErrorCode status = U_ZERO_ERROR;
847
/* get the formatter */
848
format = u_locbund_getDateFormat(output->fBundle);
854
/* format the date */
855
udat_format(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
857
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
861
u_sprintf_time_handler(u_localized_string *output,
862
const u_sprintf_spec_info *info,
863
const ufmt_args *args)
865
UDate num = (UDate) (args[0].dateValue);
867
UChar result [USPRINTF_BUFFER_SIZE];
868
UErrorCode status = U_ZERO_ERROR;
871
/* get the formatter */
872
format = u_locbund_getTimeFormat(output->fBundle);
878
/* format the time */
879
udat_format(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
881
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
886
u_sprintf_percent_handler(u_localized_string *output,
887
const u_sprintf_spec_info *info,
888
const ufmt_args *args)
890
double num = (double) (args[0].doubleValue);
891
UNumberFormat *format;
892
UChar result [USPRINTF_BUFFER_SIZE];
893
int32_t minDecimalDigits;
894
int32_t maxDecimalDigits;
895
UErrorCode status = U_ZERO_ERROR;
898
/* mask off any necessary bits */
899
/* if(! info->fIsLongDouble)
902
/* get the formatter */
903
format = u_locbund_getPercentFormat(output->fBundle);
909
/* set the appropriate flags on the formatter */
911
/* clone the stream's bundle if it isn't owned */
912
if(! output->fOwnBundle) {
913
output->fBundle = u_locbund_clone(output->fBundle);
914
output->fOwnBundle = TRUE;
915
format = u_locbund_getPercentFormat(output->fBundle);
918
/* set the number of decimal digits */
920
/* save the formatter's state */
921
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
922
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
924
if(info->fPrecision != -1) {
925
/* set the # of decimal digits */
926
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
928
else if(info->fPrecision == 0 && ! info->fAlt) {
929
/* no decimal point in this case */
930
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
932
else if(info->fAlt) {
933
/* '#' means always show decimal point */
934
/* copy of printf behavior on Solaris - '#' shows 6 digits */
935
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
938
/* # of decimal digits is 6 if precision not specified */
939
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
942
/* set whether to show the sign */
943
if(info->fShowSign) {
944
/* set whether to show the sign*/
948
/* format the number */
949
unum_formatDouble(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
951
/* restore the number format */
952
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
953
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
955
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
960
u_sprintf_currency_handler(u_localized_string *output,
961
const u_sprintf_spec_info *info,
962
const ufmt_args *args)
964
double num = (double) (args[0].doubleValue);
965
UNumberFormat *format;
966
UChar result [USPRINTF_BUFFER_SIZE];
967
int32_t minDecimalDigits;
968
int32_t maxDecimalDigits;
969
UErrorCode status = U_ZERO_ERROR;
972
/* mask off any necessary bits */
973
/* if(! info->fIsLongDouble)
976
/* get the formatter */
977
format = u_locbund_getCurrencyFormat(output->fBundle);
983
/* set the appropriate flags on the formatter */
985
/* clone the stream's bundle if it isn't owned */
986
if(! output->fOwnBundle) {
987
output->fBundle = u_locbund_clone(output->fBundle);
988
output->fOwnBundle = TRUE;
989
format = u_locbund_getCurrencyFormat(output->fBundle);
992
/* set the number of decimal digits */
994
/* save the formatter's state */
995
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
996
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
998
if(info->fPrecision != -1) {
999
/* set the # of decimal digits */
1000
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
1002
else if(info->fPrecision == 0 && ! info->fAlt) {
1003
/* no decimal point in this case */
1004
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
1006
else if(info->fAlt) {
1007
/* '#' means always show decimal point */
1008
/* copy of printf behavior on Solaris - '#' shows 6 digits */
1009
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
1012
/* # of decimal digits is 6 if precision not specified */
1013
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
1016
/* set whether to show the sign */
1017
if(info->fShowSign) {
1018
/* set whether to show the sign*/
1022
/* format the number */
1023
unum_formatDouble(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
1025
/* restore the number format */
1026
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
1027
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
1029
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
1033
u_sprintf_ustring_handler(u_localized_string *output,
1034
const u_sprintf_spec_info *info,
1035
const ufmt_args *args)
1037
int32_t len, written;
1038
const UChar *arg = (const UChar*)(args[0].ptrValue);
1040
/* allocate enough space for the buffer */
1041
len = u_strlen(arg);
1043
/* width = minimum # of characters to write */
1044
/* precision = maximum # of characters to write */
1046
/* precision takes precedence over width */
1047
/* determine if the string should be truncated */
1048
if(info->fPrecision != -1 && len > info->fPrecision) {
1049
written = u_minstrncpy(output, arg, info->fPrecision);
1052
/* determine if the string should be padded */
1053
written = u_sprintf_pad_and_justify(output, info, arg, len);
1062
u_sprintf_uchar_handler(u_localized_string *output,
1063
const u_sprintf_spec_info *info,
1064
const ufmt_args *args)
1066
int32_t written = 0;
1067
UChar arg = (UChar)(args[0].intValue);
1070
/* width = minimum # of characters to write */
1071
/* precision = maximum # of characters to write */
1073
/* precision takes precedence over width */
1074
/* determine if the char should be printed */
1075
if(info->fPrecision != -1 && info->fPrecision < 1) {
1080
/* determine if the string should be padded */
1081
written = u_sprintf_pad_and_justify(output, info, &arg, 1);
1088
u_sprintf_scidbl_handler(u_localized_string *output,
1089
const u_sprintf_spec_info *info,
1090
const ufmt_args *args)
1092
u_sprintf_spec_info scidbl_info;
1093
double num = args[0].doubleValue;
1095
memcpy(&scidbl_info, info, sizeof(u_sprintf_spec_info));
1097
/* determine whether to use 'd', 'e' or 'f' notation */
1098
if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num))
1100
/* use 'f' notation */
1101
scidbl_info.fSpec = 0x0066;
1102
scidbl_info.fPrecision = 0;
1103
/* call the double handler */
1104
return u_sprintf_double_handler(output, &scidbl_info, args);
1106
else if(num < 0.0001
1107
|| (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision)))
1109
/* use 'e' or 'E' notation */
1110
scidbl_info.fSpec = scidbl_info.fSpec - 1;
1111
/* call the scientific handler */
1112
return u_sprintf_scientific_handler(output, &scidbl_info, args);
1115
/* use 'f' notation */
1116
scidbl_info.fSpec = 0x0066;
1117
/* call the double handler */
1118
return u_sprintf_double_handler(output, &scidbl_info, args);
1124
u_sprintf_count_handler(u_localized_string *output,
1125
const u_sprintf_spec_info *info,
1126
const ufmt_args *args)
1128
int *count = (int*)(args[0].ptrValue);
1130
/* in the special case of count, the u_printf_spec_info's width */
1131
/* will contain the # of chars written thus far */
1132
*count = info->fWidth;
1139
u_sprintf_spellout_handler(u_localized_string *output,
1140
const u_sprintf_spec_info *info,
1141
const ufmt_args *args)
1143
double num = (double) (args[0].doubleValue);
1144
UNumberFormat *format;
1145
UChar result [USPRINTF_BUFFER_SIZE];
1146
int32_t minDecimalDigits;
1147
int32_t maxDecimalDigits;
1148
UErrorCode status = U_ZERO_ERROR;
1151
/* mask off any necessary bits */
1152
/* if(! info->fIsLongDouble)
1155
/* get the formatter */
1156
format = u_locbund_getSpelloutFormat(output->fBundle);
1162
/* set the appropriate flags on the formatter */
1164
/* clone the stream's bundle if it isn't owned */
1165
if(! output->fOwnBundle) {
1166
output->fBundle = u_locbund_clone(output->fBundle);
1167
output->fOwnBundle = TRUE;
1168
format = u_locbund_getSpelloutFormat(output->fBundle);
1171
/* set the number of decimal digits */
1173
/* save the formatter's state */
1174
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
1175
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
1177
if(info->fPrecision != -1) {
1178
/* set the # of decimal digits */
1179
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
1181
else if(info->fPrecision == 0 && ! info->fAlt) {
1182
/* no decimal point in this case */
1183
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
1185
else if(info->fAlt) {
1186
/* '#' means always show decimal point */
1187
/* copy of printf behavior on Solaris - '#' shows 6 digits */
1188
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
1191
/* # of decimal digits is 6 if precision not specified */
1192
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
1195
/* set whether to show the sign */
1196
if(info->fShowSign) {
1197
/* set whether to show the sign*/
1201
/* format the number */
1202
unum_formatDouble(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
1204
/* restore the number format */
1205
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
1206
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
1208
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
1211
#define UP_PERCENT 0x0025
1213
U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
1214
u_vsnprintf_u(UChar *buffer,
1217
const UChar *patternSpecification,
1220
const UChar *alias = patternSpecification;
1221
const UChar *lastAlias;
1223
int32_t written = 0;
1224
uint16_t handlerNum;
1227
u_localized_string outStr;
1228
u_sprintf_spec spec;
1229
ufmt_type_info info;
1230
u_sprintf_handler handler;
1236
outStr.str = buffer;
1238
outStr.available = count;
1240
/* if locale is 0, use the default */
1242
locale = uloc_getDefault();
1244
outStr.fBundle = u_loccache_get(locale);
1246
if(outStr.fBundle == 0) {
1249
outStr.fOwnBundle = FALSE;
1251
/* iterate through the pattern */
1252
while(outStr.available > 0) {
1254
/* find the next '%' */
1256
while(*alias != UP_PERCENT && *alias != 0x0000) {
1260
/* write any characters before the '%' */
1261
if(alias > lastAlias) {
1262
written += u_minstrncpy(&outStr, lastAlias, (int32_t)(alias - lastAlias));
1265
/* break if at end of string */
1266
if(*alias == 0x0000) {
1267
if (outStr.available > 0) {
1268
outStr.str[written] = 0; /* NULL terminate it just in case */
1273
/* parse the specifier */
1274
patCount = u_sprintf_parse_spec(alias, &spec);
1276
/* fill in the precision and width, if specified out of line */
1278
/* width specified out of line */
1279
if(spec.fInfo.fWidth == -2) {
1280
if(spec.fWidthPos == -1) {
1281
/* read the width from the argument list */
1282
spec.fInfo.fWidth = va_arg(ap, int);
1285
/* handle positional parameter */
1288
/* if it's negative, take the absolute value and set left alignment */
1289
if(spec.fInfo.fWidth < 0) {
1290
spec.fInfo.fWidth *= -1;
1291
spec.fInfo.fLeft = TRUE;
1295
/* precision specified out of line */
1296
if(spec.fInfo.fPrecision == -2) {
1297
if(spec.fPrecisionPos == -1) {
1298
/* read the precision from the argument list */
1299
spec.fInfo.fPrecision = va_arg(ap, int);
1302
/* handle positional parameter */
1305
/* if it's negative, set it to zero */
1306
if(spec.fInfo.fPrecision < 0)
1307
spec.fInfo.fPrecision = 0;
1310
handlerNum = (uint16_t)(spec.fInfo.fSpec - USPRINTF_BASE_FMT_HANDLERS);
1311
if (handlerNum < USPRINTF_NUM_FMT_HANDLERS) {
1312
/* query the info function for argument information */
1313
info = g_u_sprintf_infos[ handlerNum ].info;
1314
if(info > ufmt_simple_percent) {
1318
/* set the spec's width to the # of chars written */
1319
spec.fInfo.fWidth = written;
1324
args.intValue = va_arg(ap, int);
1328
args.wcharValue = va_arg(ap, wchar_t);
1332
args.ptrValue = va_arg(ap, char*);
1336
args.ptrValue = va_arg(ap, wchar_t*);
1340
args.ptrValue = va_arg(ap, UChar*);
1344
args.ptrValue = va_arg(ap, void*);
1348
args.floatValue = (float) va_arg(ap, double);
1352
args.doubleValue = va_arg(ap, double);
1356
args.dateValue = va_arg(ap, UDate);
1360
break; /* Should never get here */
1364
/* call the handler function */
1365
handler = g_u_sprintf_infos[ handlerNum ].handler;
1367
written += (*handler)(&outStr, &spec.fInfo, &args);
1370
/* just echo unknown tags */
1371
written += u_minstrncpy(&outStr, lastAlias, (int32_t)(alias - lastAlias));
1375
/* just echo unknown tags */
1376
written += u_minstrncpy(&outStr, lastAlias, (int32_t)(alias - lastAlias));
1379
/* update the pointer in pattern and continue */
1383
/* return # of UChars written */