]> git.saurik.com Git - apple/icu.git/blame - icuSources/io/uprntf_p.c
ICU-6.2.22.tar.gz
[apple/icu.git] / icuSources / io / uprntf_p.c
CommitLineData
374ca955
A
1/*
2******************************************************************************
3*
4* Copyright (C) 1998-2004, 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 */
84typedef int32_t U_EXPORT2
85u_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
92typedef 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 */
100typedef 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
116static const UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
117static 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? */
121static void
122u_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
160static void
161u_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 '%' */
178static int32_t
179u_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' */
192static int32_t
193u_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
229 /* precision takes precedence over width */
230 /* determine if the string should be truncated */
231 if(info->fPrecision != -1 && len > info->fPrecision) {
232 written = handler->write(context, s, info->fPrecision);
233 }
234 /* determine if the string should be padded */
235 else {
236 written = handler->pad_and_justify(context, info, s, len);
237 }
238
239 /* clean up */
240 if (gNullStr != s && buffer != s) {
241 uprv_free(s);
242 }
243
244 return written;
245}
246
247static int32_t
248u_printf_char_handler(const u_printf_stream_handler *handler,
249 void *context,
250 ULocaleBundle *formatBundle,
251 const u_printf_spec_info *info,
252 const ufmt_args *args)
253{
254 UChar s[UTF_MAX_CHAR_LENGTH+1];
255 int32_t len = 1, written;
256 unsigned char arg = (unsigned char)(args[0].int64Value);
257
258 /* convert from default codepage to Unicode */
259 ufmt_defaultCPToUnicode((const char *)&arg, 2, s, sizeof(s)/sizeof(UChar));
260
261 /* Remember that this may be an MBCS character */
262 if (arg != 0) {
263 len = u_strlen(s);
264 }
265
266 /* width = minimum # of characters to write */
267 /* precision = maximum # of characters to write */
268
269 /* precision takes precedence over width */
270 /* determine if the string should be truncated */
271 if(info->fPrecision != -1 && len > info->fPrecision) {
272 written = handler->write(context, s, info->fPrecision);
273 }
274 else {
275 /* determine if the string should be padded */
276 written = handler->pad_and_justify(context, info, s, len);
277 }
278
279 return written;
280}
281
282static int32_t
283u_printf_double_handler(const u_printf_stream_handler *handler,
284 void *context,
285 ULocaleBundle *formatBundle,
286 const u_printf_spec_info *info,
287 const ufmt_args *args)
288{
289 double num = (double) (args[0].doubleValue);
290 UNumberFormat *format;
291 UChar result[UPRINTF_BUFFER_SIZE];
292 UChar prefixBuffer[UPRINTF_BUFFER_SIZE];
293 int32_t prefixBufferLen = sizeof(prefixBuffer);
294 int32_t minDecimalDigits;
295 int32_t maxDecimalDigits;
296 int32_t resultLen;
297 UErrorCode status = U_ZERO_ERROR;
298
299 prefixBuffer[0] = 0;
300
301 /* mask off any necessary bits */
302 /* if(! info->fIsLongDouble)
303 num &= DBL_MAX;*/
304
305 /* get the formatter */
306 format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
307
308 /* handle error */
309 if(format == 0)
310 return 0;
311
312 /* save the formatter's state */
313 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
314 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
315
316 /* set the appropriate flags and number of decimal digits on the formatter */
317 if(info->fPrecision != -1) {
318 /* set the # of decimal digits */
319 unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
320 }
321 else if(info->fAlt) {
322 /* '#' means always show decimal point */
323 /* copy of printf behavior on Solaris - '#' shows 6 digits */
324 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
325 }
326 else {
327 /* # of decimal digits is 6 if precision not specified regardless of locale */
328 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
329 }
330
331 /* set whether to show the sign */
332 if (info->fShowSign) {
333 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
334 }
335
336 /* format the number */
337 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
338
339 if (U_FAILURE(status)) {
340 resultLen = 0;
341 }
342
343 /* restore the number format */
344 /* TODO: Is this needed? */
345 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
346 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
347
348 if (info->fShowSign) {
349 /* Reset back to original value regardless of what the error was */
350 UErrorCode localStatus = U_ZERO_ERROR;
351 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
352 }
353
354 return handler->pad_and_justify(context, info, result, resultLen);
355}
356
357/* HSYS */
358static int32_t
359u_printf_integer_handler(const u_printf_stream_handler *handler,
360 void *context,
361 ULocaleBundle *formatBundle,
362 const u_printf_spec_info *info,
363 const ufmt_args *args)
364{
365 int64_t num = args[0].int64Value;
366 UNumberFormat *format;
367 UChar result[UPRINTF_BUFFER_SIZE];
368 UChar prefixBuffer[UPRINTF_BUFFER_SIZE];
369 int32_t prefixBufferLen = sizeof(prefixBuffer);
370 int32_t minDigits = -1;
371 int32_t resultLen;
372 UErrorCode status = U_ZERO_ERROR;
373
374 prefixBuffer[0] = 0;
375
376 /* mask off any necessary bits */
377 if (info->fIsShort)
378 num = (int16_t)num;
379 else if (!info->fIsLongLong)
380 num = (int32_t)num;
381
382 /* get the formatter */
383 format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
384
385 /* handle error */
386 if(format == 0)
387 return 0;
388
389 /* set the appropriate flags on the formatter */
390
391 /* set the minimum integer digits */
392 if(info->fPrecision != -1) {
393 /* set the minimum # of digits */
394 minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
395 unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
396 }
397
398 /* set whether to show the sign */
399 if(info->fShowSign) {
400 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
401 }
402
403 /* format the number */
404 resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
405
406 if (U_FAILURE(status)) {
407 resultLen = 0;
408 }
409
410 /* restore the number format */
411 if (minDigits != -1) {
412 unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
413 }
414
415 if (info->fShowSign) {
416 /* Reset back to original value regardless of what the error was */
417 UErrorCode localStatus = U_ZERO_ERROR;
418 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
419 }
420
421 return handler->pad_and_justify(context, info, result, resultLen);
422}
423
424static int32_t
425u_printf_hex_handler(const u_printf_stream_handler *handler,
426 void *context,
427 ULocaleBundle *formatBundle,
428 const u_printf_spec_info *info,
429 const ufmt_args *args)
430{
431 int64_t num = args[0].int64Value;
432 UChar result[UPRINTF_BUFFER_SIZE];
433 int32_t len = UPRINTF_BUFFER_SIZE;
434
435
436 /* mask off any necessary bits */
437 if (info->fIsShort)
438 num &= UINT16_MAX;
439 else if (!info->fIsLongLong)
440 num &= UINT32_MAX;
441
442 /* format the number, preserving the minimum # of digits */
443 ufmt_64tou(result, &len, num, 16,
444 (UBool)(info->fSpec == 0x0078),
445 (info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);
446
447 /* convert to alt form, if desired */
448 if(num != 0 && info->fAlt && len < UPRINTF_BUFFER_SIZE - 2) {
449 /* shift the formatted string right by 2 chars */
450 memmove(result + 2, result, len * sizeof(UChar));
451 result[0] = 0x0030;
452 result[1] = info->fSpec;
453 len += 2;
454 }
455
456 return handler->pad_and_justify(context, info, result, len);
457}
458
459static int32_t
460u_printf_octal_handler(const u_printf_stream_handler *handler,
461 void *context,
462 ULocaleBundle *formatBundle,
463 const u_printf_spec_info *info,
464 const ufmt_args *args)
465{
466 int64_t num = args[0].int64Value;
467 UChar result[UPRINTF_BUFFER_SIZE];
468 int32_t len = UPRINTF_BUFFER_SIZE;
469
470
471 /* mask off any necessary bits */
472 if (info->fIsShort)
473 num &= UINT16_MAX;
474 else if (!info->fIsLongLong)
475 num &= UINT32_MAX;
476
477 /* format the number, preserving the minimum # of digits */
478 ufmt_64tou(result, &len, num, 8,
479 FALSE, /* doesn't matter for octal */
480 info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);
481
482 /* convert to alt form, if desired */
483 if(info->fAlt && result[0] != 0x0030 && len < UPRINTF_BUFFER_SIZE - 1) {
484 /* shift the formatted string right by 1 char */
485 memmove(result + 1, result, len * sizeof(UChar));
486 result[0] = 0x0030;
487 len += 1;
488 }
489
490 return handler->pad_and_justify(context, info, result, len);
491}
492
493static int32_t
494u_printf_uinteger_handler(const u_printf_stream_handler *handler,
495 void *context,
496 ULocaleBundle *formatBundle,
497 const u_printf_spec_info *info,
498 const ufmt_args *args)
499{
500 int64_t num = args[0].int64Value;
501 UNumberFormat *format;
502 UChar result[UPRINTF_BUFFER_SIZE];
503 int32_t minDigits = -1;
504 int32_t resultLen;
505 UErrorCode status = U_ZERO_ERROR;
506
507 /* TODO: Fix this once uint64_t can be formatted. */
508 if (info->fIsShort)
509 num &= UINT16_MAX;
510 else if (!info->fIsLongLong)
511 num &= UINT32_MAX;
512
513 /* get the formatter */
514 format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
515
516 /* handle error */
517 if(format == 0)
518 return 0;
519
520 /* set the appropriate flags on the formatter */
521
522 /* set the minimum integer digits */
523 if(info->fPrecision != -1) {
524 /* set the minimum # of digits */
525 minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
526 unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
527 }
528
529 /* To mirror other stdio implementations, we ignore the sign argument */
530
531 /* format the number */
532 resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
533
534 if (U_FAILURE(status)) {
535 resultLen = 0;
536 }
537
538 /* restore the number format */
539 if (minDigits != -1) {
540 unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
541 }
542
543 return handler->pad_and_justify(context, info, result, resultLen);
544}
545
546static int32_t
547u_printf_pointer_handler(const u_printf_stream_handler *handler,
548 void *context,
549 ULocaleBundle *formatBundle,
550 const u_printf_spec_info *info,
551 const ufmt_args *args)
552{
553 UChar result[UPRINTF_BUFFER_SIZE];
554 int32_t len = UPRINTF_BUFFER_SIZE;
555
556 /* format the pointer in hex */
557 ufmt_ptou(result, &len, args[0].ptrValue, TRUE/*, info->fPrecision*/);
558
559 return handler->pad_and_justify(context, info, result, len);
560}
561
562static int32_t
563u_printf_scientific_handler(const u_printf_stream_handler *handler,
564 void *context,
565 ULocaleBundle *formatBundle,
566 const u_printf_spec_info *info,
567 const ufmt_args *args)
568{
569 double num = (double) (args[0].doubleValue);
570 UNumberFormat *format;
571 UChar result[UPRINTF_BUFFER_SIZE];
572 UChar prefixBuffer[UPRINTF_BUFFER_SIZE];
573 int32_t prefixBufferLen = sizeof(prefixBuffer);
574 int32_t minDecimalDigits;
575 int32_t maxDecimalDigits;
576 UErrorCode status = U_ZERO_ERROR;
577 UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
578 int32_t srcLen, expLen;
579 int32_t resultLen;
580 UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
581
582 prefixBuffer[0] = 0;
583
584 /* mask off any necessary bits */
585 /* if(! info->fIsLongDouble)
586 num &= DBL_MAX;*/
587
588 /* get the formatter */
589 format = u_locbund_getNumberFormat(formatBundle, UNUM_SCIENTIFIC);
590
591 /* handle error */
592 if(format == 0)
593 return 0;
594
595 /* set the appropriate flags on the formatter */
596
597 srcLen = unum_getSymbol(format,
598 UNUM_EXPONENTIAL_SYMBOL,
599 srcExpBuf,
600 sizeof(srcExpBuf),
601 &status);
602
603 /* Upper/lower case the e */
604 if (info->fSpec == (UChar)0x65 /* e */) {
605 expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
606 srcExpBuf, srcLen,
607 formatBundle->fLocale,
608 &status);
609 }
610 else {
611 expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
612 srcExpBuf, srcLen,
613 formatBundle->fLocale,
614 &status);
615 }
616
617 unum_setSymbol(format,
618 UNUM_EXPONENTIAL_SYMBOL,
619 expBuf,
620 expLen,
621 &status);
622
623 /* save the formatter's state */
624 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
625 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
626
627 /* set the appropriate flags and number of decimal digits on the formatter */
628 if(info->fPrecision != -1) {
629 /* set the # of decimal digits */
630 unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
631 }
632 else if(info->fAlt) {
633 /* '#' means always show decimal point */
634 /* copy of printf behavior on Solaris - '#' shows 6 digits */
635 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
636 }
637 else {
638 /* # of decimal digits is 6 if precision not specified */
639 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
640 }
641
642 /* set whether to show the sign */
643 if (info->fShowSign) {
644 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
645 }
646
647 /* format the number */
648 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
649
650 if (U_FAILURE(status)) {
651 resultLen = 0;
652 }
653
654 /* restore the number format */
655 /* TODO: Is this needed? */
656 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
657 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
658
659 /* Since we're the only one using the scientific
660 format, we don't need to save the old exponent value. */
661 /*unum_setSymbol(format,
662 UNUM_EXPONENTIAL_SYMBOL,
663 srcExpBuf,
664 srcLen,
665 &status);*/
666
667 if (info->fShowSign) {
668 /* Reset back to original value regardless of what the error was */
669 UErrorCode localStatus = U_ZERO_ERROR;
670 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
671 }
672
673 return handler->pad_and_justify(context, info, result, resultLen);
674}
675
676static int32_t
677u_printf_percent_handler(const u_printf_stream_handler *handler,
678 void *context,
679 ULocaleBundle *formatBundle,
680 const u_printf_spec_info *info,
681 const ufmt_args *args)
682{
683 double num = (double) (args[0].doubleValue);
684 UNumberFormat *format;
685 UChar result[UPRINTF_BUFFER_SIZE];
686 UChar prefixBuffer[UPRINTF_BUFFER_SIZE];
687 int32_t prefixBufferLen = sizeof(prefixBuffer);
688 int32_t minDecimalDigits;
689 int32_t maxDecimalDigits;
690 int32_t resultLen;
691 UErrorCode status = U_ZERO_ERROR;
692
693 prefixBuffer[0] = 0;
694
695 /* mask off any necessary bits */
696 /* if(! info->fIsLongDouble)
697 num &= DBL_MAX;*/
698
699 /* get the formatter */
700 format = u_locbund_getNumberFormat(formatBundle, UNUM_PERCENT);
701
702 /* handle error */
703 if(format == 0)
704 return 0;
705
706 /* save the formatter's state */
707 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
708 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
709
710 /* set the appropriate flags and number of decimal digits on the formatter */
711 if(info->fPrecision != -1) {
712 /* set the # of decimal digits */
713 unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
714 }
715 else if(info->fAlt) {
716 /* '#' means always show decimal point */
717 /* copy of printf behavior on Solaris - '#' shows 6 digits */
718 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
719 }
720 else {
721 /* # of decimal digits is 6 if precision not specified */
722 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
723 }
724
725 /* set whether to show the sign */
726 if (info->fShowSign) {
727 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
728 }
729
730 /* format the number */
731 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
732
733 if (U_FAILURE(status)) {
734 resultLen = 0;
735 }
736
737 /* restore the number format */
738 /* TODO: Is this needed? */
739 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
740 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
741
742 if (info->fShowSign) {
743 /* Reset back to original value regardless of what the error was */
744 UErrorCode localStatus = U_ZERO_ERROR;
745 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
746 }
747
748 return handler->pad_and_justify(context, info, result, resultLen);
749}
750
751static int32_t
752u_printf_ustring_handler(const u_printf_stream_handler *handler,
753 void *context,
754 ULocaleBundle *formatBundle,
755 const u_printf_spec_info *info,
756 const ufmt_args *args)
757{
758 int32_t len, written;
759 const UChar *arg = (const UChar*)(args[0].ptrValue);
760
761 /* allocate enough space for the buffer */
762 if (arg == NULL) {
763 arg = gNullStr;
764 }
765 len = u_strlen(arg);
766
767 /* width = minimum # of characters to write */
768 /* precision = maximum # of characters to write */
769
770 /* precision takes precedence over width */
771 /* determine if the string should be truncated */
772 if(info->fPrecision != -1 && len > info->fPrecision) {
773 written = handler->write(context, arg, info->fPrecision);
774 }
775 else {
776 /* determine if the string should be padded */
777 written = handler->pad_and_justify(context, info, arg, len);
778 }
779
780 return written;
781}
782
783static int32_t
784u_printf_uchar_handler(const u_printf_stream_handler *handler,
785 void *context,
786 ULocaleBundle *formatBundle,
787 const u_printf_spec_info *info,
788 const ufmt_args *args)
789{
790 int32_t written = 0;
791 UChar arg = (UChar)(args[0].int64Value);
792
793
794 /* width = minimum # of characters to write */
795 /* precision = maximum # of characters to write */
796
797 /* precision takes precedence over width */
798 /* determine if the char should be printed */
799 if(info->fPrecision != -1 && info->fPrecision < 1) {
800 /* write nothing */
801 written = 0;
802 }
803 else {
804 /* determine if the string should be padded */
805 written = handler->pad_and_justify(context, info, &arg, 1);
806 }
807
808 return written;
809}
810
811static int32_t
812u_printf_scidbl_handler(const u_printf_stream_handler *handler,
813 void *context,
814 ULocaleBundle *formatBundle,
815 const u_printf_spec_info *info,
816 const ufmt_args *args)
817{
818 u_printf_spec_info scidbl_info;
819 double num = args[0].doubleValue;
820 int32_t retVal;
821
822 memcpy(&scidbl_info, info, sizeof(u_printf_spec_info));
823
824 /* determine whether to use 'd', 'e' or 'f' notation */
825 if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num))
826 {
827 /* use 'f' notation */
828 scidbl_info.fSpec = 0x0066;
829 scidbl_info.fPrecision = 0;
830 /* call the double handler */
831 retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
832 }
833 else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num)
834 || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision)))
835 {
836 /* use 'e' or 'E' notation */
837 scidbl_info.fSpec = scidbl_info.fSpec - 2;
838 if (scidbl_info.fPrecision == -1) {
839 scidbl_info.fPrecision = 5;
840 }
841 /* call the scientific handler */
842 retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args);
843 }
844 else {
845 UNumberFormat *format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
846 int32_t maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS);
847 int32_t significantDigits = scidbl_info.fPrecision;
848
849 /* use 'f' notation */
850 scidbl_info.fSpec = 0x0066;
851 if (significantDigits == -1) {
852 significantDigits = 6;
853 }
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);
860 }
861 return retVal;
862}
863
864static int32_t
865u_printf_count_handler(const u_printf_stream_handler *handler,
866 void *context,
867 ULocaleBundle *formatBundle,
868 const u_printf_spec_info *info,
869 const ufmt_args *args)
870{
871 int32_t *count = (int32_t*)(args[0].ptrValue);
872
873 /* in the special case of count, the u_printf_spec_info's width */
874 /* will contain the # of chars written thus far */
875 *count = info->fWidth;
876
877 return 0;
878}
879
880static int32_t
881u_printf_spellout_handler(const u_printf_stream_handler *handler,
882 void *context,
883 ULocaleBundle *formatBundle,
884 const u_printf_spec_info *info,
885 const ufmt_args *args)
886{
887 double num = (double) (args[0].doubleValue);
888 UNumberFormat *format;
889 UChar result[UPRINTF_BUFFER_SIZE];
890 UChar prefixBuffer[UPRINTF_BUFFER_SIZE];
891 int32_t prefixBufferLen = sizeof(prefixBuffer);
892 int32_t minDecimalDigits;
893 int32_t maxDecimalDigits;
894 int32_t resultLen;
895 UErrorCode status = U_ZERO_ERROR;
896
897 prefixBuffer[0] = 0;
898
899 /* mask off any necessary bits */
900 /* if(! info->fIsLongDouble)
901 num &= DBL_MAX;*/
902
903 /* get the formatter */
904 format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT);
905
906 /* handle error */
907 if(format == 0)
908 return 0;
909
910 /* save the formatter's state */
911 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
912 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
913
914 /* set the appropriate flags and number of decimal digits on the formatter */
915 if(info->fPrecision != -1) {
916 /* set the # of decimal digits */
917 unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
918 }
919 else if(info->fAlt) {
920 /* '#' means always show decimal point */
921 /* copy of printf behavior on Solaris - '#' shows 6 digits */
922 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
923 }
924 else {
925 /* # of decimal digits is 6 if precision not specified */
926 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
927 }
928
929 /* set whether to show the sign */
930 if (info->fShowSign) {
931 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
932 }
933
934 /* format the number */
935 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
936
937 if (U_FAILURE(status)) {
938 resultLen = 0;
939 }
940
941 /* restore the number format */
942 /* TODO: Is this needed? */
943 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
944 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
945
946 if (info->fShowSign) {
947 /* Reset back to original value regardless of what the error was */
948 UErrorCode localStatus = U_ZERO_ERROR;
949 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
950 }
951
952 return handler->pad_and_justify(context, info, result, resultLen);
953}
954
955/* Use US-ASCII characters only for formatting. Most codepages have
956 characters 20-7F from Unicode. Using any other codepage specific
957 characters will make it very difficult to format the string on
958 non-Unicode machines */
959static const u_printf_info g_u_printf_infos[UPRINTF_NUM_FMT_HANDLERS] = {
960/* 0x20 */
961 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
962 UFMT_EMPTY, UFMT_SIMPLE_PERCENT,UFMT_EMPTY, UFMT_EMPTY,
963 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
964 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
965
966/* 0x30 */
967 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
968 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
969 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
970 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
971
972/* 0x40 */
973 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR,
974 UFMT_EMPTY, UFMT_SCIENTIFIC, UFMT_EMPTY, UFMT_SCIDBL,
975#ifdef U_USE_OBSOLETE_IO_FORMATTING
976 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR/*deprecated*/,
977#else
978 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
979#endif
980 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
981
982/* 0x50 */
983 UFMT_PERCENT, UFMT_EMPTY, UFMT_EMPTY, UFMT_USTRING,
984#ifdef U_USE_OBSOLETE_IO_FORMATTING
985 UFMT_EMPTY, UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT, UFMT_EMPTY,
986#else
987 UFMT_EMPTY, UFMT_EMPTY, UFMT_SPELLOUT, UFMT_EMPTY,
988#endif
989 UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
990 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
991
992/* 0x60 */
993 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_CHAR,
994 UFMT_INT, UFMT_SCIENTIFIC, UFMT_DOUBLE, UFMT_SCIDBL,
995 UFMT_EMPTY, UFMT_INT, UFMT_EMPTY, UFMT_EMPTY,
996 UFMT_EMPTY, UFMT_EMPTY, UFMT_COUNT, UFMT_OCTAL,
997
998/* 0x70 */
999 UFMT_POINTER, UFMT_EMPTY, UFMT_EMPTY, UFMT_STRING,
1000 UFMT_EMPTY, UFMT_UINT, UFMT_EMPTY, UFMT_EMPTY,
1001 UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1002 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1003};
1004
1005/* flag characters for uprintf */
1006#define FLAG_MINUS 0x002D
1007#define FLAG_PLUS 0x002B
1008#define FLAG_SPACE 0x0020
1009#define FLAG_POUND 0x0023
1010#define FLAG_ZERO 0x0030
1011#define FLAG_PAREN 0x0028
1012
1013#define ISFLAG(s) (s) == FLAG_MINUS || \
1014 (s) == FLAG_PLUS || \
1015 (s) == FLAG_SPACE || \
1016 (s) == FLAG_POUND || \
1017 (s) == FLAG_ZERO || \
1018 (s) == FLAG_PAREN
1019
1020/* special characters for uprintf */
1021#define SPEC_ASTERISK 0x002A
1022#define SPEC_DOLLARSIGN 0x0024
1023#define SPEC_PERIOD 0x002E
1024#define SPEC_PERCENT 0x0025
1025
1026/* unicode digits */
1027#define DIGIT_ZERO 0x0030
1028#define DIGIT_ONE 0x0031
1029#define DIGIT_TWO 0x0032
1030#define DIGIT_THREE 0x0033
1031#define DIGIT_FOUR 0x0034
1032#define DIGIT_FIVE 0x0035
1033#define DIGIT_SIX 0x0036
1034#define DIGIT_SEVEN 0x0037
1035#define DIGIT_EIGHT 0x0038
1036#define DIGIT_NINE 0x0039
1037
1038#define ISDIGIT(s) (s) == DIGIT_ZERO || \
1039 (s) == DIGIT_ONE || \
1040 (s) == DIGIT_TWO || \
1041 (s) == DIGIT_THREE || \
1042 (s) == DIGIT_FOUR || \
1043 (s) == DIGIT_FIVE || \
1044 (s) == DIGIT_SIX || \
1045 (s) == DIGIT_SEVEN || \
1046 (s) == DIGIT_EIGHT || \
1047 (s) == DIGIT_NINE
1048
1049/* u_printf modifiers */
1050#define MOD_H 0x0068
1051#define MOD_LOWERL 0x006C
1052#define MOD_L 0x004C
1053
1054#define ISMOD(s) (s) == MOD_H || \
1055 (s) == MOD_LOWERL || \
1056 (s) == MOD_L
1057
1058/* We parse the argument list in Unicode */
1059U_CFUNC int32_t
1060u_printf_parse(const u_printf_stream_handler *streamHandler,
1061 const UChar *fmt,
1062 void *context,
1063 u_localized_print_string *locStringContext,
1064 ULocaleBundle *formatBundle,
1065 int32_t *written,
1066 va_list ap)
1067{
1068 uint16_t handlerNum;
1069 ufmt_args args;
1070 ufmt_type_info argType;
1071 u_printf_handler *handler;
1072 u_printf_spec spec;
1073 u_printf_spec_info *info = &(spec.fInfo);
1074
1075 const UChar *alias = fmt;
1076 const UChar *backup;
1077 const UChar *lastAlias;
1078
1079 /* iterate through the pattern */
1080 while(!locStringContext || locStringContext->available > 0) {
1081
1082 /* find the next '%' */
1083 lastAlias = alias;
1084 while(*alias != UP_PERCENT && *alias != 0x0000) {
1085 alias++;
1086 }
1087
1088 /* write any characters before the '%' */
1089 if(alias > lastAlias) {
1090 *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias));
1091 }
1092
1093 /* break if at end of string */
1094 if(*alias == 0x0000) {
1095 break;
1096 }
1097
1098 /* initialize spec to default values */
1099 spec.fWidthPos = -1;
1100 spec.fPrecisionPos = -1;
1101 spec.fArgPos = -1;
1102
1103 info->fPrecision = -1;
1104 info->fWidth = -1;
1105 info->fSpec = 0x0000;
1106 info->fPadChar = 0x0020;
1107 info->fAlt = FALSE;
1108 info->fSpace = FALSE;
1109 info->fLeft = FALSE;
1110 info->fShowSign = FALSE;
1111 info->fZero = FALSE;
1112 info->fIsLongDouble = FALSE;
1113 info->fIsShort = FALSE;
1114 info->fIsLong = FALSE;
1115 info->fIsLongLong = FALSE;
1116
1117 /* skip over the initial '%' */
1118 alias++;
1119
1120 /* Check for positional argument */
1121 if(ISDIGIT(*alias)) {
1122
1123 /* Save the current position */
1124 backup = alias;
1125
1126 /* handle positional parameters */
1127 if(ISDIGIT(*alias)) {
1128 spec.fArgPos = (int) (*alias++ - DIGIT_ZERO);
1129
1130 while(ISDIGIT(*alias)) {
1131 spec.fArgPos *= 10;
1132 spec.fArgPos += (int) (*alias++ - DIGIT_ZERO);
1133 }
1134 }
1135
1136 /* if there is no '$', don't read anything */
1137 if(*alias != SPEC_DOLLARSIGN) {
1138 spec.fArgPos = -1;
1139 alias = backup;
1140 }
1141 /* munge the '$' */
1142 else
1143 alias++;
1144 }
1145
1146 /* Get any format flags */
1147 while(ISFLAG(*alias)) {
1148 switch(*alias++) {
1149
1150 /* left justify */
1151 case FLAG_MINUS:
1152 info->fLeft = TRUE;
1153 break;
1154
1155 /* always show sign */
1156 case FLAG_PLUS:
1157 info->fShowSign = TRUE;
1158 break;
1159
1160 /* use space if no sign present */
1161 case FLAG_SPACE:
1162 info->fShowSign = TRUE;
1163 info->fSpace = TRUE;
1164 break;
1165
1166 /* use alternate form */
1167 case FLAG_POUND:
1168 info->fAlt = TRUE;
1169 break;
1170
1171 /* pad with leading zeroes */
1172 case FLAG_ZERO:
1173 info->fZero = TRUE;
1174 info->fPadChar = 0x0030;
1175 break;
1176
1177 /* pad character specified */
1178 case FLAG_PAREN:
1179
1180 /* TODO test that all four are numbers */
1181 /* first four characters are hex values for pad char */
1182 info->fPadChar = (UChar)ufmt_digitvalue(*alias++);
1183 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
1184 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
1185 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
1186
1187 /* final character is ignored */
1188 alias++;
1189
1190 break;
1191 }
1192 }
1193
1194 /* Get the width */
1195
1196 /* width is specified out of line */
1197 if(*alias == SPEC_ASTERISK) {
1198
1199 info->fWidth = -2;
1200
1201 /* Skip the '*' */
1202 alias++;
1203
1204 /* Save the current position */
1205 backup = alias;
1206
1207 /* handle positional parameters */
1208 if(ISDIGIT(*alias)) {
1209 spec.fWidthPos = (int) (*alias++ - DIGIT_ZERO);
1210
1211 while(ISDIGIT(*alias)) {
1212 spec.fWidthPos *= 10;
1213 spec.fWidthPos += (int) (*alias++ - DIGIT_ZERO);
1214 }
1215 }
1216
1217 /* if there is no '$', don't read anything */
1218 if(*alias != SPEC_DOLLARSIGN) {
1219 spec.fWidthPos = -1;
1220 alias = backup;
1221 }
1222 /* munge the '$' */
1223 else
1224 alias++;
1225 }
1226 /* read the width, if present */
1227 else if(ISDIGIT(*alias)){
1228 info->fWidth = (int) (*alias++ - DIGIT_ZERO);
1229
1230 while(ISDIGIT(*alias)) {
1231 info->fWidth *= 10;
1232 info->fWidth += (int) (*alias++ - DIGIT_ZERO);
1233 }
1234 }
1235
1236 /* Get the precision */
1237
1238 if(*alias == SPEC_PERIOD) {
1239
1240 /* eat up the '.' */
1241 alias++;
1242
1243 /* precision is specified out of line */
1244 if(*alias == SPEC_ASTERISK) {
1245
1246 info->fPrecision = -2;
1247
1248 /* Skip the '*' */
1249 alias++;
1250
1251 /* save the current position */
1252 backup = alias;
1253
1254 /* handle positional parameters */
1255 if(ISDIGIT(*alias)) {
1256 spec.fPrecisionPos = (int) (*alias++ - DIGIT_ZERO);
1257
1258 while(ISDIGIT(*alias)) {
1259 spec.fPrecisionPos *= 10;
1260 spec.fPrecisionPos += (int) (*alias++ - DIGIT_ZERO);
1261 }
1262
1263 /* if there is no '$', don't read anything */
1264 if(*alias != SPEC_DOLLARSIGN) {
1265 spec.fPrecisionPos = -1;
1266 alias = backup;
1267 }
1268 else {
1269 /* munge the '$' */
1270 alias++;
1271 }
1272 }
1273 }
1274 /* read the precision */
1275 else if(ISDIGIT(*alias)){
1276 info->fPrecision = (int) (*alias++ - DIGIT_ZERO);
1277
1278 while(ISDIGIT(*alias)) {
1279 info->fPrecision *= 10;
1280 info->fPrecision += (int) (*alias++ - DIGIT_ZERO);
1281 }
1282 }
1283 }
1284
1285 /* Get any modifiers */
1286 if(ISMOD(*alias)) {
1287 switch(*alias++) {
1288
1289 /* short */
1290 case MOD_H:
1291 info->fIsShort = TRUE;
1292 break;
1293
1294 /* long or long long */
1295 case MOD_LOWERL:
1296 if(*alias == MOD_LOWERL) {
1297 info->fIsLongLong = TRUE;
1298 /* skip over the next 'l' */
1299 alias++;
1300 }
1301 else
1302 info->fIsLong = TRUE;
1303 break;
1304
1305 /* long double */
1306 case MOD_L:
1307 info->fIsLongDouble = TRUE;
1308 break;
1309 }
1310 }
1311
1312 /* finally, get the specifier letter */
1313 info->fSpec = *alias++;
1314
1315 /* fill in the precision and width, if specified out of line */
1316
1317 /* width specified out of line */
1318 if(spec.fInfo.fWidth == -2) {
1319 if(spec.fWidthPos == -1) {
1320 /* read the width from the argument list */
1321 info->fWidth = va_arg(ap, int32_t);
1322 }
1323 else {
1324 /* handle positional parameter */
1325 }
1326
1327 /* if it's negative, take the absolute value and set left alignment */
1328 if(info->fWidth < 0) {
1329 info->fWidth *= -1;
1330 info->fLeft = TRUE;
1331 }
1332 }
1333
1334 /* precision specified out of line */
1335 if(info->fPrecision == -2) {
1336 if(spec.fPrecisionPos == -1) {
1337 /* read the precision from the argument list */
1338 info->fPrecision = va_arg(ap, int32_t);
1339 }
1340 else {
1341 /* handle positional parameter */
1342 }
1343
1344 /* if it's negative, set it to zero */
1345 if(info->fPrecision < 0)
1346 info->fPrecision = 0;
1347 }
1348
1349 handlerNum = (uint16_t)(info->fSpec - UPRINTF_BASE_FMT_HANDLERS);
1350 if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
1351 /* query the info function for argument information */
1352 argType = g_u_printf_infos[ handlerNum ].info;
1353 switch(argType) {
1354 case ufmt_count:
1355 /* set the spec's width to the # of chars written */
1356 info->fWidth = *written;
1357 /* fall through to set the pointer */
1358 case ufmt_string:
1359 case ufmt_ustring:
1360 case ufmt_pointer:
1361 args.ptrValue = va_arg(ap, void*);
1362 break;
1363 case ufmt_char:
1364 case ufmt_uchar:
1365 case ufmt_int:
1366 if (info->fIsLongLong) {
1367 args.int64Value = va_arg(ap, int64_t);
1368 }
1369 else {
1370 args.int64Value = va_arg(ap, int32_t);
1371 }
1372 break;
1373 case ufmt_float:
1374 args.floatValue = (float) va_arg(ap, double);
1375 break;
1376 case ufmt_double:
1377 args.doubleValue = va_arg(ap, double);
1378 break;
1379 default:
1380 /* else args is ignored */
1381 args.ptrValue = NULL;
1382 break;
1383 }
1384
1385 /* call the handler function */
1386 handler = g_u_printf_infos[ handlerNum ].handler;
1387 if(handler != 0) {
1388 *written += (*handler)(streamHandler, context, formatBundle, info, &args);
1389 }
1390 else {
1391 /* just echo unknown tags */
1392 *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
1393 }
1394 }
1395 else {
1396 /* just echo unknown tags */
1397 *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
1398 }
1399 }
1400 /* return # of characters in this format that have been parsed. */
1401 return (int32_t)(alias - fmt);
1402}
1403
1404#endif /* #if !UCONFIG_NO_FORMATTING */