1/*
2******************************************************************************
3*
4*   Copyright (C) 1998-2011, 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#include "unicode/utf16.h"
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[U16_MAX_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    UNumberFormat *format;
804    int32_t maxSigDecimalDigits, significantDigits;
805
806    memcpy(&scidbl_info, info, sizeof(u_printf_spec_info));
807
808    /* determine whether to use 'd', 'e' or 'f' notation */
809    if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num))
810    {
811        /* use 'f' notation */
812        scidbl_info.fSpec = 0x0066;
813        scidbl_info.fPrecision = 0;
814        /* call the double handler */
815        retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
816    }
817    else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num)
818        || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision)))
819    {
820        /* use 'e' or 'E' notation */
821        scidbl_info.fSpec = scidbl_info.fSpec - 2;
822        if (scidbl_info.fPrecision == -1) {
823            scidbl_info.fPrecision = 5;
824        }
825        /* call the scientific handler */
826        retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args);
827    }
828    else {
829        format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
830        /* Check for null pointer */
831        if (format == NULL) {
832            return 0;
833        }
834        maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS);
835        significantDigits = scidbl_info.fPrecision;
836
837        /* use 'f' notation */
838        scidbl_info.fSpec = 0x0066;
839        if (significantDigits == -1) {
840            significantDigits = 6;
841        }
842        unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
843        unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, significantDigits);
844        /* call the double handler */
845        retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
846        unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, maxSigDecimalDigits);
847        unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, FALSE);
848    }
849    return retVal;
850}
851
852static int32_t
853u_printf_count_handler(const u_printf_stream_handler  *handler,
854                       void                           *context,
855                       ULocaleBundle                  *formatBundle,
856                       const u_printf_spec_info       *info,
857                       const ufmt_args                *args)
858{
859    int32_t *count = (int32_t*)(args[0].ptrValue);
860
861    /* in the special case of count, the u_printf_spec_info's width */
862    /* will contain the # of chars written thus far */
863    *count = info->fWidth;
864
865    return 0;
866}
867
868static int32_t
869u_printf_spellout_handler(const u_printf_stream_handler *handler,
870                          void                          *context,
871                          ULocaleBundle                 *formatBundle,
872                          const u_printf_spec_info      *info,
873                          const ufmt_args               *args)
874{
875    double          num         = (double) (args[0].doubleValue);
876    UNumberFormat   *format;
877    UChar           result[UPRINTF_BUFFER_SIZE];
878    UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
879    int32_t         prefixBufferLen = sizeof(prefixBuffer);
880    int32_t         minDecimalDigits;
881    int32_t         maxDecimalDigits;
882    int32_t         resultLen;
883    UErrorCode      status        = U_ZERO_ERROR;
884
885    prefixBuffer[0] = 0;
886
887    /* mask off any necessary bits */
888    /*  if(! info->fIsLongDouble)
889    num &= DBL_MAX;*/
890
891    /* get the formatter */
892    format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT);
893
894    /* handle error */
895    if(format == 0)
896        return 0;
897
898    /* save the formatter's state */
899    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
900    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
901
902    /* set the appropriate flags and number of decimal digits on the formatter */
903    if(info->fPrecision != -1) {
904        /* set the # of decimal digits */
905        unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
906    }
907    else if(info->fAlt) {
908        /* '#' means always show decimal point */
909        /* copy of printf behavior on Solaris - '#' shows 6 digits */
910        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
911    }
912    else {
913        /* # of decimal digits is 6 if precision not specified */
914        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
915    }
916
917    /* set whether to show the sign */
918    if (info->fShowSign) {
919        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
920    }
921
922    /* format the number */
923    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
924
925    if (U_FAILURE(status)) {
926        resultLen = 0;
927    }
928
929    /* restore the number format */
930    /* TODO: Is this needed? */
931    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
932    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
933
934    if (info->fShowSign) {
935        /* Reset back to original value regardless of what the error was */
936        UErrorCode localStatus = U_ZERO_ERROR;
937        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
938    }
939
940    return handler->pad_and_justify(context, info, result, resultLen);
941}
942
943/* Use US-ASCII characters only for formatting. Most codepages have
944 characters 20-7F from Unicode. Using any other codepage specific
945 characters will make it very difficult to format the string on
946 non-Unicode machines */
947static const u_printf_info g_u_printf_infos[UPRINTF_NUM_FMT_HANDLERS] = {
948/* 0x20 */
949    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
950    UFMT_EMPTY,         UFMT_SIMPLE_PERCENT,UFMT_EMPTY,         UFMT_EMPTY,
951    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
952    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
953
954/* 0x30 */
955    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
956    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
957    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
958    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
959
960/* 0x40 */
961    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR,
962    UFMT_EMPTY,         UFMT_SCIENTIFIC,    UFMT_EMPTY,         UFMT_SCIDBL,
963#ifdef U_USE_OBSOLETE_IO_FORMATTING
964    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR/*deprecated*/,
965#else
966    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
967#endif
968    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
969
970/* 0x50 */
971    UFMT_PERCENT,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_USTRING,
972#ifdef U_USE_OBSOLETE_IO_FORMATTING
973    UFMT_EMPTY,         UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT,      UFMT_EMPTY,
974#else
975    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_SPELLOUT,      UFMT_EMPTY,
976#endif
977    UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
978    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
979
980/* 0x60 */
981    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_CHAR,
982    UFMT_INT,           UFMT_SCIENTIFIC,    UFMT_DOUBLE,        UFMT_SCIDBL,
983    UFMT_EMPTY,         UFMT_INT,           UFMT_EMPTY,         UFMT_EMPTY,
984    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_COUNT,         UFMT_OCTAL,
985
986/* 0x70 */
987    UFMT_POINTER,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_STRING,
988    UFMT_EMPTY,         UFMT_UINT,          UFMT_EMPTY,         UFMT_EMPTY,
989    UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
990    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
991};
992
993/* flag characters for uprintf */
994#define FLAG_MINUS 0x002D
995#define FLAG_PLUS 0x002B
996#define FLAG_SPACE 0x0020
997#define FLAG_POUND 0x0023
998#define FLAG_ZERO  0x0030
999#define FLAG_PAREN 0x0028
1000
1001#define ISFLAG(s)    (s) == FLAG_MINUS || \
1002            (s) == FLAG_PLUS || \
1003            (s) == FLAG_SPACE || \
1004            (s) == FLAG_POUND || \
1005            (s) == FLAG_ZERO || \
1006            (s) == FLAG_PAREN
1007
1008/* special characters for uprintf */
1009#define SPEC_ASTERISK 0x002A
1010#define SPEC_DOLLARSIGN 0x0024
1011#define SPEC_PERIOD 0x002E
1012#define SPEC_PERCENT 0x0025
1013
1014/* unicode digits */
1015#define DIGIT_ZERO 0x0030
1016#define DIGIT_ONE 0x0031
1017#define DIGIT_TWO 0x0032
1018#define DIGIT_THREE 0x0033
1019#define DIGIT_FOUR 0x0034
1020#define DIGIT_FIVE 0x0035
1021#define DIGIT_SIX 0x0036
1022#define DIGIT_SEVEN 0x0037
1023#define DIGIT_EIGHT 0x0038
1024#define DIGIT_NINE 0x0039
1025
1026#define ISDIGIT(s)    (s) == DIGIT_ZERO || \
1027            (s) == DIGIT_ONE || \
1028            (s) == DIGIT_TWO || \
1029            (s) == DIGIT_THREE || \
1030            (s) == DIGIT_FOUR || \
1031            (s) == DIGIT_FIVE || \
1032            (s) == DIGIT_SIX || \
1033            (s) == DIGIT_SEVEN || \
1034            (s) == DIGIT_EIGHT || \
1035            (s) == DIGIT_NINE
1036
1037/* u_printf modifiers */
1038#define MOD_H 0x0068
1039#define MOD_LOWERL 0x006C
1040#define MOD_L 0x004C
1041
1042#define ISMOD(s)    (s) == MOD_H || \
1043            (s) == MOD_LOWERL || \
1044            (s) == MOD_L
1045/* Returns an array of the parsed argument type given in the format string. */
1046static ufmt_args* parseArguments(const UChar *alias, va_list ap, UErrorCode *status) {
1047    ufmt_args *arglist = NULL;
1048    ufmt_type_info *typelist = NULL;
1049    UBool *islonglong = NULL;
1050    int32_t size = 0;
1051    int32_t pos = 0;
1052    UChar type;
1053    uint16_t handlerNum;
1054    const UChar *aliasStart = alias;
1055
1056    /* get maximum number of arguments */
1057    for(;;) {
1058        /* find % */
1059        while(*alias != UP_PERCENT && *alias != 0x0000) {
1060            alias++;
1061        }
1062
1063        if(*alias == 0x0000) {
1064            break;
1065        }
1066
1067        alias++;
1068
1069        /* handle the pos number */
1070        if(ISDIGIT(*alias)) {
1071
1072            /* handle positional parameters */
1073            if(ISDIGIT(*alias)) {
1074                pos = (int) (*alias++ - DIGIT_ZERO);
1075
1076                while(ISDIGIT(*alias)) {
1077                    pos *= 10;
1078                    pos += (int) (*alias++ - DIGIT_ZERO);
1079                }
1080            }
1081
1082            /* if there is no '$', don't read anything */
1083            if(*alias != SPEC_DOLLARSIGN) {
1084                return NULL;
1085            }
1086        } else {
1087            return NULL;
1088        }
1089
1090        if (pos > size) {
1091            size = pos;
1092        }
1093    }
1094
1095    /* create the parsed argument list */
1096    typelist = (ufmt_type_info*)uprv_malloc(sizeof(ufmt_type_info) * size);
1097    islonglong = (UBool*)uprv_malloc(sizeof(UBool) * size);
1098    arglist = (ufmt_args*)uprv_malloc(sizeof(ufmt_args) * size);
1099
1100    /* If malloc failed, return NULL */
1101    if (!typelist || !islonglong || !arglist) {
1102        if (typelist) {
1103            uprv_free(typelist);
1104        }
1105
1106        if (islonglong) {
1107            uprv_free(islonglong);
1108        }
1109
1110        if (arglist) {
1111            uprv_free(arglist);
1112        }
1113
1114        *status = U_MEMORY_ALLOCATION_ERROR;
1115        return NULL;
1116    }
1117
1118    /* reset alias back to the beginning */
1119    alias = aliasStart;
1120
1121    for(;;) {
1122        /* find % */
1123        while(*alias != UP_PERCENT && *alias != 0x0000) {
1124            alias++;
1125        }
1126
1127        if(*alias == 0x0000) {
1128            break;
1129        }
1130
1131        alias++;
1132
1133        /* handle positional parameters */
1134        if(ISDIGIT(*alias)) {
1135            pos = (int) (*alias++ - DIGIT_ZERO);
1136
1137            while(ISDIGIT(*alias)) {
1138                pos *= 10;
1139                pos += (int) (*alias++ - DIGIT_ZERO);
1140            }
1141        }
1142        /* offset position by 1 */
1143        pos--;
1144
1145        /* skip over everything except for the type */
1146        while (ISMOD(*alias) || ISFLAG(*alias) || ISDIGIT(*alias) ||
1147            *alias == SPEC_ASTERISK || *alias == SPEC_PERIOD || *alias == SPEC_DOLLARSIGN) {
1148                islonglong[pos] = FALSE;
1149                if (ISMOD(*alias)) {
1150                    alias++;
1151                    if (*alias == MOD_LOWERL) {
1152                        islonglong[pos] = TRUE;
1153                    }
1154                }
1155                alias++;
1156        }
1157        type = *alias;
1158
1159        /* store the argument type in the correct position of the parsed argument list */
1160        handlerNum = (uint16_t)(type - UPRINTF_BASE_FMT_HANDLERS);
1161        if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
1162            typelist[pos] = g_u_printf_infos[ handlerNum ].info;
1163        } else {
1164            typelist[pos] = ufmt_empty;
1165        }
1166    }
1167
1168    /* store argument in arglist */
1169    for (pos = 0; pos < size; pos++) {
1170        switch (typelist[pos]) {
1171        case ufmt_string:
1172        case ufmt_ustring:
1173        case ufmt_pointer:
1174            arglist[pos].ptrValue = va_arg(ap, void*);
1175            break;
1176        case ufmt_char:
1177        case ufmt_uchar:
1178        case ufmt_int:
1179            if (islonglong[pos]) {
1180                arglist[pos].int64Value = va_arg(ap, int64_t);
1181            }
1182            else {
1183                arglist[pos].int64Value = va_arg(ap, int32_t);
1184            }
1185            break;
1186        case ufmt_float:
1187            arglist[pos].floatValue = (float) va_arg(ap, double);
1188            break;
1189        case ufmt_double:
1190            arglist[pos].doubleValue = va_arg(ap, double);
1191            break;
1192        default:
1193            /* else args is ignored */
1194            arglist[pos].ptrValue = NULL;
1195            break;
1196        }
1197    }
1198
1199    uprv_free(typelist);
1200    uprv_free(islonglong);
1201
1202    return arglist;
1203}
1204
1205/* We parse the argument list in Unicode */
1206U_CFUNC int32_t
1207u_printf_parse(const u_printf_stream_handler *streamHandler,
1208               const UChar     *fmt,
1209               void            *context,
1210               u_localized_print_string *locStringContext,
1211               ULocaleBundle   *formatBundle,
1212               int32_t         *written,
1213               va_list         ap)
1214{
1215    uint16_t         handlerNum;
1216    ufmt_args        args;
1217    ufmt_type_info   argType;
1218    u_printf_handler *handler;
1219    u_printf_spec    spec;
1220    u_printf_spec_info *info = &(spec.fInfo);
1221
1222    const UChar *alias = fmt;
1223    const UChar *backup;
1224    const UChar *lastAlias;
1225    const UChar *orgAlias = fmt;
1226    /* parsed argument list */
1227    ufmt_args *arglist = NULL; /* initialized it to avoid compiler warnings */
1228    UErrorCode status = U_ZERO_ERROR;
1229    if (!locStringContext || locStringContext->available >= 0) {
1230        /* get the parsed list of argument types */
1231        arglist = parseArguments(orgAlias, ap, &status);
1232
1233        /* Return error if parsing failed. */
1234        if (U_FAILURE(status)) {
1235            return -1;
1236        }
1237    }
1238
1239    /* iterate through the pattern */
1240    while(!locStringContext || locStringContext->available >= 0) {
1241
1242        /* find the next '%' */
1243        lastAlias = alias;
1244        while(*alias != UP_PERCENT && *alias != 0x0000) {
1245            alias++;
1246        }
1247
1248        /* write any characters before the '%' */
1249        if(alias > lastAlias) {
1250            *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias));
1251        }
1252
1253        /* break if at end of string */
1254        if(*alias == 0x0000) {
1255            break;
1256        }
1257
1258        /* initialize spec to default values */
1259        spec.fWidthPos     = -1;
1260        spec.fPrecisionPos = -1;
1261        spec.fArgPos       = -1;
1262
1263        uprv_memset(info, 0, sizeof(*info));
1264        info->fPrecision    = -1;
1265        info->fWidth        = -1;
1266        info->fPadChar      = 0x0020;
1267
1268        /* skip over the initial '%' */
1269        alias++;
1270
1271        /* Check for positional argument */
1272        if(ISDIGIT(*alias)) {
1273
1274            /* Save the current position */
1275            backup = alias;
1276
1277            /* handle positional parameters */
1278            if(ISDIGIT(*alias)) {
1279                spec.fArgPos = (int) (*alias++ - DIGIT_ZERO);
1280
1281                while(ISDIGIT(*alias)) {
1282                    spec.fArgPos *= 10;
1283                    spec.fArgPos += (int) (*alias++ - DIGIT_ZERO);
1284                }
1285            }
1286
1287            /* if there is no '$', don't read anything */
1288            if(*alias != SPEC_DOLLARSIGN) {
1289                spec.fArgPos = -1;
1290                alias = backup;
1291            }
1292            /* munge the '$' */
1293            else
1294                alias++;
1295        }
1296
1297        /* Get any format flags */
1298        while(ISFLAG(*alias)) {
1299            switch(*alias++) {
1300
1301                /* left justify */
1302            case FLAG_MINUS:
1303                info->fLeft = TRUE;
1304                break;
1305
1306                /* always show sign */
1307            case FLAG_PLUS:
1308                info->fShowSign = TRUE;
1309                break;
1310
1311                /* use space if no sign present */
1312            case FLAG_SPACE:
1313                info->fShowSign = TRUE;
1314                info->fSpace = TRUE;
1315                break;
1316
1317                /* use alternate form */
1318            case FLAG_POUND:
1319                info->fAlt = TRUE;
1320                break;
1321
1322                /* pad with leading zeroes */
1323            case FLAG_ZERO:
1324                info->fZero = TRUE;
1325                info->fPadChar = 0x0030;
1326                break;
1327
1328                /* pad character specified */
1329            case FLAG_PAREN:
1330
1331                /* TODO test that all four are numbers */
1332                /* first four characters are hex values for pad char */
1333                info->fPadChar = (UChar)ufmt_digitvalue(*alias++);
1334                info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
1335                info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
1336                info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
1337
1338                /* final character is ignored */
1339                alias++;
1340
1341                break;
1342            }
1343        }
1344
1345        /* Get the width */
1346
1347        /* width is specified out of line */
1348        if(*alias == SPEC_ASTERISK) {
1349
1350            info->fWidth = -2;
1351
1352            /* Skip the '*' */
1353            alias++;
1354
1355            /* Save the current position */
1356            backup = alias;
1357
1358            /* handle positional parameters */
1359            if(ISDIGIT(*alias)) {
1360                spec.fWidthPos = (int) (*alias++ - DIGIT_ZERO);
1361
1362                while(ISDIGIT(*alias)) {
1363                    spec.fWidthPos *= 10;
1364                    spec.fWidthPos += (int) (*alias++ - DIGIT_ZERO);
1365                }
1366            }
1367
1368            /* if there is no '$', don't read anything */
1369            if(*alias != SPEC_DOLLARSIGN) {
1370                spec.fWidthPos = -1;
1371                alias = backup;
1372            }
1373            /* munge the '$' */
1374            else
1375                alias++;
1376        }
1377        /* read the width, if present */
1378        else if(ISDIGIT(*alias)){
1379            info->fWidth = (int) (*alias++ - DIGIT_ZERO);
1380
1381            while(ISDIGIT(*alias)) {
1382                info->fWidth *= 10;
1383                info->fWidth += (int) (*alias++ - DIGIT_ZERO);
1384            }
1385        }
1386
1387        /* Get the precision */
1388
1389        if(*alias == SPEC_PERIOD) {
1390
1391            /* eat up the '.' */
1392            alias++;
1393
1394            /* precision is specified out of line */
1395            if(*alias == SPEC_ASTERISK) {
1396
1397                info->fPrecision = -2;
1398
1399                /* Skip the '*' */
1400                alias++;
1401
1402                /* save the current position */
1403                backup = alias;
1404
1405                /* handle positional parameters */
1406                if(ISDIGIT(*alias)) {
1407                    spec.fPrecisionPos = (int) (*alias++ - DIGIT_ZERO);
1408
1409                    while(ISDIGIT(*alias)) {
1410                        spec.fPrecisionPos *= 10;
1411                        spec.fPrecisionPos += (int) (*alias++ - DIGIT_ZERO);
1412                    }
1413
1414                    /* if there is no '$', don't read anything */
1415                    if(*alias != SPEC_DOLLARSIGN) {
1416                        spec.fPrecisionPos = -1;
1417                        alias = backup;
1418                    }
1419                    else {
1420                        /* munge the '$' */
1421                        alias++;
1422                    }
1423                }
1424            }
1425            /* read the precision */
1426            else if(ISDIGIT(*alias)){
1427                info->fPrecision = (int) (*alias++ - DIGIT_ZERO);
1428
1429                while(ISDIGIT(*alias)) {
1430                    info->fPrecision *= 10;
1431                    info->fPrecision += (int) (*alias++ - DIGIT_ZERO);
1432                }
1433            }
1434        }
1435
1436        /* Get any modifiers */
1437        if(ISMOD(*alias)) {
1438            switch(*alias++) {
1439
1440                /* short */
1441            case MOD_H:
1442                info->fIsShort = TRUE;
1443                break;
1444
1445                /* long or long long */
1446            case MOD_LOWERL:
1447                if(*alias == MOD_LOWERL) {
1448                    info->fIsLongLong = TRUE;
1449                    /* skip over the next 'l' */
1450                    alias++;
1451                }
1452                else
1453                    info->fIsLong = TRUE;
1454                break;
1455
1456                /* long double */
1457            case MOD_L:
1458                info->fIsLongDouble = TRUE;
1459                break;
1460            }
1461        }
1462
1463        /* finally, get the specifier letter */
1464        info->fSpec = *alias++;
1465        info->fOrigSpec = info->fSpec;
1466
1467        /* fill in the precision and width, if specified out of line */
1468
1469        /* width specified out of line */
1470        if(spec.fInfo.fWidth == -2) {
1471            if(spec.fWidthPos == -1) {
1472                /* read the width from the argument list */
1473                info->fWidth = va_arg(ap, int32_t);
1474            }
1475            /* else handle positional parameter */
1476
1477            /* if it's negative, take the absolute value and set left alignment */
1478            if(info->fWidth < 0) {
1479                info->fWidth *= -1; /* Make positive */
1480                info->fLeft = TRUE;
1481            }
1482        }
1483
1484        /* precision specified out of line */
1485        if(info->fPrecision == -2) {
1486            if(spec.fPrecisionPos == -1) {
1487                /* read the precision from the argument list */
1488                info->fPrecision = va_arg(ap, int32_t);
1489            }
1490            /* else handle positional parameter */
1491
1492            /* if it's negative, set it to zero */
1493            if(info->fPrecision < 0)
1494                info->fPrecision = 0;
1495        }
1496
1497        handlerNum = (uint16_t)(info->fSpec - UPRINTF_BASE_FMT_HANDLERS);
1498        if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
1499            /* query the info function for argument information */
1500            argType = g_u_printf_infos[ handlerNum ].info;
1501
1502            /* goto the correct argument on arg_list if position is specified */
1503            if (spec.fArgPos > 0) {
1504                /* offset position by 1 */
1505                spec.fArgPos--;
1506                switch(argType) {
1507                case ufmt_count:
1508                    /* set the spec's width to the # of chars written */
1509                    info->fWidth = *written;
1510                    /* fall through to set the pointer */
1511                case ufmt_string:
1512                case ufmt_ustring:
1513                case ufmt_pointer:
1514                    args.ptrValue = arglist[spec.fArgPos].ptrValue;
1515                    break;
1516                case ufmt_char:
1517                case ufmt_uchar:
1518                case ufmt_int:
1519                    args.int64Value = arglist[spec.fArgPos].int64Value;
1520                    break;
1521                case ufmt_float:
1522                    args.floatValue = arglist[spec.fArgPos].floatValue;
1523                    break;
1524                case ufmt_double:
1525                    args.doubleValue = arglist[spec.fArgPos].doubleValue;
1526                    break;
1527                default:
1528                    /* else args is ignored */
1529                    args.ptrValue = NULL;
1530                    break;
1531                }
1532            } else { /* no positional argument specified */
1533                switch(argType) {
1534                case ufmt_count:
1535                    /* set the spec's width to the # of chars written */
1536                    info->fWidth = *written;
1537                    /* fall through to set the pointer */
1538                case ufmt_string:
1539                case ufmt_ustring:
1540                case ufmt_pointer:
1541                    args.ptrValue = va_arg(ap, void*);
1542                    break;
1543                case ufmt_char:
1544                case ufmt_uchar:
1545                case ufmt_int:
1546                    if (info->fIsLongLong) {
1547                        args.int64Value = va_arg(ap, int64_t);
1548                    }
1549                    else {
1550                        args.int64Value = va_arg(ap, int32_t);
1551                    }
1552                    break;
1553                case ufmt_float:
1554                    args.floatValue = (float) va_arg(ap, double);
1555                    break;
1556                case ufmt_double:
1557                    args.doubleValue = va_arg(ap, double);
1558                    break;
1559                default:
1560                    /* else args is ignored */
1561                    args.ptrValue = NULL;
1562                    break;
1563                }
1564            }
1565
1566            /* call the handler function */
1567            handler = g_u_printf_infos[ handlerNum ].handler;
1568            if(handler != 0) {
1569                *written += (*handler)(streamHandler, context, formatBundle, info, &args);
1570            }
1571            else {
1572                /* just echo unknown tags */
1573                *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
1574            }
1575        }
1576        else {
1577            /* just echo unknown tags */
1578            *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
1579        }
1580    }
1581    /* delete parsed argument list */
1582    if (arglist != NULL) {
1583        uprv_free(arglist);
1584    }
1585    /* return # of characters in this format that have been parsed. */
1586    return (int32_t)(alias - fmt);
1587}
1588
1589#endif /* #if !UCONFIG_NO_FORMATTING */
1590