2 ******************************************************************************
4 * Copyright (C) 1998-2004, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 ******************************************************************************
11 * Modification History:
13 * Date Name Description
14 * 11/23/98 stephen Creation.
15 * 03/12/99 stephen Modified for new C API.
16 * 08/07/2003 george Reunify printf implementations
17 ******************************************************************************
20 #include "unicode/utypes.h"
22 #if !UCONFIG_NO_FORMATTING
24 #include "unicode/ustring.h"
31 /* ANSI style formatting */
32 /* Use US-ASCII characters only for formatting */
35 #define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_printf_simple_percent_handler}
37 #define UFMT_STRING {ufmt_string, u_printf_string_handler}
39 #define UFMT_CHAR {ufmt_char, u_printf_char_handler}
41 #define UFMT_INT {ufmt_int, u_printf_integer_handler}
43 #define UFMT_UINT {ufmt_int, u_printf_uinteger_handler}
45 #define UFMT_OCTAL {ufmt_int, u_printf_octal_handler}
47 #define UFMT_HEX {ufmt_int, u_printf_hex_handler}
49 #define UFMT_DOUBLE {ufmt_double, u_printf_double_handler}
51 #define UFMT_SCIENTIFIC {ufmt_double, u_printf_scientific_handler}
53 #define UFMT_SCIDBL {ufmt_double, u_printf_scidbl_handler}
55 #define UFMT_COUNT {ufmt_count, u_printf_count_handler}
57 /* non-ANSI extensions */
58 /* Use US-ASCII characters only for formatting */
61 #define UFMT_POINTER {ufmt_pointer, u_printf_pointer_handler}
63 #define UFMT_SPELLOUT {ufmt_double, u_printf_spellout_handler}
65 #define UFMT_PERCENT {ufmt_double, u_printf_percent_handler}
66 /* C K is old format */
67 #define UFMT_UCHAR {ufmt_uchar, u_printf_uchar_handler}
68 /* S U is old format */
69 #define UFMT_USTRING {ufmt_ustring, u_printf_ustring_handler}
72 #define UFMT_EMPTY {ufmt_empty, NULL}
75 * A u_printf handler function.
76 * A u_printf handler is responsible for handling a single u_printf
77 * format specification, for example 'd' or 's'.
78 * @param stream The UFILE to which to write output.
79 * @param info A pointer to a <TT>u_printf_spec_info</TT> struct containing
80 * information on the format specification.
81 * @param args A pointer to the argument data
82 * @return The number of Unicode characters written to <TT>stream</TT>.
84 typedef int32_t U_EXPORT2
85 u_printf_handler(const u_printf_stream_handler
*handler
,
88 ULocaleBundle
*formatBundle
,
89 const u_printf_spec_info
*info
,
90 const ufmt_args
*args
);
92 typedef struct u_printf_info
{
94 u_printf_handler
*handler
;
98 * Struct encapsulating a single uprintf format specification.
100 typedef struct u_printf_spec
{
101 u_printf_spec_info fInfo
; /* Information on this spec */
102 int32_t fWidthPos
; /* Position of width in arg list */
103 int32_t fPrecisionPos
; /* Position of precision in arg list */
104 int32_t fArgPos
; /* Position of data in arg list */
107 #define UPRINTF_NUM_FMT_HANDLERS 108
109 /* We do not use handlers for 0-0x1f */
110 #define UPRINTF_BASE_FMT_HANDLERS 0x20
112 /* buffer size for formatting */
113 #define UPRINTF_BUFFER_SIZE 1024
114 #define UPRINTF_SYMBOL_BUFFER_SIZE 8
116 static const UChar gNullStr
[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
117 static const UChar gSpaceStr
[] = {0x20, 0}; /* " " */
119 /* Sets the sign of a format based on u_printf_spec_info */
120 /* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */
122 u_printf_set_sign(UNumberFormat
*format
,
123 const u_printf_spec_info
*info
,
125 int32_t *prefixBufLen
,
128 if(info
->fShowSign
) {
129 *prefixBufLen
= unum_getTextAttribute(format
,
130 UNUM_POSITIVE_PREFIX
,
135 /* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */
136 /* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */
137 unum_setTextAttribute(format
, UNUM_POSITIVE_PREFIX
, gSpaceStr
, 1, status
);
140 UChar plusSymbol
[UPRINTF_SYMBOL_BUFFER_SIZE
];
143 symbolLen
= unum_getSymbol(format
,
144 UNUM_PLUS_SIGN_SYMBOL
,
146 sizeof(plusSymbol
)/sizeof(*plusSymbol
),
148 unum_setTextAttribute(format
,
149 UNUM_POSITIVE_PREFIX
,
161 u_printf_reset_sign(UNumberFormat
*format
,
162 const u_printf_spec_info
*info
,
164 int32_t *prefixBufLen
,
167 if(info
->fShowSign
) {
168 unum_setTextAttribute(format
,
169 UNUM_POSITIVE_PREFIX
,
179 u_printf_simple_percent_handler(const u_printf_stream_handler
*handler
,
181 ULocaleBundle
*formatBundle
,
182 const u_printf_spec_info
*info
,
183 const ufmt_args
*args
)
185 static const UChar PERCENT
[] = { UP_PERCENT
};
187 /* put a single '%' onto the output */
188 return handler
->write(context
, PERCENT
, 1);
193 u_printf_string_handler(const u_printf_stream_handler
*handler
,
195 ULocaleBundle
*formatBundle
,
196 const u_printf_spec_info
*info
,
197 const ufmt_args
*args
)
200 UChar buffer
[UFMT_DEFAULT_BUFFER_SIZE
];
201 int32_t len
, written
;
203 const char *arg
= (const char*)(args
[0].ptrValue
);
205 /* convert from the default codepage to Unicode */
207 argSize
= (int32_t)strlen(arg
) + 1;
208 if (argSize
>= MAX_UCHAR_BUFFER_SIZE(buffer
)) {
209 s
= ufmt_defaultCPToUnicode(arg
, argSize
,
210 (UChar
*)uprv_malloc(MAX_UCHAR_BUFFER_NEEDED(argSize
)),
211 MAX_UCHAR_BUFFER_NEEDED(argSize
));
217 s
= ufmt_defaultCPToUnicode(arg
, argSize
, buffer
,
218 sizeof(buffer
)/sizeof(UChar
));
222 s
= (UChar
*)gNullStr
;
226 /* width = minimum # of characters to write */
227 /* precision = maximum # of characters to write */
229 /* precision takes precedence over width */
230 /* determine if the string should be truncated */
231 if(info
->fPrecision
!= -1 && len
> info
->fPrecision
) {
232 written
= handler
->write(context
, s
, info
->fPrecision
);
234 /* determine if the string should be padded */
236 written
= handler
->pad_and_justify(context
, info
, s
, len
);
240 if (gNullStr
!= s
&& buffer
!= s
) {
248 u_printf_char_handler(const u_printf_stream_handler
*handler
,
250 ULocaleBundle
*formatBundle
,
251 const u_printf_spec_info
*info
,
252 const ufmt_args
*args
)
254 UChar s
[UTF_MAX_CHAR_LENGTH
+1];
255 int32_t len
= 1, written
;
256 unsigned char arg
= (unsigned char)(args
[0].int64Value
);
258 /* convert from default codepage to Unicode */
259 ufmt_defaultCPToUnicode((const char *)&arg
, 2, s
, sizeof(s
)/sizeof(UChar
));
261 /* Remember that this may be an MBCS character */
266 /* width = minimum # of characters to write */
267 /* precision = maximum # of characters to write */
269 /* precision takes precedence over width */
270 /* determine if the string should be truncated */
271 if(info
->fPrecision
!= -1 && len
> info
->fPrecision
) {
272 written
= handler
->write(context
, s
, info
->fPrecision
);
275 /* determine if the string should be padded */
276 written
= handler
->pad_and_justify(context
, info
, s
, len
);
283 u_printf_double_handler(const u_printf_stream_handler
*handler
,
285 ULocaleBundle
*formatBundle
,
286 const u_printf_spec_info
*info
,
287 const ufmt_args
*args
)
289 double num
= (double) (args
[0].doubleValue
);
290 UNumberFormat
*format
;
291 UChar result
[UPRINTF_BUFFER_SIZE
];
292 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
293 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
294 int32_t minDecimalDigits
;
295 int32_t maxDecimalDigits
;
297 UErrorCode status
= U_ZERO_ERROR
;
301 /* mask off any necessary bits */
302 /* if(! info->fIsLongDouble)
305 /* get the formatter */
306 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_DECIMAL
);
312 /* save the formatter's state */
313 minDecimalDigits
= unum_getAttribute(format
, UNUM_MIN_FRACTION_DIGITS
);
314 maxDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_FRACTION_DIGITS
);
316 /* set the appropriate flags and number of decimal digits on the formatter */
317 if(info
->fPrecision
!= -1) {
318 /* set the # of decimal digits */
319 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, info
->fPrecision
);
321 else if(info
->fAlt
) {
322 /* '#' means always show decimal point */
323 /* copy of printf behavior on Solaris - '#' shows 6 digits */
324 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
327 /* # of decimal digits is 6 if precision not specified regardless of locale */
328 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
331 /* set whether to show the sign */
332 if (info
->fShowSign
) {
333 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
336 /* format the number */
337 resultLen
= unum_formatDouble(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
339 if (U_FAILURE(status
)) {
343 /* restore the number format */
344 /* TODO: Is this needed? */
345 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, minDecimalDigits
);
346 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, maxDecimalDigits
);
348 if (info
->fShowSign
) {
349 /* Reset back to original value regardless of what the error was */
350 UErrorCode localStatus
= U_ZERO_ERROR
;
351 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
354 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
359 u_printf_integer_handler(const u_printf_stream_handler
*handler
,
361 ULocaleBundle
*formatBundle
,
362 const u_printf_spec_info
*info
,
363 const ufmt_args
*args
)
365 int64_t num
= args
[0].int64Value
;
366 UNumberFormat
*format
;
367 UChar result
[UPRINTF_BUFFER_SIZE
];
368 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
369 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
370 int32_t minDigits
= -1;
372 UErrorCode status
= U_ZERO_ERROR
;
376 /* mask off any necessary bits */
379 else if (!info
->fIsLongLong
)
382 /* get the formatter */
383 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_DECIMAL
);
389 /* set the appropriate flags on the formatter */
391 /* set the minimum integer digits */
392 if(info
->fPrecision
!= -1) {
393 /* set the minimum # of digits */
394 minDigits
= unum_getAttribute(format
, UNUM_MIN_INTEGER_DIGITS
);
395 unum_setAttribute(format
, UNUM_MIN_INTEGER_DIGITS
, info
->fPrecision
);
398 /* set whether to show the sign */
399 if(info
->fShowSign
) {
400 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
403 /* format the number */
404 resultLen
= unum_formatInt64(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
406 if (U_FAILURE(status
)) {
410 /* restore the number format */
411 if (minDigits
!= -1) {
412 unum_setAttribute(format
, UNUM_MIN_INTEGER_DIGITS
, minDigits
);
415 if (info
->fShowSign
) {
416 /* Reset back to original value regardless of what the error was */
417 UErrorCode localStatus
= U_ZERO_ERROR
;
418 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
421 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
425 u_printf_hex_handler(const u_printf_stream_handler
*handler
,
427 ULocaleBundle
*formatBundle
,
428 const u_printf_spec_info
*info
,
429 const ufmt_args
*args
)
431 int64_t num
= args
[0].int64Value
;
432 UChar result
[UPRINTF_BUFFER_SIZE
];
433 int32_t len
= UPRINTF_BUFFER_SIZE
;
436 /* mask off any necessary bits */
439 else if (!info
->fIsLongLong
)
442 /* format the number, preserving the minimum # of digits */
443 ufmt_64tou(result
, &len
, num
, 16,
444 (UBool
)(info
->fSpec
== 0x0078),
445 (info
->fPrecision
== -1 && info
->fZero
) ? info
->fWidth
: info
->fPrecision
);
447 /* convert to alt form, if desired */
448 if(num
!= 0 && info
->fAlt
&& len
< UPRINTF_BUFFER_SIZE
- 2) {
449 /* shift the formatted string right by 2 chars */
450 memmove(result
+ 2, result
, len
* sizeof(UChar
));
452 result
[1] = info
->fSpec
;
456 return handler
->pad_and_justify(context
, info
, result
, len
);
460 u_printf_octal_handler(const u_printf_stream_handler
*handler
,
462 ULocaleBundle
*formatBundle
,
463 const u_printf_spec_info
*info
,
464 const ufmt_args
*args
)
466 int64_t num
= args
[0].int64Value
;
467 UChar result
[UPRINTF_BUFFER_SIZE
];
468 int32_t len
= UPRINTF_BUFFER_SIZE
;
471 /* mask off any necessary bits */
474 else if (!info
->fIsLongLong
)
477 /* format the number, preserving the minimum # of digits */
478 ufmt_64tou(result
, &len
, num
, 8,
479 FALSE
, /* doesn't matter for octal */
480 info
->fPrecision
== -1 && info
->fZero
? info
->fWidth
: info
->fPrecision
);
482 /* convert to alt form, if desired */
483 if(info
->fAlt
&& result
[0] != 0x0030 && len
< UPRINTF_BUFFER_SIZE
- 1) {
484 /* shift the formatted string right by 1 char */
485 memmove(result
+ 1, result
, len
* sizeof(UChar
));
490 return handler
->pad_and_justify(context
, info
, result
, len
);
494 u_printf_uinteger_handler(const u_printf_stream_handler
*handler
,
496 ULocaleBundle
*formatBundle
,
497 const u_printf_spec_info
*info
,
498 const ufmt_args
*args
)
500 int64_t num
= args
[0].int64Value
;
501 UNumberFormat
*format
;
502 UChar result
[UPRINTF_BUFFER_SIZE
];
503 int32_t minDigits
= -1;
505 UErrorCode status
= U_ZERO_ERROR
;
507 /* TODO: Fix this once uint64_t can be formatted. */
510 else if (!info
->fIsLongLong
)
513 /* get the formatter */
514 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_DECIMAL
);
520 /* set the appropriate flags on the formatter */
522 /* set the minimum integer digits */
523 if(info
->fPrecision
!= -1) {
524 /* set the minimum # of digits */
525 minDigits
= unum_getAttribute(format
, UNUM_MIN_INTEGER_DIGITS
);
526 unum_setAttribute(format
, UNUM_MIN_INTEGER_DIGITS
, info
->fPrecision
);
529 /* To mirror other stdio implementations, we ignore the sign argument */
531 /* format the number */
532 resultLen
= unum_formatInt64(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
534 if (U_FAILURE(status
)) {
538 /* restore the number format */
539 if (minDigits
!= -1) {
540 unum_setAttribute(format
, UNUM_MIN_INTEGER_DIGITS
, minDigits
);
543 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
547 u_printf_pointer_handler(const u_printf_stream_handler
*handler
,
549 ULocaleBundle
*formatBundle
,
550 const u_printf_spec_info
*info
,
551 const ufmt_args
*args
)
553 UChar result
[UPRINTF_BUFFER_SIZE
];
554 int32_t len
= UPRINTF_BUFFER_SIZE
;
556 /* format the pointer in hex */
557 ufmt_ptou(result
, &len
, args
[0].ptrValue
, TRUE
/*, info->fPrecision*/);
559 return handler
->pad_and_justify(context
, info
, result
, len
);
563 u_printf_scientific_handler(const u_printf_stream_handler
*handler
,
565 ULocaleBundle
*formatBundle
,
566 const u_printf_spec_info
*info
,
567 const ufmt_args
*args
)
569 double num
= (double) (args
[0].doubleValue
);
570 UNumberFormat
*format
;
571 UChar result
[UPRINTF_BUFFER_SIZE
];
572 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
573 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
574 int32_t minDecimalDigits
;
575 int32_t maxDecimalDigits
;
576 UErrorCode status
= U_ZERO_ERROR
;
577 UChar srcExpBuf
[UPRINTF_SYMBOL_BUFFER_SIZE
];
578 int32_t srcLen
, expLen
;
580 UChar expBuf
[UPRINTF_SYMBOL_BUFFER_SIZE
];
584 /* mask off any necessary bits */
585 /* if(! info->fIsLongDouble)
588 /* get the formatter */
589 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_SCIENTIFIC
);
595 /* set the appropriate flags on the formatter */
597 srcLen
= unum_getSymbol(format
,
598 UNUM_EXPONENTIAL_SYMBOL
,
603 /* Upper/lower case the e */
604 if (info
->fSpec
== (UChar
)0x65 /* e */) {
605 expLen
= u_strToLower(expBuf
, (int32_t)sizeof(expBuf
),
607 formatBundle
->fLocale
,
611 expLen
= u_strToUpper(expBuf
, (int32_t)sizeof(expBuf
),
613 formatBundle
->fLocale
,
617 unum_setSymbol(format
,
618 UNUM_EXPONENTIAL_SYMBOL
,
623 /* save the formatter's state */
624 minDecimalDigits
= unum_getAttribute(format
, UNUM_MIN_FRACTION_DIGITS
);
625 maxDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_FRACTION_DIGITS
);
627 /* set the appropriate flags and number of decimal digits on the formatter */
628 if(info
->fPrecision
!= -1) {
629 /* set the # of decimal digits */
630 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, info
->fPrecision
);
632 else if(info
->fAlt
) {
633 /* '#' means always show decimal point */
634 /* copy of printf behavior on Solaris - '#' shows 6 digits */
635 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
638 /* # of decimal digits is 6 if precision not specified */
639 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
642 /* set whether to show the sign */
643 if (info
->fShowSign
) {
644 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
647 /* format the number */
648 resultLen
= unum_formatDouble(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
650 if (U_FAILURE(status
)) {
654 /* restore the number format */
655 /* TODO: Is this needed? */
656 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, minDecimalDigits
);
657 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, maxDecimalDigits
);
659 /* Since we're the only one using the scientific
660 format, we don't need to save the old exponent value. */
661 /*unum_setSymbol(format,
662 UNUM_EXPONENTIAL_SYMBOL,
667 if (info
->fShowSign
) {
668 /* Reset back to original value regardless of what the error was */
669 UErrorCode localStatus
= U_ZERO_ERROR
;
670 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
673 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
677 u_printf_percent_handler(const u_printf_stream_handler
*handler
,
679 ULocaleBundle
*formatBundle
,
680 const u_printf_spec_info
*info
,
681 const ufmt_args
*args
)
683 double num
= (double) (args
[0].doubleValue
);
684 UNumberFormat
*format
;
685 UChar result
[UPRINTF_BUFFER_SIZE
];
686 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
687 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
688 int32_t minDecimalDigits
;
689 int32_t maxDecimalDigits
;
691 UErrorCode status
= U_ZERO_ERROR
;
695 /* mask off any necessary bits */
696 /* if(! info->fIsLongDouble)
699 /* get the formatter */
700 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_PERCENT
);
706 /* save the formatter's state */
707 minDecimalDigits
= unum_getAttribute(format
, UNUM_MIN_FRACTION_DIGITS
);
708 maxDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_FRACTION_DIGITS
);
710 /* set the appropriate flags and number of decimal digits on the formatter */
711 if(info
->fPrecision
!= -1) {
712 /* set the # of decimal digits */
713 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, info
->fPrecision
);
715 else if(info
->fAlt
) {
716 /* '#' means always show decimal point */
717 /* copy of printf behavior on Solaris - '#' shows 6 digits */
718 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
721 /* # of decimal digits is 6 if precision not specified */
722 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
725 /* set whether to show the sign */
726 if (info
->fShowSign
) {
727 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
730 /* format the number */
731 resultLen
= unum_formatDouble(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
733 if (U_FAILURE(status
)) {
737 /* restore the number format */
738 /* TODO: Is this needed? */
739 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, minDecimalDigits
);
740 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, maxDecimalDigits
);
742 if (info
->fShowSign
) {
743 /* Reset back to original value regardless of what the error was */
744 UErrorCode localStatus
= U_ZERO_ERROR
;
745 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
748 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
752 u_printf_ustring_handler(const u_printf_stream_handler
*handler
,
754 ULocaleBundle
*formatBundle
,
755 const u_printf_spec_info
*info
,
756 const ufmt_args
*args
)
758 int32_t len
, written
;
759 const UChar
*arg
= (const UChar
*)(args
[0].ptrValue
);
761 /* allocate enough space for the buffer */
767 /* width = minimum # of characters to write */
768 /* precision = maximum # of characters to write */
770 /* precision takes precedence over width */
771 /* determine if the string should be truncated */
772 if(info
->fPrecision
!= -1 && len
> info
->fPrecision
) {
773 written
= handler
->write(context
, arg
, info
->fPrecision
);
776 /* determine if the string should be padded */
777 written
= handler
->pad_and_justify(context
, info
, arg
, len
);
784 u_printf_uchar_handler(const u_printf_stream_handler
*handler
,
786 ULocaleBundle
*formatBundle
,
787 const u_printf_spec_info
*info
,
788 const ufmt_args
*args
)
791 UChar arg
= (UChar
)(args
[0].int64Value
);
794 /* width = minimum # of characters to write */
795 /* precision = maximum # of characters to write */
797 /* precision takes precedence over width */
798 /* determine if the char should be printed */
799 if(info
->fPrecision
!= -1 && info
->fPrecision
< 1) {
804 /* determine if the string should be padded */
805 written
= handler
->pad_and_justify(context
, info
, &arg
, 1);
812 u_printf_scidbl_handler(const u_printf_stream_handler
*handler
,
814 ULocaleBundle
*formatBundle
,
815 const u_printf_spec_info
*info
,
816 const ufmt_args
*args
)
818 u_printf_spec_info scidbl_info
;
819 double num
= args
[0].doubleValue
;
822 memcpy(&scidbl_info
, info
, sizeof(u_printf_spec_info
));
824 /* determine whether to use 'd', 'e' or 'f' notation */
825 if (scidbl_info
.fPrecision
== -1 && num
== uprv_trunc(num
))
827 /* use 'f' notation */
828 scidbl_info
.fSpec
= 0x0066;
829 scidbl_info
.fPrecision
= 0;
830 /* call the double handler */
831 retVal
= u_printf_double_handler(handler
, context
, formatBundle
, &scidbl_info
, args
);
833 else if(num
< 0.0001 || (scidbl_info
.fPrecision
< 1 && 1000000.0 <= num
)
834 || (scidbl_info
.fPrecision
!= -1 && num
> uprv_pow10(scidbl_info
.fPrecision
)))
836 /* use 'e' or 'E' notation */
837 scidbl_info
.fSpec
= scidbl_info
.fSpec
- 2;
838 if (scidbl_info
.fPrecision
== -1) {
839 scidbl_info
.fPrecision
= 5;
841 /* call the scientific handler */
842 retVal
= u_printf_scientific_handler(handler
, context
, formatBundle
, &scidbl_info
, args
);
845 UNumberFormat
*format
= u_locbund_getNumberFormat(formatBundle
, UNUM_DECIMAL
);
846 int32_t maxSigDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_SIGNIFICANT_DIGITS
);
847 int32_t significantDigits
= scidbl_info
.fPrecision
;
849 /* use 'f' notation */
850 scidbl_info
.fSpec
= 0x0066;
851 if (significantDigits
== -1) {
852 significantDigits
= 6;
854 unum_setAttribute(format
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
855 unum_setAttribute(format
, UNUM_MAX_SIGNIFICANT_DIGITS
, significantDigits
);
856 /* call the double handler */
857 retVal
= u_printf_double_handler(handler
, context
, formatBundle
, &scidbl_info
, args
);
858 unum_setAttribute(format
, UNUM_MAX_SIGNIFICANT_DIGITS
, maxSigDecimalDigits
);
859 unum_setAttribute(format
, UNUM_SIGNIFICANT_DIGITS_USED
, FALSE
);
865 u_printf_count_handler(const u_printf_stream_handler
*handler
,
867 ULocaleBundle
*formatBundle
,
868 const u_printf_spec_info
*info
,
869 const ufmt_args
*args
)
871 int32_t *count
= (int32_t*)(args
[0].ptrValue
);
873 /* in the special case of count, the u_printf_spec_info's width */
874 /* will contain the # of chars written thus far */
875 *count
= info
->fWidth
;
881 u_printf_spellout_handler(const u_printf_stream_handler
*handler
,
883 ULocaleBundle
*formatBundle
,
884 const u_printf_spec_info
*info
,
885 const ufmt_args
*args
)
887 double num
= (double) (args
[0].doubleValue
);
888 UNumberFormat
*format
;
889 UChar result
[UPRINTF_BUFFER_SIZE
];
890 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
891 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
892 int32_t minDecimalDigits
;
893 int32_t maxDecimalDigits
;
895 UErrorCode status
= U_ZERO_ERROR
;
899 /* mask off any necessary bits */
900 /* if(! info->fIsLongDouble)
903 /* get the formatter */
904 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_SPELLOUT
);
910 /* save the formatter's state */
911 minDecimalDigits
= unum_getAttribute(format
, UNUM_MIN_FRACTION_DIGITS
);
912 maxDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_FRACTION_DIGITS
);
914 /* set the appropriate flags and number of decimal digits on the formatter */
915 if(info
->fPrecision
!= -1) {
916 /* set the # of decimal digits */
917 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, info
->fPrecision
);
919 else if(info
->fAlt
) {
920 /* '#' means always show decimal point */
921 /* copy of printf behavior on Solaris - '#' shows 6 digits */
922 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
925 /* # of decimal digits is 6 if precision not specified */
926 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
929 /* set whether to show the sign */
930 if (info
->fShowSign
) {
931 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
934 /* format the number */
935 resultLen
= unum_formatDouble(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
937 if (U_FAILURE(status
)) {
941 /* restore the number format */
942 /* TODO: Is this needed? */
943 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, minDecimalDigits
);
944 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, maxDecimalDigits
);
946 if (info
->fShowSign
) {
947 /* Reset back to original value regardless of what the error was */
948 UErrorCode localStatus
= U_ZERO_ERROR
;
949 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
952 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
955 /* Use US-ASCII characters only for formatting. Most codepages have
956 characters 20-7F from Unicode. Using any other codepage specific
957 characters will make it very difficult to format the string on
958 non-Unicode machines */
959 static const u_printf_info g_u_printf_infos
[UPRINTF_NUM_FMT_HANDLERS
] = {
961 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
962 UFMT_EMPTY
, UFMT_SIMPLE_PERCENT
,UFMT_EMPTY
, UFMT_EMPTY
,
963 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
964 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
967 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
968 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
969 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
970 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
973 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_UCHAR
,
974 UFMT_EMPTY
, UFMT_SCIENTIFIC
, UFMT_EMPTY
, UFMT_SCIDBL
,
975 #ifdef U_USE_OBSOLETE_IO_FORMATTING
976 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_UCHAR
/*deprecated*/,
978 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
980 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
983 UFMT_PERCENT
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_USTRING
,
984 #ifdef U_USE_OBSOLETE_IO_FORMATTING
985 UFMT_EMPTY
, UFMT_USTRING
/*deprecated*/,UFMT_SPELLOUT
, UFMT_EMPTY
,
987 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_SPELLOUT
, UFMT_EMPTY
,
989 UFMT_HEX
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
990 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
993 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_CHAR
,
994 UFMT_INT
, UFMT_SCIENTIFIC
, UFMT_DOUBLE
, UFMT_SCIDBL
,
995 UFMT_EMPTY
, UFMT_INT
, UFMT_EMPTY
, UFMT_EMPTY
,
996 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_COUNT
, UFMT_OCTAL
,
999 UFMT_POINTER
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_STRING
,
1000 UFMT_EMPTY
, UFMT_UINT
, UFMT_EMPTY
, UFMT_EMPTY
,
1001 UFMT_HEX
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1002 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1005 /* flag characters for uprintf */
1006 #define FLAG_MINUS 0x002D
1007 #define FLAG_PLUS 0x002B
1008 #define FLAG_SPACE 0x0020
1009 #define FLAG_POUND 0x0023
1010 #define FLAG_ZERO 0x0030
1011 #define FLAG_PAREN 0x0028
1013 #define ISFLAG(s) (s) == FLAG_MINUS || \
1014 (s) == FLAG_PLUS || \
1015 (s) == FLAG_SPACE || \
1016 (s) == FLAG_POUND || \
1017 (s) == FLAG_ZERO || \
1020 /* special characters for uprintf */
1021 #define SPEC_ASTERISK 0x002A
1022 #define SPEC_DOLLARSIGN 0x0024
1023 #define SPEC_PERIOD 0x002E
1024 #define SPEC_PERCENT 0x0025
1026 /* unicode digits */
1027 #define DIGIT_ZERO 0x0030
1028 #define DIGIT_ONE 0x0031
1029 #define DIGIT_TWO 0x0032
1030 #define DIGIT_THREE 0x0033
1031 #define DIGIT_FOUR 0x0034
1032 #define DIGIT_FIVE 0x0035
1033 #define DIGIT_SIX 0x0036
1034 #define DIGIT_SEVEN 0x0037
1035 #define DIGIT_EIGHT 0x0038
1036 #define DIGIT_NINE 0x0039
1038 #define ISDIGIT(s) (s) == DIGIT_ZERO || \
1039 (s) == DIGIT_ONE || \
1040 (s) == DIGIT_TWO || \
1041 (s) == DIGIT_THREE || \
1042 (s) == DIGIT_FOUR || \
1043 (s) == DIGIT_FIVE || \
1044 (s) == DIGIT_SIX || \
1045 (s) == DIGIT_SEVEN || \
1046 (s) == DIGIT_EIGHT || \
1049 /* u_printf modifiers */
1050 #define MOD_H 0x0068
1051 #define MOD_LOWERL 0x006C
1052 #define MOD_L 0x004C
1054 #define ISMOD(s) (s) == MOD_H || \
1055 (s) == MOD_LOWERL || \
1058 /* We parse the argument list in Unicode */
1060 u_printf_parse(const u_printf_stream_handler
*streamHandler
,
1063 u_localized_print_string
*locStringContext
,
1064 ULocaleBundle
*formatBundle
,
1068 uint16_t handlerNum
;
1070 ufmt_type_info argType
;
1071 u_printf_handler
*handler
;
1073 u_printf_spec_info
*info
= &(spec
.fInfo
);
1075 const UChar
*alias
= fmt
;
1076 const UChar
*backup
;
1077 const UChar
*lastAlias
;
1079 /* iterate through the pattern */
1080 while(!locStringContext
|| locStringContext
->available
> 0) {
1082 /* find the next '%' */
1084 while(*alias
!= UP_PERCENT
&& *alias
!= 0x0000) {
1088 /* write any characters before the '%' */
1089 if(alias
> lastAlias
) {
1090 *written
+= (streamHandler
->write
)(context
, lastAlias
, (int32_t)(alias
- lastAlias
));
1093 /* break if at end of string */
1094 if(*alias
== 0x0000) {
1098 /* initialize spec to default values */
1099 spec
.fWidthPos
= -1;
1100 spec
.fPrecisionPos
= -1;
1103 info
->fPrecision
= -1;
1105 info
->fSpec
= 0x0000;
1106 info
->fPadChar
= 0x0020;
1108 info
->fSpace
= FALSE
;
1109 info
->fLeft
= FALSE
;
1110 info
->fShowSign
= FALSE
;
1111 info
->fZero
= FALSE
;
1112 info
->fIsLongDouble
= FALSE
;
1113 info
->fIsShort
= FALSE
;
1114 info
->fIsLong
= FALSE
;
1115 info
->fIsLongLong
= FALSE
;
1117 /* skip over the initial '%' */
1120 /* Check for positional argument */
1121 if(ISDIGIT(*alias
)) {
1123 /* Save the current position */
1126 /* handle positional parameters */
1127 if(ISDIGIT(*alias
)) {
1128 spec
.fArgPos
= (int) (*alias
++ - DIGIT_ZERO
);
1130 while(ISDIGIT(*alias
)) {
1132 spec
.fArgPos
+= (int) (*alias
++ - DIGIT_ZERO
);
1136 /* if there is no '$', don't read anything */
1137 if(*alias
!= SPEC_DOLLARSIGN
) {
1146 /* Get any format flags */
1147 while(ISFLAG(*alias
)) {
1155 /* always show sign */
1157 info
->fShowSign
= TRUE
;
1160 /* use space if no sign present */
1162 info
->fShowSign
= TRUE
;
1163 info
->fSpace
= TRUE
;
1166 /* use alternate form */
1171 /* pad with leading zeroes */
1174 info
->fPadChar
= 0x0030;
1177 /* pad character specified */
1180 /* TODO test that all four are numbers */
1181 /* first four characters are hex values for pad char */
1182 info
->fPadChar
= (UChar
)ufmt_digitvalue(*alias
++);
1183 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*alias
++));
1184 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*alias
++));
1185 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*alias
++));
1187 /* final character is ignored */
1196 /* width is specified out of line */
1197 if(*alias
== SPEC_ASTERISK
) {
1204 /* Save the current position */
1207 /* handle positional parameters */
1208 if(ISDIGIT(*alias
)) {
1209 spec
.fWidthPos
= (int) (*alias
++ - DIGIT_ZERO
);
1211 while(ISDIGIT(*alias
)) {
1212 spec
.fWidthPos
*= 10;
1213 spec
.fWidthPos
+= (int) (*alias
++ - DIGIT_ZERO
);
1217 /* if there is no '$', don't read anything */
1218 if(*alias
!= SPEC_DOLLARSIGN
) {
1219 spec
.fWidthPos
= -1;
1226 /* read the width, if present */
1227 else if(ISDIGIT(*alias
)){
1228 info
->fWidth
= (int) (*alias
++ - DIGIT_ZERO
);
1230 while(ISDIGIT(*alias
)) {
1232 info
->fWidth
+= (int) (*alias
++ - DIGIT_ZERO
);
1236 /* Get the precision */
1238 if(*alias
== SPEC_PERIOD
) {
1240 /* eat up the '.' */
1243 /* precision is specified out of line */
1244 if(*alias
== SPEC_ASTERISK
) {
1246 info
->fPrecision
= -2;
1251 /* save the current position */
1254 /* handle positional parameters */
1255 if(ISDIGIT(*alias
)) {
1256 spec
.fPrecisionPos
= (int) (*alias
++ - DIGIT_ZERO
);
1258 while(ISDIGIT(*alias
)) {
1259 spec
.fPrecisionPos
*= 10;
1260 spec
.fPrecisionPos
+= (int) (*alias
++ - DIGIT_ZERO
);
1263 /* if there is no '$', don't read anything */
1264 if(*alias
!= SPEC_DOLLARSIGN
) {
1265 spec
.fPrecisionPos
= -1;
1274 /* read the precision */
1275 else if(ISDIGIT(*alias
)){
1276 info
->fPrecision
= (int) (*alias
++ - DIGIT_ZERO
);
1278 while(ISDIGIT(*alias
)) {
1279 info
->fPrecision
*= 10;
1280 info
->fPrecision
+= (int) (*alias
++ - DIGIT_ZERO
);
1285 /* Get any modifiers */
1291 info
->fIsShort
= TRUE
;
1294 /* long or long long */
1296 if(*alias
== MOD_LOWERL
) {
1297 info
->fIsLongLong
= TRUE
;
1298 /* skip over the next 'l' */
1302 info
->fIsLong
= TRUE
;
1307 info
->fIsLongDouble
= TRUE
;
1312 /* finally, get the specifier letter */
1313 info
->fSpec
= *alias
++;
1315 /* fill in the precision and width, if specified out of line */
1317 /* width specified out of line */
1318 if(spec
.fInfo
.fWidth
== -2) {
1319 if(spec
.fWidthPos
== -1) {
1320 /* read the width from the argument list */
1321 info
->fWidth
= va_arg(ap
, int32_t);
1324 /* handle positional parameter */
1327 /* if it's negative, take the absolute value and set left alignment */
1328 if(info
->fWidth
< 0) {
1334 /* precision specified out of line */
1335 if(info
->fPrecision
== -2) {
1336 if(spec
.fPrecisionPos
== -1) {
1337 /* read the precision from the argument list */
1338 info
->fPrecision
= va_arg(ap
, int32_t);
1341 /* handle positional parameter */
1344 /* if it's negative, set it to zero */
1345 if(info
->fPrecision
< 0)
1346 info
->fPrecision
= 0;
1349 handlerNum
= (uint16_t)(info
->fSpec
- UPRINTF_BASE_FMT_HANDLERS
);
1350 if (handlerNum
< UPRINTF_NUM_FMT_HANDLERS
) {
1351 /* query the info function for argument information */
1352 argType
= g_u_printf_infos
[ handlerNum
].info
;
1355 /* set the spec's width to the # of chars written */
1356 info
->fWidth
= *written
;
1357 /* fall through to set the pointer */
1361 args
.ptrValue
= va_arg(ap
, void*);
1366 if (info
->fIsLongLong
) {
1367 args
.int64Value
= va_arg(ap
, int64_t);
1370 args
.int64Value
= va_arg(ap
, int32_t);
1374 args
.floatValue
= (float) va_arg(ap
, double);
1377 args
.doubleValue
= va_arg(ap
, double);
1380 /* else args is ignored */
1381 args
.ptrValue
= NULL
;
1385 /* call the handler function */
1386 handler
= g_u_printf_infos
[ handlerNum
].handler
;
1388 *written
+= (*handler
)(streamHandler
, context
, formatBundle
, info
, &args
);
1391 /* just echo unknown tags */
1392 *written
+= (streamHandler
->write
)(context
, fmt
, (int32_t)(alias
- lastAlias
));
1396 /* just echo unknown tags */
1397 *written
+= (streamHandler
->write
)(context
, fmt
, (int32_t)(alias
- lastAlias
));
1400 /* return # of characters in this format that have been parsed. */
1401 return (int32_t)(alias
- fmt
);
1404 #endif /* #if !UCONFIG_NO_FORMATTING */