]> git.saurik.com Git - apple/icu.git/blob - icuSources/io/uprntf_p.c
ICU-8.11.2.tar.gz
[apple/icu.git] / icuSources / io / uprntf_p.c
1 /*
2 ******************************************************************************
3 *
4 * Copyright (C) 1998-2006, International Business Machines
5 * Corporation and others. All Rights Reserved.
6 *
7 ******************************************************************************
8 *
9 * File uprntf_p.c
10 *
11 * Modification History:
12 *
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 ******************************************************************************
18 */
19
20 #include "unicode/utypes.h"
21
22 #if !UCONFIG_NO_FORMATTING
23
24 #include "unicode/ustring.h"
25
26 #include "uprintf.h"
27 #include "ufmt_cmn.h"
28 #include "cmemory.h"
29 #include "putilimp.h"
30
31 /* ANSI style formatting */
32 /* Use US-ASCII characters only for formatting */
33
34 /* % */
35 #define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_printf_simple_percent_handler}
36 /* s */
37 #define UFMT_STRING {ufmt_string, u_printf_string_handler}
38 /* c */
39 #define UFMT_CHAR {ufmt_char, u_printf_char_handler}
40 /* d, i */
41 #define UFMT_INT {ufmt_int, u_printf_integer_handler}
42 /* u */
43 #define UFMT_UINT {ufmt_int, u_printf_uinteger_handler}
44 /* o */
45 #define UFMT_OCTAL {ufmt_int, u_printf_octal_handler}
46 /* x, X */
47 #define UFMT_HEX {ufmt_int, u_printf_hex_handler}
48 /* f */
49 #define UFMT_DOUBLE {ufmt_double, u_printf_double_handler}
50 /* e, E */
51 #define UFMT_SCIENTIFIC {ufmt_double, u_printf_scientific_handler}
52 /* g, G */
53 #define UFMT_SCIDBL {ufmt_double, u_printf_scidbl_handler}
54 /* n */
55 #define UFMT_COUNT {ufmt_count, u_printf_count_handler}
56
57 /* non-ANSI extensions */
58 /* Use US-ASCII characters only for formatting */
59
60 /* p */
61 #define UFMT_POINTER {ufmt_pointer, u_printf_pointer_handler}
62 /* V */
63 #define UFMT_SPELLOUT {ufmt_double, u_printf_spellout_handler}
64 /* P */
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}
70
71
72 #define UFMT_EMPTY {ufmt_empty, NULL}
73
74 /**
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>.
83 */
84 typedef int32_t U_EXPORT2
85 u_printf_handler(const u_printf_stream_handler *handler,
86
87 void *context,
88 ULocaleBundle *formatBundle,
89 const u_printf_spec_info *info,
90 const ufmt_args *args);
91
92 typedef struct u_printf_info {
93 ufmt_type_info info;
94 u_printf_handler *handler;
95 } u_printf_info;
96
97 /**
98 * Struct encapsulating a single uprintf format specification.
99 */
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 */
105 } u_printf_spec;
106
107 #define UPRINTF_NUM_FMT_HANDLERS 108
108
109 /* We do not use handlers for 0-0x1f */
110 #define UPRINTF_BASE_FMT_HANDLERS 0x20
111
112 /* buffer size for formatting */
113 #define UPRINTF_BUFFER_SIZE 1024
114 #define UPRINTF_SYMBOL_BUFFER_SIZE 8
115
116 static const UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
117 static const UChar gSpaceStr[] = {0x20, 0}; /* " " */
118
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? */
121 static void
122 u_printf_set_sign(UNumberFormat *format,
123 const u_printf_spec_info *info,
124 UChar *prefixBuffer,
125 int32_t *prefixBufLen,
126 UErrorCode *status)
127 {
128 if(info->fShowSign) {
129 *prefixBufLen = unum_getTextAttribute(format,
130 UNUM_POSITIVE_PREFIX,
131 prefixBuffer,
132 *prefixBufLen,
133 status);
134 if (info->fSpace) {
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);
138 }
139 else {
140 UChar plusSymbol[UPRINTF_SYMBOL_BUFFER_SIZE];
141 int32_t symbolLen;
142
143 symbolLen = unum_getSymbol(format,
144 UNUM_PLUS_SIGN_SYMBOL,
145 plusSymbol,
146 sizeof(plusSymbol)/sizeof(*plusSymbol),
147 status);
148 unum_setTextAttribute(format,
149 UNUM_POSITIVE_PREFIX,
150 plusSymbol,
151 symbolLen,
152 status);
153 }
154 }
155 else {
156 *prefixBufLen = 0;
157 }
158 }
159
160 static void
161 u_printf_reset_sign(UNumberFormat *format,
162 const u_printf_spec_info *info,
163 UChar *prefixBuffer,
164 int32_t *prefixBufLen,
165 UErrorCode *status)
166 {
167 if(info->fShowSign) {
168 unum_setTextAttribute(format,
169 UNUM_POSITIVE_PREFIX,
170 prefixBuffer,
171 *prefixBufLen,
172 status);
173 }
174 }
175
176
177 /* handle a '%' */
178 static int32_t
179 u_printf_simple_percent_handler(const u_printf_stream_handler *handler,
180 void *context,
181 ULocaleBundle *formatBundle,
182 const u_printf_spec_info *info,
183 const ufmt_args *args)
184 {
185 static const UChar PERCENT[] = { UP_PERCENT };
186
187 /* put a single '%' onto the output */
188 return handler->write(context, PERCENT, 1);
189 }
190
191 /* handle 's' */
192 static int32_t
193 u_printf_string_handler(const u_printf_stream_handler *handler,
194 void *context,
195 ULocaleBundle *formatBundle,
196 const u_printf_spec_info *info,
197 const ufmt_args *args)
198 {
199 UChar *s;
200 UChar buffer[UFMT_DEFAULT_BUFFER_SIZE];
201 int32_t len, written;
202 int32_t argSize;
203 const char *arg = (const char*)(args[0].ptrValue);
204
205 /* convert from the default codepage to Unicode */
206 if (arg) {
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));
212 if(s == NULL) {
213 return 0;
214 }
215 }
216 else {
217 s = ufmt_defaultCPToUnicode(arg, argSize, buffer,
218 sizeof(buffer)/sizeof(UChar));
219 }
220 }
221 else {
222 s = (UChar *)gNullStr;
223 }
224 len = u_strlen(s);
225
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;
230 }
231
232 written = handler->pad_and_justify(context, info, s, len);
233
234 /* clean up */
235 if (gNullStr != s && buffer != s) {
236 uprv_free(s);
237 }
238
239 return written;
240 }
241
242 static int32_t
243 u_printf_char_handler(const u_printf_stream_handler *handler,
244 void *context,
245 ULocaleBundle *formatBundle,
246 const u_printf_spec_info *info,
247 const ufmt_args *args)
248 {
249 UChar s[UTF_MAX_CHAR_LENGTH+1];
250 int32_t len = 1, written;
251 unsigned char arg = (unsigned char)(args[0].int64Value);
252
253 /* convert from default codepage to Unicode */
254 ufmt_defaultCPToUnicode((const char *)&arg, 2, s, sizeof(s)/sizeof(UChar));
255
256 /* Remember that this may be an MBCS character */
257 if (arg != 0) {
258 len = u_strlen(s);
259 }
260
261 /* width = minimum # of characters to write */
262 /* precision = maximum # of characters to write */
263 /* precision is ignored when handling a char */
264
265 written = handler->pad_and_justify(context, info, s, len);
266
267 return written;
268 }
269
270 static int32_t
271 u_printf_double_handler(const u_printf_stream_handler *handler,
272 void *context,
273 ULocaleBundle *formatBundle,
274 const u_printf_spec_info *info,
275 const ufmt_args *args)
276 {
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;
284 int32_t resultLen;
285 UErrorCode status = U_ZERO_ERROR;
286
287 prefixBuffer[0] = 0;
288
289 /* mask off any necessary bits */
290 /* if(! info->fIsLongDouble)
291 num &= DBL_MAX;*/
292
293 /* get the formatter */
294 format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
295
296 /* handle error */
297 if(format == 0)
298 return 0;
299
300 /* save the formatter's state */
301 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
302 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
303
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);
308 }
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);
313 }
314 else {
315 /* # of decimal digits is 6 if precision not specified regardless of locale */
316 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
317 }
318
319 /* set whether to show the sign */
320 if (info->fShowSign) {
321 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
322 }
323
324 /* format the number */
325 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
326
327 if (U_FAILURE(status)) {
328 resultLen = 0;
329 }
330
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);
335
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);
340 }
341
342 return handler->pad_and_justify(context, info, result, resultLen);
343 }
344
345 /* HSYS */
346 static int32_t
347 u_printf_integer_handler(const u_printf_stream_handler *handler,
348 void *context,
349 ULocaleBundle *formatBundle,
350 const u_printf_spec_info *info,
351 const ufmt_args *args)
352 {
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;
359 int32_t resultLen;
360 UErrorCode status = U_ZERO_ERROR;
361
362 prefixBuffer[0] = 0;
363
364 /* mask off any necessary bits */
365 if (info->fIsShort)
366 num = (int16_t)num;
367 else if (!info->fIsLongLong)
368 num = (int32_t)num;
369
370 /* get the formatter */
371 format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
372
373 /* handle error */
374 if(format == 0)
375 return 0;
376
377 /* set the appropriate flags on the formatter */
378
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);
384 }
385
386 /* set whether to show the sign */
387 if(info->fShowSign) {
388 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
389 }
390
391 /* format the number */
392 resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
393
394 if (U_FAILURE(status)) {
395 resultLen = 0;
396 }
397
398 /* restore the number format */
399 if (minDigits != -1) {
400 unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
401 }
402
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);
407 }
408
409 return handler->pad_and_justify(context, info, result, resultLen);
410 }
411
412 static int32_t
413 u_printf_hex_handler(const u_printf_stream_handler *handler,
414 void *context,
415 ULocaleBundle *formatBundle,
416 const u_printf_spec_info *info,
417 const ufmt_args *args)
418 {
419 int64_t num = args[0].int64Value;
420 UChar result[UPRINTF_BUFFER_SIZE];
421 int32_t len = UPRINTF_BUFFER_SIZE;
422
423
424 /* mask off any necessary bits */
425 if (info->fIsShort)
426 num &= UINT16_MAX;
427 else if (!info->fIsLongLong)
428 num &= UINT32_MAX;
429
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);
434
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));
439 result[0] = 0x0030;
440 result[1] = info->fSpec;
441 len += 2;
442 }
443
444 return handler->pad_and_justify(context, info, result, len);
445 }
446
447 static int32_t
448 u_printf_octal_handler(const u_printf_stream_handler *handler,
449 void *context,
450 ULocaleBundle *formatBundle,
451 const u_printf_spec_info *info,
452 const ufmt_args *args)
453 {
454 int64_t num = args[0].int64Value;
455 UChar result[UPRINTF_BUFFER_SIZE];
456 int32_t len = UPRINTF_BUFFER_SIZE;
457
458
459 /* mask off any necessary bits */
460 if (info->fIsShort)
461 num &= UINT16_MAX;
462 else if (!info->fIsLongLong)
463 num &= UINT32_MAX;
464
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);
469
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));
474 result[0] = 0x0030;
475 len += 1;
476 }
477
478 return handler->pad_and_justify(context, info, result, len);
479 }
480
481 static int32_t
482 u_printf_uinteger_handler(const u_printf_stream_handler *handler,
483 void *context,
484 ULocaleBundle *formatBundle,
485 const u_printf_spec_info *info,
486 const ufmt_args *args)
487 {
488 int64_t num = args[0].int64Value;
489 UNumberFormat *format;
490 UChar result[UPRINTF_BUFFER_SIZE];
491 int32_t minDigits = -1;
492 int32_t resultLen;
493 UErrorCode status = U_ZERO_ERROR;
494
495 /* TODO: Fix this once uint64_t can be formatted. */
496 if (info->fIsShort)
497 num &= UINT16_MAX;
498 else if (!info->fIsLongLong)
499 num &= UINT32_MAX;
500
501 /* get the formatter */
502 format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
503
504 /* handle error */
505 if(format == 0)
506 return 0;
507
508 /* set the appropriate flags on the formatter */
509
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);
515 }
516
517 /* To mirror other stdio implementations, we ignore the sign argument */
518
519 /* format the number */
520 resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
521
522 if (U_FAILURE(status)) {
523 resultLen = 0;
524 }
525
526 /* restore the number format */
527 if (minDigits != -1) {
528 unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
529 }
530
531 return handler->pad_and_justify(context, info, result, resultLen);
532 }
533
534 static int32_t
535 u_printf_pointer_handler(const u_printf_stream_handler *handler,
536 void *context,
537 ULocaleBundle *formatBundle,
538 const u_printf_spec_info *info,
539 const ufmt_args *args)
540 {
541 UChar result[UPRINTF_BUFFER_SIZE];
542 int32_t len = UPRINTF_BUFFER_SIZE;
543
544 /* format the pointer in hex */
545 ufmt_ptou(result, &len, args[0].ptrValue, TRUE/*, info->fPrecision*/);
546
547 return handler->pad_and_justify(context, info, result, len);
548 }
549
550 static int32_t
551 u_printf_scientific_handler(const u_printf_stream_handler *handler,
552 void *context,
553 ULocaleBundle *formatBundle,
554 const u_printf_spec_info *info,
555 const ufmt_args *args)
556 {
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;
567 int32_t resultLen;
568 UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
569
570 prefixBuffer[0] = 0;
571
572 /* mask off any necessary bits */
573 /* if(! info->fIsLongDouble)
574 num &= DBL_MAX;*/
575
576 /* get the formatter */
577 format = u_locbund_getNumberFormat(formatBundle, UNUM_SCIENTIFIC);
578
579 /* handle error */
580 if(format == 0)
581 return 0;
582
583 /* set the appropriate flags on the formatter */
584
585 srcLen = unum_getSymbol(format,
586 UNUM_EXPONENTIAL_SYMBOL,
587 srcExpBuf,
588 sizeof(srcExpBuf),
589 &status);
590
591 /* Upper/lower case the e */
592 if (info->fSpec == (UChar)0x65 /* e */) {
593 expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
594 srcExpBuf, srcLen,
595 formatBundle->fLocale,
596 &status);
597 }
598 else {
599 expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
600 srcExpBuf, srcLen,
601 formatBundle->fLocale,
602 &status);
603 }
604
605 unum_setSymbol(format,
606 UNUM_EXPONENTIAL_SYMBOL,
607 expBuf,
608 expLen,
609 &status);
610
611 /* save the formatter's state */
612 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
613 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
614
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);
620 }
621 else {
622 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, 1);
623 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, info->fPrecision);
624 }
625 }
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);
630 }
631 else {
632 /* # of decimal digits is 6 if precision not specified */
633 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
634 }
635
636 /* set whether to show the sign */
637 if (info->fShowSign) {
638 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
639 }
640
641 /* format the number */
642 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
643
644 if (U_FAILURE(status)) {
645 resultLen = 0;
646 }
647
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);
652
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,
657 srcExpBuf,
658 srcLen,
659 &status);*/
660
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);
665 }
666
667 return handler->pad_and_justify(context, info, result, resultLen);
668 }
669
670 static int32_t
671 u_printf_percent_handler(const u_printf_stream_handler *handler,
672 void *context,
673 ULocaleBundle *formatBundle,
674 const u_printf_spec_info *info,
675 const ufmt_args *args)
676 {
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;
684 int32_t resultLen;
685 UErrorCode status = U_ZERO_ERROR;
686
687 prefixBuffer[0] = 0;
688
689 /* mask off any necessary bits */
690 /* if(! info->fIsLongDouble)
691 num &= DBL_MAX;*/
692
693 /* get the formatter */
694 format = u_locbund_getNumberFormat(formatBundle, UNUM_PERCENT);
695
696 /* handle error */
697 if(format == 0)
698 return 0;
699
700 /* save the formatter's state */
701 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
702 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
703
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);
708 }
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);
713 }
714 else {
715 /* # of decimal digits is 6 if precision not specified */
716 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
717 }
718
719 /* set whether to show the sign */
720 if (info->fShowSign) {
721 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
722 }
723
724 /* format the number */
725 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
726
727 if (U_FAILURE(status)) {
728 resultLen = 0;
729 }
730
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);
735
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);
740 }
741
742 return handler->pad_and_justify(context, info, result, resultLen);
743 }
744
745 static int32_t
746 u_printf_ustring_handler(const u_printf_stream_handler *handler,
747 void *context,
748 ULocaleBundle *formatBundle,
749 const u_printf_spec_info *info,
750 const ufmt_args *args)
751 {
752 int32_t len, written;
753 const UChar *arg = (const UChar*)(args[0].ptrValue);
754
755 /* allocate enough space for the buffer */
756 if (arg == NULL) {
757 arg = gNullStr;
758 }
759 len = u_strlen(arg);
760
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;
765 }
766
767 /* determine if the string should be padded */
768 written = handler->pad_and_justify(context, info, arg, len);
769
770 return written;
771 }
772
773 static int32_t
774 u_printf_uchar_handler(const u_printf_stream_handler *handler,
775 void *context,
776 ULocaleBundle *formatBundle,
777 const u_printf_spec_info *info,
778 const ufmt_args *args)
779 {
780 int32_t written = 0;
781 UChar arg = (UChar)(args[0].int64Value);
782
783 /* width = minimum # of characters to write */
784 /* precision = maximum # of characters to write */
785 /* precision is ignored when handling a uchar */
786
787 /* determine if the string should be padded */
788 written = handler->pad_and_justify(context, info, &arg, 1);
789
790 return written;
791 }
792
793 static int32_t
794 u_printf_scidbl_handler(const u_printf_stream_handler *handler,
795 void *context,
796 ULocaleBundle *formatBundle,
797 const u_printf_spec_info *info,
798 const ufmt_args *args)
799 {
800 u_printf_spec_info scidbl_info;
801 double num = args[0].doubleValue;
802 int32_t retVal;
803
804 memcpy(&scidbl_info, info, sizeof(u_printf_spec_info));
805
806 /* determine whether to use 'd', 'e' or 'f' notation */
807 if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num))
808 {
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);
814 }
815 else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num)
816 || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision)))
817 {
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;
822 }
823 /* call the scientific handler */
824 retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args);
825 }
826 else {
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;
830
831 /* use 'f' notation */
832 scidbl_info.fSpec = 0x0066;
833 if (significantDigits == -1) {
834 significantDigits = 6;
835 }
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);
842 }
843 return retVal;
844 }
845
846 static int32_t
847 u_printf_count_handler(const u_printf_stream_handler *handler,
848 void *context,
849 ULocaleBundle *formatBundle,
850 const u_printf_spec_info *info,
851 const ufmt_args *args)
852 {
853 int32_t *count = (int32_t*)(args[0].ptrValue);
854
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;
858
859 return 0;
860 }
861
862 static int32_t
863 u_printf_spellout_handler(const u_printf_stream_handler *handler,
864 void *context,
865 ULocaleBundle *formatBundle,
866 const u_printf_spec_info *info,
867 const ufmt_args *args)
868 {
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;
876 int32_t resultLen;
877 UErrorCode status = U_ZERO_ERROR;
878
879 prefixBuffer[0] = 0;
880
881 /* mask off any necessary bits */
882 /* if(! info->fIsLongDouble)
883 num &= DBL_MAX;*/
884
885 /* get the formatter */
886 format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT);
887
888 /* handle error */
889 if(format == 0)
890 return 0;
891
892 /* save the formatter's state */
893 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
894 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
895
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);
900 }
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);
905 }
906 else {
907 /* # of decimal digits is 6 if precision not specified */
908 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
909 }
910
911 /* set whether to show the sign */
912 if (info->fShowSign) {
913 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
914 }
915
916 /* format the number */
917 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
918
919 if (U_FAILURE(status)) {
920 resultLen = 0;
921 }
922
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);
927
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);
932 }
933
934 return handler->pad_and_justify(context, info, result, resultLen);
935 }
936
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] = {
942 /* 0x20 */
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,
947
948 /* 0x30 */
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,
953
954 /* 0x40 */
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*/,
959 #else
960 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
961 #endif
962 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
963
964 /* 0x50 */
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,
968 #else
969 UFMT_EMPTY, UFMT_EMPTY, UFMT_SPELLOUT, UFMT_EMPTY,
970 #endif
971 UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
972 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
973
974 /* 0x60 */
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,
979
980 /* 0x70 */
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,
985 };
986
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
994
995 #define ISFLAG(s) (s) == FLAG_MINUS || \
996 (s) == FLAG_PLUS || \
997 (s) == FLAG_SPACE || \
998 (s) == FLAG_POUND || \
999 (s) == FLAG_ZERO || \
1000 (s) == FLAG_PAREN
1001
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
1007
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
1019
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 || \
1029 (s) == DIGIT_NINE
1030
1031 /* u_printf modifiers */
1032 #define MOD_H 0x0068
1033 #define MOD_LOWERL 0x006C
1034 #define MOD_L 0x004C
1035
1036 #define ISMOD(s) (s) == MOD_H || \
1037 (s) == MOD_LOWERL || \
1038 (s) == MOD_L
1039
1040 /* We parse the argument list in Unicode */
1041 U_CFUNC int32_t
1042 u_printf_parse(const u_printf_stream_handler *streamHandler,
1043 const UChar *fmt,
1044 void *context,
1045 u_localized_print_string *locStringContext,
1046 ULocaleBundle *formatBundle,
1047 int32_t *written,
1048 va_list ap)
1049 {
1050 uint16_t handlerNum;
1051 ufmt_args args;
1052 ufmt_type_info argType;
1053 u_printf_handler *handler;
1054 u_printf_spec spec;
1055 u_printf_spec_info *info = &(spec.fInfo);
1056
1057 const UChar *alias = fmt;
1058 const UChar *backup;
1059 const UChar *lastAlias;
1060
1061 /* iterate through the pattern */
1062 while(!locStringContext || locStringContext->available > 0) {
1063
1064 /* find the next '%' */
1065 lastAlias = alias;
1066 while(*alias != UP_PERCENT && *alias != 0x0000) {
1067 alias++;
1068 }
1069
1070 /* write any characters before the '%' */
1071 if(alias > lastAlias) {
1072 *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias));
1073 }
1074
1075 /* break if at end of string */
1076 if(*alias == 0x0000) {
1077 break;
1078 }
1079
1080 /* initialize spec to default values */
1081 spec.fWidthPos = -1;
1082 spec.fPrecisionPos = -1;
1083 spec.fArgPos = -1;
1084
1085 uprv_memset(info, 0, sizeof(*info));
1086 info->fPrecision = -1;
1087 info->fWidth = -1;
1088 info->fPadChar = 0x0020;
1089
1090 /* skip over the initial '%' */
1091 alias++;
1092
1093 /* Check for positional argument */
1094 if(ISDIGIT(*alias)) {
1095
1096 /* Save the current position */
1097 backup = alias;
1098
1099 /* handle positional parameters */
1100 if(ISDIGIT(*alias)) {
1101 spec.fArgPos = (int) (*alias++ - DIGIT_ZERO);
1102
1103 while(ISDIGIT(*alias)) {
1104 spec.fArgPos *= 10;
1105 spec.fArgPos += (int) (*alias++ - DIGIT_ZERO);
1106 }
1107 }
1108
1109 /* if there is no '$', don't read anything */
1110 if(*alias != SPEC_DOLLARSIGN) {
1111 spec.fArgPos = -1;
1112 alias = backup;
1113 }
1114 /* munge the '$' */
1115 else
1116 alias++;
1117 }
1118
1119 /* Get any format flags */
1120 while(ISFLAG(*alias)) {
1121 switch(*alias++) {
1122
1123 /* left justify */
1124 case FLAG_MINUS:
1125 info->fLeft = TRUE;
1126 break;
1127
1128 /* always show sign */
1129 case FLAG_PLUS:
1130 info->fShowSign = TRUE;
1131 break;
1132
1133 /* use space if no sign present */
1134 case FLAG_SPACE:
1135 info->fShowSign = TRUE;
1136 info->fSpace = TRUE;
1137 break;
1138
1139 /* use alternate form */
1140 case FLAG_POUND:
1141 info->fAlt = TRUE;
1142 break;
1143
1144 /* pad with leading zeroes */
1145 case FLAG_ZERO:
1146 info->fZero = TRUE;
1147 info->fPadChar = 0x0030;
1148 break;
1149
1150 /* pad character specified */
1151 case FLAG_PAREN:
1152
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++));
1159
1160 /* final character is ignored */
1161 alias++;
1162
1163 break;
1164 }
1165 }
1166
1167 /* Get the width */
1168
1169 /* width is specified out of line */
1170 if(*alias == SPEC_ASTERISK) {
1171
1172 info->fWidth = -2;
1173
1174 /* Skip the '*' */
1175 alias++;
1176
1177 /* Save the current position */
1178 backup = alias;
1179
1180 /* handle positional parameters */
1181 if(ISDIGIT(*alias)) {
1182 spec.fWidthPos = (int) (*alias++ - DIGIT_ZERO);
1183
1184 while(ISDIGIT(*alias)) {
1185 spec.fWidthPos *= 10;
1186 spec.fWidthPos += (int) (*alias++ - DIGIT_ZERO);
1187 }
1188 }
1189
1190 /* if there is no '$', don't read anything */
1191 if(*alias != SPEC_DOLLARSIGN) {
1192 spec.fWidthPos = -1;
1193 alias = backup;
1194 }
1195 /* munge the '$' */
1196 else
1197 alias++;
1198 }
1199 /* read the width, if present */
1200 else if(ISDIGIT(*alias)){
1201 info->fWidth = (int) (*alias++ - DIGIT_ZERO);
1202
1203 while(ISDIGIT(*alias)) {
1204 info->fWidth *= 10;
1205 info->fWidth += (int) (*alias++ - DIGIT_ZERO);
1206 }
1207 }
1208
1209 /* Get the precision */
1210
1211 if(*alias == SPEC_PERIOD) {
1212
1213 /* eat up the '.' */
1214 alias++;
1215
1216 /* precision is specified out of line */
1217 if(*alias == SPEC_ASTERISK) {
1218
1219 info->fPrecision = -2;
1220
1221 /* Skip the '*' */
1222 alias++;
1223
1224 /* save the current position */
1225 backup = alias;
1226
1227 /* handle positional parameters */
1228 if(ISDIGIT(*alias)) {
1229 spec.fPrecisionPos = (int) (*alias++ - DIGIT_ZERO);
1230
1231 while(ISDIGIT(*alias)) {
1232 spec.fPrecisionPos *= 10;
1233 spec.fPrecisionPos += (int) (*alias++ - DIGIT_ZERO);
1234 }
1235
1236 /* if there is no '$', don't read anything */
1237 if(*alias != SPEC_DOLLARSIGN) {
1238 spec.fPrecisionPos = -1;
1239 alias = backup;
1240 }
1241 else {
1242 /* munge the '$' */
1243 alias++;
1244 }
1245 }
1246 }
1247 /* read the precision */
1248 else if(ISDIGIT(*alias)){
1249 info->fPrecision = (int) (*alias++ - DIGIT_ZERO);
1250
1251 while(ISDIGIT(*alias)) {
1252 info->fPrecision *= 10;
1253 info->fPrecision += (int) (*alias++ - DIGIT_ZERO);
1254 }
1255 }
1256 }
1257
1258 /* Get any modifiers */
1259 if(ISMOD(*alias)) {
1260 switch(*alias++) {
1261
1262 /* short */
1263 case MOD_H:
1264 info->fIsShort = TRUE;
1265 break;
1266
1267 /* long or long long */
1268 case MOD_LOWERL:
1269 if(*alias == MOD_LOWERL) {
1270 info->fIsLongLong = TRUE;
1271 /* skip over the next 'l' */
1272 alias++;
1273 }
1274 else
1275 info->fIsLong = TRUE;
1276 break;
1277
1278 /* long double */
1279 case MOD_L:
1280 info->fIsLongDouble = TRUE;
1281 break;
1282 }
1283 }
1284
1285 /* finally, get the specifier letter */
1286 info->fSpec = *alias++;
1287 info->fOrigSpec = info->fSpec;
1288
1289 /* fill in the precision and width, if specified out of line */
1290
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);
1296 }
1297 /* else handle positional parameter */
1298
1299 /* if it's negative, take the absolute value and set left alignment */
1300 if(info->fWidth < 0) {
1301 info->fWidth *= -1; /* Make positive */
1302 info->fLeft = TRUE;
1303 }
1304 }
1305
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);
1311 }
1312 /* else handle positional parameter */
1313
1314 /* if it's negative, set it to zero */
1315 if(info->fPrecision < 0)
1316 info->fPrecision = 0;
1317 }
1318
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;
1323 switch(argType) {
1324 case ufmt_count:
1325 /* set the spec's width to the # of chars written */
1326 info->fWidth = *written;
1327 /* fall through to set the pointer */
1328 case ufmt_string:
1329 case ufmt_ustring:
1330 case ufmt_pointer:
1331 args.ptrValue = va_arg(ap, void*);
1332 break;
1333 case ufmt_char:
1334 case ufmt_uchar:
1335 case ufmt_int:
1336 if (info->fIsLongLong) {
1337 args.int64Value = va_arg(ap, int64_t);
1338 }
1339 else {
1340 args.int64Value = va_arg(ap, int32_t);
1341 }
1342 break;
1343 case ufmt_float:
1344 args.floatValue = (float) va_arg(ap, double);
1345 break;
1346 case ufmt_double:
1347 args.doubleValue = va_arg(ap, double);
1348 break;
1349 default:
1350 /* else args is ignored */
1351 args.ptrValue = NULL;
1352 break;
1353 }
1354
1355 /* call the handler function */
1356 handler = g_u_printf_infos[ handlerNum ].handler;
1357 if(handler != 0) {
1358 *written += (*handler)(streamHandler, context, formatBundle, info, &args);
1359 }
1360 else {
1361 /* just echo unknown tags */
1362 *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
1363 }
1364 }
1365 else {
1366 /* just echo unknown tags */
1367 *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
1368 }
1369 }
1370 /* return # of characters in this format that have been parsed. */
1371 return (int32_t)(alias - fmt);
1372 }
1373
1374 #endif /* #if !UCONFIG_NO_FORMATTING */