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
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 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
u_printf_string_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_char_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_double_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_integer_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_hex_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_octal_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_uinteger_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_pointer_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_scientific_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_percent_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_ustring_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_uchar_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_scidbl_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_count_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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
u_printf_spellout_handler(const u_printf_stream_handler * handler,void * context,ULocaleBundle * formatBundle,const u_printf_spec_info * info,const ufmt_args * args)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. */
parseArguments(const UChar * alias,va_list ap,UErrorCode * status)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
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)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 */
1594