]> git.saurik.com Git - apple/icu.git/blame - icuSources/io/uprntf_p.cpp
ICU-64243.0.1.tar.gz
[apple/icu.git] / icuSources / io / uprntf_p.cpp
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
374ca955
A
3/*
4******************************************************************************
5*
2ca993e8 6* Copyright (C) 1998-2016, International Business Machines
374ca955
A
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
b331163b 24#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_CONVERSION
374ca955
A
25
26#include "unicode/ustring.h"
4388f060 27#include "unicode/utf16.h"
374ca955
A
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 */
86typedef int32_t U_EXPORT2
87u_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
94typedef 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 */
102typedef 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
118static const UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
119static 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? */
123static void
124u_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,
2ca993e8 148 UPRV_LENGTHOF(plusSymbol),
374ca955
A
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
162static void
163u_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 '%' */
180static int32_t
181u_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{
f3c0d7a5
A
187 (void)formatBundle;
188 (void)info;
189 (void)args;
374ca955
A
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' */
197static int32_t
198u_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{
f3c0d7a5 204 (void)formatBundle;
374ca955
A
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,
2ca993e8 224 UPRV_LENGTHOF(buffer));
374ca955
A
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 */
73c04bcf
A
234 if (info->fPrecision != -1 && info->fPrecision < len) {
235 len = info->fPrecision;
374ca955
A
236 }
237
73c04bcf
A
238 written = handler->pad_and_justify(context, info, s, len);
239
374ca955
A
240 /* clean up */
241 if (gNullStr != s && buffer != s) {
242 uprv_free(s);
243 }
244
245 return written;
246}
247
248static int32_t
249u_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{
f3c0d7a5 255 (void)formatBundle;
4388f060 256 UChar s[U16_MAX_LENGTH+1];
374ca955
A
257 int32_t len = 1, written;
258 unsigned char arg = (unsigned char)(args[0].int64Value);
259
260 /* convert from default codepage to Unicode */
2ca993e8 261 ufmt_defaultCPToUnicode((const char *)&arg, 2, s, UPRV_LENGTHOF(s));
374ca955
A
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 */
73c04bcf 270 /* precision is ignored when handling a char */
374ca955 271
73c04bcf 272 written = handler->pad_and_justify(context, info, s, len);
374ca955
A
273
274 return written;
275}
276
277static int32_t
278u_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 */
353static int32_t
354u_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
419static int32_t
420u_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{
f3c0d7a5 426 (void)formatBundle;
374ca955
A
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
455static int32_t
456u_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{
f3c0d7a5 462 (void)formatBundle;
374ca955
A
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
490static int32_t
491u_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
543static int32_t
544u_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)
f3c0d7a5
A
549{
550 (void)formatBundle;
374ca955
A
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
560static int32_t
561u_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 */
73c04bcf
A
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 }
374ca955
A
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
680static int32_t
681u_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
755static int32_t
756u_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{
f3c0d7a5 762 (void)formatBundle;
374ca955
A
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 */
73c04bcf
A
774 if (info->fPrecision != -1 && info->fPrecision < len) {
775 len = info->fPrecision;
374ca955
A
776 }
777
73c04bcf
A
778 /* determine if the string should be padded */
779 written = handler->pad_and_justify(context, info, arg, len);
780
374ca955
A
781 return written;
782}
783
784static int32_t
785u_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{
f3c0d7a5 791 (void)formatBundle;
374ca955
A
792 int32_t written = 0;
793 UChar arg = (UChar)(args[0].int64Value);
794
374ca955
A
795 /* width = minimum # of characters to write */
796 /* precision = maximum # of characters to write */
73c04bcf 797 /* precision is ignored when handling a uchar */
374ca955 798
73c04bcf
A
799 /* determine if the string should be padded */
800 written = handler->pad_and_justify(context, info, &arg, 1);
374ca955
A
801
802 return written;
803}
804
805static int32_t
806u_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;
46f4442e
A
815 UNumberFormat *format;
816 int32_t maxSigDecimalDigits, significantDigits;
374ca955
A
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 {
46f4442e
A
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;
374ca955
A
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
864static int32_t
865u_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{
f3c0d7a5
A
871 (void)handler;
872 (void)context;
873 (void)formatBundle;
374ca955
A
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
883static int32_t
884u_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 */
962static 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
46f4442e
A
1060/* Returns an array of the parsed argument type given in the format string. */
1061static 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}
374ca955
A
1219
1220/* We parse the argument list in Unicode */
1221U_CFUNC int32_t
1222u_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;
46f4442e
A
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
374ca955 1254 /* iterate through the pattern */
46f4442e 1255 while(!locStringContext || locStringContext->available >= 0) {
374ca955
A
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
73c04bcf 1278 uprv_memset(info, 0, sizeof(*info));
374ca955
A
1279 info->fPrecision = -1;
1280 info->fWidth = -1;
374ca955 1281 info->fPadChar = 0x0020;
374ca955
A
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++;
73c04bcf 1480 info->fOrigSpec = info->fSpec;
374ca955
A
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 }
73c04bcf 1490 /* else handle positional parameter */
374ca955
A
1491
1492 /* if it's negative, take the absolute value and set left alignment */
1493 if(info->fWidth < 0) {
73c04bcf
A
1494 info->fWidth *= -1; /* Make positive */
1495 info->fLeft = TRUE;
374ca955
A
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 }
73c04bcf 1505 /* else handle positional parameter */
374ca955
A
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;
46f4442e
A
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 */
2ca993e8 1526 U_FALLTHROUGH;
46f4442e
A
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;
374ca955 1547 }
46f4442e
A
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 */
2ca993e8 1554 U_FALLTHROUGH;
46f4442e
A
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;
374ca955 1580 }
374ca955
A
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 }
46f4442e
A
1598 /* delete parsed argument list */
1599 if (arglist != NULL) {
1600 uprv_free(arglist);
1601 }
374ca955
A
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 */