2 *******************************************************************************
4 * Copyright (C) 1998-2004, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
11 * Modification History:
13 * Date Name Description
14 * 12/02/98 stephen Creation.
15 * 03/13/99 stephen Modified for new C API.
16 *******************************************************************************
19 #include "unicode/utypes.h"
21 #if !UCONFIG_NO_FORMATTING
23 #include "unicode/uchar.h"
24 #include "unicode/ustring.h"
25 #include "unicode/unum.h"
26 #include "unicode/udat.h"
27 #include "unicode/uset.h"
36 /* flag characters for u_scanf */
37 #define FLAG_ASTERISK 0x002A
38 #define FLAG_PAREN 0x0028
40 #define ISFLAG(s) (s) == FLAG_ASTERISK || \
43 /* special characters for u_scanf */
44 #define SPEC_DOLLARSIGN 0x0024
47 #define DIGIT_ZERO 0x0030
48 #define DIGIT_ONE 0x0031
49 #define DIGIT_TWO 0x0032
50 #define DIGIT_THREE 0x0033
51 #define DIGIT_FOUR 0x0034
52 #define DIGIT_FIVE 0x0035
53 #define DIGIT_SIX 0x0036
54 #define DIGIT_SEVEN 0x0037
55 #define DIGIT_EIGHT 0x0038
56 #define DIGIT_NINE 0x0039
58 #define ISDIGIT(s) (s) == DIGIT_ZERO || \
61 (s) == DIGIT_THREE || \
62 (s) == DIGIT_FOUR || \
63 (s) == DIGIT_FIVE || \
65 (s) == DIGIT_SEVEN || \
66 (s) == DIGIT_EIGHT || \
69 /* u_scanf modifiers */
71 #define MOD_LOWERL 0x006C
74 #define ISMOD(s) (s) == MOD_H || \
75 (s) == MOD_LOWERL || \
79 * Struct encapsulating a single uscanf format specification.
81 typedef struct u_scanf_spec_info
{
82 int32_t fWidth
; /* Width */
84 UChar fSpec
; /* Format specification */
86 UChar fPadChar
; /* Padding character */
88 UBool fSkipArg
; /* TRUE if arg should be skipped */
89 UBool fIsLongDouble
; /* L flag */
90 UBool fIsShort
; /* h flag */
91 UBool fIsLong
; /* l flag */
92 UBool fIsLongLong
; /* ll flag */
93 UBool fIsString
; /* TRUE if this is a NULL-terminated string. */
98 * Struct encapsulating a single u_scanf format specification.
100 typedef struct u_scanf_spec
{
101 u_scanf_spec_info fInfo
; /* Information on this spec */
102 int32_t fArgPos
; /* Position of data in arg list */
106 * Parse a single u_scanf format specifier in Unicode.
107 * @param fmt A pointer to a '%' character in a u_scanf format specification.
108 * @param spec A pointer to a <TT>u_scanf_spec</TT> to receive the parsed
110 * @return The number of characters contained in this specifier.
113 u_scanf_parse_spec (const UChar
*fmt
,
116 const UChar
*s
= fmt
;
118 u_scanf_spec_info
*info
= &(spec
->fInfo
);
120 /* initialize spec to default values */
124 info
->fSpec
= 0x0000;
125 info
->fPadChar
= 0x0020;
126 info
->fSkipArg
= FALSE
;
127 info
->fIsLongDouble
= FALSE
;
128 info
->fIsShort
= FALSE
;
129 info
->fIsLong
= FALSE
;
130 info
->fIsLongLong
= FALSE
;
131 info
->fIsString
= TRUE
;
134 /* skip over the initial '%' */
137 /* Check for positional argument */
140 /* Save the current position */
143 /* handle positional parameters */
145 spec
->fArgPos
= (int) (*s
++ - DIGIT_ZERO
);
149 spec
->fArgPos
+= (int) (*s
++ - DIGIT_ZERO
);
153 /* if there is no '$', don't read anything */
154 if(*s
!= SPEC_DOLLARSIGN
) {
163 /* Get any format flags */
169 info
->fSkipArg
= TRUE
;
172 /* pad character specified */
175 /* first four characters are hex values for pad char */
176 info
->fPadChar
= (UChar
)ufmt_digitvalue(*s
++);
177 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*s
++));
178 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*s
++));
179 info
->fPadChar
= (UChar
)((info
->fPadChar
* 16) + ufmt_digitvalue(*s
++));
181 /* final character is ignored */
190 info
->fWidth
= (int) (*s
++ - DIGIT_ZERO
);
194 info
->fWidth
+= (int) (*s
++ - DIGIT_ZERO
);
198 /* Get any modifiers */
204 info
->fIsShort
= TRUE
;
207 /* long or long long */
209 if(*s
== MOD_LOWERL
) {
210 info
->fIsLongLong
= TRUE
;
211 /* skip over the next 'l' */
215 info
->fIsLong
= TRUE
;
220 info
->fIsLongDouble
= TRUE
;
225 /* finally, get the specifier letter */
228 /* return # of characters in this specifier */
229 return (int32_t)(s
- fmt
);
232 #define UP_PERCENT 0x0025
235 /* ANSI style formatting */
236 /* Use US-ASCII characters only for formatting */
239 #define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_scanf_simple_percent_handler}
241 #define UFMT_STRING {ufmt_string, u_scanf_string_handler}
243 #define UFMT_CHAR {ufmt_string, u_scanf_char_handler}
245 #define UFMT_INT {ufmt_int, u_scanf_integer_handler}
247 #define UFMT_UINT {ufmt_int, u_scanf_uinteger_handler}
249 #define UFMT_OCTAL {ufmt_int, u_scanf_octal_handler}
251 #define UFMT_HEX {ufmt_int, u_scanf_hex_handler}
253 #define UFMT_DOUBLE {ufmt_double, u_scanf_double_handler}
255 #define UFMT_SCIENTIFIC {ufmt_double, u_scanf_scientific_handler}
257 #define UFMT_SCIDBL {ufmt_double, u_scanf_scidbl_handler}
259 #define UFMT_COUNT {ufmt_count, u_scanf_count_handler}
261 #define UFMT_SCANSET {ufmt_string, u_scanf_scanset_handler}
263 /* non-ANSI extensions */
264 /* Use US-ASCII characters only for formatting */
267 #define UFMT_POINTER {ufmt_pointer, u_scanf_pointer_handler}
269 #define UFMT_SPELLOUT {ufmt_double, u_scanf_spellout_handler}
271 #define UFMT_PERCENT {ufmt_double, u_scanf_percent_handler}
272 /* C K is old format */
273 #define UFMT_UCHAR {ufmt_uchar, u_scanf_uchar_handler}
274 /* S U is old format */
275 #define UFMT_USTRING {ufmt_ustring, u_scanf_ustring_handler}
278 #define UFMT_EMPTY {ufmt_empty, NULL}
281 * A u_scanf handler function.
282 * A u_scanf handler is responsible for handling a single u_scanf
283 * format specification, for example 'd' or 's'.
284 * @param stream The UFILE to which to write output.
285 * @param info A pointer to a <TT>u_scanf_spec_info</TT> struct containing
286 * information on the format specification.
287 * @param args A pointer to the argument data
288 * @param fmt A pointer to the first character in the format string
289 * following the spec.
290 * @param fmtConsumed On output, set to the number of characters consumed
291 * in <TT>fmt</TT>. Do nothing, if the argument isn't variable width.
292 * @param argConverted The number of arguments converted and assigned, or -1 if an
294 * @return The number of code points consumed during reading.
296 typedef int32_t (*u_scanf_handler
) (UFILE
*stream
,
297 u_scanf_spec_info
*info
,
300 int32_t *fmtConsumed
,
301 int32_t *argConverted
);
303 typedef struct u_scanf_info
{
305 u_scanf_handler handler
;
308 #define USCANF_NUM_FMT_HANDLERS 108
310 /* We do not use handlers for 0-0x1f */
311 #define USCANF_BASE_FMT_HANDLERS 0x20
315 u_scanf_skip_leading_ws(UFILE
*input
,
322 /* skip all leading ws in the input */
323 while( (isNotEOF
= ufile_getch(input
, &c
)) && (c
== pad
|| u_isWhitespace(c
)) )
328 /* put the final character back on the input */
336 u_scanf_simple_percent_handler(UFILE
*input
,
337 u_scanf_spec_info
*info
,
340 int32_t *fmtConsumed
,
341 int32_t *argConverted
)
343 /* make sure the next character in the input is a percent */
345 if(u_fgetc(input
) != 0x0025) {
352 u_scanf_count_handler(UFILE
*input
,
353 u_scanf_spec_info
*info
,
356 int32_t *fmtConsumed
,
357 int32_t *argConverted
)
359 /* in the special case of count, the u_scanf_spec_info's width */
360 /* will contain the # of items converted thus far */
361 if (!info
->fSkipArg
) {
363 *(int16_t*)(args
[0].ptrValue
) = (int16_t)(UINT16_MAX
& info
->fWidth
);
364 else if (info
->fIsLongLong
)
365 *(int64_t*)(args
[0].ptrValue
) = info
->fWidth
;
367 *(int32_t*)(args
[0].ptrValue
) = (int32_t)(UINT32_MAX
& info
->fWidth
);
370 /* we converted 0 args */
375 u_scanf_double_handler(UFILE
*input
,
376 u_scanf_spec_info
*info
,
379 int32_t *fmtConsumed
,
380 int32_t *argConverted
)
384 UNumberFormat
*format
;
385 int32_t parsePos
= 0;
386 UErrorCode status
= U_ZERO_ERROR
;
389 /* skip all ws in the input */
390 u_scanf_skip_leading_ws(input
, info
->fPadChar
);
392 /* fill the input's internal buffer */
393 ufile_fill_uchar_buffer(input
);
395 /* determine the size of the input's buffer */
396 len
= input
->str
.fLimit
- input
->str
.fPos
;
398 /* truncate to the width, if specified */
399 if(info
->fWidth
!= -1)
400 len
= ufmt_min(len
, info
->fWidth
);
402 /* get the formatter */
403 format
= u_locbund_getNumberFormat(&input
->str
.fBundle
, UNUM_DECIMAL
);
409 /* parse the number */
410 num
= unum_parseDouble(format
, input
->str
.fPos
, len
, &parsePos
, &status
);
412 if (!info
->fSkipArg
) {
413 *(double*)(args
[0].ptrValue
) = num
;
416 /* mask off any necessary bits */
417 /* if(! info->fIsLong_double)
420 /* update the input's position to reflect consumed data */
421 input
->str
.fPos
+= parsePos
;
423 /* we converted 1 arg */
424 *argConverted
= !info
->fSkipArg
;
429 u_scanf_scientific_handler(UFILE
*input
,
430 u_scanf_spec_info
*info
,
433 int32_t *fmtConsumed
,
434 int32_t *argConverted
)
438 UNumberFormat
*format
;
439 int32_t parsePos
= 0;
440 UErrorCode status
= U_ZERO_ERROR
;
443 /* skip all ws in the input */
444 u_scanf_skip_leading_ws(input
, info
->fPadChar
);
446 /* fill the input's internal buffer */
447 ufile_fill_uchar_buffer(input
);
449 /* determine the size of the input's buffer */
450 len
= input
->str
.fLimit
- input
->str
.fPos
;
452 /* truncate to the width, if specified */
453 if(info
->fWidth
!= -1)
454 len
= ufmt_min(len
, info
->fWidth
);
456 /* get the formatter */
457 format
= u_locbund_getNumberFormat(&input
->str
.fBundle
, UNUM_SCIENTIFIC
);
463 /* parse the number */
464 num
= unum_parseDouble(format
, input
->str
.fPos
, len
, &parsePos
, &status
);
466 if (!info
->fSkipArg
) {
467 *(double*)(args
[0].ptrValue
) = num
;
470 /* mask off any necessary bits */
471 /* if(! info->fIsLong_double)
474 /* update the input's position to reflect consumed data */
475 input
->str
.fPos
+= parsePos
;
477 /* we converted 1 arg */
478 *argConverted
= !info
->fSkipArg
;
483 u_scanf_scidbl_handler(UFILE
*input
,
484 u_scanf_spec_info
*info
,
487 int32_t *fmtConsumed
,
488 int32_t *argConverted
)
492 UNumberFormat
*scientificFormat
, *genericFormat
;
493 /*int32_t scientificResult, genericResult;*/
494 double scientificResult
, genericResult
;
495 int32_t scientificParsePos
= 0, genericParsePos
= 0, parsePos
= 0;
496 UErrorCode scientificStatus
= U_ZERO_ERROR
;
497 UErrorCode genericStatus
= U_ZERO_ERROR
;
500 /* since we can't determine by scanning the characters whether */
501 /* a number was formatted in the 'f' or 'g' styles, parse the */
502 /* string with both formatters, and assume whichever one */
503 /* parsed the most is the correct formatter to use */
506 /* skip all ws in the input */
507 u_scanf_skip_leading_ws(input
, info
->fPadChar
);
509 /* fill the input's internal buffer */
510 ufile_fill_uchar_buffer(input
);
512 /* determine the size of the input's buffer */
513 len
= input
->str
.fLimit
- input
->str
.fPos
;
515 /* truncate to the width, if specified */
516 if(info
->fWidth
!= -1)
517 len
= ufmt_min(len
, info
->fWidth
);
519 /* get the formatters */
520 scientificFormat
= u_locbund_getNumberFormat(&input
->str
.fBundle
, UNUM_SCIENTIFIC
);
521 genericFormat
= u_locbund_getNumberFormat(&input
->str
.fBundle
, UNUM_DECIMAL
);
524 if(scientificFormat
== 0 || genericFormat
== 0)
527 /* parse the number using each format*/
529 scientificResult
= unum_parseDouble(scientificFormat
, input
->str
.fPos
, len
,
530 &scientificParsePos
, &scientificStatus
);
532 genericResult
= unum_parseDouble(genericFormat
, input
->str
.fPos
, len
,
533 &genericParsePos
, &genericStatus
);
535 /* determine which parse made it farther */
536 if(scientificParsePos
> genericParsePos
) {
537 /* stash the result in num */
538 num
= scientificResult
;
539 /* update the input's position to reflect consumed data */
540 parsePos
+= scientificParsePos
;
543 /* stash the result in num */
545 /* update the input's position to reflect consumed data */
546 parsePos
+= genericParsePos
;
548 input
->str
.fPos
+= parsePos
;
550 if (!info
->fSkipArg
) {
551 *(double*)(args
[0].ptrValue
) = num
;
554 /* mask off any necessary bits */
555 /* if(! info->fIsLong_double)
558 /* we converted 1 arg */
559 *argConverted
= !info
->fSkipArg
;
564 u_scanf_integer_handler(UFILE
*input
,
565 u_scanf_spec_info
*info
,
568 int32_t *fmtConsumed
,
569 int32_t *argConverted
)
572 void *num
= (void*) (args
[0].ptrValue
);
573 UNumberFormat
*format
;
574 int32_t parsePos
= 0;
575 UErrorCode status
= U_ZERO_ERROR
;
579 /* skip all ws in the input */
580 u_scanf_skip_leading_ws(input
, info
->fPadChar
);
582 /* fill the input's internal buffer */
583 ufile_fill_uchar_buffer(input
);
585 /* determine the size of the input's buffer */
586 len
= input
->str
.fLimit
- input
->str
.fPos
;
588 /* truncate to the width, if specified */
589 if(info
->fWidth
!= -1)
590 len
= ufmt_min(len
, info
->fWidth
);
592 /* get the formatter */
593 format
= u_locbund_getNumberFormat(&input
->str
.fBundle
, UNUM_DECIMAL
);
599 /* parse the number */
600 result
= unum_parseInt64(format
, input
->str
.fPos
, len
, &parsePos
, &status
);
602 /* mask off any necessary bits */
603 if (!info
->fSkipArg
) {
605 *(int16_t*)num
= (int16_t)(UINT16_MAX
& result
);
606 else if (info
->fIsLongLong
)
607 *(int64_t*)num
= result
;
609 *(int32_t*)num
= (int32_t)(UINT32_MAX
& result
);
612 /* update the input's position to reflect consumed data */
613 input
->str
.fPos
+= parsePos
;
615 /* we converted 1 arg */
616 *argConverted
= !info
->fSkipArg
;
621 u_scanf_uinteger_handler(UFILE
*input
,
622 u_scanf_spec_info
*info
,
625 int32_t *fmtConsumed
,
626 int32_t *argConverted
)
628 /* TODO Fix this when Numberformat handles uint64_t */
629 return u_scanf_integer_handler(input
, info
, args
, fmt
, fmtConsumed
, argConverted
);
633 u_scanf_percent_handler(UFILE
*input
,
634 u_scanf_spec_info
*info
,
637 int32_t *fmtConsumed
,
638 int32_t *argConverted
)
642 UNumberFormat
*format
;
643 int32_t parsePos
= 0;
644 UErrorCode status
= U_ZERO_ERROR
;
647 /* skip all ws in the input */
648 u_scanf_skip_leading_ws(input
, info
->fPadChar
);
650 /* fill the input's internal buffer */
651 ufile_fill_uchar_buffer(input
);
653 /* determine the size of the input's buffer */
654 len
= input
->str
.fLimit
- input
->str
.fPos
;
656 /* truncate to the width, if specified */
657 if(info
->fWidth
!= -1)
658 len
= ufmt_min(len
, info
->fWidth
);
660 /* get the formatter */
661 format
= u_locbund_getNumberFormat(&input
->str
.fBundle
, UNUM_PERCENT
);
667 /* parse the number */
668 num
= unum_parseDouble(format
, input
->str
.fPos
, len
, &parsePos
, &status
);
670 if (!info
->fSkipArg
) {
671 *(double*)(args
[0].ptrValue
) = num
;
674 /* mask off any necessary bits */
675 /* if(! info->fIsLong_double)
678 /* update the input's position to reflect consumed data */
679 input
->str
.fPos
+= parsePos
;
681 /* we converted 1 arg */
682 *argConverted
= !info
->fSkipArg
;
687 u_scanf_string_handler(UFILE
*input
,
688 u_scanf_spec_info
*info
,
691 int32_t *fmtConsumed
,
692 int32_t *argConverted
)
696 char *arg
= (char*)(args
[0].ptrValue
);
699 UErrorCode status
= U_ZERO_ERROR
;
702 UBool isNotEOF
= FALSE
;
704 /* skip all ws in the input */
705 if (info
->fIsString
) {
706 u_scanf_skip_leading_ws(input
, info
->fPadChar
);
709 /* get the string one character at a time, truncating to the width */
712 /* open the default converter */
713 conv
= u_getDefaultConverter(&status
);
715 if(U_FAILURE(status
))
718 while( (info
->fWidth
== -1 || count
< info
->fWidth
)
719 && (isNotEOF
= ufile_getch(input
, &c
))
720 && (!info
->fIsString
|| (c
!= info
->fPadChar
&& !u_isWhitespace(c
))))
723 if (!info
->fSkipArg
) {
724 /* put the character from the input onto the target */
726 /* Since we do this one character at a time, do it this way. */
727 if (info
->fWidth
> 0) {
728 limit
= alias
+ info
->fWidth
- count
;
731 limit
= alias
+ ucnv_getMaxCharSize(conv
);
734 /* convert the character to the default codepage */
735 ucnv_fromUnicode(conv
, &alias
, limit
, &source
, source
+ 1,
736 NULL
, TRUE
, &status
);
738 if(U_FAILURE(status
)) {
740 u_releaseDefaultConverter(conv
);
745 /* increment the count */
749 /* put the final character we read back on the input */
750 if (!info
->fSkipArg
) {
751 if ((info
->fWidth
== -1 || count
< info
->fWidth
) && isNotEOF
)
754 /* add the terminator */
755 if (info
->fIsString
) {
761 u_releaseDefaultConverter(conv
);
763 /* we converted 1 arg */
764 *argConverted
= !info
->fSkipArg
;
769 u_scanf_char_handler(UFILE
*input
,
770 u_scanf_spec_info
*info
,
773 int32_t *fmtConsumed
,
774 int32_t *argConverted
)
776 if (info
->fWidth
< 0) {
779 info
->fIsString
= FALSE
;
780 return u_scanf_string_handler(input
, info
, args
, fmt
, fmtConsumed
, argConverted
);
784 u_scanf_ustring_handler(UFILE
*input
,
785 u_scanf_spec_info
*info
,
788 int32_t *fmtConsumed
,
789 int32_t *argConverted
)
791 UChar
*arg
= (UChar
*)(args
[0].ptrValue
);
795 UBool isNotEOF
= FALSE
;
797 /* skip all ws in the input */
798 if (info
->fIsString
) {
799 u_scanf_skip_leading_ws(input
, info
->fPadChar
);
802 /* get the string one character at a time, truncating to the width */
805 while( (info
->fWidth
== -1 || count
< info
->fWidth
)
806 && (isNotEOF
= ufile_getch(input
, &c
))
807 && (!info
->fIsString
|| (c
!= info
->fPadChar
&& !u_isWhitespace(c
))))
810 /* put the character from the input onto the target */
811 if (!info
->fSkipArg
) {
815 /* increment the count */
819 /* put the final character we read back on the input */
820 if (!info
->fSkipArg
) {
821 if((info
->fWidth
== -1 || count
< info
->fWidth
) && isNotEOF
) {
825 /* add the terminator */
826 if (info
->fIsString
) {
831 /* we converted 1 arg */
832 *argConverted
= !info
->fSkipArg
;
837 u_scanf_uchar_handler(UFILE
*input
,
838 u_scanf_spec_info
*info
,
841 int32_t *fmtConsumed
,
842 int32_t *argConverted
)
844 if (info
->fWidth
< 0) {
847 info
->fIsString
= FALSE
;
848 return u_scanf_ustring_handler(input
, info
, args
, fmt
, fmtConsumed
, argConverted
);
852 u_scanf_spellout_handler(UFILE
*input
,
853 u_scanf_spec_info
*info
,
856 int32_t *fmtConsumed
,
857 int32_t *argConverted
)
861 UNumberFormat
*format
;
862 int32_t parsePos
= 0;
863 UErrorCode status
= U_ZERO_ERROR
;
866 /* skip all ws in the input */
867 u_scanf_skip_leading_ws(input
, info
->fPadChar
);
869 /* fill the input's internal buffer */
870 ufile_fill_uchar_buffer(input
);
872 /* determine the size of the input's buffer */
873 len
= input
->str
.fLimit
- input
->str
.fPos
;
875 /* truncate to the width, if specified */
876 if(info
->fWidth
!= -1)
877 len
= ufmt_min(len
, info
->fWidth
);
879 /* get the formatter */
880 format
= u_locbund_getNumberFormat(&input
->str
.fBundle
, UNUM_SPELLOUT
);
886 /* parse the number */
887 num
= unum_parseDouble(format
, input
->str
.fPos
, len
, &parsePos
, &status
);
889 if (!info
->fSkipArg
) {
890 *(double*)(args
[0].ptrValue
) = num
;
893 /* mask off any necessary bits */
894 /* if(! info->fIsLong_double)
897 /* update the input's position to reflect consumed data */
898 input
->str
.fPos
+= parsePos
;
900 /* we converted 1 arg */
901 *argConverted
= !info
->fSkipArg
;
906 u_scanf_hex_handler(UFILE
*input
,
907 u_scanf_spec_info
*info
,
910 int32_t *fmtConsumed
,
911 int32_t *argConverted
)
914 void *num
= (void*) (args
[0].ptrValue
);
917 /* skip all ws in the input */
918 u_scanf_skip_leading_ws(input
, info
->fPadChar
);
920 /* fill the input's internal buffer */
921 ufile_fill_uchar_buffer(input
);
923 /* determine the size of the input's buffer */
924 len
= input
->str
.fLimit
- input
->str
.fPos
;
926 /* truncate to the width, if specified */
927 if(info
->fWidth
!= -1)
928 len
= ufmt_min(len
, info
->fWidth
);
930 /* check for alternate form */
931 if( *(input
->str
.fPos
) == 0x0030 &&
932 (*(input
->str
.fPos
+ 1) == 0x0078 || *(input
->str
.fPos
+ 1) == 0x0058) ) {
934 /* skip the '0' and 'x' or 'X' if present */
935 input
->str
.fPos
+= 2;
939 /* parse the number */
940 result
= ufmt_uto64(input
->str
.fPos
, &len
, 16);
942 /* update the input's position to reflect consumed data */
943 input
->str
.fPos
+= len
;
945 /* mask off any necessary bits */
946 if (!info
->fSkipArg
) {
948 *(int16_t*)num
= (int16_t)(UINT16_MAX
& result
);
949 else if (info
->fIsLongLong
)
950 *(int64_t*)num
= result
;
952 *(int32_t*)num
= (int32_t)(UINT32_MAX
& result
);
955 /* we converted 1 arg */
956 *argConverted
= !info
->fSkipArg
;
961 u_scanf_octal_handler(UFILE
*input
,
962 u_scanf_spec_info
*info
,
965 int32_t *fmtConsumed
,
966 int32_t *argConverted
)
969 void *num
= (void*) (args
[0].ptrValue
);
972 /* skip all ws in the input */
973 u_scanf_skip_leading_ws(input
, info
->fPadChar
);
975 /* fill the input's internal buffer */
976 ufile_fill_uchar_buffer(input
);
978 /* determine the size of the input's buffer */
979 len
= input
->str
.fLimit
- input
->str
.fPos
;
981 /* truncate to the width, if specified */
982 if(info
->fWidth
!= -1)
983 len
= ufmt_min(len
, info
->fWidth
);
985 /* parse the number */
986 result
= ufmt_uto64(input
->str
.fPos
, &len
, 8);
988 /* update the input's position to reflect consumed data */
989 input
->str
.fPos
+= len
;
991 /* mask off any necessary bits */
992 if (!info
->fSkipArg
) {
994 *(int16_t*)num
= (int16_t)(UINT16_MAX
& result
);
995 else if (info
->fIsLongLong
)
996 *(int64_t*)num
= result
;
998 *(int32_t*)num
= (int32_t)(UINT32_MAX
& result
);
1001 /* we converted 1 arg */
1002 *argConverted
= !info
->fSkipArg
;
1007 u_scanf_pointer_handler(UFILE
*input
,
1008 u_scanf_spec_info
*info
,
1011 int32_t *fmtConsumed
,
1012 int32_t *argConverted
)
1016 void **p
= (void**)(args
[0].ptrValue
);
1019 /* skip all ws in the input */
1020 u_scanf_skip_leading_ws(input
, info
->fPadChar
);
1022 /* fill the input's internal buffer */
1023 ufile_fill_uchar_buffer(input
);
1025 /* determine the size of the input's buffer */
1026 len
= input
->str
.fLimit
- input
->str
.fPos
;
1028 /* truncate to the width, if specified */
1029 if(info
->fWidth
!= -1) {
1030 len
= ufmt_min(len
, info
->fWidth
);
1034 /* TODO: Fix this code so that it will work on all platforms */
1037 int32_t lenOrig
= len
;
1039 /* Make sure that we don't consume too much */
1040 if (len
> (int32_t)(sizeof(int64_t)*2)) {
1041 len
= (int32_t)(sizeof(int64_t)*2);
1044 /* parse the pointer - set first half of big endian pointer */
1045 result
[0] = (int64_t)ufmt_utop(input
->str
.fPos
, &len
);
1047 /* update the input's position to reflect consumed data */
1048 input
->str
.fPos
+= len
;
1049 len
= lenOrig
- len
;
1051 /* Make sure that we don't consume too much */
1052 if (len
> (int32_t)(sizeof(int64_t)*2)) {
1053 len
= (int32_t)(sizeof(int64_t)*2);
1056 /* parse the pointer - set second half of big endian pointer */
1057 result
[1] = (int64_t)ufmt_utop(input
->str
.fPos
, &len
);
1059 if (!info
->fSkipArg
) {
1060 p
= *((void **)result
);
1064 /* Make sure that we don't consume too much */
1065 if (len
> (int32_t)(sizeof(void*)*2)) {
1066 len
= (int32_t)(sizeof(void*)*2);
1069 /* parse the pointer - assign to temporary value */
1070 result
= ufmt_utop(input
->str
.fPos
, &len
);
1072 if (!info
->fSkipArg
) {
1078 /* update the input's position to reflect consumed data */
1079 input
->str
.fPos
+= len
;
1081 /* we converted 1 arg */
1082 *argConverted
= !info
->fSkipArg
;
1087 u_scanf_scanset_handler(UFILE
*input
,
1088 u_scanf_spec_info
*info
,
1091 int32_t *fmtConsumed
,
1092 int32_t *argConverted
)
1095 UErrorCode status
= U_ZERO_ERROR
;
1096 int32_t chLeft
= INT32_MAX
;
1098 UChar
*alias
= (UChar
*) (args
[0].ptrValue
);
1099 UBool isNotEOF
= FALSE
;
1100 UBool readCharacter
= FALSE
;
1102 /* Create an empty set */
1103 scanset
= uset_open(0, -1);
1105 /* Back up one to get the [ */
1108 /* truncate to the width, if specified and alias the target */
1109 if(info
->fWidth
>= 0) {
1110 chLeft
= info
->fWidth
;
1113 /* parse the scanset from the fmt string */
1114 *fmtConsumed
= uset_applyPattern(scanset
, fmt
, -1, 0, &status
);
1116 /* verify that the parse was successful */
1117 if (U_SUCCESS(status
)) {
1120 /* grab characters one at a time and make sure they are in the scanset */
1122 if ((isNotEOF
= ufile_getch32(input
, &c
)) && uset_contains(scanset
, c
)) {
1123 readCharacter
= TRUE
;
1124 if (!info
->fSkipArg
) {
1126 UBool isError
= FALSE
;
1128 U16_APPEND(alias
, idx
, chLeft
, c
, isError
);
1134 chLeft
-= (1 + U_IS_SUPPLEMENTARY(c
));
1137 /* if the character's not in the scanset, break out */
1142 /* put the final character we read back on the input */
1143 if(isNotEOF
&& chLeft
> 0) {
1144 u_fungetc(c
, input
);
1148 uset_close(scanset
);
1150 /* if we didn't match at least 1 character, fail */
1153 /* otherwise, add the terminator */
1154 else if (!info
->fSkipArg
) {
1158 /* we converted 1 arg */
1159 *argConverted
= !info
->fSkipArg
;
1160 return (info
->fWidth
>= 0 ? info
->fWidth
: INT32_MAX
) - chLeft
;
1163 /* Use US-ASCII characters only for formatting. Most codepages have
1164 characters 20-7F from Unicode. Using any other codepage specific
1165 characters will make it very difficult to format the string on
1166 non-Unicode machines */
1167 static const u_scanf_info g_u_scanf_infos
[USCANF_NUM_FMT_HANDLERS
] = {
1169 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1170 UFMT_EMPTY
, UFMT_SIMPLE_PERCENT
,UFMT_EMPTY
, UFMT_EMPTY
,
1171 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1172 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1175 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1176 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1177 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1178 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1181 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_UCHAR
,
1182 UFMT_EMPTY
, UFMT_SCIENTIFIC
, UFMT_EMPTY
, UFMT_SCIDBL
,
1183 #ifdef U_USE_OBSOLETE_IO_FORMATTING
1184 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_UCHAR
/*deprecated*/,
1186 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1188 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1191 UFMT_PERCENT
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_USTRING
,
1192 #ifdef U_USE_OBSOLETE_IO_FORMATTING
1193 UFMT_EMPTY
, UFMT_USTRING
/*deprecated*/,UFMT_SPELLOUT
, UFMT_EMPTY
,
1195 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_SPELLOUT
, UFMT_EMPTY
,
1197 UFMT_HEX
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_SCANSET
,
1198 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1201 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_CHAR
,
1202 UFMT_INT
, UFMT_SCIENTIFIC
, UFMT_DOUBLE
, UFMT_SCIDBL
,
1203 UFMT_EMPTY
, UFMT_INT
, UFMT_EMPTY
, UFMT_EMPTY
,
1204 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_COUNT
, UFMT_OCTAL
,
1207 UFMT_POINTER
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_STRING
,
1208 UFMT_EMPTY
, UFMT_UINT
, UFMT_EMPTY
, UFMT_EMPTY
,
1209 UFMT_HEX
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1210 UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
, UFMT_EMPTY
,
1214 u_scanf_parse(UFILE
*f
,
1215 const UChar
*patternSpecification
,
1219 int32_t count
, converted
, argConsumed
, cpConsumed
;
1220 uint16_t handlerNum
;
1224 ufmt_type_info info
;
1225 u_scanf_handler handler
;
1227 /* alias the pattern */
1228 alias
= patternSpecification
;
1230 /* haven't converted anything yet */
1235 /* iterate through the pattern */
1238 /* match any characters up to the next '%' */
1239 while(*alias
!= UP_PERCENT
&& *alias
!= 0x0000 && u_fgetc(f
) == *alias
) {
1243 /* if we aren't at a '%', or if we're at end of string, break*/
1244 if(*alias
!= UP_PERCENT
|| *alias
== 0x0000)
1247 /* parse the specifier */
1248 count
= u_scanf_parse_spec(alias
, &spec
);
1250 /* update the pointer in pattern */
1253 handlerNum
= (uint16_t)(spec
.fInfo
.fSpec
- USCANF_BASE_FMT_HANDLERS
);
1254 if (handlerNum
< USCANF_NUM_FMT_HANDLERS
) {
1255 /* skip the argument, if necessary */
1256 /* query the info function for argument information */
1257 info
= g_u_scanf_infos
[ handlerNum
].info
;
1258 if (info
!= ufmt_count
&& u_feof(f
)) {
1261 else if(spec
.fInfo
.fSkipArg
) {
1262 args
.ptrValue
= NULL
;
1267 /* set the spec's width to the # of items converted */
1268 spec
.fInfo
.fWidth
= cpConsumed
;
1269 /* fall through to next case */
1278 args
.ptrValue
= va_arg(ap
, void*);
1282 /* else args is ignored */
1283 args
.ptrValue
= NULL
;
1288 /* call the handler function */
1289 handler
= g_u_scanf_infos
[ handlerNum
].handler
;
1292 /* reset count to 1 so that += for alias works. */
1295 cpConsumed
+= (*handler
)(f
, &spec
.fInfo
, &args
, alias
, &count
, &argConsumed
);
1297 /* if the handler encountered an error condition, break */
1298 if(argConsumed
< 0) {
1303 /* add to the # of items converted */
1304 converted
+= argConsumed
;
1306 /* update the pointer in pattern */
1309 /* else do nothing */
1311 /* else do nothing */
1313 /* just ignore unknown tags */
1316 /* return # of items converted */
1320 #endif /* #if !UCONFIG_NO_FORMATTING */