2 ******************************************************************************
4 * Copyright (C) 1998-2006, 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 */
228 if (info
->fPrecision
!= -1 && info
->fPrecision
< len
) {
229 len
= info
->fPrecision
;
232 written
= handler
->pad_and_justify(context
, info
, s
, len
);
235 if (gNullStr
!= s
&& buffer
!= s
) {
243 u_printf_char_handler(const u_printf_stream_handler
*handler
,
245 ULocaleBundle
*formatBundle
,
246 const u_printf_spec_info
*info
,
247 const ufmt_args
*args
)
249 UChar s
[UTF_MAX_CHAR_LENGTH
+1];
250 int32_t len
= 1, written
;
251 unsigned char arg
= (unsigned char)(args
[0].int64Value
);
253 /* convert from default codepage to Unicode */
254 ufmt_defaultCPToUnicode((const char *)&arg
, 2, s
, sizeof(s
)/sizeof(UChar
));
256 /* Remember that this may be an MBCS character */
261 /* width = minimum # of characters to write */
262 /* precision = maximum # of characters to write */
263 /* precision is ignored when handling a char */
265 written
= handler
->pad_and_justify(context
, info
, s
, len
);
271 u_printf_double_handler(const u_printf_stream_handler
*handler
,
273 ULocaleBundle
*formatBundle
,
274 const u_printf_spec_info
*info
,
275 const ufmt_args
*args
)
277 double num
= (double) (args
[0].doubleValue
);
278 UNumberFormat
*format
;
279 UChar result
[UPRINTF_BUFFER_SIZE
];
280 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
281 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
282 int32_t minDecimalDigits
;
283 int32_t maxDecimalDigits
;
285 UErrorCode status
= U_ZERO_ERROR
;
289 /* mask off any necessary bits */
290 /* if(! info->fIsLongDouble)
293 /* get the formatter */
294 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_DECIMAL
);
300 /* save the formatter's state */
301 minDecimalDigits
= unum_getAttribute(format
, UNUM_MIN_FRACTION_DIGITS
);
302 maxDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_FRACTION_DIGITS
);
304 /* set the appropriate flags and number of decimal digits on the formatter */
305 if(info
->fPrecision
!= -1) {
306 /* set the # of decimal digits */
307 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, info
->fPrecision
);
309 else if(info
->fAlt
) {
310 /* '#' means always show decimal point */
311 /* copy of printf behavior on Solaris - '#' shows 6 digits */
312 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
315 /* # of decimal digits is 6 if precision not specified regardless of locale */
316 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
319 /* set whether to show the sign */
320 if (info
->fShowSign
) {
321 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
324 /* format the number */
325 resultLen
= unum_formatDouble(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
327 if (U_FAILURE(status
)) {
331 /* restore the number format */
332 /* TODO: Is this needed? */
333 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, minDecimalDigits
);
334 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, maxDecimalDigits
);
336 if (info
->fShowSign
) {
337 /* Reset back to original value regardless of what the error was */
338 UErrorCode localStatus
= U_ZERO_ERROR
;
339 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
342 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
347 u_printf_integer_handler(const u_printf_stream_handler
*handler
,
349 ULocaleBundle
*formatBundle
,
350 const u_printf_spec_info
*info
,
351 const ufmt_args
*args
)
353 int64_t num
= args
[0].int64Value
;
354 UNumberFormat
*format
;
355 UChar result
[UPRINTF_BUFFER_SIZE
];
356 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
357 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
358 int32_t minDigits
= -1;
360 UErrorCode status
= U_ZERO_ERROR
;
364 /* mask off any necessary bits */
367 else if (!info
->fIsLongLong
)
370 /* get the formatter */
371 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_DECIMAL
);
377 /* set the appropriate flags on the formatter */
379 /* set the minimum integer digits */
380 if(info
->fPrecision
!= -1) {
381 /* set the minimum # of digits */
382 minDigits
= unum_getAttribute(format
, UNUM_MIN_INTEGER_DIGITS
);
383 unum_setAttribute(format
, UNUM_MIN_INTEGER_DIGITS
, info
->fPrecision
);
386 /* set whether to show the sign */
387 if(info
->fShowSign
) {
388 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
391 /* format the number */
392 resultLen
= unum_formatInt64(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
394 if (U_FAILURE(status
)) {
398 /* restore the number format */
399 if (minDigits
!= -1) {
400 unum_setAttribute(format
, UNUM_MIN_INTEGER_DIGITS
, minDigits
);
403 if (info
->fShowSign
) {
404 /* Reset back to original value regardless of what the error was */
405 UErrorCode localStatus
= U_ZERO_ERROR
;
406 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
409 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
413 u_printf_hex_handler(const u_printf_stream_handler
*handler
,
415 ULocaleBundle
*formatBundle
,
416 const u_printf_spec_info
*info
,
417 const ufmt_args
*args
)
419 int64_t num
= args
[0].int64Value
;
420 UChar result
[UPRINTF_BUFFER_SIZE
];
421 int32_t len
= UPRINTF_BUFFER_SIZE
;
424 /* mask off any necessary bits */
427 else if (!info
->fIsLongLong
)
430 /* format the number, preserving the minimum # of digits */
431 ufmt_64tou(result
, &len
, num
, 16,
432 (UBool
)(info
->fSpec
== 0x0078),
433 (info
->fPrecision
== -1 && info
->fZero
) ? info
->fWidth
: info
->fPrecision
);
435 /* convert to alt form, if desired */
436 if(num
!= 0 && info
->fAlt
&& len
< UPRINTF_BUFFER_SIZE
- 2) {
437 /* shift the formatted string right by 2 chars */
438 memmove(result
+ 2, result
, len
* sizeof(UChar
));
440 result
[1] = info
->fSpec
;
444 return handler
->pad_and_justify(context
, info
, result
, len
);
448 u_printf_octal_handler(const u_printf_stream_handler
*handler
,
450 ULocaleBundle
*formatBundle
,
451 const u_printf_spec_info
*info
,
452 const ufmt_args
*args
)
454 int64_t num
= args
[0].int64Value
;
455 UChar result
[UPRINTF_BUFFER_SIZE
];
456 int32_t len
= UPRINTF_BUFFER_SIZE
;
459 /* mask off any necessary bits */
462 else if (!info
->fIsLongLong
)
465 /* format the number, preserving the minimum # of digits */
466 ufmt_64tou(result
, &len
, num
, 8,
467 FALSE
, /* doesn't matter for octal */
468 info
->fPrecision
== -1 && info
->fZero
? info
->fWidth
: info
->fPrecision
);
470 /* convert to alt form, if desired */
471 if(info
->fAlt
&& result
[0] != 0x0030 && len
< UPRINTF_BUFFER_SIZE
- 1) {
472 /* shift the formatted string right by 1 char */
473 memmove(result
+ 1, result
, len
* sizeof(UChar
));
478 return handler
->pad_and_justify(context
, info
, result
, len
);
482 u_printf_uinteger_handler(const u_printf_stream_handler
*handler
,
484 ULocaleBundle
*formatBundle
,
485 const u_printf_spec_info
*info
,
486 const ufmt_args
*args
)
488 int64_t num
= args
[0].int64Value
;
489 UNumberFormat
*format
;
490 UChar result
[UPRINTF_BUFFER_SIZE
];
491 int32_t minDigits
= -1;
493 UErrorCode status
= U_ZERO_ERROR
;
495 /* TODO: Fix this once uint64_t can be formatted. */
498 else if (!info
->fIsLongLong
)
501 /* get the formatter */
502 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_DECIMAL
);
508 /* set the appropriate flags on the formatter */
510 /* set the minimum integer digits */
511 if(info
->fPrecision
!= -1) {
512 /* set the minimum # of digits */
513 minDigits
= unum_getAttribute(format
, UNUM_MIN_INTEGER_DIGITS
);
514 unum_setAttribute(format
, UNUM_MIN_INTEGER_DIGITS
, info
->fPrecision
);
517 /* To mirror other stdio implementations, we ignore the sign argument */
519 /* format the number */
520 resultLen
= unum_formatInt64(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
522 if (U_FAILURE(status
)) {
526 /* restore the number format */
527 if (minDigits
!= -1) {
528 unum_setAttribute(format
, UNUM_MIN_INTEGER_DIGITS
, minDigits
);
531 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
535 u_printf_pointer_handler(const u_printf_stream_handler
*handler
,
537 ULocaleBundle
*formatBundle
,
538 const u_printf_spec_info
*info
,
539 const ufmt_args
*args
)
541 UChar result
[UPRINTF_BUFFER_SIZE
];
542 int32_t len
= UPRINTF_BUFFER_SIZE
;
544 /* format the pointer in hex */
545 ufmt_ptou(result
, &len
, args
[0].ptrValue
, TRUE
/*, info->fPrecision*/);
547 return handler
->pad_and_justify(context
, info
, result
, len
);
551 u_printf_scientific_handler(const u_printf_stream_handler
*handler
,
553 ULocaleBundle
*formatBundle
,
554 const u_printf_spec_info
*info
,
555 const ufmt_args
*args
)
557 double num
= (double) (args
[0].doubleValue
);
558 UNumberFormat
*format
;
559 UChar result
[UPRINTF_BUFFER_SIZE
];
560 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
561 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
562 int32_t minDecimalDigits
;
563 int32_t maxDecimalDigits
;
564 UErrorCode status
= U_ZERO_ERROR
;
565 UChar srcExpBuf
[UPRINTF_SYMBOL_BUFFER_SIZE
];
566 int32_t srcLen
, expLen
;
568 UChar expBuf
[UPRINTF_SYMBOL_BUFFER_SIZE
];
572 /* mask off any necessary bits */
573 /* if(! info->fIsLongDouble)
576 /* get the formatter */
577 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_SCIENTIFIC
);
583 /* set the appropriate flags on the formatter */
585 srcLen
= unum_getSymbol(format
,
586 UNUM_EXPONENTIAL_SYMBOL
,
591 /* Upper/lower case the e */
592 if (info
->fSpec
== (UChar
)0x65 /* e */) {
593 expLen
= u_strToLower(expBuf
, (int32_t)sizeof(expBuf
),
595 formatBundle
->fLocale
,
599 expLen
= u_strToUpper(expBuf
, (int32_t)sizeof(expBuf
),
601 formatBundle
->fLocale
,
605 unum_setSymbol(format
,
606 UNUM_EXPONENTIAL_SYMBOL
,
611 /* save the formatter's state */
612 minDecimalDigits
= unum_getAttribute(format
, UNUM_MIN_FRACTION_DIGITS
);
613 maxDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_FRACTION_DIGITS
);
615 /* set the appropriate flags and number of decimal digits on the formatter */
616 if(info
->fPrecision
!= -1) {
617 /* set the # of decimal digits */
618 if (info
->fOrigSpec
== (UChar
)0x65 /* e */ || info
->fOrigSpec
== (UChar
)0x45 /* E */) {
619 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, info
->fPrecision
);
622 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, 1);
623 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, info
->fPrecision
);
626 else if(info
->fAlt
) {
627 /* '#' means always show decimal point */
628 /* copy of printf behavior on Solaris - '#' shows 6 digits */
629 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
632 /* # of decimal digits is 6 if precision not specified */
633 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
636 /* set whether to show the sign */
637 if (info
->fShowSign
) {
638 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
641 /* format the number */
642 resultLen
= unum_formatDouble(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
644 if (U_FAILURE(status
)) {
648 /* restore the number format */
649 /* TODO: Is this needed? */
650 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, minDecimalDigits
);
651 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, maxDecimalDigits
);
653 /* Since we're the only one using the scientific
654 format, we don't need to save the old exponent value. */
655 /*unum_setSymbol(format,
656 UNUM_EXPONENTIAL_SYMBOL,
661 if (info
->fShowSign
) {
662 /* Reset back to original value regardless of what the error was */
663 UErrorCode localStatus
= U_ZERO_ERROR
;
664 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
667 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
671 u_printf_percent_handler(const u_printf_stream_handler
*handler
,
673 ULocaleBundle
*formatBundle
,
674 const u_printf_spec_info
*info
,
675 const ufmt_args
*args
)
677 double num
= (double) (args
[0].doubleValue
);
678 UNumberFormat
*format
;
679 UChar result
[UPRINTF_BUFFER_SIZE
];
680 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
681 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
682 int32_t minDecimalDigits
;
683 int32_t maxDecimalDigits
;
685 UErrorCode status
= U_ZERO_ERROR
;
689 /* mask off any necessary bits */
690 /* if(! info->fIsLongDouble)
693 /* get the formatter */
694 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_PERCENT
);
700 /* save the formatter's state */
701 minDecimalDigits
= unum_getAttribute(format
, UNUM_MIN_FRACTION_DIGITS
);
702 maxDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_FRACTION_DIGITS
);
704 /* set the appropriate flags and number of decimal digits on the formatter */
705 if(info
->fPrecision
!= -1) {
706 /* set the # of decimal digits */
707 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, info
->fPrecision
);
709 else if(info
->fAlt
) {
710 /* '#' means always show decimal point */
711 /* copy of printf behavior on Solaris - '#' shows 6 digits */
712 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
715 /* # of decimal digits is 6 if precision not specified */
716 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
719 /* set whether to show the sign */
720 if (info
->fShowSign
) {
721 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
724 /* format the number */
725 resultLen
= unum_formatDouble(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
727 if (U_FAILURE(status
)) {
731 /* restore the number format */
732 /* TODO: Is this needed? */
733 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, minDecimalDigits
);
734 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, maxDecimalDigits
);
736 if (info
->fShowSign
) {
737 /* Reset back to original value regardless of what the error was */
738 UErrorCode localStatus
= U_ZERO_ERROR
;
739 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
742 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
746 u_printf_ustring_handler(const u_printf_stream_handler
*handler
,
748 ULocaleBundle
*formatBundle
,
749 const u_printf_spec_info
*info
,
750 const ufmt_args
*args
)
752 int32_t len
, written
;
753 const UChar
*arg
= (const UChar
*)(args
[0].ptrValue
);
755 /* allocate enough space for the buffer */
761 /* width = minimum # of characters to write */
762 /* precision = maximum # of characters to write */
763 if (info
->fPrecision
!= -1 && info
->fPrecision
< len
) {
764 len
= info
->fPrecision
;
767 /* determine if the string should be padded */
768 written
= handler
->pad_and_justify(context
, info
, arg
, len
);
774 u_printf_uchar_handler(const u_printf_stream_handler
*handler
,
776 ULocaleBundle
*formatBundle
,
777 const u_printf_spec_info
*info
,
778 const ufmt_args
*args
)
781 UChar arg
= (UChar
)(args
[0].int64Value
);
783 /* width = minimum # of characters to write */
784 /* precision = maximum # of characters to write */
785 /* precision is ignored when handling a uchar */
787 /* determine if the string should be padded */
788 written
= handler
->pad_and_justify(context
, info
, &arg
, 1);
794 u_printf_scidbl_handler(const u_printf_stream_handler
*handler
,
796 ULocaleBundle
*formatBundle
,
797 const u_printf_spec_info
*info
,
798 const ufmt_args
*args
)
800 u_printf_spec_info scidbl_info
;
801 double num
= args
[0].doubleValue
;
804 memcpy(&scidbl_info
, info
, sizeof(u_printf_spec_info
));
806 /* determine whether to use 'd', 'e' or 'f' notation */
807 if (scidbl_info
.fPrecision
== -1 && num
== uprv_trunc(num
))
809 /* use 'f' notation */
810 scidbl_info
.fSpec
= 0x0066;
811 scidbl_info
.fPrecision
= 0;
812 /* call the double handler */
813 retVal
= u_printf_double_handler(handler
, context
, formatBundle
, &scidbl_info
, args
);
815 else if(num
< 0.0001 || (scidbl_info
.fPrecision
< 1 && 1000000.0 <= num
)
816 || (scidbl_info
.fPrecision
!= -1 && num
> uprv_pow10(scidbl_info
.fPrecision
)))
818 /* use 'e' or 'E' notation */
819 scidbl_info
.fSpec
= scidbl_info
.fSpec
- 2;
820 if (scidbl_info
.fPrecision
== -1) {
821 scidbl_info
.fPrecision
= 5;
823 /* call the scientific handler */
824 retVal
= u_printf_scientific_handler(handler
, context
, formatBundle
, &scidbl_info
, args
);
827 UNumberFormat
*format
= u_locbund_getNumberFormat(formatBundle
, UNUM_DECIMAL
);
828 int32_t maxSigDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_SIGNIFICANT_DIGITS
);
829 int32_t significantDigits
= scidbl_info
.fPrecision
;
831 /* use 'f' notation */
832 scidbl_info
.fSpec
= 0x0066;
833 if (significantDigits
== -1) {
834 significantDigits
= 6;
836 unum_setAttribute(format
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
837 unum_setAttribute(format
, UNUM_MAX_SIGNIFICANT_DIGITS
, significantDigits
);
838 /* call the double handler */
839 retVal
= u_printf_double_handler(handler
, context
, formatBundle
, &scidbl_info
, args
);
840 unum_setAttribute(format
, UNUM_MAX_SIGNIFICANT_DIGITS
, maxSigDecimalDigits
);
841 unum_setAttribute(format
, UNUM_SIGNIFICANT_DIGITS_USED
, FALSE
);
847 u_printf_count_handler(const u_printf_stream_handler
*handler
,
849 ULocaleBundle
*formatBundle
,
850 const u_printf_spec_info
*info
,
851 const ufmt_args
*args
)
853 int32_t *count
= (int32_t*)(args
[0].ptrValue
);
855 /* in the special case of count, the u_printf_spec_info's width */
856 /* will contain the # of chars written thus far */
857 *count
= info
->fWidth
;
863 u_printf_spellout_handler(const u_printf_stream_handler
*handler
,
865 ULocaleBundle
*formatBundle
,
866 const u_printf_spec_info
*info
,
867 const ufmt_args
*args
)
869 double num
= (double) (args
[0].doubleValue
);
870 UNumberFormat
*format
;
871 UChar result
[UPRINTF_BUFFER_SIZE
];
872 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
873 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
874 int32_t minDecimalDigits
;
875 int32_t maxDecimalDigits
;
877 UErrorCode status
= U_ZERO_ERROR
;
881 /* mask off any necessary bits */
882 /* if(! info->fIsLongDouble)
885 /* get the formatter */
886 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_SPELLOUT
);
892 /* save the formatter's state */
893 minDecimalDigits
= unum_getAttribute(format
, UNUM_MIN_FRACTION_DIGITS
);
894 maxDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_FRACTION_DIGITS
);
896 /* set the appropriate flags and number of decimal digits on the formatter */
897 if(info
->fPrecision
!= -1) {
898 /* set the # of decimal digits */
899 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, info
->fPrecision
);
901 else if(info
->fAlt
) {
902 /* '#' means always show decimal point */
903 /* copy of printf behavior on Solaris - '#' shows 6 digits */
904 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
907 /* # of decimal digits is 6 if precision not specified */
908 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
911 /* set whether to show the sign */
912 if (info
->fShowSign
) {
913 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
916 /* format the number */
917 resultLen
= unum_formatDouble(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
919 if (U_FAILURE(status
)) {
923 /* restore the number format */
924 /* TODO: Is this needed? */
925 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, minDecimalDigits
);
926 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, maxDecimalDigits
);
928 if (info
->fShowSign
) {
929 /* Reset back to original value regardless of what the error was */
930 UErrorCode localStatus
= U_ZERO_ERROR
;
931 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
934 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
937 /* Use US-ASCII characters only for formatting. Most codepages have
938 characters 20-7F from Unicode. Using any other codepage specific
939 characters will make it very difficult to format the string on
940 non-Unicode machines */
941 static const u_printf_info g_u_printf_infos
[UPRINTF_NUM_FMT_HANDLERS
] = {
943 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
944 UFMT_EMPTY
, UFMT_SIMPLE_PERCENT
,UFMT_EMPTY
, UFMT_EMPTY
,
945 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
946 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
949 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
950 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
951 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
952 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
955 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_UCHAR
,
956 UFMT_EMPTY
, UFMT_SCIENTIFIC
, UFMT_EMPTY
, UFMT_SCIDBL
,
957 #ifdef U_USE_OBSOLETE_IO_FORMATTING
958 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_UCHAR
/*deprecated*/,
960 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
962 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
965 UFMT_PERCENT
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_USTRING
,
966 #ifdef U_USE_OBSOLETE_IO_FORMATTING
967 UFMT_EMPTY
, UFMT_USTRING
/*deprecated*/,UFMT_SPELLOUT
, UFMT_EMPTY
,
969 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_SPELLOUT
, UFMT_EMPTY
,
971 UFMT_HEX
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
972 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
975 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_CHAR
,
976 UFMT_INT
, UFMT_SCIENTIFIC
, UFMT_DOUBLE
, UFMT_SCIDBL
,
977 UFMT_EMPTY
, UFMT_INT
, UFMT_EMPTY
, UFMT_EMPTY
,
978 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_COUNT
, UFMT_OCTAL
,
981 UFMT_POINTER
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_STRING
,
982 UFMT_EMPTY
, UFMT_UINT
, UFMT_EMPTY
, UFMT_EMPTY
,
983 UFMT_HEX
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
984 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
987 /* flag characters for uprintf */
988 #define FLAG_MINUS 0x002D
989 #define FLAG_PLUS 0x002B
990 #define FLAG_SPACE 0x0020
991 #define FLAG_POUND 0x0023
992 #define FLAG_ZERO 0x0030
993 #define FLAG_PAREN 0x0028
995 #define ISFLAG(s) (s) == FLAG_MINUS || \
996 (s) == FLAG_PLUS || \
997 (s) == FLAG_SPACE || \
998 (s) == FLAG_POUND || \
999 (s) == FLAG_ZERO || \
1002 /* special characters for uprintf */
1003 #define SPEC_ASTERISK 0x002A
1004 #define SPEC_DOLLARSIGN 0x0024
1005 #define SPEC_PERIOD 0x002E
1006 #define SPEC_PERCENT 0x0025
1008 /* unicode digits */
1009 #define DIGIT_ZERO 0x0030
1010 #define DIGIT_ONE 0x0031
1011 #define DIGIT_TWO 0x0032
1012 #define DIGIT_THREE 0x0033
1013 #define DIGIT_FOUR 0x0034
1014 #define DIGIT_FIVE 0x0035
1015 #define DIGIT_SIX 0x0036
1016 #define DIGIT_SEVEN 0x0037
1017 #define DIGIT_EIGHT 0x0038
1018 #define DIGIT_NINE 0x0039
1020 #define ISDIGIT(s) (s) == DIGIT_ZERO || \
1021 (s) == DIGIT_ONE || \
1022 (s) == DIGIT_TWO || \
1023 (s) == DIGIT_THREE || \
1024 (s) == DIGIT_FOUR || \
1025 (s) == DIGIT_FIVE || \
1026 (s) == DIGIT_SIX || \
1027 (s) == DIGIT_SEVEN || \
1028 (s) == DIGIT_EIGHT || \
1031 /* u_printf modifiers */
1032 #define MOD_H 0x0068
1033 #define MOD_LOWERL 0x006C
1034 #define MOD_L 0x004C
1036 #define ISMOD(s) (s) == MOD_H || \
1037 (s) == MOD_LOWERL || \
1040 /* We parse the argument list in Unicode */
1042 u_printf_parse(const u_printf_stream_handler
*streamHandler
,
1045 u_localized_print_string
*locStringContext
,
1046 ULocaleBundle
*formatBundle
,
1050 uint16_t handlerNum
;
1052 ufmt_type_info argType
;
1053 u_printf_handler
*handler
;
1055 u_printf_spec_info
*info
= &(spec
.fInfo
);
1057 const UChar
*alias
= fmt
;
1058 const UChar
*backup
;
1059 const UChar
*lastAlias
;
1061 /* iterate through the pattern */
1062 while(!locStringContext
|| locStringContext
->available
> 0) {
1064 /* find the next '%' */
1066 while(*alias
!= UP_PERCENT
&& *alias
!= 0x0000) {
1070 /* write any characters before the '%' */
1071 if(alias
> lastAlias
) {
1072 *written
+= (streamHandler
->write
)(context
, lastAlias
, (int32_t)(alias
- lastAlias
));
1075 /* break if at end of string */
1076 if(*alias
== 0x0000) {
1080 /* initialize spec to default values */
1081 spec
.fWidthPos
= -1;
1082 spec
.fPrecisionPos
= -1;
1085 uprv_memset(info
, 0, sizeof(*info
));
1086 info
->fPrecision
= -1;
1088 info
->fPadChar
= 0x0020;
1090 /* skip over the initial '%' */
1093 /* Check for positional argument */
1094 if(ISDIGIT(*alias
)) {
1096 /* Save the current position */
1099 /* handle positional parameters */
1100 if(ISDIGIT(*alias
)) {
1101 spec
.fArgPos
= (int) (*alias
++ - DIGIT_ZERO
);
1103 while(ISDIGIT(*alias
)) {
1105 spec
.fArgPos
+= (int) (*alias
++ - DIGIT_ZERO
);
1109 /* if there is no '$', don't read anything */
1110 if(*alias
!= SPEC_DOLLARSIGN
) {
1119 /* Get any format flags */
1120 while(ISFLAG(*alias
)) {
1128 /* always show sign */
1130 info
->fShowSign
= TRUE
;
1133 /* use space if no sign present */
1135 info
->fShowSign
= TRUE
;
1136 info
->fSpace
= TRUE
;
1139 /* use alternate form */
1144 /* pad with leading zeroes */
1147 info
->fPadChar
= 0x0030;
1150 /* pad character specified */
1153 /* TODO test that all four are numbers */
1154 /* first four characters are hex values for pad char */
1155 info
->fPadChar
= (UChar
)ufmt_digitvalue(*alias
++);
1156 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*alias
++));
1157 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*alias
++));
1158 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*alias
++));
1160 /* final character is ignored */
1169 /* width is specified out of line */
1170 if(*alias
== SPEC_ASTERISK
) {
1177 /* Save the current position */
1180 /* handle positional parameters */
1181 if(ISDIGIT(*alias
)) {
1182 spec
.fWidthPos
= (int) (*alias
++ - DIGIT_ZERO
);
1184 while(ISDIGIT(*alias
)) {
1185 spec
.fWidthPos
*= 10;
1186 spec
.fWidthPos
+= (int) (*alias
++ - DIGIT_ZERO
);
1190 /* if there is no '$', don't read anything */
1191 if(*alias
!= SPEC_DOLLARSIGN
) {
1192 spec
.fWidthPos
= -1;
1199 /* read the width, if present */
1200 else if(ISDIGIT(*alias
)){
1201 info
->fWidth
= (int) (*alias
++ - DIGIT_ZERO
);
1203 while(ISDIGIT(*alias
)) {
1205 info
->fWidth
+= (int) (*alias
++ - DIGIT_ZERO
);
1209 /* Get the precision */
1211 if(*alias
== SPEC_PERIOD
) {
1213 /* eat up the '.' */
1216 /* precision is specified out of line */
1217 if(*alias
== SPEC_ASTERISK
) {
1219 info
->fPrecision
= -2;
1224 /* save the current position */
1227 /* handle positional parameters */
1228 if(ISDIGIT(*alias
)) {
1229 spec
.fPrecisionPos
= (int) (*alias
++ - DIGIT_ZERO
);
1231 while(ISDIGIT(*alias
)) {
1232 spec
.fPrecisionPos
*= 10;
1233 spec
.fPrecisionPos
+= (int) (*alias
++ - DIGIT_ZERO
);
1236 /* if there is no '$', don't read anything */
1237 if(*alias
!= SPEC_DOLLARSIGN
) {
1238 spec
.fPrecisionPos
= -1;
1247 /* read the precision */
1248 else if(ISDIGIT(*alias
)){
1249 info
->fPrecision
= (int) (*alias
++ - DIGIT_ZERO
);
1251 while(ISDIGIT(*alias
)) {
1252 info
->fPrecision
*= 10;
1253 info
->fPrecision
+= (int) (*alias
++ - DIGIT_ZERO
);
1258 /* Get any modifiers */
1264 info
->fIsShort
= TRUE
;
1267 /* long or long long */
1269 if(*alias
== MOD_LOWERL
) {
1270 info
->fIsLongLong
= TRUE
;
1271 /* skip over the next 'l' */
1275 info
->fIsLong
= TRUE
;
1280 info
->fIsLongDouble
= TRUE
;
1285 /* finally, get the specifier letter */
1286 info
->fSpec
= *alias
++;
1287 info
->fOrigSpec
= info
->fSpec
;
1289 /* fill in the precision and width, if specified out of line */
1291 /* width specified out of line */
1292 if(spec
.fInfo
.fWidth
== -2) {
1293 if(spec
.fWidthPos
== -1) {
1294 /* read the width from the argument list */
1295 info
->fWidth
= va_arg(ap
, int32_t);
1297 /* else handle positional parameter */
1299 /* if it's negative, take the absolute value and set left alignment */
1300 if(info
->fWidth
< 0) {
1301 info
->fWidth
*= -1; /* Make positive */
1306 /* precision specified out of line */
1307 if(info
->fPrecision
== -2) {
1308 if(spec
.fPrecisionPos
== -1) {
1309 /* read the precision from the argument list */
1310 info
->fPrecision
= va_arg(ap
, int32_t);
1312 /* else handle positional parameter */
1314 /* if it's negative, set it to zero */
1315 if(info
->fPrecision
< 0)
1316 info
->fPrecision
= 0;
1319 handlerNum
= (uint16_t)(info
->fSpec
- UPRINTF_BASE_FMT_HANDLERS
);
1320 if (handlerNum
< UPRINTF_NUM_FMT_HANDLERS
) {
1321 /* query the info function for argument information */
1322 argType
= g_u_printf_infos
[ handlerNum
].info
;
1325 /* set the spec's width to the # of chars written */
1326 info
->fWidth
= *written
;
1327 /* fall through to set the pointer */
1331 args
.ptrValue
= va_arg(ap
, void*);
1336 if (info
->fIsLongLong
) {
1337 args
.int64Value
= va_arg(ap
, int64_t);
1340 args
.int64Value
= va_arg(ap
, int32_t);
1344 args
.floatValue
= (float) va_arg(ap
, double);
1347 args
.doubleValue
= va_arg(ap
, double);
1350 /* else args is ignored */
1351 args
.ptrValue
= NULL
;
1355 /* call the handler function */
1356 handler
= g_u_printf_infos
[ handlerNum
].handler
;
1358 *written
+= (*handler
)(streamHandler
, context
, formatBundle
, info
, &args
);
1361 /* just echo unknown tags */
1362 *written
+= (streamHandler
->write
)(context
, fmt
, (int32_t)(alias
- lastAlias
));
1366 /* just echo unknown tags */
1367 *written
+= (streamHandler
->write
)(context
, fmt
, (int32_t)(alias
- lastAlias
));
1370 /* return # of characters in this format that have been parsed. */
1371 return (int32_t)(alias
- fmt
);
1374 #endif /* #if !UCONFIG_NO_FORMATTING */