Imported Upstream version 58.1
[platform/upstream/icu.git] / source / io / uprntf_p.c
1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 ******************************************************************************
5 *
6 *   Copyright (C) 1998-2016, International Business Machines
7 *   Corporation and others.  All Rights Reserved.
8 *
9 ******************************************************************************
10 *
11 * File uprntf_p.c
12 *
13 * Modification History:
14 *
15 *   Date        Name        Description
16 *   11/23/98    stephen     Creation.
17 *   03/12/99    stephen     Modified for new C API.
18 *   08/07/2003  george      Reunify printf implementations
19 ******************************************************************************
20 */
21
22 #include "unicode/utypes.h"
23
24 #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_CONVERSION
25
26 #include "unicode/ustring.h"
27 #include "unicode/utf16.h"
28 #include "uprintf.h"
29 #include "ufmt_cmn.h"
30 #include "cmemory.h"
31 #include "putilimp.h"
32
33 /* ANSI style formatting */
34 /* Use US-ASCII characters only for formatting */
35
36 /* % */
37 #define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_printf_simple_percent_handler}
38 /* s */
39 #define UFMT_STRING         {ufmt_string, u_printf_string_handler}
40 /* c */
41 #define UFMT_CHAR           {ufmt_char, u_printf_char_handler}
42 /* d, i */
43 #define UFMT_INT            {ufmt_int, u_printf_integer_handler}
44 /* u */
45 #define UFMT_UINT           {ufmt_int, u_printf_uinteger_handler}
46 /* o */
47 #define UFMT_OCTAL          {ufmt_int, u_printf_octal_handler}
48 /* x, X */
49 #define UFMT_HEX            {ufmt_int, u_printf_hex_handler}
50 /* f */
51 #define UFMT_DOUBLE         {ufmt_double, u_printf_double_handler}
52 /* e, E */
53 #define UFMT_SCIENTIFIC     {ufmt_double, u_printf_scientific_handler}
54 /* g, G */
55 #define UFMT_SCIDBL         {ufmt_double, u_printf_scidbl_handler}
56 /* n */
57 #define UFMT_COUNT          {ufmt_count, u_printf_count_handler}
58
59 /* non-ANSI extensions */
60 /* Use US-ASCII characters only for formatting */
61
62 /* p */
63 #define UFMT_POINTER        {ufmt_pointer, u_printf_pointer_handler}
64 /* V */
65 #define UFMT_SPELLOUT       {ufmt_double, u_printf_spellout_handler}
66 /* P */
67 #define UFMT_PERCENT        {ufmt_double, u_printf_percent_handler}
68 /* C  K is old format */
69 #define UFMT_UCHAR          {ufmt_uchar, u_printf_uchar_handler}
70 /* S  U is old format */
71 #define UFMT_USTRING        {ufmt_ustring, u_printf_ustring_handler}
72
73
74 #define UFMT_EMPTY {ufmt_empty, NULL}
75
76 /**
77  * A u_printf handler function.  
78  * A u_printf handler is responsible for handling a single u_printf 
79  * format specification, for example 'd' or 's'.
80  * @param stream The UFILE to which to write output.
81  * @param info A pointer to a <TT>u_printf_spec_info</TT> struct containing
82  * information on the format specification.
83  * @param args A pointer to the argument data
84  * @return The number of Unicode characters written to <TT>stream</TT>.
85  */
86 typedef int32_t U_EXPORT2
87 u_printf_handler(const u_printf_stream_handler  *handler,
88
89                  void                           *context,
90                  ULocaleBundle                  *formatBundle,
91                  const u_printf_spec_info       *info,
92                  const ufmt_args                *args);
93
94 typedef struct u_printf_info {
95     ufmt_type_info info;
96     u_printf_handler *handler;
97 } u_printf_info;
98
99 /**
100  * Struct encapsulating a single uprintf format specification.
101  */
102 typedef struct u_printf_spec {
103   u_printf_spec_info    fInfo;        /* Information on this spec */
104   int32_t        fWidthPos;     /* Position of width in arg list */
105   int32_t        fPrecisionPos;    /* Position of precision in arg list */
106   int32_t        fArgPos;    /* Position of data in arg list */
107 } u_printf_spec;
108
109 #define UPRINTF_NUM_FMT_HANDLERS 108
110
111 /* We do not use handlers for 0-0x1f */
112 #define UPRINTF_BASE_FMT_HANDLERS 0x20
113
114 /* buffer size for formatting */
115 #define UPRINTF_BUFFER_SIZE 1024
116 #define UPRINTF_SYMBOL_BUFFER_SIZE 8
117
118 static const UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
119 static const UChar gSpaceStr[] = {0x20, 0}; /* " " */
120
121 /* Sets the sign of a format based on u_printf_spec_info */
122 /* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */
123 static void
124 u_printf_set_sign(UNumberFormat        *format,
125                    const u_printf_spec_info     *info,
126                    UChar *prefixBuffer,
127                    int32_t *prefixBufLen,
128                    UErrorCode *status)
129 {
130     if(info->fShowSign) {
131         *prefixBufLen = unum_getTextAttribute(format,
132                                               UNUM_POSITIVE_PREFIX,
133                                               prefixBuffer,
134                                               *prefixBufLen,
135                                               status);
136         if (info->fSpace) {
137             /* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */
138             /* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */
139             unum_setTextAttribute(format, UNUM_POSITIVE_PREFIX, gSpaceStr, 1, status);
140         }
141         else {
142             UChar plusSymbol[UPRINTF_SYMBOL_BUFFER_SIZE];
143             int32_t symbolLen;
144
145             symbolLen = unum_getSymbol(format,
146                 UNUM_PLUS_SIGN_SYMBOL,
147                 plusSymbol,
148                 UPRV_LENGTHOF(plusSymbol),
149                 status);
150             unum_setTextAttribute(format,
151                 UNUM_POSITIVE_PREFIX,
152                 plusSymbol,
153                 symbolLen,
154                 status);
155         }
156     }
157     else {
158         *prefixBufLen = 0;
159     }
160 }
161
162 static void
163 u_printf_reset_sign(UNumberFormat        *format,
164                    const u_printf_spec_info     *info,
165                    UChar *prefixBuffer,
166                    int32_t *prefixBufLen,
167                    UErrorCode *status)
168 {
169     if(info->fShowSign) {
170         unum_setTextAttribute(format,
171                               UNUM_POSITIVE_PREFIX,
172                               prefixBuffer,
173                               *prefixBufLen,
174                               status);
175     }
176 }
177
178
179 /* handle a '%' */
180 static int32_t
181 u_printf_simple_percent_handler(const u_printf_stream_handler  *handler,
182                                 void                           *context,
183                                 ULocaleBundle                  *formatBundle,
184                                 const u_printf_spec_info       *info,
185                                 const ufmt_args                *args)
186 {
187     static const UChar PERCENT[] = { UP_PERCENT };
188
189     /* put a single '%' onto the output */
190     return handler->write(context, PERCENT, 1);
191 }
192
193 /* handle 's' */
194 static int32_t
195 u_printf_string_handler(const u_printf_stream_handler  *handler,
196                         void                           *context,
197                         ULocaleBundle                  *formatBundle,
198                         const u_printf_spec_info       *info,
199                         const ufmt_args                *args)
200 {
201     UChar *s;
202     UChar buffer[UFMT_DEFAULT_BUFFER_SIZE];
203     int32_t len, written;
204     int32_t argSize;
205     const char *arg = (const char*)(args[0].ptrValue);
206
207     /* convert from the default codepage to Unicode */
208     if (arg) {
209         argSize = (int32_t)strlen(arg) + 1;
210         if (argSize >= MAX_UCHAR_BUFFER_SIZE(buffer)) {
211             s = ufmt_defaultCPToUnicode(arg, argSize,
212                     (UChar *)uprv_malloc(MAX_UCHAR_BUFFER_NEEDED(argSize)),
213                     MAX_UCHAR_BUFFER_NEEDED(argSize));
214             if(s == NULL) {
215                 return 0;
216             }
217         }
218         else {
219             s = ufmt_defaultCPToUnicode(arg, argSize, buffer,
220                     UPRV_LENGTHOF(buffer));
221         }
222     }
223     else {
224         s = (UChar *)gNullStr;
225     }
226     len = u_strlen(s);
227
228     /* width = minimum # of characters to write */
229     /* precision = maximum # of characters to write */
230     if (info->fPrecision != -1 && info->fPrecision < len) {
231         len = info->fPrecision;
232     }
233
234     written = handler->pad_and_justify(context, info, s, len);
235
236     /* clean up */
237     if (gNullStr != s && buffer != s) {
238         uprv_free(s);
239     }
240
241     return written;
242 }
243
244 static int32_t
245 u_printf_char_handler(const u_printf_stream_handler  *handler,
246                       void                           *context,
247                       ULocaleBundle                  *formatBundle,
248                       const u_printf_spec_info       *info,
249                       const ufmt_args                *args)
250 {
251     UChar s[U16_MAX_LENGTH+1];
252     int32_t len = 1, written;
253     unsigned char arg = (unsigned char)(args[0].int64Value);
254
255     /* convert from default codepage to Unicode */
256     ufmt_defaultCPToUnicode((const char *)&arg, 2, s, UPRV_LENGTHOF(s));
257
258     /* Remember that this may be an MBCS character */
259     if (arg != 0) {
260         len = u_strlen(s);
261     }
262
263     /* width = minimum # of characters to write */
264     /* precision = maximum # of characters to write */
265     /* precision is ignored when handling a char */
266
267     written = handler->pad_and_justify(context, info, s, len);
268
269     return written;
270 }
271
272 static int32_t
273 u_printf_double_handler(const u_printf_stream_handler  *handler,
274                         void                           *context,
275                         ULocaleBundle                  *formatBundle,
276                         const u_printf_spec_info       *info,
277                         const ufmt_args                *args)
278 {
279     double        num         = (double) (args[0].doubleValue);
280     UNumberFormat  *format;
281     UChar          result[UPRINTF_BUFFER_SIZE];
282     UChar          prefixBuffer[UPRINTF_BUFFER_SIZE];
283     int32_t        prefixBufferLen = sizeof(prefixBuffer);
284     int32_t        minDecimalDigits;
285     int32_t        maxDecimalDigits;
286     int32_t        resultLen;
287     UErrorCode     status        = U_ZERO_ERROR;
288
289     prefixBuffer[0] = 0;
290
291     /* mask off any necessary bits */
292     /*  if(! info->fIsLongDouble)
293     num &= DBL_MAX;*/
294
295     /* get the formatter */
296     format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
297
298     /* handle error */
299     if(format == 0)
300         return 0;
301
302     /* save the formatter's state */
303     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
304     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
305
306     /* set the appropriate flags and number of decimal digits on the formatter */
307     if(info->fPrecision != -1) {
308         /* set the # of decimal digits */
309         unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
310     }
311     else if(info->fAlt) {
312         /* '#' means always show decimal point */
313         /* copy of printf behavior on Solaris - '#' shows 6 digits */
314         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
315     }
316     else {
317         /* # of decimal digits is 6 if precision not specified regardless of locale */
318         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
319     }
320
321     /* set whether to show the sign */
322     if (info->fShowSign) {
323         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
324     }
325
326     /* format the number */
327     resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
328
329     if (U_FAILURE(status)) {
330         resultLen = 0;
331     }
332
333     /* restore the number format */
334     /* TODO: Is this needed? */
335     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
336     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
337
338     if (info->fShowSign) {
339         /* Reset back to original value regardless of what the error was */
340         UErrorCode localStatus = U_ZERO_ERROR;
341         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
342     }
343
344     return handler->pad_and_justify(context, info, result, resultLen);
345 }
346
347 /* HSYS */
348 static int32_t
349 u_printf_integer_handler(const u_printf_stream_handler  *handler,
350                          void                           *context,
351                          ULocaleBundle                  *formatBundle,
352                          const u_printf_spec_info       *info,
353                          const ufmt_args                *args)
354 {
355     int64_t         num        = args[0].int64Value;
356     UNumberFormat   *format;
357     UChar           result[UPRINTF_BUFFER_SIZE];
358     UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
359     int32_t         prefixBufferLen = sizeof(prefixBuffer);
360     int32_t         minDigits     = -1;
361     int32_t         resultLen;
362     UErrorCode      status        = U_ZERO_ERROR;
363
364     prefixBuffer[0] = 0;
365
366     /* mask off any necessary bits */
367     if (info->fIsShort)
368         num = (int16_t)num;
369     else if (!info->fIsLongLong)
370         num = (int32_t)num;
371
372     /* get the formatter */
373     format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
374
375     /* handle error */
376     if(format == 0)
377         return 0;
378
379     /* set the appropriate flags on the formatter */
380
381     /* set the minimum integer digits */
382     if(info->fPrecision != -1) {
383         /* set the minimum # of digits */
384         minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
385         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
386     }
387
388     /* set whether to show the sign */
389     if(info->fShowSign) {
390         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
391     }
392
393     /* format the number */
394     resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
395
396     if (U_FAILURE(status)) {
397         resultLen = 0;
398     }
399
400     /* restore the number format */
401     if (minDigits != -1) {
402         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
403     }
404
405     if (info->fShowSign) {
406         /* Reset back to original value regardless of what the error was */
407         UErrorCode localStatus = U_ZERO_ERROR;
408         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
409     }
410
411     return handler->pad_and_justify(context, info, result, resultLen);
412 }
413
414 static int32_t
415 u_printf_hex_handler(const u_printf_stream_handler  *handler,
416                      void                           *context,
417                      ULocaleBundle                  *formatBundle,
418                      const u_printf_spec_info       *info,
419                      const ufmt_args                *args)
420 {
421     int64_t         num        = args[0].int64Value;
422     UChar           result[UPRINTF_BUFFER_SIZE];
423     int32_t         len        = UPRINTF_BUFFER_SIZE;
424
425
426     /* mask off any necessary bits */
427     if (info->fIsShort)
428         num &= UINT16_MAX;
429     else if (!info->fIsLongLong)
430         num &= UINT32_MAX;
431
432     /* format the number, preserving the minimum # of digits */
433     ufmt_64tou(result, &len, num, 16,
434         (UBool)(info->fSpec == 0x0078),
435         (info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);
436
437     /* convert to alt form, if desired */
438     if(num != 0 && info->fAlt && len < UPRINTF_BUFFER_SIZE - 2) {
439         /* shift the formatted string right by 2 chars */
440         memmove(result + 2, result, len * sizeof(UChar));
441         result[0] = 0x0030;
442         result[1] = info->fSpec;
443         len += 2;
444     }
445
446     return handler->pad_and_justify(context, info, result, len);
447 }
448
449 static int32_t
450 u_printf_octal_handler(const u_printf_stream_handler  *handler,
451                        void                           *context,
452                        ULocaleBundle                  *formatBundle,
453                        const u_printf_spec_info       *info,
454                        const ufmt_args                *args)
455 {
456     int64_t         num        = args[0].int64Value;
457     UChar           result[UPRINTF_BUFFER_SIZE];
458     int32_t         len        = UPRINTF_BUFFER_SIZE;
459
460
461     /* mask off any necessary bits */
462     if (info->fIsShort)
463         num &= UINT16_MAX;
464     else if (!info->fIsLongLong)
465         num &= UINT32_MAX;
466
467     /* format the number, preserving the minimum # of digits */
468     ufmt_64tou(result, &len, num, 8,
469         FALSE, /* doesn't matter for octal */
470         info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);
471
472     /* convert to alt form, if desired */
473     if(info->fAlt && result[0] != 0x0030 && len < UPRINTF_BUFFER_SIZE - 1) {
474         /* shift the formatted string right by 1 char */
475         memmove(result + 1, result, len * sizeof(UChar));
476         result[0] = 0x0030;
477         len += 1;
478     }
479
480     return handler->pad_and_justify(context, info, result, len);
481 }
482
483 static int32_t
484 u_printf_uinteger_handler(const u_printf_stream_handler *handler,
485                           void                          *context,
486                           ULocaleBundle                 *formatBundle,
487                           const u_printf_spec_info      *info,
488                           const ufmt_args               *args)
489 {
490     int64_t         num        = args[0].int64Value;
491     UNumberFormat   *format;
492     UChar           result[UPRINTF_BUFFER_SIZE];
493     int32_t         minDigits     = -1;
494     int32_t         resultLen;
495     UErrorCode      status        = U_ZERO_ERROR;
496
497     /* TODO: Fix this once uint64_t can be formatted. */
498     if (info->fIsShort)
499         num &= UINT16_MAX;
500     else if (!info->fIsLongLong)
501         num &= UINT32_MAX;
502
503     /* get the formatter */
504     format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
505
506     /* handle error */
507     if(format == 0)
508         return 0;
509
510     /* set the appropriate flags on the formatter */
511
512     /* set the minimum integer digits */
513     if(info->fPrecision != -1) {
514         /* set the minimum # of digits */
515         minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
516         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
517     }
518
519     /* To mirror other stdio implementations, we ignore the sign argument */
520
521     /* format the number */
522     resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
523
524     if (U_FAILURE(status)) {
525         resultLen = 0;
526     }
527
528     /* restore the number format */
529     if (minDigits != -1) {
530         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
531     }
532
533     return handler->pad_and_justify(context, info, result, resultLen);
534 }
535
536 static int32_t
537 u_printf_pointer_handler(const u_printf_stream_handler  *handler,
538                          void                           *context,
539                          ULocaleBundle                  *formatBundle,
540                          const u_printf_spec_info       *info,
541                          const ufmt_args                *args)
542 {
543     UChar           result[UPRINTF_BUFFER_SIZE];
544     int32_t         len  = UPRINTF_BUFFER_SIZE;
545
546     /* format the pointer in hex */
547     ufmt_ptou(result, &len, args[0].ptrValue, TRUE/*, info->fPrecision*/);
548
549     return handler->pad_and_justify(context, info, result, len);
550 }
551
552 static int32_t
553 u_printf_scientific_handler(const u_printf_stream_handler  *handler,
554                             void                           *context,
555                             ULocaleBundle                  *formatBundle,
556                             const u_printf_spec_info       *info,
557                             const ufmt_args                *args)
558 {
559     double          num         = (double) (args[0].doubleValue);
560     UNumberFormat   *format;
561     UChar           result[UPRINTF_BUFFER_SIZE];
562     UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
563     int32_t         prefixBufferLen = sizeof(prefixBuffer);
564     int32_t         minDecimalDigits;
565     int32_t         maxDecimalDigits;
566     UErrorCode      status        = U_ZERO_ERROR;
567     UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
568     int32_t srcLen, expLen;
569     int32_t resultLen;
570     UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
571
572     prefixBuffer[0] = 0;
573
574     /* mask off any necessary bits */
575     /*  if(! info->fIsLongDouble)
576     num &= DBL_MAX;*/
577
578     /* get the formatter */
579     format = u_locbund_getNumberFormat(formatBundle, UNUM_SCIENTIFIC);
580
581     /* handle error */
582     if(format == 0)
583         return 0;
584
585     /* set the appropriate flags on the formatter */
586
587     srcLen = unum_getSymbol(format,
588         UNUM_EXPONENTIAL_SYMBOL,
589         srcExpBuf,
590         sizeof(srcExpBuf),
591         &status);
592
593     /* Upper/lower case the e */
594     if (info->fSpec == (UChar)0x65 /* e */) {
595         expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
596             srcExpBuf, srcLen,
597             formatBundle->fLocale,
598             &status);
599     }
600     else {
601         expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
602             srcExpBuf, srcLen,
603             formatBundle->fLocale,
604             &status);
605     }
606
607     unum_setSymbol(format,
608         UNUM_EXPONENTIAL_SYMBOL,
609         expBuf,
610         expLen,
611         &status);
612
613     /* save the formatter's state */
614     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
615     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
616
617     /* set the appropriate flags and number of decimal digits on the formatter */
618     if(info->fPrecision != -1) {
619         /* set the # of decimal digits */
620         if (info->fOrigSpec == (UChar)0x65 /* e */ || info->fOrigSpec == (UChar)0x45 /* E */) {
621             unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
622         }
623         else {
624             unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, 1);
625             unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, info->fPrecision);
626         }
627     }
628     else if(info->fAlt) {
629         /* '#' means always show decimal point */
630         /* copy of printf behavior on Solaris - '#' shows 6 digits */
631         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
632     }
633     else {
634         /* # of decimal digits is 6 if precision not specified */
635         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
636     }
637
638     /* set whether to show the sign */
639     if (info->fShowSign) {
640         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
641     }
642
643     /* format the number */
644     resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
645
646     if (U_FAILURE(status)) {
647         resultLen = 0;
648     }
649
650     /* restore the number format */
651     /* TODO: Is this needed? */
652     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
653     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
654
655     /* Since we're the only one using the scientific
656        format, we don't need to save the old exponent value. */
657     /*unum_setSymbol(format,
658         UNUM_EXPONENTIAL_SYMBOL,
659         srcExpBuf,
660         srcLen,
661         &status);*/
662
663     if (info->fShowSign) {
664         /* Reset back to original value regardless of what the error was */
665         UErrorCode localStatus = U_ZERO_ERROR;
666         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
667     }
668
669     return handler->pad_and_justify(context, info, result, resultLen);
670 }
671
672 static int32_t
673 u_printf_percent_handler(const u_printf_stream_handler  *handler,
674                          void                           *context,
675                          ULocaleBundle                  *formatBundle,
676                          const u_printf_spec_info       *info,
677                          const ufmt_args                *args)
678 {
679     double          num         = (double) (args[0].doubleValue);
680     UNumberFormat   *format;
681     UChar           result[UPRINTF_BUFFER_SIZE];
682     UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
683     int32_t         prefixBufferLen = sizeof(prefixBuffer);
684     int32_t         minDecimalDigits;
685     int32_t         maxDecimalDigits;
686     int32_t         resultLen;
687     UErrorCode      status        = U_ZERO_ERROR;
688
689     prefixBuffer[0] = 0;
690
691     /* mask off any necessary bits */
692     /*  if(! info->fIsLongDouble)
693     num &= DBL_MAX;*/
694
695     /* get the formatter */
696     format = u_locbund_getNumberFormat(formatBundle, UNUM_PERCENT);
697
698     /* handle error */
699     if(format == 0)
700         return 0;
701
702     /* save the formatter's state */
703     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
704     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
705
706     /* set the appropriate flags and number of decimal digits on the formatter */
707     if(info->fPrecision != -1) {
708         /* set the # of decimal digits */
709         unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
710     }
711     else if(info->fAlt) {
712         /* '#' means always show decimal point */
713         /* copy of printf behavior on Solaris - '#' shows 6 digits */
714         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
715     }
716     else {
717         /* # of decimal digits is 6 if precision not specified */
718         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
719     }
720
721     /* set whether to show the sign */
722     if (info->fShowSign) {
723         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
724     }
725
726     /* format the number */
727     resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
728
729     if (U_FAILURE(status)) {
730         resultLen = 0;
731     }
732
733     /* restore the number format */
734     /* TODO: Is this needed? */
735     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
736     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
737
738     if (info->fShowSign) {
739         /* Reset back to original value regardless of what the error was */
740         UErrorCode localStatus = U_ZERO_ERROR;
741         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
742     }
743
744     return handler->pad_and_justify(context, info, result, resultLen);
745 }
746
747 static int32_t
748 u_printf_ustring_handler(const u_printf_stream_handler  *handler,
749                          void                           *context,
750                          ULocaleBundle                  *formatBundle,
751                          const u_printf_spec_info       *info,
752                          const ufmt_args                *args)
753 {
754     int32_t len, written;
755     const UChar *arg = (const UChar*)(args[0].ptrValue);
756
757     /* allocate enough space for the buffer */
758     if (arg == NULL) {
759         arg = gNullStr;
760     }
761     len = u_strlen(arg);
762
763     /* width = minimum # of characters to write */
764     /* precision = maximum # of characters to write */
765     if (info->fPrecision != -1 && info->fPrecision < len) {
766         len = info->fPrecision;
767     }
768
769     /* determine if the string should be padded */
770     written = handler->pad_and_justify(context, info, arg, len);
771
772     return written;
773 }
774
775 static int32_t
776 u_printf_uchar_handler(const u_printf_stream_handler  *handler,
777                        void                           *context,
778                        ULocaleBundle                  *formatBundle,
779                        const u_printf_spec_info       *info,
780                        const ufmt_args                *args)
781 {
782     int32_t written = 0;
783     UChar arg = (UChar)(args[0].int64Value);
784
785     /* width = minimum # of characters to write */
786     /* precision = maximum # of characters to write */
787     /* precision is ignored when handling a uchar */
788
789     /* determine if the string should be padded */
790     written = handler->pad_and_justify(context, info, &arg, 1);
791
792     return written;
793 }
794
795 static int32_t
796 u_printf_scidbl_handler(const u_printf_stream_handler  *handler,
797                         void                           *context,
798                         ULocaleBundle                  *formatBundle,
799                         const u_printf_spec_info       *info,
800                         const ufmt_args                *args)
801 {
802     u_printf_spec_info scidbl_info;
803     double      num = args[0].doubleValue;
804     int32_t     retVal;
805     UNumberFormat *format;
806     int32_t maxSigDecimalDigits, significantDigits;
807
808     memcpy(&scidbl_info, info, sizeof(u_printf_spec_info));
809
810     /* determine whether to use 'd', 'e' or 'f' notation */
811     if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num))
812     {
813         /* use 'f' notation */
814         scidbl_info.fSpec = 0x0066;
815         scidbl_info.fPrecision = 0;
816         /* call the double handler */
817         retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
818     }
819     else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num)
820         || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision)))
821     {
822         /* use 'e' or 'E' notation */
823         scidbl_info.fSpec = scidbl_info.fSpec - 2;
824         if (scidbl_info.fPrecision == -1) {
825             scidbl_info.fPrecision = 5;
826         }
827         /* call the scientific handler */
828         retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args);
829     }
830     else {
831         format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
832         /* Check for null pointer */
833         if (format == NULL) {
834             return 0;
835         }
836         maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS);
837         significantDigits = scidbl_info.fPrecision;
838
839         /* use 'f' notation */
840         scidbl_info.fSpec = 0x0066;
841         if (significantDigits == -1) {
842             significantDigits = 6;
843         }
844         unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
845         unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, significantDigits);
846         /* call the double handler */
847         retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
848         unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, maxSigDecimalDigits);
849         unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, FALSE);
850     }
851     return retVal;
852 }
853
854 static int32_t
855 u_printf_count_handler(const u_printf_stream_handler  *handler,
856                        void                           *context,
857                        ULocaleBundle                  *formatBundle,
858                        const u_printf_spec_info       *info,
859                        const ufmt_args                *args)
860 {
861     int32_t *count = (int32_t*)(args[0].ptrValue);
862
863     /* in the special case of count, the u_printf_spec_info's width */
864     /* will contain the # of chars written thus far */
865     *count = info->fWidth;
866
867     return 0;
868 }
869
870 static int32_t
871 u_printf_spellout_handler(const u_printf_stream_handler *handler,
872                           void                          *context,
873                           ULocaleBundle                 *formatBundle,
874                           const u_printf_spec_info      *info,
875                           const ufmt_args               *args)
876 {
877     double          num         = (double) (args[0].doubleValue);
878     UNumberFormat   *format;
879     UChar           result[UPRINTF_BUFFER_SIZE];
880     UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
881     int32_t         prefixBufferLen = sizeof(prefixBuffer);
882     int32_t         minDecimalDigits;
883     int32_t         maxDecimalDigits;
884     int32_t         resultLen;
885     UErrorCode      status        = U_ZERO_ERROR;
886
887     prefixBuffer[0] = 0;
888
889     /* mask off any necessary bits */
890     /*  if(! info->fIsLongDouble)
891     num &= DBL_MAX;*/
892
893     /* get the formatter */
894     format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT);
895
896     /* handle error */
897     if(format == 0)
898         return 0;
899
900     /* save the formatter's state */
901     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
902     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
903
904     /* set the appropriate flags and number of decimal digits on the formatter */
905     if(info->fPrecision != -1) {
906         /* set the # of decimal digits */
907         unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
908     }
909     else if(info->fAlt) {
910         /* '#' means always show decimal point */
911         /* copy of printf behavior on Solaris - '#' shows 6 digits */
912         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
913     }
914     else {
915         /* # of decimal digits is 6 if precision not specified */
916         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
917     }
918
919     /* set whether to show the sign */
920     if (info->fShowSign) {
921         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
922     }
923
924     /* format the number */
925     resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
926
927     if (U_FAILURE(status)) {
928         resultLen = 0;
929     }
930
931     /* restore the number format */
932     /* TODO: Is this needed? */
933     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
934     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
935
936     if (info->fShowSign) {
937         /* Reset back to original value regardless of what the error was */
938         UErrorCode localStatus = U_ZERO_ERROR;
939         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
940     }
941
942     return handler->pad_and_justify(context, info, result, resultLen);
943 }
944
945 /* Use US-ASCII characters only for formatting. Most codepages have
946  characters 20-7F from Unicode. Using any other codepage specific
947  characters will make it very difficult to format the string on
948  non-Unicode machines */
949 static const u_printf_info g_u_printf_infos[UPRINTF_NUM_FMT_HANDLERS] = {
950 /* 0x20 */
951     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
952     UFMT_EMPTY,         UFMT_SIMPLE_PERCENT,UFMT_EMPTY,         UFMT_EMPTY,
953     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
954     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
955
956 /* 0x30 */
957     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
958     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
959     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
960     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
961
962 /* 0x40 */
963     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR,
964     UFMT_EMPTY,         UFMT_SCIENTIFIC,    UFMT_EMPTY,         UFMT_SCIDBL,
965 #ifdef U_USE_OBSOLETE_IO_FORMATTING
966     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR/*deprecated*/,
967 #else
968     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
969 #endif
970     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
971
972 /* 0x50 */
973     UFMT_PERCENT,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_USTRING,
974 #ifdef U_USE_OBSOLETE_IO_FORMATTING
975     UFMT_EMPTY,         UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT,      UFMT_EMPTY,
976 #else
977     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_SPELLOUT,      UFMT_EMPTY,
978 #endif
979     UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
980     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
981
982 /* 0x60 */
983     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_CHAR,
984     UFMT_INT,           UFMT_SCIENTIFIC,    UFMT_DOUBLE,        UFMT_SCIDBL,
985     UFMT_EMPTY,         UFMT_INT,           UFMT_EMPTY,         UFMT_EMPTY,
986     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_COUNT,         UFMT_OCTAL,
987
988 /* 0x70 */
989     UFMT_POINTER,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_STRING,
990     UFMT_EMPTY,         UFMT_UINT,          UFMT_EMPTY,         UFMT_EMPTY,
991     UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
992     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
993 };
994
995 /* flag characters for uprintf */
996 #define FLAG_MINUS 0x002D
997 #define FLAG_PLUS 0x002B
998 #define FLAG_SPACE 0x0020
999 #define FLAG_POUND 0x0023
1000 #define FLAG_ZERO  0x0030
1001 #define FLAG_PAREN 0x0028
1002
1003 #define ISFLAG(s)    (s) == FLAG_MINUS || \
1004             (s) == FLAG_PLUS || \
1005             (s) == FLAG_SPACE || \
1006             (s) == FLAG_POUND || \
1007             (s) == FLAG_ZERO || \
1008             (s) == FLAG_PAREN
1009
1010 /* special characters for uprintf */
1011 #define SPEC_ASTERISK 0x002A
1012 #define SPEC_DOLLARSIGN 0x0024
1013 #define SPEC_PERIOD 0x002E
1014 #define SPEC_PERCENT 0x0025
1015
1016 /* unicode digits */
1017 #define DIGIT_ZERO 0x0030
1018 #define DIGIT_ONE 0x0031
1019 #define DIGIT_TWO 0x0032
1020 #define DIGIT_THREE 0x0033
1021 #define DIGIT_FOUR 0x0034
1022 #define DIGIT_FIVE 0x0035
1023 #define DIGIT_SIX 0x0036
1024 #define DIGIT_SEVEN 0x0037
1025 #define DIGIT_EIGHT 0x0038
1026 #define DIGIT_NINE 0x0039
1027
1028 #define ISDIGIT(s)    (s) == DIGIT_ZERO || \
1029             (s) == DIGIT_ONE || \
1030             (s) == DIGIT_TWO || \
1031             (s) == DIGIT_THREE || \
1032             (s) == DIGIT_FOUR || \
1033             (s) == DIGIT_FIVE || \
1034             (s) == DIGIT_SIX || \
1035             (s) == DIGIT_SEVEN || \
1036             (s) == DIGIT_EIGHT || \
1037             (s) == DIGIT_NINE
1038
1039 /* u_printf modifiers */
1040 #define MOD_H 0x0068
1041 #define MOD_LOWERL 0x006C
1042 #define MOD_L 0x004C
1043
1044 #define ISMOD(s)    (s) == MOD_H || \
1045             (s) == MOD_LOWERL || \
1046             (s) == MOD_L
1047 /* Returns an array of the parsed argument type given in the format string. */
1048 static ufmt_args* parseArguments(const UChar *alias, va_list ap, UErrorCode *status) {
1049     ufmt_args *arglist = NULL;
1050     ufmt_type_info *typelist = NULL;
1051     UBool *islonglong = NULL;
1052     int32_t size = 0;
1053     int32_t pos = 0;
1054     UChar type;
1055     uint16_t handlerNum;
1056     const UChar *aliasStart = alias;
1057
1058     /* get maximum number of arguments */
1059     for(;;) {
1060         /* find % */
1061         while(*alias != UP_PERCENT && *alias != 0x0000) {
1062             alias++;
1063         }
1064
1065         if(*alias == 0x0000) {
1066             break;
1067         }
1068
1069         alias++;
1070
1071         /* handle the pos number */
1072         if(ISDIGIT(*alias)) {
1073
1074             /* handle positional parameters */
1075             if(ISDIGIT(*alias)) {
1076                 pos = (int) (*alias++ - DIGIT_ZERO);
1077
1078                 while(ISDIGIT(*alias)) {
1079                     pos *= 10;
1080                     pos += (int) (*alias++ - DIGIT_ZERO);
1081                 }
1082             }
1083
1084             /* if there is no '$', don't read anything */
1085             if(*alias != SPEC_DOLLARSIGN) {
1086                 return NULL;
1087             }
1088         } else {
1089             return NULL;
1090         }
1091
1092         if (pos > size) {
1093             size = pos;
1094         }
1095     }
1096
1097     /* create the parsed argument list */
1098     typelist = (ufmt_type_info*)uprv_malloc(sizeof(ufmt_type_info) * size);
1099     islonglong = (UBool*)uprv_malloc(sizeof(UBool) * size);
1100     arglist = (ufmt_args*)uprv_malloc(sizeof(ufmt_args) * size);
1101
1102     /* If malloc failed, return NULL */
1103     if (!typelist || !islonglong || !arglist) {
1104         if (typelist) {
1105             uprv_free(typelist);
1106         }
1107
1108         if (islonglong) {
1109             uprv_free(islonglong);
1110         }
1111
1112         if (arglist) {
1113             uprv_free(arglist);
1114         }
1115
1116         *status = U_MEMORY_ALLOCATION_ERROR;
1117         return NULL;
1118     }
1119
1120     /* reset alias back to the beginning */
1121     alias = aliasStart;
1122
1123     for(;;) {
1124         /* find % */
1125         while(*alias != UP_PERCENT && *alias != 0x0000) {
1126             alias++;
1127         }
1128
1129         if(*alias == 0x0000) {
1130             break;
1131         }
1132
1133         alias++;
1134
1135         /* handle positional parameters */
1136         if(ISDIGIT(*alias)) {
1137             pos = (int) (*alias++ - DIGIT_ZERO);
1138
1139             while(ISDIGIT(*alias)) {
1140                 pos *= 10;
1141                 pos += (int) (*alias++ - DIGIT_ZERO);
1142             }
1143         }
1144         /* offset position by 1 */
1145         pos--;
1146
1147         /* skip over everything except for the type */
1148         while (ISMOD(*alias) || ISFLAG(*alias) || ISDIGIT(*alias) || 
1149             *alias == SPEC_ASTERISK || *alias == SPEC_PERIOD || *alias == SPEC_DOLLARSIGN) {
1150                 islonglong[pos] = FALSE;
1151                 if (ISMOD(*alias)) {
1152                     alias++;
1153                     if (*alias == MOD_LOWERL) {
1154                         islonglong[pos] = TRUE;
1155                     } 
1156                 } 
1157                 alias++;
1158         }
1159         type = *alias;
1160
1161         /* store the argument type in the correct position of the parsed argument list */
1162         handlerNum = (uint16_t)(type - UPRINTF_BASE_FMT_HANDLERS);
1163         if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
1164             typelist[pos] = g_u_printf_infos[ handlerNum ].info;
1165         } else {
1166             typelist[pos] = ufmt_empty;
1167         }
1168     }
1169
1170     /* store argument in arglist */
1171     for (pos = 0; pos < size; pos++) {
1172         switch (typelist[pos]) {
1173         case ufmt_string:
1174         case ufmt_ustring:
1175         case ufmt_pointer:
1176             arglist[pos].ptrValue = va_arg(ap, void*);
1177             break;
1178         case ufmt_char:
1179         case ufmt_uchar:
1180         case ufmt_int:
1181             if (islonglong[pos]) {
1182                 arglist[pos].int64Value = va_arg(ap, int64_t);
1183             }
1184             else {
1185                 arglist[pos].int64Value = va_arg(ap, int32_t);
1186             }
1187             break;
1188         case ufmt_float:
1189             arglist[pos].floatValue = (float) va_arg(ap, double);
1190             break;
1191         case ufmt_double:
1192             arglist[pos].doubleValue = va_arg(ap, double);
1193             break;
1194         default:
1195             /* else args is ignored */
1196             arglist[pos].ptrValue = NULL;
1197             break;
1198         }
1199     }
1200
1201     uprv_free(typelist);
1202     uprv_free(islonglong);
1203
1204     return arglist;
1205 }
1206
1207 /* We parse the argument list in Unicode */
1208 U_CFUNC int32_t
1209 u_printf_parse(const u_printf_stream_handler *streamHandler,
1210                const UChar     *fmt,
1211                void            *context,
1212                u_localized_print_string *locStringContext,
1213                ULocaleBundle   *formatBundle,
1214                int32_t         *written,
1215                va_list         ap)
1216 {
1217     uint16_t         handlerNum;
1218     ufmt_args        args;
1219     ufmt_type_info   argType;
1220     u_printf_handler *handler;
1221     u_printf_spec    spec;
1222     u_printf_spec_info *info = &(spec.fInfo);
1223
1224     const UChar *alias = fmt;
1225     const UChar *backup;
1226     const UChar *lastAlias;
1227     const UChar *orgAlias = fmt;
1228     /* parsed argument list */
1229     ufmt_args *arglist = NULL; /* initialized it to avoid compiler warnings */
1230     UErrorCode status = U_ZERO_ERROR;
1231     if (!locStringContext || locStringContext->available >= 0) {
1232         /* get the parsed list of argument types */
1233         arglist = parseArguments(orgAlias, ap, &status);
1234
1235         /* Return error if parsing failed. */
1236         if (U_FAILURE(status)) {
1237             return -1;
1238         }
1239     }
1240     
1241     /* iterate through the pattern */
1242     while(!locStringContext || locStringContext->available >= 0) {
1243
1244         /* find the next '%' */
1245         lastAlias = alias;
1246         while(*alias != UP_PERCENT && *alias != 0x0000) {
1247             alias++;
1248         }
1249
1250         /* write any characters before the '%' */
1251         if(alias > lastAlias) {
1252             *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias));
1253         }
1254
1255         /* break if at end of string */
1256         if(*alias == 0x0000) {
1257             break;
1258         }
1259
1260         /* initialize spec to default values */
1261         spec.fWidthPos     = -1;
1262         spec.fPrecisionPos = -1;
1263         spec.fArgPos       = -1;
1264
1265         uprv_memset(info, 0, sizeof(*info));
1266         info->fPrecision    = -1;
1267         info->fWidth        = -1;
1268         info->fPadChar      = 0x0020;
1269
1270         /* skip over the initial '%' */
1271         alias++;
1272
1273         /* Check for positional argument */
1274         if(ISDIGIT(*alias)) {
1275
1276             /* Save the current position */
1277             backup = alias;
1278
1279             /* handle positional parameters */
1280             if(ISDIGIT(*alias)) {
1281                 spec.fArgPos = (int) (*alias++ - DIGIT_ZERO);
1282
1283                 while(ISDIGIT(*alias)) {
1284                     spec.fArgPos *= 10;
1285                     spec.fArgPos += (int) (*alias++ - DIGIT_ZERO);
1286                 }
1287             }
1288
1289             /* if there is no '$', don't read anything */
1290             if(*alias != SPEC_DOLLARSIGN) {
1291                 spec.fArgPos = -1;
1292                 alias = backup;
1293             }
1294             /* munge the '$' */
1295             else
1296                 alias++;
1297         }
1298
1299         /* Get any format flags */
1300         while(ISFLAG(*alias)) {
1301             switch(*alias++) {
1302
1303                 /* left justify */
1304             case FLAG_MINUS:
1305                 info->fLeft = TRUE;
1306                 break;
1307
1308                 /* always show sign */
1309             case FLAG_PLUS:
1310                 info->fShowSign = TRUE;
1311                 break;
1312
1313                 /* use space if no sign present */
1314             case FLAG_SPACE:
1315                 info->fShowSign = TRUE;
1316                 info->fSpace = TRUE;
1317                 break;
1318
1319                 /* use alternate form */
1320             case FLAG_POUND:
1321                 info->fAlt = TRUE;
1322                 break;
1323
1324                 /* pad with leading zeroes */
1325             case FLAG_ZERO:
1326                 info->fZero = TRUE;
1327                 info->fPadChar = 0x0030;
1328                 break;
1329
1330                 /* pad character specified */
1331             case FLAG_PAREN:
1332
1333                 /* TODO test that all four are numbers */
1334                 /* first four characters are hex values for pad char */
1335                 info->fPadChar = (UChar)ufmt_digitvalue(*alias++);
1336                 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
1337                 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
1338                 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
1339
1340                 /* final character is ignored */
1341                 alias++;
1342
1343                 break;
1344             }
1345         }
1346
1347         /* Get the width */
1348
1349         /* width is specified out of line */
1350         if(*alias == SPEC_ASTERISK) {
1351
1352             info->fWidth = -2;
1353
1354             /* Skip the '*' */
1355             alias++;
1356
1357             /* Save the current position */
1358             backup = alias;
1359
1360             /* handle positional parameters */
1361             if(ISDIGIT(*alias)) {
1362                 spec.fWidthPos = (int) (*alias++ - DIGIT_ZERO);
1363
1364                 while(ISDIGIT(*alias)) {
1365                     spec.fWidthPos *= 10;
1366                     spec.fWidthPos += (int) (*alias++ - DIGIT_ZERO);
1367                 }
1368             }
1369
1370             /* if there is no '$', don't read anything */
1371             if(*alias != SPEC_DOLLARSIGN) {
1372                 spec.fWidthPos = -1;
1373                 alias = backup;
1374             }
1375             /* munge the '$' */
1376             else
1377                 alias++;
1378         }
1379         /* read the width, if present */
1380         else if(ISDIGIT(*alias)){
1381             info->fWidth = (int) (*alias++ - DIGIT_ZERO);
1382
1383             while(ISDIGIT(*alias)) {
1384                 info->fWidth *= 10;
1385                 info->fWidth += (int) (*alias++ - DIGIT_ZERO);
1386             }
1387         }
1388
1389         /* Get the precision */
1390
1391         if(*alias == SPEC_PERIOD) {
1392
1393             /* eat up the '.' */
1394             alias++;
1395
1396             /* precision is specified out of line */
1397             if(*alias == SPEC_ASTERISK) {
1398
1399                 info->fPrecision = -2;
1400
1401                 /* Skip the '*' */
1402                 alias++;
1403
1404                 /* save the current position */
1405                 backup = alias;
1406
1407                 /* handle positional parameters */
1408                 if(ISDIGIT(*alias)) {
1409                     spec.fPrecisionPos = (int) (*alias++ - DIGIT_ZERO);
1410
1411                     while(ISDIGIT(*alias)) {
1412                         spec.fPrecisionPos *= 10;
1413                         spec.fPrecisionPos += (int) (*alias++ - DIGIT_ZERO);
1414                     }
1415
1416                     /* if there is no '$', don't read anything */
1417                     if(*alias != SPEC_DOLLARSIGN) {
1418                         spec.fPrecisionPos = -1;
1419                         alias = backup;
1420                     }
1421                     else {
1422                         /* munge the '$' */
1423                         alias++;
1424                     }
1425                 }
1426             }
1427             /* read the precision */
1428             else if(ISDIGIT(*alias)){
1429                 info->fPrecision = (int) (*alias++ - DIGIT_ZERO);
1430
1431                 while(ISDIGIT(*alias)) {
1432                     info->fPrecision *= 10;
1433                     info->fPrecision += (int) (*alias++ - DIGIT_ZERO);
1434                 }
1435             }
1436         }
1437
1438         /* Get any modifiers */
1439         if(ISMOD(*alias)) {
1440             switch(*alias++) {
1441
1442                 /* short */
1443             case MOD_H:
1444                 info->fIsShort = TRUE;
1445                 break;
1446
1447                 /* long or long long */
1448             case MOD_LOWERL:
1449                 if(*alias == MOD_LOWERL) {
1450                     info->fIsLongLong = TRUE;
1451                     /* skip over the next 'l' */
1452                     alias++;
1453                 }
1454                 else
1455                     info->fIsLong = TRUE;
1456                 break;
1457
1458                 /* long double */
1459             case MOD_L:
1460                 info->fIsLongDouble = TRUE;
1461                 break;
1462             }
1463         }
1464
1465         /* finally, get the specifier letter */
1466         info->fSpec = *alias++;
1467         info->fOrigSpec = info->fSpec;
1468
1469         /* fill in the precision and width, if specified out of line */
1470
1471         /* width specified out of line */
1472         if(spec.fInfo.fWidth == -2) {
1473             if(spec.fWidthPos == -1) {
1474                 /* read the width from the argument list */
1475                 info->fWidth = va_arg(ap, int32_t);
1476             }
1477             /* else handle positional parameter */
1478
1479             /* if it's negative, take the absolute value and set left alignment */
1480             if(info->fWidth < 0) {
1481                 info->fWidth *= -1; /* Make positive */
1482                 info->fLeft = TRUE;
1483             }
1484         }
1485
1486         /* precision specified out of line */
1487         if(info->fPrecision == -2) {
1488             if(spec.fPrecisionPos == -1) {
1489                 /* read the precision from the argument list */
1490                 info->fPrecision = va_arg(ap, int32_t);
1491             }
1492             /* else handle positional parameter */
1493
1494             /* if it's negative, set it to zero */
1495             if(info->fPrecision < 0)
1496                 info->fPrecision = 0;
1497         }
1498
1499         handlerNum = (uint16_t)(info->fSpec - UPRINTF_BASE_FMT_HANDLERS);
1500         if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
1501             /* query the info function for argument information */
1502             argType = g_u_printf_infos[ handlerNum ].info;
1503
1504             /* goto the correct argument on arg_list if position is specified */
1505             if (spec.fArgPos > 0) {
1506                 /* offset position by 1 */
1507                 spec.fArgPos--;
1508                 switch(argType) {
1509                 case ufmt_count:
1510                     /* set the spec's width to the # of chars written */
1511                     info->fWidth = *written;
1512                     /* fall through to set the pointer */
1513                     U_FALLTHROUGH;
1514                 case ufmt_string:
1515                 case ufmt_ustring:
1516                 case ufmt_pointer:
1517                     args.ptrValue = arglist[spec.fArgPos].ptrValue;
1518                     break;
1519                 case ufmt_char:
1520                 case ufmt_uchar:
1521                 case ufmt_int:
1522                     args.int64Value = arglist[spec.fArgPos].int64Value;
1523                     break;
1524                 case ufmt_float:
1525                     args.floatValue = arglist[spec.fArgPos].floatValue;
1526                     break;
1527                 case ufmt_double:
1528                     args.doubleValue = arglist[spec.fArgPos].doubleValue;
1529                     break;
1530                 default:
1531                     /* else args is ignored */
1532                     args.ptrValue = NULL;
1533                     break;
1534                 }
1535             } else { /* no positional argument specified */
1536                 switch(argType) {
1537                 case ufmt_count:
1538                     /* set the spec's width to the # of chars written */
1539                     info->fWidth = *written;
1540                     /* fall through to set the pointer */
1541                     U_FALLTHROUGH;
1542                 case ufmt_string:
1543                 case ufmt_ustring:
1544                 case ufmt_pointer:
1545                     args.ptrValue = va_arg(ap, void*);
1546                     break;
1547                 case ufmt_char:
1548                 case ufmt_uchar:
1549                 case ufmt_int:
1550                     if (info->fIsLongLong) {
1551                         args.int64Value = va_arg(ap, int64_t);
1552                     }
1553                     else {
1554                         args.int64Value = va_arg(ap, int32_t);
1555                     }
1556                     break;
1557                 case ufmt_float:
1558                     args.floatValue = (float) va_arg(ap, double);
1559                     break;
1560                 case ufmt_double:
1561                     args.doubleValue = va_arg(ap, double);
1562                     break;
1563                 default:
1564                     /* else args is ignored */
1565                     args.ptrValue = NULL;
1566                     break;
1567                 }
1568             }
1569
1570             /* call the handler function */
1571             handler = g_u_printf_infos[ handlerNum ].handler;
1572             if(handler != 0) {
1573                 *written += (*handler)(streamHandler, context, formatBundle, info, &args);
1574             }
1575             else {
1576                 /* just echo unknown tags */
1577                 *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
1578             }
1579         }
1580         else {
1581             /* just echo unknown tags */
1582             *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
1583         }
1584     }
1585     /* delete parsed argument list */
1586     if (arglist != NULL) {
1587         uprv_free(arglist);
1588     }
1589     /* return # of characters in this format that have been parsed. */
1590     return (int32_t)(alias - fmt);
1591 }
1592
1593 #endif /* #if !UCONFIG_NO_FORMATTING */