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