uprntf_p.c revision 51cfa1a9a96cad34675a6415fe86dfdf3f525bb6
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 */
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    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
242static int32_t
243u_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
270static int32_t
271u_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 */
346static int32_t
347u_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
412static int32_t
413u_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
447static int32_t
448u_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
481static int32_t
482u_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
534static int32_t
535u_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
550static int32_t
551u_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
670static int32_t
671u_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
745static int32_t
746u_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
773static int32_t
774u_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
793static int32_t
794u_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
846static int32_t
847u_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
862static int32_t
863u_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 */
941static 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 */
1041U_CFUNC int32_t
1042u_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 */
1375