2 ******************************************************************************
4 * Copyright (C) 1998-2008, 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
;
803 UNumberFormat
*format
;
804 int32_t maxSigDecimalDigits
, significantDigits
;
806 memcpy(&scidbl_info
, info
, sizeof(u_printf_spec_info
));
808 /* determine whether to use 'd', 'e' or 'f' notation */
809 if (scidbl_info
.fPrecision
== -1 && num
== uprv_trunc(num
))
811 /* use 'f' notation */
812 scidbl_info
.fSpec
= 0x0066;
813 scidbl_info
.fPrecision
= 0;
814 /* call the double handler */
815 retVal
= u_printf_double_handler(handler
, context
, formatBundle
, &scidbl_info
, args
);
817 else if(num
< 0.0001 || (scidbl_info
.fPrecision
< 1 && 1000000.0 <= num
)
818 || (scidbl_info
.fPrecision
!= -1 && num
> uprv_pow10(scidbl_info
.fPrecision
)))
820 /* use 'e' or 'E' notation */
821 scidbl_info
.fSpec
= scidbl_info
.fSpec
- 2;
822 if (scidbl_info
.fPrecision
== -1) {
823 scidbl_info
.fPrecision
= 5;
825 /* call the scientific handler */
826 retVal
= u_printf_scientific_handler(handler
, context
, formatBundle
, &scidbl_info
, args
);
829 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_DECIMAL
);
830 /* Check for null pointer */
831 if (format
== NULL
) {
834 maxSigDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_SIGNIFICANT_DIGITS
);
835 significantDigits
= scidbl_info
.fPrecision
;
837 /* use 'f' notation */
838 scidbl_info
.fSpec
= 0x0066;
839 if (significantDigits
== -1) {
840 significantDigits
= 6;
842 unum_setAttribute(format
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
843 unum_setAttribute(format
, UNUM_MAX_SIGNIFICANT_DIGITS
, significantDigits
);
844 /* call the double handler */
845 retVal
= u_printf_double_handler(handler
, context
, formatBundle
, &scidbl_info
, args
);
846 unum_setAttribute(format
, UNUM_MAX_SIGNIFICANT_DIGITS
, maxSigDecimalDigits
);
847 unum_setAttribute(format
, UNUM_SIGNIFICANT_DIGITS_USED
, FALSE
);
853 u_printf_count_handler(const u_printf_stream_handler
*handler
,
855 ULocaleBundle
*formatBundle
,
856 const u_printf_spec_info
*info
,
857 const ufmt_args
*args
)
859 int32_t *count
= (int32_t*)(args
[0].ptrValue
);
861 /* in the special case of count, the u_printf_spec_info's width */
862 /* will contain the # of chars written thus far */
863 *count
= info
->fWidth
;
869 u_printf_spellout_handler(const u_printf_stream_handler
*handler
,
871 ULocaleBundle
*formatBundle
,
872 const u_printf_spec_info
*info
,
873 const ufmt_args
*args
)
875 double num
= (double) (args
[0].doubleValue
);
876 UNumberFormat
*format
;
877 UChar result
[UPRINTF_BUFFER_SIZE
];
878 UChar prefixBuffer
[UPRINTF_BUFFER_SIZE
];
879 int32_t prefixBufferLen
= sizeof(prefixBuffer
);
880 int32_t minDecimalDigits
;
881 int32_t maxDecimalDigits
;
883 UErrorCode status
= U_ZERO_ERROR
;
887 /* mask off any necessary bits */
888 /* if(! info->fIsLongDouble)
891 /* get the formatter */
892 format
= u_locbund_getNumberFormat(formatBundle
, UNUM_SPELLOUT
);
898 /* save the formatter's state */
899 minDecimalDigits
= unum_getAttribute(format
, UNUM_MIN_FRACTION_DIGITS
);
900 maxDecimalDigits
= unum_getAttribute(format
, UNUM_MAX_FRACTION_DIGITS
);
902 /* set the appropriate flags and number of decimal digits on the formatter */
903 if(info
->fPrecision
!= -1) {
904 /* set the # of decimal digits */
905 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, info
->fPrecision
);
907 else if(info
->fAlt
) {
908 /* '#' means always show decimal point */
909 /* copy of printf behavior on Solaris - '#' shows 6 digits */
910 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
913 /* # of decimal digits is 6 if precision not specified */
914 unum_setAttribute(format
, UNUM_FRACTION_DIGITS
, 6);
917 /* set whether to show the sign */
918 if (info
->fShowSign
) {
919 u_printf_set_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &status
);
922 /* format the number */
923 resultLen
= unum_formatDouble(format
, num
, result
, UPRINTF_BUFFER_SIZE
, 0, &status
);
925 if (U_FAILURE(status
)) {
929 /* restore the number format */
930 /* TODO: Is this needed? */
931 unum_setAttribute(format
, UNUM_MIN_FRACTION_DIGITS
, minDecimalDigits
);
932 unum_setAttribute(format
, UNUM_MAX_FRACTION_DIGITS
, maxDecimalDigits
);
934 if (info
->fShowSign
) {
935 /* Reset back to original value regardless of what the error was */
936 UErrorCode localStatus
= U_ZERO_ERROR
;
937 u_printf_reset_sign(format
, info
, prefixBuffer
, &prefixBufferLen
, &localStatus
);
940 return handler
->pad_and_justify(context
, info
, result
, resultLen
);
943 /* Use US-ASCII characters only for formatting. Most codepages have
944 characters 20-7F from Unicode. Using any other codepage specific
945 characters will make it very difficult to format the string on
946 non-Unicode machines */
947 static const u_printf_info g_u_printf_infos
[UPRINTF_NUM_FMT_HANDLERS
] = {
949 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
950 UFMT_EMPTY
, UFMT_SIMPLE_PERCENT
,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_EMPTY
,
956 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
957 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
958 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
961 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_UCHAR
,
962 UFMT_EMPTY
, UFMT_SCIENTIFIC
, UFMT_EMPTY
, UFMT_SCIDBL
,
963 #ifdef U_USE_OBSOLETE_IO_FORMATTING
964 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_UCHAR
/*deprecated*/,
966 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
968 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
971 UFMT_PERCENT
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_USTRING
,
972 #ifdef U_USE_OBSOLETE_IO_FORMATTING
973 UFMT_EMPTY
, UFMT_USTRING
/*deprecated*/,UFMT_SPELLOUT
, UFMT_EMPTY
,
975 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_SPELLOUT
, UFMT_EMPTY
,
977 UFMT_HEX
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
978 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
981 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_CHAR
,
982 UFMT_INT
, UFMT_SCIENTIFIC
, UFMT_DOUBLE
, UFMT_SCIDBL
,
983 UFMT_EMPTY
, UFMT_INT
, UFMT_EMPTY
, UFMT_EMPTY
,
984 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_COUNT
, UFMT_OCTAL
,
987 UFMT_POINTER
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_STRING
,
988 UFMT_EMPTY
, UFMT_UINT
, UFMT_EMPTY
, UFMT_EMPTY
,
989 UFMT_HEX
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
990 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
993 /* flag characters for uprintf */
994 #define FLAG_MINUS 0x002D
995 #define FLAG_PLUS 0x002B
996 #define FLAG_SPACE 0x0020
997 #define FLAG_POUND 0x0023
998 #define FLAG_ZERO 0x0030
999 #define FLAG_PAREN 0x0028
1001 #define ISFLAG(s) (s) == FLAG_MINUS || \
1002 (s) == FLAG_PLUS || \
1003 (s) == FLAG_SPACE || \
1004 (s) == FLAG_POUND || \
1005 (s) == FLAG_ZERO || \
1008 /* special characters for uprintf */
1009 #define SPEC_ASTERISK 0x002A
1010 #define SPEC_DOLLARSIGN 0x0024
1011 #define SPEC_PERIOD 0x002E
1012 #define SPEC_PERCENT 0x0025
1014 /* unicode digits */
1015 #define DIGIT_ZERO 0x0030
1016 #define DIGIT_ONE 0x0031
1017 #define DIGIT_TWO 0x0032
1018 #define DIGIT_THREE 0x0033
1019 #define DIGIT_FOUR 0x0034
1020 #define DIGIT_FIVE 0x0035
1021 #define DIGIT_SIX 0x0036
1022 #define DIGIT_SEVEN 0x0037
1023 #define DIGIT_EIGHT 0x0038
1024 #define DIGIT_NINE 0x0039
1026 #define ISDIGIT(s) (s) == DIGIT_ZERO || \
1027 (s) == DIGIT_ONE || \
1028 (s) == DIGIT_TWO || \
1029 (s) == DIGIT_THREE || \
1030 (s) == DIGIT_FOUR || \
1031 (s) == DIGIT_FIVE || \
1032 (s) == DIGIT_SIX || \
1033 (s) == DIGIT_SEVEN || \
1034 (s) == DIGIT_EIGHT || \
1037 /* u_printf modifiers */
1038 #define MOD_H 0x0068
1039 #define MOD_LOWERL 0x006C
1040 #define MOD_L 0x004C
1042 #define ISMOD(s) (s) == MOD_H || \
1043 (s) == MOD_LOWERL || \
1045 /* Returns an array of the parsed argument type given in the format string. */
1046 static ufmt_args
* parseArguments(const UChar
*alias
, va_list ap
, UErrorCode
*status
) {
1047 ufmt_args
*arglist
= NULL
;
1048 ufmt_type_info
*typelist
= NULL
;
1049 UBool
*islonglong
= NULL
;
1053 uint16_t handlerNum
;
1054 const UChar
*aliasStart
= alias
;
1056 /* get maximum number of arguments */
1059 while(*alias
!= UP_PERCENT
&& *alias
!= 0x0000) {
1063 if(*alias
== 0x0000) {
1069 /* handle the pos number */
1070 if(ISDIGIT(*alias
)) {
1072 /* handle positional parameters */
1073 if(ISDIGIT(*alias
)) {
1074 pos
= (int) (*alias
++ - DIGIT_ZERO
);
1076 while(ISDIGIT(*alias
)) {
1078 pos
+= (int) (*alias
++ - DIGIT_ZERO
);
1082 /* if there is no '$', don't read anything */
1083 if(*alias
!= SPEC_DOLLARSIGN
) {
1095 /* create the parsed argument list */
1096 typelist
= (ufmt_type_info
*)uprv_malloc(sizeof(ufmt_type_info
) * size
);
1097 islonglong
= (UBool
*)uprv_malloc(sizeof(UBool
) * size
);
1098 arglist
= (ufmt_args
*)uprv_malloc(sizeof(ufmt_args
) * size
);
1100 /* If malloc failed, return NULL */
1101 if (!typelist
|| !islonglong
|| !arglist
) {
1103 uprv_free(typelist
);
1107 uprv_free(islonglong
);
1114 *status
= U_MEMORY_ALLOCATION_ERROR
;
1118 /* reset alias back to the beginning */
1123 while(*alias
!= UP_PERCENT
&& *alias
!= 0x0000) {
1127 if(*alias
== 0x0000) {
1133 /* handle positional parameters */
1134 if(ISDIGIT(*alias
)) {
1135 pos
= (int) (*alias
++ - DIGIT_ZERO
);
1137 while(ISDIGIT(*alias
)) {
1139 pos
+= (int) (*alias
++ - DIGIT_ZERO
);
1142 /* offset position by 1 */
1145 /* skip over everything except for the type */
1146 while (ISMOD(*alias
) || ISFLAG(*alias
) || ISDIGIT(*alias
) ||
1147 *alias
== SPEC_ASTERISK
|| *alias
== SPEC_PERIOD
|| *alias
== SPEC_DOLLARSIGN
) {
1148 islonglong
[pos
] = FALSE
;
1149 if (ISMOD(*alias
)) {
1151 if (*alias
== MOD_LOWERL
) {
1152 islonglong
[pos
] = TRUE
;
1159 /* store the argument type in the correct position of the parsed argument list */
1160 handlerNum
= (uint16_t)(type
- UPRINTF_BASE_FMT_HANDLERS
);
1161 if (handlerNum
< UPRINTF_NUM_FMT_HANDLERS
) {
1162 typelist
[pos
] = g_u_printf_infos
[ handlerNum
].info
;
1164 typelist
[pos
] = ufmt_empty
;
1168 /* store argument in arglist */
1169 for (pos
= 0; pos
< size
; pos
++) {
1170 switch (typelist
[pos
]) {
1174 arglist
[pos
].ptrValue
= va_arg(ap
, void*);
1179 if (islonglong
[pos
]) {
1180 arglist
[pos
].int64Value
= va_arg(ap
, int64_t);
1183 arglist
[pos
].int64Value
= va_arg(ap
, int32_t);
1187 arglist
[pos
].floatValue
= (float) va_arg(ap
, double);
1190 arglist
[pos
].doubleValue
= va_arg(ap
, double);
1193 /* else args is ignored */
1194 arglist
[pos
].ptrValue
= NULL
;
1199 uprv_free(typelist
);
1200 uprv_free(islonglong
);
1205 /* We parse the argument list in Unicode */
1207 u_printf_parse(const u_printf_stream_handler
*streamHandler
,
1210 u_localized_print_string
*locStringContext
,
1211 ULocaleBundle
*formatBundle
,
1215 uint16_t handlerNum
;
1217 ufmt_type_info argType
;
1218 u_printf_handler
*handler
;
1220 u_printf_spec_info
*info
= &(spec
.fInfo
);
1222 const UChar
*alias
= fmt
;
1223 const UChar
*backup
;
1224 const UChar
*lastAlias
;
1225 const UChar
*orgAlias
= fmt
;
1226 /* parsed argument list */
1227 ufmt_args
*arglist
= NULL
; /* initialized it to avoid compiler warnings */
1228 UErrorCode status
= U_ZERO_ERROR
;
1229 if (!locStringContext
|| locStringContext
->available
>= 0) {
1230 /* get the parsed list of argument types */
1231 arglist
= parseArguments(orgAlias
, ap
, &status
);
1233 /* Return error if parsing failed. */
1234 if (U_FAILURE(status
)) {
1239 /* iterate through the pattern */
1240 while(!locStringContext
|| locStringContext
->available
>= 0) {
1242 /* find the next '%' */
1244 while(*alias
!= UP_PERCENT
&& *alias
!= 0x0000) {
1248 /* write any characters before the '%' */
1249 if(alias
> lastAlias
) {
1250 *written
+= (streamHandler
->write
)(context
, lastAlias
, (int32_t)(alias
- lastAlias
));
1253 /* break if at end of string */
1254 if(*alias
== 0x0000) {
1258 /* initialize spec to default values */
1259 spec
.fWidthPos
= -1;
1260 spec
.fPrecisionPos
= -1;
1263 uprv_memset(info
, 0, sizeof(*info
));
1264 info
->fPrecision
= -1;
1266 info
->fPadChar
= 0x0020;
1268 /* skip over the initial '%' */
1271 /* Check for positional argument */
1272 if(ISDIGIT(*alias
)) {
1274 /* Save the current position */
1277 /* handle positional parameters */
1278 if(ISDIGIT(*alias
)) {
1279 spec
.fArgPos
= (int) (*alias
++ - DIGIT_ZERO
);
1281 while(ISDIGIT(*alias
)) {
1283 spec
.fArgPos
+= (int) (*alias
++ - DIGIT_ZERO
);
1287 /* if there is no '$', don't read anything */
1288 if(*alias
!= SPEC_DOLLARSIGN
) {
1297 /* Get any format flags */
1298 while(ISFLAG(*alias
)) {
1306 /* always show sign */
1308 info
->fShowSign
= TRUE
;
1311 /* use space if no sign present */
1313 info
->fShowSign
= TRUE
;
1314 info
->fSpace
= TRUE
;
1317 /* use alternate form */
1322 /* pad with leading zeroes */
1325 info
->fPadChar
= 0x0030;
1328 /* pad character specified */
1331 /* TODO test that all four are numbers */
1332 /* first four characters are hex values for pad char */
1333 info
->fPadChar
= (UChar
)ufmt_digitvalue(*alias
++);
1334 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*alias
++));
1335 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*alias
++));
1336 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*alias
++));
1338 /* final character is ignored */
1347 /* width is specified out of line */
1348 if(*alias
== SPEC_ASTERISK
) {
1355 /* Save the current position */
1358 /* handle positional parameters */
1359 if(ISDIGIT(*alias
)) {
1360 spec
.fWidthPos
= (int) (*alias
++ - DIGIT_ZERO
);
1362 while(ISDIGIT(*alias
)) {
1363 spec
.fWidthPos
*= 10;
1364 spec
.fWidthPos
+= (int) (*alias
++ - DIGIT_ZERO
);
1368 /* if there is no '$', don't read anything */
1369 if(*alias
!= SPEC_DOLLARSIGN
) {
1370 spec
.fWidthPos
= -1;
1377 /* read the width, if present */
1378 else if(ISDIGIT(*alias
)){
1379 info
->fWidth
= (int) (*alias
++ - DIGIT_ZERO
);
1381 while(ISDIGIT(*alias
)) {
1383 info
->fWidth
+= (int) (*alias
++ - DIGIT_ZERO
);
1387 /* Get the precision */
1389 if(*alias
== SPEC_PERIOD
) {
1391 /* eat up the '.' */
1394 /* precision is specified out of line */
1395 if(*alias
== SPEC_ASTERISK
) {
1397 info
->fPrecision
= -2;
1402 /* save the current position */
1405 /* handle positional parameters */
1406 if(ISDIGIT(*alias
)) {
1407 spec
.fPrecisionPos
= (int) (*alias
++ - DIGIT_ZERO
);
1409 while(ISDIGIT(*alias
)) {
1410 spec
.fPrecisionPos
*= 10;
1411 spec
.fPrecisionPos
+= (int) (*alias
++ - DIGIT_ZERO
);
1414 /* if there is no '$', don't read anything */
1415 if(*alias
!= SPEC_DOLLARSIGN
) {
1416 spec
.fPrecisionPos
= -1;
1425 /* read the precision */
1426 else if(ISDIGIT(*alias
)){
1427 info
->fPrecision
= (int) (*alias
++ - DIGIT_ZERO
);
1429 while(ISDIGIT(*alias
)) {
1430 info
->fPrecision
*= 10;
1431 info
->fPrecision
+= (int) (*alias
++ - DIGIT_ZERO
);
1436 /* Get any modifiers */
1442 info
->fIsShort
= TRUE
;
1445 /* long or long long */
1447 if(*alias
== MOD_LOWERL
) {
1448 info
->fIsLongLong
= TRUE
;
1449 /* skip over the next 'l' */
1453 info
->fIsLong
= TRUE
;
1458 info
->fIsLongDouble
= TRUE
;
1463 /* finally, get the specifier letter */
1464 info
->fSpec
= *alias
++;
1465 info
->fOrigSpec
= info
->fSpec
;
1467 /* fill in the precision and width, if specified out of line */
1469 /* width specified out of line */
1470 if(spec
.fInfo
.fWidth
== -2) {
1471 if(spec
.fWidthPos
== -1) {
1472 /* read the width from the argument list */
1473 info
->fWidth
= va_arg(ap
, int32_t);
1475 /* else handle positional parameter */
1477 /* if it's negative, take the absolute value and set left alignment */
1478 if(info
->fWidth
< 0) {
1479 info
->fWidth
*= -1; /* Make positive */
1484 /* precision specified out of line */
1485 if(info
->fPrecision
== -2) {
1486 if(spec
.fPrecisionPos
== -1) {
1487 /* read the precision from the argument list */
1488 info
->fPrecision
= va_arg(ap
, int32_t);
1490 /* else handle positional parameter */
1492 /* if it's negative, set it to zero */
1493 if(info
->fPrecision
< 0)
1494 info
->fPrecision
= 0;
1497 handlerNum
= (uint16_t)(info
->fSpec
- UPRINTF_BASE_FMT_HANDLERS
);
1498 if (handlerNum
< UPRINTF_NUM_FMT_HANDLERS
) {
1499 /* query the info function for argument information */
1500 argType
= g_u_printf_infos
[ handlerNum
].info
;
1502 /* goto the correct argument on arg_list if position is specified */
1503 if (spec
.fArgPos
> 0) {
1504 /* offset position by 1 */
1508 /* set the spec's width to the # of chars written */
1509 info
->fWidth
= *written
;
1510 /* fall through to set the pointer */
1514 args
.ptrValue
= arglist
[spec
.fArgPos
].ptrValue
;
1519 args
.int64Value
= arglist
[spec
.fArgPos
].int64Value
;
1522 args
.floatValue
= arglist
[spec
.fArgPos
].floatValue
;
1525 args
.doubleValue
= arglist
[spec
.fArgPos
].doubleValue
;
1528 /* else args is ignored */
1529 args
.ptrValue
= NULL
;
1532 } else { /* no positional argument specified */
1535 /* set the spec's width to the # of chars written */
1536 info
->fWidth
= *written
;
1537 /* fall through to set the pointer */
1541 args
.ptrValue
= va_arg(ap
, void*);
1546 if (info
->fIsLongLong
) {
1547 args
.int64Value
= va_arg(ap
, int64_t);
1550 args
.int64Value
= va_arg(ap
, int32_t);
1554 args
.floatValue
= (float) va_arg(ap
, double);
1557 args
.doubleValue
= va_arg(ap
, double);
1560 /* else args is ignored */
1561 args
.ptrValue
= NULL
;
1566 /* call the handler function */
1567 handler
= g_u_printf_infos
[ handlerNum
].handler
;
1569 *written
+= (*handler
)(streamHandler
, context
, formatBundle
, info
, &args
);
1572 /* just echo unknown tags */
1573 *written
+= (streamHandler
->write
)(context
, fmt
, (int32_t)(alias
- lastAlias
));
1577 /* just echo unknown tags */
1578 *written
+= (streamHandler
->write
)(context
, fmt
, (int32_t)(alias
- lastAlias
));
1581 /* delete parsed argument list */
1582 if (arglist
!= NULL
) {
1585 /* return # of characters in this format that have been parsed. */
1586 return (int32_t)(alias
- fmt
);
1589 #endif /* #if !UCONFIG_NO_FORMATTING */