Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / icu / source / io / uprntf_p.c
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  */
84 typedef int32_t U_EXPORT2
85 u_printf_handler(const u_printf_stream_handler  *handler,
86
87                  void                           *context,
88                  ULocaleBundle                  *formatBundle,
89                  const u_printf_spec_info       *info,
90                  const ufmt_args                *args);
91
92 typedef struct u_printf_info {
93     ufmt_type_info info;
94     u_printf_handler *handler;
95 } u_printf_info;
96
97 /**
98  * Struct encapsulating a single uprintf format specification.
99  */
100 typedef struct u_printf_spec {
101   u_printf_spec_info    fInfo;        /* Information on this spec */
102   int32_t        fWidthPos;     /* Position of width in arg list */
103   int32_t        fPrecisionPos;    /* Position of precision in arg list */
104   int32_t        fArgPos;    /* Position of data in arg list */
105 } u_printf_spec;
106
107 #define UPRINTF_NUM_FMT_HANDLERS 108
108
109 /* We do not use handlers for 0-0x1f */
110 #define UPRINTF_BASE_FMT_HANDLERS 0x20
111
112 /* buffer size for formatting */
113 #define UPRINTF_BUFFER_SIZE 1024
114 #define UPRINTF_SYMBOL_BUFFER_SIZE 8
115
116 static const UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
117 static const UChar gSpaceStr[] = {0x20, 0}; /* " " */
118
119 /* Sets the sign of a format based on u_printf_spec_info */
120 /* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */
121 static void
122 u_printf_set_sign(UNumberFormat        *format,
123                    const u_printf_spec_info     *info,
124                    UChar *prefixBuffer,
125                    int32_t *prefixBufLen,
126                    UErrorCode *status)
127 {
128     if(info->fShowSign) {
129         *prefixBufLen = unum_getTextAttribute(format,
130                                               UNUM_POSITIVE_PREFIX,
131                                               prefixBuffer,
132                                               *prefixBufLen,
133                                               status);
134         if (info->fSpace) {
135             /* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */
136             /* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */
137             unum_setTextAttribute(format, UNUM_POSITIVE_PREFIX, gSpaceStr, 1, status);
138         }
139         else {
140             UChar plusSymbol[UPRINTF_SYMBOL_BUFFER_SIZE];
141             int32_t symbolLen;
142
143             symbolLen = unum_getSymbol(format,
144                 UNUM_PLUS_SIGN_SYMBOL,
145                 plusSymbol,
146                 sizeof(plusSymbol)/sizeof(*plusSymbol),
147                 status);
148             unum_setTextAttribute(format,
149                 UNUM_POSITIVE_PREFIX,
150                 plusSymbol,
151                 symbolLen,
152                 status);
153         }
154     }
155     else {
156         *prefixBufLen = 0;
157     }
158 }
159
160 static void
161 u_printf_reset_sign(UNumberFormat        *format,
162                    const u_printf_spec_info     *info,
163                    UChar *prefixBuffer,
164                    int32_t *prefixBufLen,
165                    UErrorCode *status)
166 {
167     if(info->fShowSign) {
168         unum_setTextAttribute(format,
169                               UNUM_POSITIVE_PREFIX,
170                               prefixBuffer,
171                               *prefixBufLen,
172                               status);
173     }
174 }
175
176
177 /* handle a '%' */
178 static int32_t
179 u_printf_simple_percent_handler(const u_printf_stream_handler  *handler,
180                                 void                           *context,
181                                 ULocaleBundle                  *formatBundle,
182                                 const u_printf_spec_info       *info,
183                                 const ufmt_args                *args)
184 {
185     static const UChar PERCENT[] = { UP_PERCENT };
186
187     /* put a single '%' onto the output */
188     return handler->write(context, PERCENT, 1);
189 }
190
191 /* handle 's' */
192 static int32_t
193 u_printf_string_handler(const u_printf_stream_handler  *handler,
194                         void                           *context,
195                         ULocaleBundle                  *formatBundle,
196                         const u_printf_spec_info       *info,
197                         const ufmt_args                *args)
198 {
199     UChar *s;
200     UChar buffer[UFMT_DEFAULT_BUFFER_SIZE];
201     int32_t len, written;
202     int32_t argSize;
203     const char *arg = (const char*)(args[0].ptrValue);
204
205     /* convert from the default codepage to Unicode */
206     if (arg) {
207         argSize = (int32_t)strlen(arg) + 1;
208         if (argSize >= MAX_UCHAR_BUFFER_SIZE(buffer)) {
209             s = ufmt_defaultCPToUnicode(arg, argSize,
210                     (UChar *)uprv_malloc(MAX_UCHAR_BUFFER_NEEDED(argSize)),
211                     MAX_UCHAR_BUFFER_NEEDED(argSize));
212             if(s == NULL) {
213                 return 0;
214             }
215         }
216         else {
217             s = ufmt_defaultCPToUnicode(arg, argSize, buffer,
218                     sizeof(buffer)/sizeof(UChar));
219         }
220     }
221     else {
222         s = (UChar *)gNullStr;
223     }
224     len = u_strlen(s);
225
226     /* width = minimum # of characters to write */
227     /* precision = maximum # of characters to write */
228     if (info->fPrecision != -1 && info->fPrecision < len) {
229         len = info->fPrecision;
230     }
231
232     written = handler->pad_and_justify(context, info, s, len);
233
234     /* clean up */
235     if (gNullStr != s && buffer != s) {
236         uprv_free(s);
237     }
238
239     return written;
240 }
241
242 static int32_t
243 u_printf_char_handler(const u_printf_stream_handler  *handler,
244                       void                           *context,
245                       ULocaleBundle                  *formatBundle,
246                       const u_printf_spec_info       *info,
247                       const ufmt_args                *args)
248 {
249     UChar s[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
270 static int32_t
271 u_printf_double_handler(const u_printf_stream_handler  *handler,
272                         void                           *context,
273                         ULocaleBundle                  *formatBundle,
274                         const u_printf_spec_info       *info,
275                         const ufmt_args                *args)
276 {
277     double        num         = (double) (args[0].doubleValue);
278     UNumberFormat  *format;
279     UChar          result[UPRINTF_BUFFER_SIZE];
280     UChar          prefixBuffer[UPRINTF_BUFFER_SIZE];
281     int32_t        prefixBufferLen = sizeof(prefixBuffer);
282     int32_t        minDecimalDigits;
283     int32_t        maxDecimalDigits;
284     int32_t        resultLen;
285     UErrorCode     status        = U_ZERO_ERROR;
286
287     prefixBuffer[0] = 0;
288
289     /* mask off any necessary bits */
290     /*  if(! info->fIsLongDouble)
291     num &= DBL_MAX;*/
292
293     /* get the formatter */
294     format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
295
296     /* handle error */
297     if(format == 0)
298         return 0;
299
300     /* save the formatter's state */
301     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
302     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
303
304     /* set the appropriate flags and number of decimal digits on the formatter */
305     if(info->fPrecision != -1) {
306         /* set the # of decimal digits */
307         unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
308     }
309     else if(info->fAlt) {
310         /* '#' means always show decimal point */
311         /* copy of printf behavior on Solaris - '#' shows 6 digits */
312         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
313     }
314     else {
315         /* # of decimal digits is 6 if precision not specified regardless of locale */
316         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
317     }
318
319     /* set whether to show the sign */
320     if (info->fShowSign) {
321         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
322     }
323
324     /* format the number */
325     resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
326
327     if (U_FAILURE(status)) {
328         resultLen = 0;
329     }
330
331     /* restore the number format */
332     /* TODO: Is this needed? */
333     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
334     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
335
336     if (info->fShowSign) {
337         /* Reset back to original value regardless of what the error was */
338         UErrorCode localStatus = U_ZERO_ERROR;
339         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
340     }
341
342     return handler->pad_and_justify(context, info, result, resultLen);
343 }
344
345 /* HSYS */
346 static int32_t
347 u_printf_integer_handler(const u_printf_stream_handler  *handler,
348                          void                           *context,
349                          ULocaleBundle                  *formatBundle,
350                          const u_printf_spec_info       *info,
351                          const ufmt_args                *args)
352 {
353     int64_t         num        = args[0].int64Value;
354     UNumberFormat   *format;
355     UChar           result[UPRINTF_BUFFER_SIZE];
356     UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
357     int32_t         prefixBufferLen = sizeof(prefixBuffer);
358     int32_t         minDigits     = -1;
359     int32_t         resultLen;
360     UErrorCode      status        = U_ZERO_ERROR;
361
362     prefixBuffer[0] = 0;
363
364     /* mask off any necessary bits */
365     if (info->fIsShort)
366         num = (int16_t)num;
367     else if (!info->fIsLongLong)
368         num = (int32_t)num;
369
370     /* get the formatter */
371     format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
372
373     /* handle error */
374     if(format == 0)
375         return 0;
376
377     /* set the appropriate flags on the formatter */
378
379     /* set the minimum integer digits */
380     if(info->fPrecision != -1) {
381         /* set the minimum # of digits */
382         minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
383         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
384     }
385
386     /* set whether to show the sign */
387     if(info->fShowSign) {
388         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
389     }
390
391     /* format the number */
392     resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
393
394     if (U_FAILURE(status)) {
395         resultLen = 0;
396     }
397
398     /* restore the number format */
399     if (minDigits != -1) {
400         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
401     }
402
403     if (info->fShowSign) {
404         /* Reset back to original value regardless of what the error was */
405         UErrorCode localStatus = U_ZERO_ERROR;
406         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
407     }
408
409     return handler->pad_and_justify(context, info, result, resultLen);
410 }
411
412 static int32_t
413 u_printf_hex_handler(const u_printf_stream_handler  *handler,
414                      void                           *context,
415                      ULocaleBundle                  *formatBundle,
416                      const u_printf_spec_info       *info,
417                      const ufmt_args                *args)
418 {
419     int64_t         num        = args[0].int64Value;
420     UChar           result[UPRINTF_BUFFER_SIZE];
421     int32_t         len        = UPRINTF_BUFFER_SIZE;
422
423
424     /* mask off any necessary bits */
425     if (info->fIsShort)
426         num &= UINT16_MAX;
427     else if (!info->fIsLongLong)
428         num &= UINT32_MAX;
429
430     /* format the number, preserving the minimum # of digits */
431     ufmt_64tou(result, &len, num, 16,
432         (UBool)(info->fSpec == 0x0078),
433         (info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);
434
435     /* convert to alt form, if desired */
436     if(num != 0 && info->fAlt && len < UPRINTF_BUFFER_SIZE - 2) {
437         /* shift the formatted string right by 2 chars */
438         memmove(result + 2, result, len * sizeof(UChar));
439         result[0] = 0x0030;
440         result[1] = info->fSpec;
441         len += 2;
442     }
443
444     return handler->pad_and_justify(context, info, result, len);
445 }
446
447 static int32_t
448 u_printf_octal_handler(const u_printf_stream_handler  *handler,
449                        void                           *context,
450                        ULocaleBundle                  *formatBundle,
451                        const u_printf_spec_info       *info,
452                        const ufmt_args                *args)
453 {
454     int64_t         num        = args[0].int64Value;
455     UChar           result[UPRINTF_BUFFER_SIZE];
456     int32_t         len        = UPRINTF_BUFFER_SIZE;
457
458
459     /* mask off any necessary bits */
460     if (info->fIsShort)
461         num &= UINT16_MAX;
462     else if (!info->fIsLongLong)
463         num &= UINT32_MAX;
464
465     /* format the number, preserving the minimum # of digits */
466     ufmt_64tou(result, &len, num, 8,
467         FALSE, /* doesn't matter for octal */
468         info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);
469
470     /* convert to alt form, if desired */
471     if(info->fAlt && result[0] != 0x0030 && len < UPRINTF_BUFFER_SIZE - 1) {
472         /* shift the formatted string right by 1 char */
473         memmove(result + 1, result, len * sizeof(UChar));
474         result[0] = 0x0030;
475         len += 1;
476     }
477
478     return handler->pad_and_justify(context, info, result, len);
479 }
480
481 static int32_t
482 u_printf_uinteger_handler(const u_printf_stream_handler *handler,
483                           void                          *context,
484                           ULocaleBundle                 *formatBundle,
485                           const u_printf_spec_info      *info,
486                           const ufmt_args               *args)
487 {
488     int64_t         num        = args[0].int64Value;
489     UNumberFormat   *format;
490     UChar           result[UPRINTF_BUFFER_SIZE];
491     int32_t         minDigits     = -1;
492     int32_t         resultLen;
493     UErrorCode      status        = U_ZERO_ERROR;
494
495     /* TODO: Fix this once uint64_t can be formatted. */
496     if (info->fIsShort)
497         num &= UINT16_MAX;
498     else if (!info->fIsLongLong)
499         num &= UINT32_MAX;
500
501     /* get the formatter */
502     format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
503
504     /* handle error */
505     if(format == 0)
506         return 0;
507
508     /* set the appropriate flags on the formatter */
509
510     /* set the minimum integer digits */
511     if(info->fPrecision != -1) {
512         /* set the minimum # of digits */
513         minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
514         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
515     }
516
517     /* To mirror other stdio implementations, we ignore the sign argument */
518
519     /* format the number */
520     resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
521
522     if (U_FAILURE(status)) {
523         resultLen = 0;
524     }
525
526     /* restore the number format */
527     if (minDigits != -1) {
528         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
529     }
530
531     return handler->pad_and_justify(context, info, result, resultLen);
532 }
533
534 static int32_t
535 u_printf_pointer_handler(const u_printf_stream_handler  *handler,
536                          void                           *context,
537                          ULocaleBundle                  *formatBundle,
538                          const u_printf_spec_info       *info,
539                          const ufmt_args                *args)
540 {
541     UChar           result[UPRINTF_BUFFER_SIZE];
542     int32_t         len  = UPRINTF_BUFFER_SIZE;
543
544     /* format the pointer in hex */
545     ufmt_ptou(result, &len, args[0].ptrValue, TRUE/*, info->fPrecision*/);
546
547     return handler->pad_and_justify(context, info, result, len);
548 }
549
550 static int32_t
551 u_printf_scientific_handler(const u_printf_stream_handler  *handler,
552                             void                           *context,
553                             ULocaleBundle                  *formatBundle,
554                             const u_printf_spec_info       *info,
555                             const ufmt_args                *args)
556 {
557     double          num         = (double) (args[0].doubleValue);
558     UNumberFormat   *format;
559     UChar           result[UPRINTF_BUFFER_SIZE];
560     UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
561     int32_t         prefixBufferLen = sizeof(prefixBuffer);
562     int32_t         minDecimalDigits;
563     int32_t         maxDecimalDigits;
564     UErrorCode      status        = U_ZERO_ERROR;
565     UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
566     int32_t srcLen, expLen;
567     int32_t resultLen;
568     UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
569
570     prefixBuffer[0] = 0;
571
572     /* mask off any necessary bits */
573     /*  if(! info->fIsLongDouble)
574     num &= DBL_MAX;*/
575
576     /* get the formatter */
577     format = u_locbund_getNumberFormat(formatBundle, UNUM_SCIENTIFIC);
578
579     /* handle error */
580     if(format == 0)
581         return 0;
582
583     /* set the appropriate flags on the formatter */
584
585     srcLen = unum_getSymbol(format,
586         UNUM_EXPONENTIAL_SYMBOL,
587         srcExpBuf,
588         sizeof(srcExpBuf),
589         &status);
590
591     /* Upper/lower case the e */
592     if (info->fSpec == (UChar)0x65 /* e */) {
593         expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
594             srcExpBuf, srcLen,
595             formatBundle->fLocale,
596             &status);
597     }
598     else {
599         expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
600             srcExpBuf, srcLen,
601             formatBundle->fLocale,
602             &status);
603     }
604
605     unum_setSymbol(format,
606         UNUM_EXPONENTIAL_SYMBOL,
607         expBuf,
608         expLen,
609         &status);
610
611     /* save the formatter's state */
612     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
613     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
614
615     /* set the appropriate flags and number of decimal digits on the formatter */
616     if(info->fPrecision != -1) {
617         /* set the # of decimal digits */
618         if (info->fOrigSpec == (UChar)0x65 /* e */ || info->fOrigSpec == (UChar)0x45 /* E */) {
619             unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
620         }
621         else {
622             unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, 1);
623             unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, info->fPrecision);
624         }
625     }
626     else if(info->fAlt) {
627         /* '#' means always show decimal point */
628         /* copy of printf behavior on Solaris - '#' shows 6 digits */
629         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
630     }
631     else {
632         /* # of decimal digits is 6 if precision not specified */
633         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
634     }
635
636     /* set whether to show the sign */
637     if (info->fShowSign) {
638         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
639     }
640
641     /* format the number */
642     resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
643
644     if (U_FAILURE(status)) {
645         resultLen = 0;
646     }
647
648     /* restore the number format */
649     /* TODO: Is this needed? */
650     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
651     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
652
653     /* Since we're the only one using the scientific
654        format, we don't need to save the old exponent value. */
655     /*unum_setSymbol(format,
656         UNUM_EXPONENTIAL_SYMBOL,
657         srcExpBuf,
658         srcLen,
659         &status);*/
660
661     if (info->fShowSign) {
662         /* Reset back to original value regardless of what the error was */
663         UErrorCode localStatus = U_ZERO_ERROR;
664         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
665     }
666
667     return handler->pad_and_justify(context, info, result, resultLen);
668 }
669
670 static int32_t
671 u_printf_percent_handler(const u_printf_stream_handler  *handler,
672                          void                           *context,
673                          ULocaleBundle                  *formatBundle,
674                          const u_printf_spec_info       *info,
675                          const ufmt_args                *args)
676 {
677     double          num         = (double) (args[0].doubleValue);
678     UNumberFormat   *format;
679     UChar           result[UPRINTF_BUFFER_SIZE];
680     UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
681     int32_t         prefixBufferLen = sizeof(prefixBuffer);
682     int32_t         minDecimalDigits;
683     int32_t         maxDecimalDigits;
684     int32_t         resultLen;
685     UErrorCode      status        = U_ZERO_ERROR;
686
687     prefixBuffer[0] = 0;
688
689     /* mask off any necessary bits */
690     /*  if(! info->fIsLongDouble)
691     num &= DBL_MAX;*/
692
693     /* get the formatter */
694     format = u_locbund_getNumberFormat(formatBundle, UNUM_PERCENT);
695
696     /* handle error */
697     if(format == 0)
698         return 0;
699
700     /* save the formatter's state */
701     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
702     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
703
704     /* set the appropriate flags and number of decimal digits on the formatter */
705     if(info->fPrecision != -1) {
706         /* set the # of decimal digits */
707         unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
708     }
709     else if(info->fAlt) {
710         /* '#' means always show decimal point */
711         /* copy of printf behavior on Solaris - '#' shows 6 digits */
712         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
713     }
714     else {
715         /* # of decimal digits is 6 if precision not specified */
716         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
717     }
718
719     /* set whether to show the sign */
720     if (info->fShowSign) {
721         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
722     }
723
724     /* format the number */
725     resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
726
727     if (U_FAILURE(status)) {
728         resultLen = 0;
729     }
730
731     /* restore the number format */
732     /* TODO: Is this needed? */
733     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
734     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
735
736     if (info->fShowSign) {
737         /* Reset back to original value regardless of what the error was */
738         UErrorCode localStatus = U_ZERO_ERROR;
739         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
740     }
741
742     return handler->pad_and_justify(context, info, result, resultLen);
743 }
744
745 static int32_t
746 u_printf_ustring_handler(const u_printf_stream_handler  *handler,
747                          void                           *context,
748                          ULocaleBundle                  *formatBundle,
749                          const u_printf_spec_info       *info,
750                          const ufmt_args                *args)
751 {
752     int32_t len, written;
753     const UChar *arg = (const UChar*)(args[0].ptrValue);
754
755     /* allocate enough space for the buffer */
756     if (arg == NULL) {
757         arg = gNullStr;
758     }
759     len = u_strlen(arg);
760
761     /* width = minimum # of characters to write */
762     /* precision = maximum # of characters to write */
763     if (info->fPrecision != -1 && info->fPrecision < len) {
764         len = info->fPrecision;
765     }
766
767     /* determine if the string should be padded */
768     written = handler->pad_and_justify(context, info, arg, len);
769
770     return written;
771 }
772
773 static int32_t
774 u_printf_uchar_handler(const u_printf_stream_handler  *handler,
775                        void                           *context,
776                        ULocaleBundle                  *formatBundle,
777                        const u_printf_spec_info       *info,
778                        const ufmt_args                *args)
779 {
780     int32_t written = 0;
781     UChar arg = (UChar)(args[0].int64Value);
782
783     /* width = minimum # of characters to write */
784     /* precision = maximum # of characters to write */
785     /* precision is ignored when handling a uchar */
786
787     /* determine if the string should be padded */
788     written = handler->pad_and_justify(context, info, &arg, 1);
789
790     return written;
791 }
792
793 static int32_t
794 u_printf_scidbl_handler(const u_printf_stream_handler  *handler,
795                         void                           *context,
796                         ULocaleBundle                  *formatBundle,
797                         const u_printf_spec_info       *info,
798                         const ufmt_args                *args)
799 {
800     u_printf_spec_info scidbl_info;
801     double      num = args[0].doubleValue;
802     int32_t     retVal;
803     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
852 static int32_t
853 u_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
868 static int32_t
869 u_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 */
947 static 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. */
1046 static ufmt_args* parseArguments(const UChar *alias, va_list ap, UErrorCode *status) {
1047     ufmt_args *arglist = NULL;
1048     ufmt_type_info *typelist = NULL;
1049     UBool *islonglong = NULL;
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 */
1206 U_CFUNC int32_t
1207 u_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 */