1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 ******************************************************************************
6 * Copyright (C) 1998-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 ******************************************************************************
13 * Modification History:
15 * Date Name Description
16 * 11/23/98 stephen Creation.
17 * 03/12/99 stephen Modified for new C API.
18 * 08/07/2003 george Reunify printf implementations
19 ******************************************************************************
22 #include "unicode/utypes.h"
24 #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_CONVERSION
26 #include "unicode/ustring.h"
27 #include "unicode/utf16.h"
33 /* ANSI style formatting */
34 /* Use US-ASCII characters only for formatting */
37 #define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_printf_simple_percent_handler}
39 #define UFMT_STRING {ufmt_string, u_printf_string_handler}
41 #define UFMT_CHAR {ufmt_char, u_printf_char_handler}
43 #define UFMT_INT {ufmt_int, u_printf_integer_handler}
45 #define UFMT_UINT {ufmt_int, u_printf_uinteger_handler}
47 #define UFMT_OCTAL {ufmt_int, u_printf_octal_handler}
49 #define UFMT_HEX {ufmt_int, u_printf_hex_handler}
51 #define UFMT_DOUBLE {ufmt_double, u_printf_double_handler}
53 #define UFMT_SCIENTIFIC {ufmt_double, u_printf_scientific_handler}
55 #define UFMT_SCIDBL {ufmt_double, u_printf_scidbl_handler}
57 #define UFMT_COUNT {ufmt_count, u_printf_count_handler}
59 /* non-ANSI extensions */
60 /* Use US-ASCII characters only for formatting */
63 #define UFMT_POINTER {ufmt_pointer, u_printf_pointer_handler}
65 #define UFMT_SPELLOUT {ufmt_double, u_printf_spellout_handler}
67 #define UFMT_PERCENT {ufmt_double, u_printf_percent_handler}
68 /* C K is old format */
69 #define UFMT_UCHAR {ufmt_uchar, u_printf_uchar_handler}
70 /* S U is old format */
71 #define UFMT_USTRING {ufmt_ustring, u_printf_ustring_handler}
74 #define UFMT_EMPTY {ufmt_empty, NULL}
77 * A u_printf handler function.
78 * A u_printf handler is responsible for handling a single u_printf
79 * format specification, for example 'd' or 's'.
80 * @param stream The UFILE to which to write output.
81 * @param info A pointer to a <TT>u_printf_spec_info</TT> struct containing
82 * information on the format specification.
83 * @param args A pointer to the argument data
84 * @return The number of Unicode characters written to <TT>stream</TT>.
86 typedef int32_t U_EXPORT2
87 u_printf_handler(const u_printf_stream_handler
*handler
,
90 ULocaleBundle
*formatBundle
,
91 const u_printf_spec_info
*info
,
92 const ufmt_args
*args
);
94 typedef struct u_printf_info
{
96 u_printf_handler
*handler
;
100 * Struct encapsulating a single uprintf format specification.
102 typedef struct u_printf_spec
{
103 u_printf_spec_info fInfo
; /* Information on this spec */
104 int32_t fWidthPos
; /* Position of width in arg list */
105 int32_t fPrecisionPos
; /* Position of precision in arg list */
106 int32_t fArgPos
; /* Position of data in arg list */
109 #define UPRINTF_NUM_FMT_HANDLERS 108
111 /* We do not use handlers for 0-0x1f */
112 #define UPRINTF_BASE_FMT_HANDLERS 0x20
114 /* buffer size for formatting */
115 #define UPRINTF_BUFFER_SIZE 1024
116 #define UPRINTF_SYMBOL_BUFFER_SIZE 8
118 static const UChar gNullStr
[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
119 static const UChar gSpaceStr
[] = {0x20, 0}; /* " " */
121 /* Sets the sign of a format based on u_printf_spec_info */
122 /* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */
124 u_printf_set_sign(UNumberFormat
*format
,
125 const u_printf_spec_info
*info
,
127 int32_t *prefixBufLen
,
130 if(info
->fShowSign
) {
131 *prefixBufLen
= unum_getTextAttribute(format
,
132 UNUM_POSITIVE_PREFIX
,
137 /* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */
138 /* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */
139 unum_setTextAttribute(format
, UNUM_POSITIVE_PREFIX
, gSpaceStr
, 1, status
);
142 UChar plusSymbol
[UPRINTF_SYMBOL_BUFFER_SIZE
];
145 symbolLen
= unum_getSymbol(format
,
146 UNUM_PLUS_SIGN_SYMBOL
,
148 UPRV_LENGTHOF(plusSymbol
),
150 unum_setTextAttribute(format
,
151 UNUM_POSITIVE_PREFIX
,
163 u_printf_reset_sign(UNumberFormat
*format
,
164 const u_printf_spec_info
*info
,
166 int32_t *prefixBufLen
,
169 if(info
->fShowSign
) {
170 unum_setTextAttribute(format
,
171 UNUM_POSITIVE_PREFIX
,
181 u_printf_simple_percent_handler(const u_printf_stream_handler
*handler
,
183 ULocaleBundle
*formatBundle
,
184 const u_printf_spec_info
*info
,
185 const ufmt_args
*args
)
190 static const UChar PERCENT
[] = { UP_PERCENT
};
192 /* put a single '%' onto the output */
193 return handler
->write(context
, PERCENT
, 1);
198 u_printf_string_handler(const u_printf_stream_handler
*handler
,
200 ULocaleBundle
*formatBundle
,
201 const u_printf_spec_info
*info
,
202 const ufmt_args
*args
)
206 UChar buffer
[UFMT_DEFAULT_BUFFER_SIZE
];
207 int32_t len
, written
;
209 const char *arg
= (const char*)(args
[0].ptrValue
);
211 /* convert from the default codepage to Unicode */
213 argSize
= (int32_t)strlen(arg
) + 1;
214 if (argSize
>= MAX_UCHAR_BUFFER_SIZE(buffer
)) {
215 s
= ufmt_defaultCPToUnicode(arg
, argSize
,
216 (UChar
*)uprv_malloc(MAX_UCHAR_BUFFER_NEEDED(argSize
)),
217 MAX_UCHAR_BUFFER_NEEDED(argSize
));
223 s
= ufmt_defaultCPToUnicode(arg
, argSize
, buffer
,
224 UPRV_LENGTHOF(buffer
));
228 s
= (UChar
*)gNullStr
;
232 /* width = minimum # of characters to write */
233 /* precision = maximum # of characters to write */
234 if (info
->fPrecision
!= -1 && info
->fPrecision
< len
) {
235 len
= info
->fPrecision
;
238 written
= handler
->pad_and_justify(context
, info
, s
, len
);
241 if (gNullStr
!= s
&& buffer
!= s
) {
249 u_printf_char_handler(const u_printf_stream_handler
*handler
,
251 ULocaleBundle
*formatBundle
,
252 const u_printf_spec_info
*info
,
253 const ufmt_args
*args
)
256 UChar s
[U16_MAX_LENGTH
+1];
257 int32_t len
= 1, written
;
258 unsigned char arg
= (unsigned char)(args
[0].int64Value
);
260 /* convert from default codepage to Unicode */
261 ufmt_defaultCPToUnicode((const char *)&arg
, 2, s
, UPRV_LENGTHOF(s
));
263 /* Remember that this may be an MBCS character */
268 /* width = minimum # of characters to write */
269 /* precision = maximum # of characters to write */
270 /* precision is ignored when handling a char */
272 written
= handler
->pad_and_justify(context
, info
, s
, len
);
278 u_printf_double_handler(const u_printf_stream_handler
*handler
,
280 ULocaleBundle
*formatBundle
,
281 const u_printf_spec_info
*info
,
282 const ufmt_args
*args
)
284 double num
= (double) (args
[0].doubleValue
);
285 UNumberFormat
*format
;
286 UChar result
[UPRINTF_BUFFER_SIZE
];
287 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
288 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
289 int32_t minDecimalDigits
;
290 int32_t maxDecimalDigits
;
292 UErrorCode status
= U_ZERO_ERROR
;
296 /* mask off any necessary bits */
297 /* if(! info->fIsLongDouble)
300 /* get the formatter */
301 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_DECIMAL
);
307 /* save the formatter's state */
308 minDecimalDigits
= unum_getAttribute(format
, UNUM_MIN_FRACTION_DIGITS
);
309 maxDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_FRACTION_DIGITS
);
311 /* set the appropriate flags and number of decimal digits on the formatter */
312 if(info
->fPrecision
!= -1) {
313 /* set the # of decimal digits */
314 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, info
->fPrecision
);
316 else if(info
->fAlt
) {
317 /* '#' means always show decimal point */
318 /* copy of printf behavior on Solaris - '#' shows 6 digits */
319 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
322 /* # of decimal digits is 6 if precision not specified regardless of locale */
323 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
326 /* set whether to show the sign */
327 if (info
->fShowSign
) {
328 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
331 /* format the number */
332 resultLen
= unum_formatDouble(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
334 if (U_FAILURE(status
)) {
338 /* restore the number format */
339 /* TODO: Is this needed? */
340 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, minDecimalDigits
);
341 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, maxDecimalDigits
);
343 if (info
->fShowSign
) {
344 /* Reset back to original value regardless of what the error was */
345 UErrorCode localStatus
= U_ZERO_ERROR
;
346 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
349 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
354 u_printf_integer_handler(const u_printf_stream_handler
*handler
,
356 ULocaleBundle
*formatBundle
,
357 const u_printf_spec_info
*info
,
358 const ufmt_args
*args
)
360 int64_t num
= args
[0].int64Value
;
361 UNumberFormat
*format
;
362 UChar result
[UPRINTF_BUFFER_SIZE
];
363 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
364 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
365 int32_t minDigits
= -1;
367 UErrorCode status
= U_ZERO_ERROR
;
371 /* mask off any necessary bits */
374 else if (!info
->fIsLongLong
)
377 /* get the formatter */
378 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_DECIMAL
);
384 /* set the appropriate flags on the formatter */
386 /* set the minimum integer digits */
387 if(info
->fPrecision
!= -1) {
388 /* set the minimum # of digits */
389 minDigits
= unum_getAttribute(format
, UNUM_MIN_INTEGER_DIGITS
);
390 unum_setAttribute(format
, UNUM_MIN_INTEGER_DIGITS
, info
->fPrecision
);
393 /* set whether to show the sign */
394 if(info
->fShowSign
) {
395 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
398 /* format the number */
399 resultLen
= unum_formatInt64(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
401 if (U_FAILURE(status
)) {
405 /* restore the number format */
406 if (minDigits
!= -1) {
407 unum_setAttribute(format
, UNUM_MIN_INTEGER_DIGITS
, minDigits
);
410 if (info
->fShowSign
) {
411 /* Reset back to original value regardless of what the error was */
412 UErrorCode localStatus
= U_ZERO_ERROR
;
413 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
416 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
420 u_printf_hex_handler(const u_printf_stream_handler
*handler
,
422 ULocaleBundle
*formatBundle
,
423 const u_printf_spec_info
*info
,
424 const ufmt_args
*args
)
427 int64_t num
= args
[0].int64Value
;
428 UChar result
[UPRINTF_BUFFER_SIZE
];
429 int32_t len
= UPRINTF_BUFFER_SIZE
;
432 /* mask off any necessary bits */
435 else if (!info
->fIsLongLong
)
438 /* format the number, preserving the minimum # of digits */
439 ufmt_64tou(result
, &len
, num
, 16,
440 (UBool
)(info
->fSpec
== 0x0078),
441 (info
->fPrecision
== -1 && info
->fZero
) ? info
->fWidth
: info
->fPrecision
);
443 /* convert to alt form, if desired */
444 if(num
!= 0 && info
->fAlt
&& len
< UPRINTF_BUFFER_SIZE
- 2) {
445 /* shift the formatted string right by 2 chars */
446 memmove(result
+ 2, result
, len
* sizeof(UChar
));
448 result
[1] = info
->fSpec
;
452 return handler
->pad_and_justify(context
, info
, result
, len
);
456 u_printf_octal_handler(const u_printf_stream_handler
*handler
,
458 ULocaleBundle
*formatBundle
,
459 const u_printf_spec_info
*info
,
460 const ufmt_args
*args
)
463 int64_t num
= args
[0].int64Value
;
464 UChar result
[UPRINTF_BUFFER_SIZE
];
465 int32_t len
= UPRINTF_BUFFER_SIZE
;
468 /* mask off any necessary bits */
471 else if (!info
->fIsLongLong
)
474 /* format the number, preserving the minimum # of digits */
475 ufmt_64tou(result
, &len
, num
, 8,
476 FALSE
, /* doesn't matter for octal */
477 info
->fPrecision
== -1 && info
->fZero
? info
->fWidth
: info
->fPrecision
);
479 /* convert to alt form, if desired */
480 if(info
->fAlt
&& result
[0] != 0x0030 && len
< UPRINTF_BUFFER_SIZE
- 1) {
481 /* shift the formatted string right by 1 char */
482 memmove(result
+ 1, result
, len
* sizeof(UChar
));
487 return handler
->pad_and_justify(context
, info
, result
, len
);
491 u_printf_uinteger_handler(const u_printf_stream_handler
*handler
,
493 ULocaleBundle
*formatBundle
,
494 const u_printf_spec_info
*info
,
495 const ufmt_args
*args
)
497 int64_t num
= args
[0].int64Value
;
498 UNumberFormat
*format
;
499 UChar result
[UPRINTF_BUFFER_SIZE
];
500 int32_t minDigits
= -1;
502 UErrorCode status
= U_ZERO_ERROR
;
504 /* TODO: Fix this once uint64_t can be formatted. */
507 else if (!info
->fIsLongLong
)
510 /* get the formatter */
511 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_DECIMAL
);
517 /* set the appropriate flags on the formatter */
519 /* set the minimum integer digits */
520 if(info
->fPrecision
!= -1) {
521 /* set the minimum # of digits */
522 minDigits
= unum_getAttribute(format
, UNUM_MIN_INTEGER_DIGITS
);
523 unum_setAttribute(format
, UNUM_MIN_INTEGER_DIGITS
, info
->fPrecision
);
526 /* To mirror other stdio implementations, we ignore the sign argument */
528 /* format the number */
529 resultLen
= unum_formatInt64(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
531 if (U_FAILURE(status
)) {
535 /* restore the number format */
536 if (minDigits
!= -1) {
537 unum_setAttribute(format
, UNUM_MIN_INTEGER_DIGITS
, minDigits
);
540 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
544 u_printf_pointer_handler(const u_printf_stream_handler
*handler
,
546 ULocaleBundle
*formatBundle
,
547 const u_printf_spec_info
*info
,
548 const ufmt_args
*args
)
551 UChar result
[UPRINTF_BUFFER_SIZE
];
552 int32_t len
= UPRINTF_BUFFER_SIZE
;
554 /* format the pointer in hex */
555 ufmt_ptou(result
, &len
, args
[0].ptrValue
, TRUE
/*, info->fPrecision*/);
557 return handler
->pad_and_justify(context
, info
, result
, len
);
561 u_printf_scientific_handler(const u_printf_stream_handler
*handler
,
563 ULocaleBundle
*formatBundle
,
564 const u_printf_spec_info
*info
,
565 const ufmt_args
*args
)
567 double num
= (double) (args
[0].doubleValue
);
568 UNumberFormat
*format
;
569 UChar result
[UPRINTF_BUFFER_SIZE
];
570 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
571 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
572 int32_t minDecimalDigits
;
573 int32_t maxDecimalDigits
;
574 UErrorCode status
= U_ZERO_ERROR
;
575 UChar srcExpBuf
[UPRINTF_SYMBOL_BUFFER_SIZE
];
576 int32_t srcLen
, expLen
;
578 UChar expBuf
[UPRINTF_SYMBOL_BUFFER_SIZE
];
582 /* mask off any necessary bits */
583 /* if(! info->fIsLongDouble)
586 /* get the formatter */
587 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_SCIENTIFIC
);
593 /* set the appropriate flags on the formatter */
595 srcLen
= unum_getSymbol(format
,
596 UNUM_EXPONENTIAL_SYMBOL
,
601 /* Upper/lower case the e */
602 if (info
->fSpec
== (UChar
)0x65 /* e */) {
603 expLen
= u_strToLower(expBuf
, (int32_t)sizeof(expBuf
),
605 formatBundle
->fLocale
,
609 expLen
= u_strToUpper(expBuf
, (int32_t)sizeof(expBuf
),
611 formatBundle
->fLocale
,
615 unum_setSymbol(format
,
616 UNUM_EXPONENTIAL_SYMBOL
,
621 /* save the formatter's state */
622 minDecimalDigits
= unum_getAttribute(format
, UNUM_MIN_FRACTION_DIGITS
);
623 maxDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_FRACTION_DIGITS
);
625 /* set the appropriate flags and number of decimal digits on the formatter */
626 if(info
->fPrecision
!= -1) {
627 /* set the # of decimal digits */
628 if (info
->fOrigSpec
== (UChar
)0x65 /* e */ || info
->fOrigSpec
== (UChar
)0x45 /* E */) {
629 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, info
->fPrecision
);
632 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, 1);
633 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, info
->fPrecision
);
636 else if(info
->fAlt
) {
637 /* '#' means always show decimal point */
638 /* copy of printf behavior on Solaris - '#' shows 6 digits */
639 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
642 /* # of decimal digits is 6 if precision not specified */
643 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
646 /* set whether to show the sign */
647 if (info
->fShowSign
) {
648 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
651 /* format the number */
652 resultLen
= unum_formatDouble(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
654 if (U_FAILURE(status
)) {
658 /* restore the number format */
659 /* TODO: Is this needed? */
660 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, minDecimalDigits
);
661 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, maxDecimalDigits
);
663 /* Since we're the only one using the scientific
664 format, we don't need to save the old exponent value. */
665 /*unum_setSymbol(format,
666 UNUM_EXPONENTIAL_SYMBOL,
671 if (info
->fShowSign
) {
672 /* Reset back to original value regardless of what the error was */
673 UErrorCode localStatus
= U_ZERO_ERROR
;
674 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
677 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
681 u_printf_percent_handler(const u_printf_stream_handler
*handler
,
683 ULocaleBundle
*formatBundle
,
684 const u_printf_spec_info
*info
,
685 const ufmt_args
*args
)
687 double num
= (double) (args
[0].doubleValue
);
688 UNumberFormat
*format
;
689 UChar result
[UPRINTF_BUFFER_SIZE
];
690 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
691 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
692 int32_t minDecimalDigits
;
693 int32_t maxDecimalDigits
;
695 UErrorCode status
= U_ZERO_ERROR
;
699 /* mask off any necessary bits */
700 /* if(! info->fIsLongDouble)
703 /* get the formatter */
704 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_PERCENT
);
710 /* save the formatter's state */
711 minDecimalDigits
= unum_getAttribute(format
, UNUM_MIN_FRACTION_DIGITS
);
712 maxDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_FRACTION_DIGITS
);
714 /* set the appropriate flags and number of decimal digits on the formatter */
715 if(info
->fPrecision
!= -1) {
716 /* set the # of decimal digits */
717 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, info
->fPrecision
);
719 else if(info
->fAlt
) {
720 /* '#' means always show decimal point */
721 /* copy of printf behavior on Solaris - '#' shows 6 digits */
722 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
725 /* # of decimal digits is 6 if precision not specified */
726 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
729 /* set whether to show the sign */
730 if (info
->fShowSign
) {
731 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
734 /* format the number */
735 resultLen
= unum_formatDouble(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
737 if (U_FAILURE(status
)) {
741 /* restore the number format */
742 /* TODO: Is this needed? */
743 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, minDecimalDigits
);
744 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, maxDecimalDigits
);
746 if (info
->fShowSign
) {
747 /* Reset back to original value regardless of what the error was */
748 UErrorCode localStatus
= U_ZERO_ERROR
;
749 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
752 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
756 u_printf_ustring_handler(const u_printf_stream_handler
*handler
,
758 ULocaleBundle
*formatBundle
,
759 const u_printf_spec_info
*info
,
760 const ufmt_args
*args
)
763 int32_t len
, written
;
764 const UChar
*arg
= (const UChar
*)(args
[0].ptrValue
);
766 /* allocate enough space for the buffer */
772 /* width = minimum # of characters to write */
773 /* precision = maximum # of characters to write */
774 if (info
->fPrecision
!= -1 && info
->fPrecision
< len
) {
775 len
= info
->fPrecision
;
778 /* determine if the string should be padded */
779 written
= handler
->pad_and_justify(context
, info
, arg
, len
);
785 u_printf_uchar_handler(const u_printf_stream_handler
*handler
,
787 ULocaleBundle
*formatBundle
,
788 const u_printf_spec_info
*info
,
789 const ufmt_args
*args
)
793 UChar arg
= (UChar
)(args
[0].int64Value
);
795 /* width = minimum # of characters to write */
796 /* precision = maximum # of characters to write */
797 /* precision is ignored when handling a uchar */
799 /* determine if the string should be padded */
800 written
= handler
->pad_and_justify(context
, info
, &arg
, 1);
806 u_printf_scidbl_handler(const u_printf_stream_handler
*handler
,
808 ULocaleBundle
*formatBundle
,
809 const u_printf_spec_info
*info
,
810 const ufmt_args
*args
)
812 u_printf_spec_info scidbl_info
;
813 double num
= args
[0].doubleValue
;
815 UNumberFormat
*format
;
816 int32_t maxSigDecimalDigits
, significantDigits
;
818 memcpy(&scidbl_info
, info
, sizeof(u_printf_spec_info
));
820 /* determine whether to use 'd', 'e' or 'f' notation */
821 if (scidbl_info
.fPrecision
== -1 && num
== uprv_trunc(num
))
823 /* use 'f' notation */
824 scidbl_info
.fSpec
= 0x0066;
825 scidbl_info
.fPrecision
= 0;
826 /* call the double handler */
827 retVal
= u_printf_double_handler(handler
, context
, formatBundle
, &scidbl_info
, args
);
829 else if(num
< 0.0001 || (scidbl_info
.fPrecision
< 1 && 1000000.0 <= num
)
830 || (scidbl_info
.fPrecision
!= -1 && num
> uprv_pow10(scidbl_info
.fPrecision
)))
832 /* use 'e' or 'E' notation */
833 scidbl_info
.fSpec
= scidbl_info
.fSpec
- 2;
834 if (scidbl_info
.fPrecision
== -1) {
835 scidbl_info
.fPrecision
= 5;
837 /* call the scientific handler */
838 retVal
= u_printf_scientific_handler(handler
, context
, formatBundle
, &scidbl_info
, args
);
841 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_DECIMAL
);
842 /* Check for null pointer */
843 if (format
== NULL
) {
846 maxSigDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_SIGNIFICANT_DIGITS
);
847 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
)
874 int32_t *count
= (int32_t*)(args
[0].ptrValue
);
876 /* in the special case of count, the u_printf_spec_info's width */
877 /* will contain the # of chars written thus far */
878 *count
= info
->fWidth
;
884 u_printf_spellout_handler(const u_printf_stream_handler
*handler
,
886 ULocaleBundle
*formatBundle
,
887 const u_printf_spec_info
*info
,
888 const ufmt_args
*args
)
890 double num
= (double) (args
[0].doubleValue
);
891 UNumberFormat
*format
;
892 UChar result
[UPRINTF_BUFFER_SIZE
];
893 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
894 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
895 int32_t minDecimalDigits
;
896 int32_t maxDecimalDigits
;
898 UErrorCode status
= U_ZERO_ERROR
;
902 /* mask off any necessary bits */
903 /* if(! info->fIsLongDouble)
906 /* get the formatter */
907 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_SPELLOUT
);
913 /* save the formatter's state */
914 minDecimalDigits
= unum_getAttribute(format
, UNUM_MIN_FRACTION_DIGITS
);
915 maxDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_FRACTION_DIGITS
);
917 /* set the appropriate flags and number of decimal digits on the formatter */
918 if(info
->fPrecision
!= -1) {
919 /* set the # of decimal digits */
920 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, info
->fPrecision
);
922 else if(info
->fAlt
) {
923 /* '#' means always show decimal point */
924 /* copy of printf behavior on Solaris - '#' shows 6 digits */
925 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
928 /* # of decimal digits is 6 if precision not specified */
929 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
932 /* set whether to show the sign */
933 if (info
->fShowSign
) {
934 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
937 /* format the number */
938 resultLen
= unum_formatDouble(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
940 if (U_FAILURE(status
)) {
944 /* restore the number format */
945 /* TODO: Is this needed? */
946 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, minDecimalDigits
);
947 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, maxDecimalDigits
);
949 if (info
->fShowSign
) {
950 /* Reset back to original value regardless of what the error was */
951 UErrorCode localStatus
= U_ZERO_ERROR
;
952 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
955 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
958 /* Use US-ASCII characters only for formatting. Most codepages have
959 characters 20-7F from Unicode. Using any other codepage specific
960 characters will make it very difficult to format the string on
961 non-Unicode machines */
962 static const u_printf_info g_u_printf_infos
[UPRINTF_NUM_FMT_HANDLERS
] = {
964 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
965 UFMT_EMPTY
, UFMT_SIMPLE_PERCENT
,UFMT_EMPTY
, UFMT_EMPTY
,
966 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
967 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
970 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
971 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
972 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
973 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
976 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_UCHAR
,
977 UFMT_EMPTY
, UFMT_SCIENTIFIC
, UFMT_EMPTY
, UFMT_SCIDBL
,
978 #ifdef U_USE_OBSOLETE_IO_FORMATTING
979 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_UCHAR
/*deprecated*/,
981 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
983 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
986 UFMT_PERCENT
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_USTRING
,
987 #ifdef U_USE_OBSOLETE_IO_FORMATTING
988 UFMT_EMPTY
, UFMT_USTRING
/*deprecated*/,UFMT_SPELLOUT
, UFMT_EMPTY
,
990 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_SPELLOUT
, UFMT_EMPTY
,
992 UFMT_HEX
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
993 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
996 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_CHAR
,
997 UFMT_INT
, UFMT_SCIENTIFIC
, UFMT_DOUBLE
, UFMT_SCIDBL
,
998 UFMT_EMPTY
, UFMT_INT
, UFMT_EMPTY
, UFMT_EMPTY
,
999 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_COUNT
, UFMT_OCTAL
,
1002 UFMT_POINTER
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_STRING
,
1003 UFMT_EMPTY
, UFMT_UINT
, UFMT_EMPTY
, UFMT_EMPTY
,
1004 UFMT_HEX
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1005 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1008 /* flag characters for uprintf */
1009 #define FLAG_MINUS 0x002D
1010 #define FLAG_PLUS 0x002B
1011 #define FLAG_SPACE 0x0020
1012 #define FLAG_POUND 0x0023
1013 #define FLAG_ZERO 0x0030
1014 #define FLAG_PAREN 0x0028
1016 #define ISFLAG(s) (s) == FLAG_MINUS || \
1017 (s) == FLAG_PLUS || \
1018 (s) == FLAG_SPACE || \
1019 (s) == FLAG_POUND || \
1020 (s) == FLAG_ZERO || \
1023 /* special characters for uprintf */
1024 #define SPEC_ASTERISK 0x002A
1025 #define SPEC_DOLLARSIGN 0x0024
1026 #define SPEC_PERIOD 0x002E
1027 #define SPEC_PERCENT 0x0025
1029 /* unicode digits */
1030 #define DIGIT_ZERO 0x0030
1031 #define DIGIT_ONE 0x0031
1032 #define DIGIT_TWO 0x0032
1033 #define DIGIT_THREE 0x0033
1034 #define DIGIT_FOUR 0x0034
1035 #define DIGIT_FIVE 0x0035
1036 #define DIGIT_SIX 0x0036
1037 #define DIGIT_SEVEN 0x0037
1038 #define DIGIT_EIGHT 0x0038
1039 #define DIGIT_NINE 0x0039
1041 #define ISDIGIT(s) (s) == DIGIT_ZERO || \
1042 (s) == DIGIT_ONE || \
1043 (s) == DIGIT_TWO || \
1044 (s) == DIGIT_THREE || \
1045 (s) == DIGIT_FOUR || \
1046 (s) == DIGIT_FIVE || \
1047 (s) == DIGIT_SIX || \
1048 (s) == DIGIT_SEVEN || \
1049 (s) == DIGIT_EIGHT || \
1052 /* u_printf modifiers */
1053 #define MOD_H 0x0068
1054 #define MOD_LOWERL 0x006C
1055 #define MOD_L 0x004C
1057 #define ISMOD(s) (s) == MOD_H || \
1058 (s) == MOD_LOWERL || \
1060 /* Returns an array of the parsed argument type given in the format string. */
1061 static ufmt_args
* parseArguments(const UChar
*alias
, va_list ap
, UErrorCode
*status
) {
1062 ufmt_args
*arglist
= NULL
;
1063 ufmt_type_info
*typelist
= NULL
;
1064 UBool
*islonglong
= NULL
;
1068 uint16_t handlerNum
;
1069 const UChar
*aliasStart
= alias
;
1071 /* get maximum number of arguments */
1074 while(*alias
!= UP_PERCENT
&& *alias
!= 0x0000) {
1078 if(*alias
== 0x0000) {
1084 /* handle the pos number */
1085 if(ISDIGIT(*alias
)) {
1087 /* handle positional parameters */
1088 if(ISDIGIT(*alias
)) {
1089 pos
= (int) (*alias
++ - DIGIT_ZERO
);
1091 while(ISDIGIT(*alias
)) {
1093 pos
+= (int) (*alias
++ - DIGIT_ZERO
);
1097 /* if there is no '$', don't read anything */
1098 if(*alias
!= SPEC_DOLLARSIGN
) {
1110 /* create the parsed argument list */
1111 typelist
= (ufmt_type_info
*)uprv_malloc(sizeof(ufmt_type_info
) * size
);
1112 islonglong
= (UBool
*)uprv_malloc(sizeof(UBool
) * size
);
1113 arglist
= (ufmt_args
*)uprv_malloc(sizeof(ufmt_args
) * size
);
1115 /* If malloc failed, return NULL */
1116 if (!typelist
|| !islonglong
|| !arglist
) {
1118 uprv_free(typelist
);
1122 uprv_free(islonglong
);
1129 *status
= U_MEMORY_ALLOCATION_ERROR
;
1133 /* reset alias back to the beginning */
1138 while(*alias
!= UP_PERCENT
&& *alias
!= 0x0000) {
1142 if(*alias
== 0x0000) {
1148 /* handle positional parameters */
1149 if(ISDIGIT(*alias
)) {
1150 pos
= (int) (*alias
++ - DIGIT_ZERO
);
1152 while(ISDIGIT(*alias
)) {
1154 pos
+= (int) (*alias
++ - DIGIT_ZERO
);
1157 /* offset position by 1 */
1160 /* skip over everything except for the type */
1161 while (ISMOD(*alias
) || ISFLAG(*alias
) || ISDIGIT(*alias
) ||
1162 *alias
== SPEC_ASTERISK
|| *alias
== SPEC_PERIOD
|| *alias
== SPEC_DOLLARSIGN
) {
1163 islonglong
[pos
] = FALSE
;
1164 if (ISMOD(*alias
)) {
1166 if (*alias
== MOD_LOWERL
) {
1167 islonglong
[pos
] = TRUE
;
1174 /* store the argument type in the correct position of the parsed argument list */
1175 handlerNum
= (uint16_t)(type
- UPRINTF_BASE_FMT_HANDLERS
);
1176 if (handlerNum
< UPRINTF_NUM_FMT_HANDLERS
) {
1177 typelist
[pos
] = g_u_printf_infos
[ handlerNum
].info
;
1179 typelist
[pos
] = ufmt_empty
;
1183 /* store argument in arglist */
1184 for (pos
= 0; pos
< size
; pos
++) {
1185 switch (typelist
[pos
]) {
1189 arglist
[pos
].ptrValue
= va_arg(ap
, void*);
1194 if (islonglong
[pos
]) {
1195 arglist
[pos
].int64Value
= va_arg(ap
, int64_t);
1198 arglist
[pos
].int64Value
= va_arg(ap
, int32_t);
1202 arglist
[pos
].floatValue
= (float) va_arg(ap
, double);
1205 arglist
[pos
].doubleValue
= va_arg(ap
, double);
1208 /* else args is ignored */
1209 arglist
[pos
].ptrValue
= NULL
;
1214 uprv_free(typelist
);
1215 uprv_free(islonglong
);
1220 /* We parse the argument list in Unicode */
1222 u_printf_parse(const u_printf_stream_handler
*streamHandler
,
1225 u_localized_print_string
*locStringContext
,
1226 ULocaleBundle
*formatBundle
,
1230 uint16_t handlerNum
;
1232 ufmt_type_info argType
;
1233 u_printf_handler
*handler
;
1235 u_printf_spec_info
*info
= &(spec
.fInfo
);
1237 const UChar
*alias
= fmt
;
1238 const UChar
*backup
;
1239 const UChar
*lastAlias
;
1240 const UChar
*orgAlias
= fmt
;
1241 /* parsed argument list */
1242 ufmt_args
*arglist
= NULL
; /* initialized it to avoid compiler warnings */
1243 UErrorCode status
= U_ZERO_ERROR
;
1244 if (!locStringContext
|| locStringContext
->available
>= 0) {
1245 /* get the parsed list of argument types */
1246 arglist
= parseArguments(orgAlias
, ap
, &status
);
1248 /* Return error if parsing failed. */
1249 if (U_FAILURE(status
)) {
1254 /* iterate through the pattern */
1255 while(!locStringContext
|| locStringContext
->available
>= 0) {
1257 /* find the next '%' */
1259 while(*alias
!= UP_PERCENT
&& *alias
!= 0x0000) {
1263 /* write any characters before the '%' */
1264 if(alias
> lastAlias
) {
1265 *written
+= (streamHandler
->write
)(context
, lastAlias
, (int32_t)(alias
- lastAlias
));
1268 /* break if at end of string */
1269 if(*alias
== 0x0000) {
1273 /* initialize spec to default values */
1274 spec
.fWidthPos
= -1;
1275 spec
.fPrecisionPos
= -1;
1278 uprv_memset(info
, 0, sizeof(*info
));
1279 info
->fPrecision
= -1;
1281 info
->fPadChar
= 0x0020;
1283 /* skip over the initial '%' */
1286 /* Check for positional argument */
1287 if(ISDIGIT(*alias
)) {
1289 /* Save the current position */
1292 /* handle positional parameters */
1293 if(ISDIGIT(*alias
)) {
1294 spec
.fArgPos
= (int) (*alias
++ - DIGIT_ZERO
);
1296 while(ISDIGIT(*alias
)) {
1298 spec
.fArgPos
+= (int) (*alias
++ - DIGIT_ZERO
);
1302 /* if there is no '$', don't read anything */
1303 if(*alias
!= SPEC_DOLLARSIGN
) {
1312 /* Get any format flags */
1313 while(ISFLAG(*alias
)) {
1321 /* always show sign */
1323 info
->fShowSign
= TRUE
;
1326 /* use space if no sign present */
1328 info
->fShowSign
= TRUE
;
1329 info
->fSpace
= TRUE
;
1332 /* use alternate form */
1337 /* pad with leading zeroes */
1340 info
->fPadChar
= 0x0030;
1343 /* pad character specified */
1346 /* TODO test that all four are numbers */
1347 /* first four characters are hex values for pad char */
1348 info
->fPadChar
= (UChar
)ufmt_digitvalue(*alias
++);
1349 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*alias
++));
1350 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*alias
++));
1351 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*alias
++));
1353 /* final character is ignored */
1362 /* width is specified out of line */
1363 if(*alias
== SPEC_ASTERISK
) {
1370 /* Save the current position */
1373 /* handle positional parameters */
1374 if(ISDIGIT(*alias
)) {
1375 spec
.fWidthPos
= (int) (*alias
++ - DIGIT_ZERO
);
1377 while(ISDIGIT(*alias
)) {
1378 spec
.fWidthPos
*= 10;
1379 spec
.fWidthPos
+= (int) (*alias
++ - DIGIT_ZERO
);
1383 /* if there is no '$', don't read anything */
1384 if(*alias
!= SPEC_DOLLARSIGN
) {
1385 spec
.fWidthPos
= -1;
1392 /* read the width, if present */
1393 else if(ISDIGIT(*alias
)){
1394 info
->fWidth
= (int) (*alias
++ - DIGIT_ZERO
);
1396 while(ISDIGIT(*alias
)) {
1398 info
->fWidth
+= (int) (*alias
++ - DIGIT_ZERO
);
1402 /* Get the precision */
1404 if(*alias
== SPEC_PERIOD
) {
1406 /* eat up the '.' */
1409 /* precision is specified out of line */
1410 if(*alias
== SPEC_ASTERISK
) {
1412 info
->fPrecision
= -2;
1417 /* save the current position */
1420 /* handle positional parameters */
1421 if(ISDIGIT(*alias
)) {
1422 spec
.fPrecisionPos
= (int) (*alias
++ - DIGIT_ZERO
);
1424 while(ISDIGIT(*alias
)) {
1425 spec
.fPrecisionPos
*= 10;
1426 spec
.fPrecisionPos
+= (int) (*alias
++ - DIGIT_ZERO
);
1429 /* if there is no '$', don't read anything */
1430 if(*alias
!= SPEC_DOLLARSIGN
) {
1431 spec
.fPrecisionPos
= -1;
1440 /* read the precision */
1441 else if(ISDIGIT(*alias
)){
1442 info
->fPrecision
= (int) (*alias
++ - DIGIT_ZERO
);
1444 while(ISDIGIT(*alias
)) {
1445 info
->fPrecision
*= 10;
1446 info
->fPrecision
+= (int) (*alias
++ - DIGIT_ZERO
);
1451 /* Get any modifiers */
1457 info
->fIsShort
= TRUE
;
1460 /* long or long long */
1462 if(*alias
== MOD_LOWERL
) {
1463 info
->fIsLongLong
= TRUE
;
1464 /* skip over the next 'l' */
1468 info
->fIsLong
= TRUE
;
1473 info
->fIsLongDouble
= TRUE
;
1478 /* finally, get the specifier letter */
1479 info
->fSpec
= *alias
++;
1480 info
->fOrigSpec
= info
->fSpec
;
1482 /* fill in the precision and width, if specified out of line */
1484 /* width specified out of line */
1485 if(spec
.fInfo
.fWidth
== -2) {
1486 if(spec
.fWidthPos
== -1) {
1487 /* read the width from the argument list */
1488 info
->fWidth
= va_arg(ap
, int32_t);
1490 /* else handle positional parameter */
1492 /* if it's negative, take the absolute value and set left alignment */
1493 if(info
->fWidth
< 0) {
1494 info
->fWidth
*= -1; /* Make positive */
1499 /* precision specified out of line */
1500 if(info
->fPrecision
== -2) {
1501 if(spec
.fPrecisionPos
== -1) {
1502 /* read the precision from the argument list */
1503 info
->fPrecision
= va_arg(ap
, int32_t);
1505 /* else handle positional parameter */
1507 /* if it's negative, set it to zero */
1508 if(info
->fPrecision
< 0)
1509 info
->fPrecision
= 0;
1512 handlerNum
= (uint16_t)(info
->fSpec
- UPRINTF_BASE_FMT_HANDLERS
);
1513 if (handlerNum
< UPRINTF_NUM_FMT_HANDLERS
) {
1514 /* query the info function for argument information */
1515 argType
= g_u_printf_infos
[ handlerNum
].info
;
1517 /* goto the correct argument on arg_list if position is specified */
1518 if (spec
.fArgPos
> 0) {
1519 /* offset position by 1 */
1523 /* set the spec's width to the # of chars written */
1524 info
->fWidth
= *written
;
1525 /* fall through to set the pointer */
1530 args
.ptrValue
= arglist
[spec
.fArgPos
].ptrValue
;
1535 args
.int64Value
= arglist
[spec
.fArgPos
].int64Value
;
1538 args
.floatValue
= arglist
[spec
.fArgPos
].floatValue
;
1541 args
.doubleValue
= arglist
[spec
.fArgPos
].doubleValue
;
1544 /* else args is ignored */
1545 args
.ptrValue
= NULL
;
1548 } else { /* no positional argument specified */
1551 /* set the spec's width to the # of chars written */
1552 info
->fWidth
= *written
;
1553 /* fall through to set the pointer */
1558 args
.ptrValue
= va_arg(ap
, void*);
1563 if (info
->fIsLongLong
) {
1564 args
.int64Value
= va_arg(ap
, int64_t);
1567 args
.int64Value
= va_arg(ap
, int32_t);
1571 args
.floatValue
= (float) va_arg(ap
, double);
1574 args
.doubleValue
= va_arg(ap
, double);
1577 /* else args is ignored */
1578 args
.ptrValue
= NULL
;
1583 /* call the handler function */
1584 handler
= g_u_printf_infos
[ handlerNum
].handler
;
1586 *written
+= (*handler
)(streamHandler
, context
, formatBundle
, info
, &args
);
1589 /* just echo unknown tags */
1590 *written
+= (streamHandler
->write
)(context
, fmt
, (int32_t)(alias
- lastAlias
));
1594 /* just echo unknown tags */
1595 *written
+= (streamHandler
->write
)(context
, fmt
, (int32_t)(alias
- lastAlias
));
1598 /* delete parsed argument list */
1599 if (arglist
!= NULL
) {
1602 /* return # of characters in this format that have been parsed. */
1603 return (int32_t)(alias
- fmt
);
1606 #endif /* #if !UCONFIG_NO_FORMATTING */