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