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/2000 george Creation. Copied from uprintf.c
15
* 03/27/2002 Mark Schneckloth Many fixes regarding alignment, null termination
16
* (mschneckloth@atomz.com) and other various problems.
17
*******************************************************************************
20
#include "unicode/utypes.h"
23
#include "unicode/ustdio.h"
24
#include "unicode/ustring.h"
27
#include "unicode/unum.h"
28
#include "unicode/udat.h"
29
#include "unicode/uloc.h"
35
/* --- Prototypes ---------------------------- */
38
u_sprintf_simple_percent_handler(u_localized_string *output,
39
const u_sprintf_spec_info *info,
40
const ufmt_args *args);
43
u_sprintf_string_handler(u_localized_string *output,
44
const u_sprintf_spec_info *info,
45
const ufmt_args *args);
48
u_sprintf_date_handler(u_localized_string *output,
49
const u_sprintf_spec_info *info,
50
const ufmt_args *args);
53
u_sprintf_scientific_handler(u_localized_string *output,
54
const u_sprintf_spec_info *info,
55
const ufmt_args *args);
58
u_sprintf_scidbl_handler(u_localized_string *output,
59
const u_sprintf_spec_info *info,
60
const ufmt_args *args);
63
u_sprintf_uchar_handler(u_localized_string *output,
64
const u_sprintf_spec_info *info,
65
const ufmt_args *args);
68
u_sprintf_currency_handler(u_localized_string *output,
69
const u_sprintf_spec_info *info,
70
const ufmt_args *args);
73
u_sprintf_ustring_handler(u_localized_string *output,
74
const u_sprintf_spec_info *info,
75
const ufmt_args *args);
78
u_sprintf_percent_handler(u_localized_string *output,
79
const u_sprintf_spec_info *info,
80
const ufmt_args *args);
83
u_sprintf_time_handler(u_localized_string *output,
84
const u_sprintf_spec_info *info,
85
const ufmt_args *args);
88
u_sprintf_spellout_handler(u_localized_string *output,
89
const u_sprintf_spec_info *info,
90
const ufmt_args *args);
93
u_sprintf_hex_handler(u_localized_string *output,
94
const u_sprintf_spec_info *info,
95
const ufmt_args *args);
98
u_sprintf_char_handler(u_localized_string *output,
99
const u_sprintf_spec_info *info,
100
const ufmt_args *args);
103
u_sprintf_integer_handler(u_localized_string *output,
104
const u_sprintf_spec_info *info,
105
const ufmt_args *args);
108
u_sprintf_uinteger_handler(u_localized_string *output,
109
const u_sprintf_spec_info *info,
110
const ufmt_args *args);
113
u_sprintf_double_handler(u_localized_string *output,
114
const u_sprintf_spec_info *info,
115
const ufmt_args *args);
118
u_sprintf_count_handler(u_localized_string *output,
119
const u_sprintf_spec_info *info,
120
const ufmt_args *args);
123
u_sprintf_octal_handler(u_localized_string *output,
124
const u_sprintf_spec_info *info,
125
const ufmt_args *args);
128
u_sprintf_pointer_handler(u_localized_string *output,
129
const u_sprintf_spec_info *info,
130
const ufmt_args *args);
132
/* ANSI style formatting */
133
/* Use US-ASCII characters only for formatting */
136
#define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_sprintf_simple_percent_handler}
138
#define UFMT_STRING {ufmt_string, u_sprintf_string_handler}
140
#define UFMT_CHAR {ufmt_char, u_sprintf_char_handler}
142
#define UFMT_INT {ufmt_int, u_sprintf_integer_handler}
144
#define UFMT_UINT {ufmt_int, u_sprintf_uinteger_handler}
146
#define UFMT_OCTAL {ufmt_int, u_sprintf_octal_handler}
148
#define UFMT_HEX {ufmt_int, u_sprintf_hex_handler}
150
#define UFMT_DOUBLE {ufmt_double, u_sprintf_double_handler}
152
#define UFMT_SCIENTIFIC {ufmt_double, u_sprintf_scientific_handler}
154
#define UFMT_SCIDBL {ufmt_double, u_sprintf_scidbl_handler}
156
#define UFMT_COUNT {ufmt_count, u_sprintf_count_handler}
158
/* non-ANSI extensions */
159
/* Use US-ASCII characters only for formatting */
162
#define UFMT_POINTER {ufmt_pointer, u_sprintf_pointer_handler}
164
#define UFMT_DATE {ufmt_date, u_sprintf_date_handler}
166
#define UFMT_TIME {ufmt_date, u_sprintf_time_handler}
168
#define UFMT_SPELLOUT {ufmt_double, u_sprintf_spellout_handler}
170
#define UFMT_PERCENT {ufmt_double, u_sprintf_percent_handler}
172
#define UFMT_CURRENCY {ufmt_double, u_sprintf_currency_handler}
174
#define UFMT_UCHAR {ufmt_uchar, u_sprintf_uchar_handler}
176
#define UFMT_USTRING {ufmt_ustring, u_sprintf_ustring_handler}
179
#define UFMT_EMPTY {ufmt_empty, NULL}
181
struct u_sprintf_info {
182
enum ufmt_type_info info;
183
u_sprintf_handler handler;
185
typedef struct u_sprintf_info u_sprintf_info;
187
/* Use US-ASCII characters only for formatting. Most codepages have
188
characters 20-7F from Unicode. Using any other codepage specific
189
characters will make it very difficult to format the string on
190
non-Unicode machines */
191
static const u_sprintf_info g_u_sprintf_infos[108] = {
193
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
194
UFMT_EMPTY, UFMT_SIMPLE_PERCENT,UFMT_EMPTY, UFMT_EMPTY,
195
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
196
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,
201
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
202
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
205
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
206
UFMT_DATE, UFMT_SCIENTIFIC, UFMT_EMPTY, UFMT_SCIDBL,
207
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR,
208
UFMT_EMPTY, UFMT_CURRENCY, UFMT_EMPTY, UFMT_EMPTY,
211
UFMT_PERCENT, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
212
UFMT_TIME, UFMT_USTRING, UFMT_SPELLOUT, UFMT_EMPTY,
213
UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
214
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
217
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_CHAR,
218
UFMT_INT, UFMT_SCIENTIFIC, UFMT_DOUBLE, UFMT_SCIDBL,
219
UFMT_EMPTY, UFMT_INT, UFMT_EMPTY, UFMT_EMPTY,
220
UFMT_EMPTY, UFMT_EMPTY, UFMT_COUNT, UFMT_OCTAL,
223
UFMT_POINTER, UFMT_EMPTY, UFMT_EMPTY, UFMT_STRING,
224
UFMT_EMPTY, UFMT_UINT, UFMT_EMPTY, UFMT_EMPTY,
225
UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
226
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
229
#define USPRINTF_NUM_FMT_HANDLERS sizeof(g_u_sprintf_infos)
231
/* We do not use handlers for 0-0x1f */
232
#define USPRINTF_BASE_FMT_HANDLERS 0x20
234
/* buffer size for formatting */
235
#define USPRINTF_BUFFER_SIZE 1024
236
#define USPRINTF_SYMBOL_BUFFER_SIZE 8
238
static UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
239
static UChar gSpaceStr[] = {0x20, 0}; /* " " */
241
U_CAPI int32_t U_EXPORT2
242
u_sprintf(UChar *buffer,
244
const char *patternSpecification,
250
va_start(ap, patternSpecification);
251
written = u_vsnprintf(buffer, INT32_MAX, locale, patternSpecification, ap);
257
U_CAPI int32_t U_EXPORT2
258
u_sprintf_u(UChar *buffer,
260
const UChar *patternSpecification,
266
va_start(ap, patternSpecification);
267
written = u_vsnprintf_u(buffer, INT32_MAX, locale, patternSpecification, ap);
273
U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
274
u_vsprintf(UChar *buffer,
276
const char *patternSpecification,
279
return u_vsnprintf(buffer, INT32_MAX, locale, patternSpecification, ap);
282
U_CAPI int32_t U_EXPORT2
283
u_snprintf(UChar *buffer,
286
const char *patternSpecification,
292
va_start(ap, patternSpecification);
293
written = u_vsnprintf(buffer, count, locale, patternSpecification, ap);
299
U_CAPI int32_t U_EXPORT2
300
u_snprintf_u(UChar *buffer,
303
const UChar *patternSpecification,
309
va_start(ap, patternSpecification);
310
written = u_vsnprintf_u(buffer, count, locale, patternSpecification, ap);
316
U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
317
u_vsnprintf(UChar *buffer,
320
const char *patternSpecification,
326
/* convert from the default codepage to Unicode */
327
pattern = ufmt_defaultCPToUnicode(patternSpecification,
328
strlen(patternSpecification));
334
written = u_vsnprintf_u(buffer, count, locale, pattern, ap);
342
U_CAPI int32_t U_EXPORT2
343
u_vsprintf_u(UChar *buffer,
345
const UChar *patternSpecification,
348
return u_vsnprintf_u(buffer, INT32_MAX, locale, patternSpecification, ap);
353
u_strset(UChar *str, int32_t count, UChar c) {
355
for(idx = 0; idx < count; ++idx) {
361
/* copies the minimum number of code units of (count or output->available) */
363
u_minstrncpy(u_localized_string *output, const UChar *str, int32_t count) {
364
int32_t size = ufmt_min(count, output->available);
366
u_strncpy(output->str + (output->len - output->available), str, size);
367
output->available -= size;
372
u_sprintf_pad_and_justify(u_localized_string *output,
373
const u_sprintf_spec_info *info,
379
resultLen = ufmt_min(resultLen, output->available);
381
/* pad and justify, if needed */
382
if(info->fWidth != -1 && resultLen < info->fWidth) {
383
int32_t paddingLeft = info->fWidth - resultLen;
384
int32_t outputPos = output->len - output->available;
386
if (paddingLeft + resultLen > output->available) {
387
paddingLeft = output->available - resultLen;
388
if (paddingLeft < 0) {
391
/* paddingLeft = output->available - resultLen;*/
393
written += paddingLeft;
397
written += u_minstrncpy(output, result, resultLen);
398
u_strset(&output->str[outputPos + resultLen], paddingLeft, info->fPadChar);
399
output->available -= paddingLeft;
403
u_strset(&output->str[outputPos], paddingLeft, info->fPadChar);
404
output->available -= paddingLeft;
405
written += u_minstrncpy(output, result, resultLen);
408
/* just write the formatted output */
410
written = u_minstrncpy(output, result, resultLen);
416
/* Sets the sign of a format based on u_sprintf_spec_info */
417
/* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */
419
u_sprintf_set_sign(UNumberFormat *format,
420
const u_sprintf_spec_info *info,
423
if(info->fShowSign) {
425
/* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */
426
/* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */
427
unum_setTextAttribute(format, UNUM_POSITIVE_PREFIX, gSpaceStr, 1, status);
430
UChar plusSymbol[USPRINTF_SYMBOL_BUFFER_SIZE];
433
symbolLen = unum_getSymbol(format,
434
UNUM_PLUS_SIGN_SYMBOL,
436
sizeof(plusSymbol)/sizeof(*plusSymbol),
438
unum_setTextAttribute(format,
439
UNUM_POSITIVE_PREFIX,
450
u_sprintf_simple_percent_handler(u_localized_string *output,
451
const u_sprintf_spec_info *info,
452
const ufmt_args *args)
454
/* put a single '%' on the stream */
455
if (output->available >= 1) {
456
output->str[output->len - output->available--] = 0x0025;
457
/* we wrote one character */
466
u_sprintf_string_handler(u_localized_string *output,
467
const u_sprintf_spec_info *info,
468
const ufmt_args *args)
471
int32_t len, written;
472
const char *arg = (const char*)(args[0].ptrValue);
474
/* convert from the default codepage to Unicode */
476
s = ufmt_defaultCPToUnicode(arg, strlen(arg));
485
/* width = minimum # of characters to write */
486
/* precision = maximum # of characters to write */
488
/* precision takes precedence over width */
489
/* determine if the string should be truncated */
490
if(info->fPrecision != -1 && len > info->fPrecision) {
491
written = u_minstrncpy(output, s, info->fPrecision);
493
/* determine if the string should be padded */
495
written = u_sprintf_pad_and_justify(output, info, s, len);
508
u_sprintf_integer_handler(u_localized_string *output,
509
const u_sprintf_spec_info *info,
510
const ufmt_args *args)
512
long num = (long) (args[0].intValue);
513
UNumberFormat *format;
514
UChar result [USPRINTF_BUFFER_SIZE];
515
int32_t minDigits = -1;
516
UErrorCode status = U_ZERO_ERROR;
519
/* mask off any necessary bits */
522
else if(! info->fIsLong || ! info->fIsLongLong)
525
/* get the formatter */
526
format = u_locbund_getNumberFormat(output->fBundle);
532
/* set the appropriate flags on the formatter */
534
/* set the minimum integer digits */
535
if(info->fPrecision != -1) {
536
/* clone the stream's bundle if it isn't owned */
537
if(! output->fOwnBundle) {
538
output->fBundle = u_locbund_clone(output->fBundle);
539
output->fOwnBundle = TRUE;
540
format = u_locbund_getNumberFormat(output->fBundle);
543
/* set the minimum # of digits */
544
minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
545
unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
548
/* set whether to show the sign */
549
if(info->fShowSign) {
550
/* clone the stream's bundle if it isn't owned */
551
if(! output->fOwnBundle) {
552
output->fBundle = u_locbund_clone(output->fBundle);
553
output->fOwnBundle = TRUE;
554
format = u_locbund_getNumberFormat(output->fBundle);
557
u_sprintf_set_sign(format, info, &status);
560
/* format the number */
561
unum_format(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
563
/* restore the number format */
564
if(minDigits != -1) {
565
unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
568
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
572
u_sprintf_hex_handler(u_localized_string *output,
573
const u_sprintf_spec_info *info,
574
const ufmt_args *args)
576
long num = (long) (args[0].intValue);
577
UChar result [USPRINTF_BUFFER_SIZE];
578
int32_t len = USPRINTF_BUFFER_SIZE;
581
/* mask off any necessary bits */
584
else if(! info->fIsLong || ! info->fIsLongLong)
587
/* format the number, preserving the minimum # of digits */
588
ufmt_ltou(result, &len, num, 16,
589
(UBool)(info->fSpec == 0x0078),
590
(info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);
592
/* convert to alt form, if desired */
593
if(num != 0 && info->fAlt && len < USPRINTF_BUFFER_SIZE - 2) {
594
/* shift the formatted string right by 2 chars */
595
memmove(result + 2, result, len * sizeof(UChar));
597
result[1] = info->fSpec;
601
return u_sprintf_pad_and_justify(output, info, result, len);
605
u_sprintf_octal_handler(u_localized_string *output,
606
const u_sprintf_spec_info *info,
607
const ufmt_args *args)
609
long num = (long) (args[0].intValue);
610
UChar result [USPRINTF_BUFFER_SIZE];
611
int32_t len = USPRINTF_BUFFER_SIZE;
614
/* mask off any necessary bits */
617
else if(! info->fIsLong || ! info->fIsLongLong)
620
/* format the number, preserving the minimum # of digits */
621
ufmt_ltou(result, &len, num, 8,
622
FALSE, /* doesn't matter for octal */
623
info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);
625
/* convert to alt form, if desired */
626
if(info->fAlt && result[0] != 0x0030 && len < USPRINTF_BUFFER_SIZE - 1) {
627
/* shift the formatted string right by 1 char */
628
memmove(result + 1, result, len * sizeof(UChar));
633
return u_sprintf_pad_and_justify(output, info, result, len);
638
u_sprintf_uinteger_handler(u_localized_string *output,
639
const u_sprintf_spec_info *info,
640
const ufmt_args *args)
642
u_sprintf_spec_info uint_info;
645
memcpy(&uint_info, info, sizeof(u_sprintf_spec_info));
646
memcpy(&uint_args, args, sizeof(ufmt_args));
648
uint_info.fPrecision = 0;
649
uint_info.fAlt = FALSE;
651
/* Get around int32_t limitations */
652
uint_args.doubleValue = ((double) ((uint32_t) (uint_args.intValue)));
654
return u_sprintf_double_handler(output, &uint_info, &uint_args);
658
u_sprintf_double_handler(u_localized_string *output,
659
const u_sprintf_spec_info *info,
660
const ufmt_args *args)
662
double num = (double) (args[0].doubleValue);
663
UNumberFormat *format;
664
UChar result [USPRINTF_BUFFER_SIZE];
665
int32_t minDecimalDigits;
666
int32_t maxDecimalDigits;
667
UErrorCode status = U_ZERO_ERROR;
669
/* mask off any necessary bits */
670
/* if(! info->fIsLongDouble)
673
/* get the formatter */
674
format = u_locbund_getNumberFormat(output->fBundle);
680
/* set the appropriate flags on the formatter */
682
/* clone the stream's bundle if it isn't owned */
683
if(! output->fOwnBundle) {
684
output->fBundle = u_locbund_clone(output->fBundle);
685
output->fOwnBundle = TRUE;
686
format = u_locbund_getNumberFormat(output->fBundle);
689
/* set the number of decimal digits */
691
/* save the formatter's state */
692
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
693
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
695
if(info->fPrecision != -1) {
696
/* set the # of decimal digits */
697
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
699
else if(info->fPrecision == 0 && ! info->fAlt) {
700
/* no decimal point in this case */
701
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
703
else if(info->fAlt) {
704
/* '#' means always show decimal point */
705
/* copy of printf behavior on Solaris - '#' shows 6 digits */
706
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
709
/* # of decimal digits is 6 if precision not specified regardless of locale */
710
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
713
/* set whether to show the sign */
714
u_sprintf_set_sign(format, info, &status);
716
/* format the number */
717
unum_formatDouble(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
719
/* restore the number format */
720
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
721
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
723
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
728
u_sprintf_char_handler(u_localized_string *output,
729
const u_sprintf_spec_info *info,
730
const ufmt_args *args)
733
int32_t len, written;
734
unsigned char arg = (unsigned char)(args[0].intValue);
736
/* convert from default codepage to Unicode */
737
s = ufmt_defaultCPToUnicode((const char *)&arg, 1);
742
/* Remember that this may be a surrogate pair */
745
/* width = minimum # of characters to write */
746
/* precision = maximum # of characters to write */
748
/* precision takes precedence over width */
749
/* determine if the string should be truncated */
750
if(info->fPrecision != -1 && len > info->fPrecision) {
751
written = u_minstrncpy(output, s, info->fPrecision);
754
/* determine if the string should be padded */
755
written = u_sprintf_pad_and_justify(output, info, s, len);
766
u_sprintf_pointer_handler(u_localized_string *output,
767
const u_sprintf_spec_info *info,
768
const ufmt_args *args)
770
long num = (long) (args[0].intValue);
771
UChar result [USPRINTF_BUFFER_SIZE];
772
int32_t len = USPRINTF_BUFFER_SIZE;
775
/* format the pointer in hex */
776
ufmt_ltou(result, &len, num, 16, TRUE, info->fPrecision);
778
return u_sprintf_pad_and_justify(output, info, result, len);
782
u_sprintf_scientific_handler(u_localized_string *output,
783
const u_sprintf_spec_info *info,
784
const ufmt_args *args)
786
double num = (double) (args[0].doubleValue);
787
UNumberFormat *format;
788
UChar result [USPRINTF_BUFFER_SIZE];
789
int32_t minDecimalDigits;
790
int32_t maxDecimalDigits;
791
UErrorCode status = U_ZERO_ERROR;
792
UChar srcExpBuf[USPRINTF_SYMBOL_BUFFER_SIZE];
793
int32_t srcLen, expLen;
794
UChar expBuf[USPRINTF_SYMBOL_BUFFER_SIZE];
797
/* mask off any necessary bits */
798
/* if(! info->fIsLongDouble)
801
/* get the formatter */
802
format = u_locbund_getScientificFormat(output->fBundle);
808
/* set the appropriate flags on the formatter */
810
/* clone the stream's bundle if it isn't owned */
811
if(! output->fOwnBundle) {
812
output->fBundle = u_locbund_clone(output->fBundle);
813
output->fOwnBundle = TRUE;
814
format = u_locbund_getScientificFormat(output->fBundle);
817
srcLen = unum_getSymbol(format,
818
UNUM_EXPONENTIAL_SYMBOL,
823
/* Upper/lower case the e */
824
if (info->fSpec == (UChar)0x65 /* e */) {
825
expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
827
output->fBundle->fLocale,
831
expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
833
output->fBundle->fLocale,
837
unum_setSymbol(format,
838
UNUM_EXPONENTIAL_SYMBOL,
843
/* set the number of decimal digits */
845
/* save the formatter's state */
846
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
847
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
849
if(info->fPrecision != -1) {
850
/* set the # of decimal digits */
851
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
853
else if(info->fPrecision == 0 && ! info->fAlt) {
854
/* no decimal point in this case */
855
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
857
else if(info->fAlt) {
858
/* '#' means always show decimal point */
859
/* copy of printf behavior on Solaris - '#' shows 6 digits */
860
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
863
/* # of decimal digits is 6 if precision not specified */
864
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
867
/* set whether to show the sign */
868
u_sprintf_set_sign(format, info, &status);
870
/* format the number */
871
unum_formatDouble(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
873
/* restore the number format */
874
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
875
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
877
unum_setSymbol(format,
878
UNUM_EXPONENTIAL_SYMBOL,
883
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
887
u_sprintf_date_handler(u_localized_string *output,
888
const u_sprintf_spec_info *info,
889
const ufmt_args *args)
891
UDate num = (UDate) (args[0].dateValue);
893
UChar result [USPRINTF_BUFFER_SIZE];
894
UErrorCode status = U_ZERO_ERROR;
897
/* get the formatter */
898
format = u_locbund_getDateFormat(output->fBundle);
904
/* format the date */
905
udat_format(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
907
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
911
u_sprintf_time_handler(u_localized_string *output,
912
const u_sprintf_spec_info *info,
913
const ufmt_args *args)
915
UDate num = (UDate) (args[0].dateValue);
917
UChar result [USPRINTF_BUFFER_SIZE];
918
UErrorCode status = U_ZERO_ERROR;
921
/* get the formatter */
922
format = u_locbund_getTimeFormat(output->fBundle);
928
/* format the time */
929
udat_format(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
931
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
936
u_sprintf_percent_handler(u_localized_string *output,
937
const u_sprintf_spec_info *info,
938
const ufmt_args *args)
940
double num = (double) (args[0].doubleValue);
941
UNumberFormat *format;
942
UChar result [USPRINTF_BUFFER_SIZE];
943
int32_t minDecimalDigits;
944
int32_t maxDecimalDigits;
945
UErrorCode status = U_ZERO_ERROR;
948
/* mask off any necessary bits */
949
/* if(! info->fIsLongDouble)
952
/* get the formatter */
953
format = u_locbund_getPercentFormat(output->fBundle);
959
/* set the appropriate flags on the formatter */
961
/* clone the stream's bundle if it isn't owned */
962
if(! output->fOwnBundle) {
963
output->fBundle = u_locbund_clone(output->fBundle);
964
output->fOwnBundle = TRUE;
965
format = u_locbund_getPercentFormat(output->fBundle);
968
/* set the number of decimal digits */
970
/* save the formatter's state */
971
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
972
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
974
if(info->fPrecision != -1) {
975
/* set the # of decimal digits */
976
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
978
else if(info->fPrecision == 0 && ! info->fAlt) {
979
/* no decimal point in this case */
980
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
982
else if(info->fAlt) {
983
/* '#' means always show decimal point */
984
/* copy of printf behavior on Solaris - '#' shows 6 digits */
985
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
988
/* # of decimal digits is 6 if precision not specified */
989
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
992
/* set whether to show the sign */
993
u_sprintf_set_sign(format, info, &status);
995
/* format the number */
996
unum_formatDouble(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
998
/* restore the number format */
999
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
1000
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
1002
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
1007
u_sprintf_currency_handler(u_localized_string *output,
1008
const u_sprintf_spec_info *info,
1009
const ufmt_args *args)
1011
double num = (double) (args[0].doubleValue);
1012
UNumberFormat *format;
1013
UChar result [USPRINTF_BUFFER_SIZE];
1014
int32_t minDecimalDigits;
1015
int32_t maxDecimalDigits;
1016
UErrorCode status = U_ZERO_ERROR;
1019
/* mask off any necessary bits */
1020
/* if(! info->fIsLongDouble)
1023
/* get the formatter */
1024
format = u_locbund_getCurrencyFormat(output->fBundle);
1030
/* set the appropriate flags on the formatter */
1032
/* clone the stream's bundle if it isn't owned */
1033
if(! output->fOwnBundle) {
1034
output->fBundle = u_locbund_clone(output->fBundle);
1035
output->fOwnBundle = TRUE;
1036
format = u_locbund_getCurrencyFormat(output->fBundle);
1039
/* set the number of decimal digits */
1041
/* save the formatter's state */
1042
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
1043
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
1045
if(info->fPrecision != -1) {
1046
/* set the # of decimal digits */
1047
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
1049
else if(info->fPrecision == 0 && ! info->fAlt) {
1050
/* no decimal point in this case */
1051
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
1053
else if(info->fAlt) {
1054
/* '#' means always show decimal point */
1055
/* copy of printf behavior on Solaris - '#' shows 6 digits */
1056
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
1059
/* # of decimal digits is 6 if precision not specified */
1060
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
1063
/* set whether to show the sign */
1064
u_sprintf_set_sign(format, info, &status);
1066
/* format the number */
1067
unum_formatDouble(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
1069
/* restore the number format */
1070
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
1071
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
1073
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
1077
u_sprintf_ustring_handler(u_localized_string *output,
1078
const u_sprintf_spec_info *info,
1079
const ufmt_args *args)
1081
int32_t len, written;
1082
const UChar *arg = (const UChar*)(args[0].ptrValue);
1084
/* allocate enough space for the buffer */
1088
len = u_strlen(arg);
1090
/* width = minimum # of characters to write */
1091
/* precision = maximum # of characters to write */
1093
/* precision takes precedence over width */
1094
/* determine if the string should be truncated */
1095
if(info->fPrecision != -1 && len > info->fPrecision) {
1096
written = u_minstrncpy(output, arg, info->fPrecision);
1099
/* determine if the string should be padded */
1100
written = u_sprintf_pad_and_justify(output, info, arg, len);
1109
u_sprintf_uchar_handler(u_localized_string *output,
1110
const u_sprintf_spec_info *info,
1111
const ufmt_args *args)
1113
int32_t written = 0;
1114
UChar arg = (UChar)(args[0].intValue);
1117
/* width = minimum # of characters to write */
1118
/* precision = maximum # of characters to write */
1120
/* precision takes precedence over width */
1121
/* determine if the char should be printed */
1122
if(info->fPrecision != -1 && info->fPrecision < 1) {
1127
/* determine if the string should be padded */
1128
written = u_sprintf_pad_and_justify(output, info, &arg, 1);
1135
u_sprintf_scidbl_handler(u_localized_string *output,
1136
const u_sprintf_spec_info *info,
1137
const ufmt_args *args)
1139
u_sprintf_spec_info scidbl_info;
1140
double num = args[0].doubleValue;
1142
memcpy(&scidbl_info, info, sizeof(u_sprintf_spec_info));
1144
/* determine whether to use 'd', 'e' or 'f' notation */
1145
if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num))
1147
/* use 'f' notation */
1148
scidbl_info.fSpec = 0x0066;
1149
scidbl_info.fPrecision = 0;
1150
/* call the double handler */
1151
return u_sprintf_double_handler(output, &scidbl_info, args);
1153
else if(num < 0.0001
1154
|| (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision)))
1156
/* use 'e' or 'E' notation */
1157
scidbl_info.fSpec = scidbl_info.fSpec - 1;
1158
/* call the scientific handler */
1159
return u_sprintf_scientific_handler(output, &scidbl_info, args);
1162
/* use 'f' notation */
1163
scidbl_info.fSpec = 0x0066;
1164
/* call the double handler */
1165
return u_sprintf_double_handler(output, &scidbl_info, args);
1171
u_sprintf_count_handler(u_localized_string *output,
1172
const u_sprintf_spec_info *info,
1173
const ufmt_args *args)
1175
int *count = (int*)(args[0].ptrValue);
1177
/* in the special case of count, the u_printf_spec_info's width */
1178
/* will contain the # of chars written thus far */
1179
*count = info->fWidth;
1186
u_sprintf_spellout_handler(u_localized_string *output,
1187
const u_sprintf_spec_info *info,
1188
const ufmt_args *args)
1190
double num = (double) (args[0].doubleValue);
1191
UNumberFormat *format;
1192
UChar result [USPRINTF_BUFFER_SIZE];
1193
int32_t minDecimalDigits;
1194
int32_t maxDecimalDigits;
1195
UErrorCode status = U_ZERO_ERROR;
1198
/* mask off any necessary bits */
1199
/* if(! info->fIsLongDouble)
1202
/* get the formatter */
1203
format = u_locbund_getSpelloutFormat(output->fBundle);
1209
/* set the appropriate flags on the formatter */
1211
/* clone the stream's bundle if it isn't owned */
1212
if(! output->fOwnBundle) {
1213
output->fBundle = u_locbund_clone(output->fBundle);
1214
output->fOwnBundle = TRUE;
1215
format = u_locbund_getSpelloutFormat(output->fBundle);
1218
/* set the number of decimal digits */
1220
/* save the formatter's state */
1221
minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
1222
maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
1224
if(info->fPrecision != -1) {
1225
/* set the # of decimal digits */
1226
unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
1228
else if(info->fPrecision == 0 && ! info->fAlt) {
1229
/* no decimal point in this case */
1230
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
1232
else if(info->fAlt) {
1233
/* '#' means always show decimal point */
1234
/* copy of printf behavior on Solaris - '#' shows 6 digits */
1235
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
1238
/* # of decimal digits is 6 if precision not specified */
1239
unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
1242
/* set whether to show the sign */
1243
u_sprintf_set_sign(format, info, &status);
1245
/* format the number */
1246
unum_formatDouble(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status);
1248
/* restore the number format */
1249
unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
1250
unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
1252
return u_sprintf_pad_and_justify(output, info, result, u_strlen(result));
1255
#define UP_PERCENT 0x0025
1257
U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
1258
u_vsnprintf_u(UChar *buffer,
1261
const UChar *patternSpecification,
1264
const UChar *alias = patternSpecification;
1265
const UChar *lastAlias;
1267
int32_t written = 0;
1268
uint16_t handlerNum;
1271
u_localized_string outStr;
1272
u_sprintf_spec spec;
1273
ufmt_type_info info;
1274
u_sprintf_handler handler;
1280
outStr.str = buffer;
1282
outStr.available = count;
1284
/* if locale is 0, use the default */
1286
locale = uloc_getDefault();
1288
outStr.fBundle = u_loccache_get(locale);
1290
if(outStr.fBundle == 0) {
1293
outStr.fOwnBundle = FALSE;
1295
/* iterate through the pattern */
1296
while(outStr.available > 0) {
1298
/* find the next '%' */
1300
while(*alias != UP_PERCENT && *alias != 0x0000) {
1304
/* write any characters before the '%' */
1305
if(alias > lastAlias) {
1306
written += u_minstrncpy(&outStr, lastAlias, (int32_t)(alias - lastAlias));
1309
/* break if at end of string */
1310
if(*alias == 0x0000) {
1314
/* parse the specifier */
1315
patCount = u_sprintf_parse_spec(alias, &spec);
1317
/* fill in the precision and width, if specified out of line */
1319
/* width specified out of line */
1320
if(spec.fInfo.fWidth == -2) {
1321
if(spec.fWidthPos == -1) {
1322
/* read the width from the argument list */
1323
spec.fInfo.fWidth = va_arg(ap, int);
1326
/* handle positional parameter */
1329
/* if it's negative, take the absolute value and set left alignment */
1330
if(spec.fInfo.fWidth < 0) {
1331
spec.fInfo.fWidth *= -1;
1332
spec.fInfo.fLeft = TRUE;
1336
/* precision specified out of line */
1337
if(spec.fInfo.fPrecision == -2) {
1338
if(spec.fPrecisionPos == -1) {
1339
/* read the precision from the argument list */
1340
spec.fInfo.fPrecision = va_arg(ap, int);
1343
/* handle positional parameter */
1346
/* if it's negative, set it to zero */
1347
if(spec.fInfo.fPrecision < 0)
1348
spec.fInfo.fPrecision = 0;
1351
handlerNum = (uint16_t)(spec.fInfo.fSpec - USPRINTF_BASE_FMT_HANDLERS);
1352
if (handlerNum < USPRINTF_NUM_FMT_HANDLERS) {
1353
/* query the info function for argument information */
1354
info = g_u_sprintf_infos[ handlerNum ].info;
1355
if(info > ufmt_simple_percent) {
1358
/* set the spec's width to the # of chars written */
1359
spec.fInfo.fWidth = written;
1363
args.intValue = va_arg(ap, int);
1366
args.wcharValue = va_arg(ap, wchar_t);
1369
args.ptrValue = va_arg(ap, char*);
1372
args.ptrValue = va_arg(ap, wchar_t*);
1375
args.ptrValue = va_arg(ap, UChar*);
1378
args.ptrValue = va_arg(ap, void*);
1381
args.floatValue = (float) va_arg(ap, double);
1384
args.doubleValue = va_arg(ap, double);
1387
args.dateValue = va_arg(ap, UDate);
1390
break; /* Should never get here */
1394
/* call the handler function */
1395
handler = g_u_sprintf_infos[ handlerNum ].handler;
1397
written += (*handler)(&outStr, &spec.fInfo, &args);
1400
/* just echo unknown tags */
1401
written += u_minstrncpy(&outStr, lastAlias, (int32_t)(alias - lastAlias));
1405
/* just echo unknown tags */
1406
written += u_minstrncpy(&outStr, lastAlias, (int32_t)(alias - lastAlias));
1409
/* update the pointer in pattern and continue */
1413
/* Terminate the buffer, if there's room. */
1414
if (outStr.available > 0) {
1415
buffer[outStr.len - outStr.available] = 0x0000;
1418
/* Release the cloned bundle, if we cloned it. */
1419
if(outStr.fOwnBundle) {
1420
u_locbund_delete(outStr.fBundle);
1421
outStr.fBundle = NULL;
1422
outStr.fOwnBundle = FALSE;
1425
/* return # of UChars written */