blob: 9b27e2ebf8d44d124244a301e45b4a2c38f0910b [file] [log] [blame]
Jungshik Shin87232d82017-05-13 21:10:13 -07001// © 2016 and later: Unicode, Inc. and others.
Jungshik Shin5feb9ad2016-10-21 12:52:48 -07002// License & terms of use: http://www.unicode.org/copyright.html
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003/*
4*******************************************************************************
5*
Jungshik Shin5feb9ad2016-10-21 12:52:48 -07006* Copyright (C) 1998-2016, International Business Machines
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00007* Corporation and others. All Rights Reserved.
8*
9*******************************************************************************
10*
11* File uscnnf_p.c
12*
13* Modification History:
14*
15* Date Name Description
16* 12/02/98 stephen Creation.
17* 03/13/99 stephen Modified for new C API.
18*******************************************************************************
19*/
20
21#include "unicode/utypes.h"
22
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080023#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_CONVERSION
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000024
25#include "unicode/uchar.h"
26#include "unicode/ustring.h"
27#include "unicode/unum.h"
28#include "unicode/udat.h"
29#include "unicode/uset.h"
30#include "uscanf.h"
31#include "ufmt_cmn.h"
32#include "ufile.h"
33#include "locbund.h"
34
35#include "cmemory.h"
36#include "ustr_cnv.h"
37
38/* flag characters for u_scanf */
39#define FLAG_ASTERISK 0x002A
40#define FLAG_PAREN 0x0028
41
42#define ISFLAG(s) (s) == FLAG_ASTERISK || \
43 (s) == FLAG_PAREN
44
45/* special characters for u_scanf */
46#define SPEC_DOLLARSIGN 0x0024
47
48/* unicode digits */
49#define DIGIT_ZERO 0x0030
50#define DIGIT_ONE 0x0031
51#define DIGIT_TWO 0x0032
52#define DIGIT_THREE 0x0033
53#define DIGIT_FOUR 0x0034
54#define DIGIT_FIVE 0x0035
55#define DIGIT_SIX 0x0036
56#define DIGIT_SEVEN 0x0037
57#define DIGIT_EIGHT 0x0038
58#define DIGIT_NINE 0x0039
59
60#define ISDIGIT(s) (s) == DIGIT_ZERO || \
61 (s) == DIGIT_ONE || \
62 (s) == DIGIT_TWO || \
63 (s) == DIGIT_THREE || \
64 (s) == DIGIT_FOUR || \
65 (s) == DIGIT_FIVE || \
66 (s) == DIGIT_SIX || \
67 (s) == DIGIT_SEVEN || \
68 (s) == DIGIT_EIGHT || \
69 (s) == DIGIT_NINE
70
71/* u_scanf modifiers */
72#define MOD_H 0x0068
73#define MOD_LOWERL 0x006C
74#define MOD_L 0x004C
75
76#define ISMOD(s) (s) == MOD_H || \
77 (s) == MOD_LOWERL || \
78 (s) == MOD_L
79
80/**
81 * Struct encapsulating a single uscanf format specification.
82 */
83typedef struct u_scanf_spec_info {
84 int32_t fWidth; /* Width */
85
86 UChar fSpec; /* Format specification */
87
88 UChar fPadChar; /* Padding character */
89
Frank Tang1f164ee2022-11-08 12:31:27 -080090 UBool fSkipArg; /* true if arg should be skipped */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000091 UBool fIsLongDouble; /* L flag */
92 UBool fIsShort; /* h flag */
93 UBool fIsLong; /* l flag */
94 UBool fIsLongLong; /* ll flag */
Frank Tang1f164ee2022-11-08 12:31:27 -080095 UBool fIsString; /* true if this is a NULL-terminated string. */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000096} u_scanf_spec_info;
97
98
99/**
100 * Struct encapsulating a single u_scanf format specification.
101 */
102typedef struct u_scanf_spec {
103 u_scanf_spec_info fInfo; /* Information on this spec */
104 int32_t fArgPos; /* Position of data in arg list */
105} u_scanf_spec;
106
107/**
108 * Parse a single u_scanf format specifier in Unicode.
109 * @param fmt A pointer to a '%' character in a u_scanf format specification.
110 * @param spec A pointer to a <TT>u_scanf_spec</TT> to receive the parsed
111 * format specifier.
112 * @return The number of characters contained in this specifier.
113 */
114static int32_t
115u_scanf_parse_spec (const UChar *fmt,
116 u_scanf_spec *spec)
117{
118 const UChar *s = fmt;
119 const UChar *backup;
120 u_scanf_spec_info *info = &(spec->fInfo);
121
122 /* initialize spec to default values */
123 spec->fArgPos = -1;
124
125 info->fWidth = -1;
126 info->fSpec = 0x0000;
127 info->fPadChar = 0x0020;
Frank Tang1f164ee2022-11-08 12:31:27 -0800128 info->fSkipArg = false;
129 info->fIsLongDouble = false;
130 info->fIsShort = false;
131 info->fIsLong = false;
132 info->fIsLongLong = false;
133 info->fIsString = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000134
135
136 /* skip over the initial '%' */
137 s++;
138
139 /* Check for positional argument */
140 if(ISDIGIT(*s)) {
141
142 /* Save the current position */
143 backup = s;
144
145 /* handle positional parameters */
146 if(ISDIGIT(*s)) {
147 spec->fArgPos = (int) (*s++ - DIGIT_ZERO);
148
149 while(ISDIGIT(*s)) {
150 spec->fArgPos *= 10;
151 spec->fArgPos += (int) (*s++ - DIGIT_ZERO);
152 }
153 }
154
155 /* if there is no '$', don't read anything */
156 if(*s != SPEC_DOLLARSIGN) {
157 spec->fArgPos = -1;
158 s = backup;
159 }
160 /* munge the '$' */
161 else
162 s++;
163 }
164
165 /* Get any format flags */
166 while(ISFLAG(*s)) {
167 switch(*s++) {
168
169 /* skip argument */
170 case FLAG_ASTERISK:
Frank Tang1f164ee2022-11-08 12:31:27 -0800171 info->fSkipArg = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000172 break;
173
174 /* pad character specified */
175 case FLAG_PAREN:
176
177 /* first four characters are hex values for pad char */
178 info->fPadChar = (UChar)ufmt_digitvalue(*s++);
179 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++));
180 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++));
181 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++));
182
183 /* final character is ignored */
184 s++;
185
186 break;
187 }
188 }
189
190 /* Get the width */
191 if(ISDIGIT(*s)){
192 info->fWidth = (int) (*s++ - DIGIT_ZERO);
193
194 while(ISDIGIT(*s)) {
195 info->fWidth *= 10;
196 info->fWidth += (int) (*s++ - DIGIT_ZERO);
197 }
198 }
199
200 /* Get any modifiers */
201 if(ISMOD(*s)) {
202 switch(*s++) {
203
204 /* short */
205 case MOD_H:
Frank Tang1f164ee2022-11-08 12:31:27 -0800206 info->fIsShort = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000207 break;
208
209 /* long or long long */
210 case MOD_LOWERL:
211 if(*s == MOD_LOWERL) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800212 info->fIsLongLong = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000213 /* skip over the next 'l' */
214 s++;
215 }
216 else
Frank Tang1f164ee2022-11-08 12:31:27 -0800217 info->fIsLong = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000218 break;
219
220 /* long double */
221 case MOD_L:
Frank Tang1f164ee2022-11-08 12:31:27 -0800222 info->fIsLongDouble = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000223 break;
224 }
225 }
226
227 /* finally, get the specifier letter */
228 info->fSpec = *s++;
229
230 /* return # of characters in this specifier */
231 return (int32_t)(s - fmt);
232}
233
234#define UP_PERCENT 0x0025
235
236
237/* ANSI style formatting */
238/* Use US-ASCII characters only for formatting */
239
240/* % */
241#define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_scanf_simple_percent_handler}
242/* s */
243#define UFMT_STRING {ufmt_string, u_scanf_string_handler}
244/* c */
245#define UFMT_CHAR {ufmt_string, u_scanf_char_handler}
246/* d, i */
247#define UFMT_INT {ufmt_int, u_scanf_integer_handler}
248/* u */
249#define UFMT_UINT {ufmt_int, u_scanf_uinteger_handler}
250/* o */
251#define UFMT_OCTAL {ufmt_int, u_scanf_octal_handler}
252/* x, X */
253#define UFMT_HEX {ufmt_int, u_scanf_hex_handler}
254/* f */
255#define UFMT_DOUBLE {ufmt_double, u_scanf_double_handler}
256/* e, E */
257#define UFMT_SCIENTIFIC {ufmt_double, u_scanf_scientific_handler}
258/* g, G */
259#define UFMT_SCIDBL {ufmt_double, u_scanf_scidbl_handler}
260/* n */
261#define UFMT_COUNT {ufmt_count, u_scanf_count_handler}
262/* [ */
263#define UFMT_SCANSET {ufmt_string, u_scanf_scanset_handler}
264
265/* non-ANSI extensions */
266/* Use US-ASCII characters only for formatting */
267
268/* p */
269#define UFMT_POINTER {ufmt_pointer, u_scanf_pointer_handler}
270/* V */
271#define UFMT_SPELLOUT {ufmt_double, u_scanf_spellout_handler}
272/* P */
273#define UFMT_PERCENT {ufmt_double, u_scanf_percent_handler}
274/* C K is old format */
275#define UFMT_UCHAR {ufmt_uchar, u_scanf_uchar_handler}
276/* S U is old format */
277#define UFMT_USTRING {ufmt_ustring, u_scanf_ustring_handler}
278
279
280#define UFMT_EMPTY {ufmt_empty, NULL}
281
282/**
283 * A u_scanf handler function.
284 * A u_scanf handler is responsible for handling a single u_scanf
285 * format specification, for example 'd' or 's'.
286 * @param stream The UFILE to which to write output.
287 * @param info A pointer to a <TT>u_scanf_spec_info</TT> struct containing
288 * information on the format specification.
289 * @param args A pointer to the argument data
290 * @param fmt A pointer to the first character in the format string
291 * following the spec.
292 * @param fmtConsumed On output, set to the number of characters consumed
293 * in <TT>fmt</TT>. Do nothing, if the argument isn't variable width.
294 * @param argConverted The number of arguments converted and assigned, or -1 if an
295 * error occurred.
296 * @return The number of code points consumed during reading.
297 */
298typedef int32_t (*u_scanf_handler) (UFILE *stream,
299 u_scanf_spec_info *info,
300 ufmt_args *args,
301 const UChar *fmt,
302 int32_t *fmtConsumed,
303 int32_t *argConverted);
304
305typedef struct u_scanf_info {
306 ufmt_type_info info;
307 u_scanf_handler handler;
308} u_scanf_info;
309
310#define USCANF_NUM_FMT_HANDLERS 108
311#define USCANF_SYMBOL_BUFFER_SIZE 8
312
313/* We do not use handlers for 0-0x1f */
314#define USCANF_BASE_FMT_HANDLERS 0x20
315
316
317static int32_t
318u_scanf_skip_leading_ws(UFILE *input,
319 UChar pad)
320{
321 UChar c;
322 int32_t count = 0;
323 UBool isNotEOF;
324
325 /* skip all leading ws in the input */
Frank Tang1f164ee2022-11-08 12:31:27 -0800326 while( ((isNotEOF = ufile_getch(input, &c)) == true) && (c == pad || u_isWhitespace(c)) )
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000327 {
328 count++;
329 }
330
331 /* put the final character back on the input */
332 if(isNotEOF)
333 u_fungetc(c, input);
334
335 return count;
336}
337
338/* TODO: Is always skipping the prefix symbol as a positive sign a good idea in all locales? */
339static int32_t
340u_scanf_skip_leading_positive_sign(UFILE *input,
341 UNumberFormat *format,
342 UErrorCode *status)
343{
344 UChar c;
345 int32_t count = 0;
346 UBool isNotEOF;
347 UChar plusSymbol[USCANF_SYMBOL_BUFFER_SIZE];
348 int32_t symbolLen;
349 UErrorCode localStatus = U_ZERO_ERROR;
350
351 if (U_SUCCESS(*status)) {
352 symbolLen = unum_getSymbol(format,
353 UNUM_PLUS_SIGN_SYMBOL,
354 plusSymbol,
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700355 UPRV_LENGTHOF(plusSymbol),
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000356 &localStatus);
357
358 if (U_SUCCESS(localStatus)) {
359 /* skip all leading ws in the input */
Frank Tang1f164ee2022-11-08 12:31:27 -0800360 while( ((isNotEOF = ufile_getch(input, &c)) == true) && (count < symbolLen && c == plusSymbol[count]) )
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000361 {
362 count++;
363 }
364
365 /* put the final character back on the input */
366 if(isNotEOF) {
367 u_fungetc(c, input);
368 }
369 }
370 }
371
372 return count;
373}
374
375static int32_t
376u_scanf_simple_percent_handler(UFILE *input,
377 u_scanf_spec_info *info,
378 ufmt_args *args,
379 const UChar *fmt,
380 int32_t *fmtConsumed,
381 int32_t *argConverted)
382{
Jungshik Shin87232d82017-05-13 21:10:13 -0700383 (void)info;
384 (void)args;
385 (void)fmt;
386 (void)fmtConsumed;
387
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000388 /* make sure the next character in the input is a percent */
389 *argConverted = 0;
390 if(u_fgetc(input) != 0x0025) {
391 *argConverted = -1;
392 }
393 return 1;
394}
395
396static int32_t
397u_scanf_count_handler(UFILE *input,
398 u_scanf_spec_info *info,
399 ufmt_args *args,
400 const UChar *fmt,
401 int32_t *fmtConsumed,
402 int32_t *argConverted)
403{
Jungshik Shin87232d82017-05-13 21:10:13 -0700404 (void)input;
405 (void)fmt;
406 (void)fmtConsumed;
407
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000408 /* in the special case of count, the u_scanf_spec_info's width */
409 /* will contain the # of items converted thus far */
410 if (!info->fSkipArg) {
411 if (info->fIsShort)
412 *(int16_t*)(args[0].ptrValue) = (int16_t)(UINT16_MAX & info->fWidth);
413 else if (info->fIsLongLong)
414 *(int64_t*)(args[0].ptrValue) = info->fWidth;
415 else
416 *(int32_t*)(args[0].ptrValue) = (int32_t)(UINT32_MAX & info->fWidth);
417 }
418 *argConverted = 0;
419
420 /* we converted 0 args */
421 return 0;
422}
423
424static int32_t
425u_scanf_double_handler(UFILE *input,
426 u_scanf_spec_info *info,
427 ufmt_args *args,
428 const UChar *fmt,
429 int32_t *fmtConsumed,
430 int32_t *argConverted)
431{
Jungshik Shin87232d82017-05-13 21:10:13 -0700432 (void)fmt;
433 (void)fmtConsumed;
434
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000435 int32_t len;
436 double num;
437 UNumberFormat *format;
438 int32_t parsePos = 0;
439 int32_t skipped;
440 UErrorCode status = U_ZERO_ERROR;
441
442
443 /* skip all ws in the input */
444 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
445
446 /* fill the input's internal buffer */
447 ufile_fill_uchar_buffer(input);
448
449 /* determine the size of the input's buffer */
450 len = (int32_t)(input->str.fLimit - input->str.fPos);
451
452 /* truncate to the width, if specified */
453 if(info->fWidth != -1)
454 len = ufmt_min(len, info->fWidth);
455
456 /* get the formatter */
457 format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
458
459 /* handle error */
460 if(format == 0)
461 return 0;
462
463 /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
464 skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
465
466 /* parse the number */
467 num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
468
469 if (!info->fSkipArg) {
470 if (info->fIsLong)
471 *(double*)(args[0].ptrValue) = num;
472 else if (info->fIsLongDouble)
473 *(long double*)(args[0].ptrValue) = num;
474 else
475 *(float*)(args[0].ptrValue) = (float)num;
476 }
477
478 /* mask off any necessary bits */
479 /* if(! info->fIsLong_double)
480 num &= DBL_MAX;*/
481
482 /* update the input's position to reflect consumed data */
483 input->str.fPos += parsePos;
484
485 /* we converted 1 arg */
486 *argConverted = !info->fSkipArg;
487 return parsePos + skipped;
488}
489
490#define UPRINTF_SYMBOL_BUFFER_SIZE 8
491
492static int32_t
493u_scanf_scientific_handler(UFILE *input,
494 u_scanf_spec_info *info,
495 ufmt_args *args,
496 const UChar *fmt,
497 int32_t *fmtConsumed,
498 int32_t *argConverted)
499{
Jungshik Shin87232d82017-05-13 21:10:13 -0700500 (void)fmt;
501 (void)fmtConsumed;
502
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000503 int32_t len;
504 double num;
505 UNumberFormat *format;
506 int32_t parsePos = 0;
507 int32_t skipped;
508 UErrorCode status = U_ZERO_ERROR;
509 UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
510 int32_t srcLen, expLen;
511 UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
512
513
514 /* skip all ws in the input */
515 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
516
517 /* fill the input's internal buffer */
518 ufile_fill_uchar_buffer(input);
519
520 /* determine the size of the input's buffer */
521 len = (int32_t)(input->str.fLimit - input->str.fPos);
522
523 /* truncate to the width, if specified */
524 if(info->fWidth != -1)
525 len = ufmt_min(len, info->fWidth);
526
527 /* get the formatter */
528 format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SCIENTIFIC);
529
530 /* handle error */
531 if(format == 0)
532 return 0;
533
534 /* set the appropriate flags on the formatter */
535
536 srcLen = unum_getSymbol(format,
537 UNUM_EXPONENTIAL_SYMBOL,
538 srcExpBuf,
539 sizeof(srcExpBuf),
540 &status);
541
542 /* Upper/lower case the e */
543 if (info->fSpec == (UChar)0x65 /* e */) {
544 expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
545 srcExpBuf, srcLen,
546 input->str.fBundle.fLocale,
547 &status);
548 }
549 else {
550 expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
551 srcExpBuf, srcLen,
552 input->str.fBundle.fLocale,
553 &status);
554 }
555
556 unum_setSymbol(format,
557 UNUM_EXPONENTIAL_SYMBOL,
558 expBuf,
559 expLen,
560 &status);
561
562
563
564
565 /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
566 skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
567
568 /* parse the number */
569 num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
570
571 if (!info->fSkipArg) {
572 if (info->fIsLong)
573 *(double*)(args[0].ptrValue) = num;
574 else if (info->fIsLongDouble)
575 *(long double*)(args[0].ptrValue) = num;
576 else
577 *(float*)(args[0].ptrValue) = (float)num;
578 }
579
580 /* mask off any necessary bits */
581 /* if(! info->fIsLong_double)
582 num &= DBL_MAX;*/
583
584 /* update the input's position to reflect consumed data */
585 input->str.fPos += parsePos;
586
587 /* we converted 1 arg */
588 *argConverted = !info->fSkipArg;
589 return parsePos + skipped;
590}
591
592static int32_t
593u_scanf_scidbl_handler(UFILE *input,
594 u_scanf_spec_info *info,
595 ufmt_args *args,
596 const UChar *fmt,
597 int32_t *fmtConsumed,
598 int32_t *argConverted)
599{
Jungshik Shin87232d82017-05-13 21:10:13 -0700600 (void)fmt;
601 (void)fmtConsumed;
602
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000603 int32_t len;
604 double num;
605 UNumberFormat *scientificFormat, *genericFormat;
606 /*int32_t scientificResult, genericResult;*/
607 double scientificResult, genericResult;
608 int32_t scientificParsePos = 0, genericParsePos = 0, parsePos = 0;
609 int32_t skipped;
610 UErrorCode scientificStatus = U_ZERO_ERROR;
611 UErrorCode genericStatus = U_ZERO_ERROR;
612
613
614 /* since we can't determine by scanning the characters whether */
615 /* a number was formatted in the 'f' or 'g' styles, parse the */
616 /* string with both formatters, and assume whichever one */
617 /* parsed the most is the correct formatter to use */
618
619
620 /* skip all ws in the input */
621 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
622
623 /* fill the input's internal buffer */
624 ufile_fill_uchar_buffer(input);
625
626 /* determine the size of the input's buffer */
627 len = (int32_t)(input->str.fLimit - input->str.fPos);
628
629 /* truncate to the width, if specified */
630 if(info->fWidth != -1)
631 len = ufmt_min(len, info->fWidth);
632
633 /* get the formatters */
634 scientificFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SCIENTIFIC);
635 genericFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
636
637 /* handle error */
638 if(scientificFormat == 0 || genericFormat == 0)
639 return 0;
640
641 /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
642 skipped += u_scanf_skip_leading_positive_sign(input, genericFormat, &genericStatus);
643
644 /* parse the number using each format*/
645
646 scientificResult = unum_parseDouble(scientificFormat, input->str.fPos, len,
647 &scientificParsePos, &scientificStatus);
648
649 genericResult = unum_parseDouble(genericFormat, input->str.fPos, len,
650 &genericParsePos, &genericStatus);
651
652 /* determine which parse made it farther */
653 if(scientificParsePos > genericParsePos) {
654 /* stash the result in num */
655 num = scientificResult;
656 /* update the input's position to reflect consumed data */
657 parsePos += scientificParsePos;
658 }
659 else {
660 /* stash the result in num */
661 num = genericResult;
662 /* update the input's position to reflect consumed data */
663 parsePos += genericParsePos;
664 }
665 input->str.fPos += parsePos;
666
667 if (!info->fSkipArg) {
668 if (info->fIsLong)
669 *(double*)(args[0].ptrValue) = num;
670 else if (info->fIsLongDouble)
671 *(long double*)(args[0].ptrValue) = num;
672 else
673 *(float*)(args[0].ptrValue) = (float)num;
674 }
675
676 /* mask off any necessary bits */
677 /* if(! info->fIsLong_double)
678 num &= DBL_MAX;*/
679
680 /* we converted 1 arg */
681 *argConverted = !info->fSkipArg;
682 return parsePos + skipped;
683}
684
685static int32_t
686u_scanf_integer_handler(UFILE *input,
687 u_scanf_spec_info *info,
688 ufmt_args *args,
689 const UChar *fmt,
690 int32_t *fmtConsumed,
691 int32_t *argConverted)
692{
Jungshik Shin87232d82017-05-13 21:10:13 -0700693 (void)fmt;
694 (void)fmtConsumed;
695
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000696 int32_t len;
697 void *num = (void*) (args[0].ptrValue);
Frank Tangf90543d2020-10-30 19:02:04 -0700698 UNumberFormat *format, *localFormat;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000699 int32_t parsePos = 0;
700 int32_t skipped;
Frank Tangf90543d2020-10-30 19:02:04 -0700701 int32_t parseIntOnly = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000702 UErrorCode status = U_ZERO_ERROR;
703 int64_t result;
704
705
706 /* skip all ws in the input */
707 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
708
709 /* fill the input's internal buffer */
710 ufile_fill_uchar_buffer(input);
711
712 /* determine the size of the input's buffer */
713 len = (int32_t)(input->str.fLimit - input->str.fPos);
714
715 /* truncate to the width, if specified */
716 if(info->fWidth != -1)
717 len = ufmt_min(len, info->fWidth);
718
719 /* get the formatter */
720 format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
721
722 /* handle error */
723 if(format == 0)
724 return 0;
725
Frank Tangf90543d2020-10-30 19:02:04 -0700726 /* for integer types, do not attempt to parse fractions */
727 localFormat = unum_clone(format, &status);
728 if(U_FAILURE(status))
729 return 0;
730
731 if(info->fSpec == 'd' || info->fSpec == 'i' || info->fSpec == 'u')
732 parseIntOnly = 1;
733 unum_setAttribute(localFormat, UNUM_PARSE_INT_ONLY, parseIntOnly);
734
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000735 /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
Frank Tangf90543d2020-10-30 19:02:04 -0700736 skipped += u_scanf_skip_leading_positive_sign(input, localFormat, &status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000737
738 /* parse the number */
Frank Tangf90543d2020-10-30 19:02:04 -0700739 result = unum_parseInt64(localFormat, input->str.fPos, len, &parsePos, &status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000740
741 /* mask off any necessary bits */
742 if (!info->fSkipArg) {
743 if (info->fIsShort)
744 *(int16_t*)num = (int16_t)(UINT16_MAX & result);
745 else if (info->fIsLongLong)
746 *(int64_t*)num = result;
747 else
748 *(int32_t*)num = (int32_t)(UINT32_MAX & result);
749 }
750
751 /* update the input's position to reflect consumed data */
752 input->str.fPos += parsePos;
753
Frank Tangf90543d2020-10-30 19:02:04 -0700754 /* cleanup cloned formatter */
755 unum_close(localFormat);
756
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000757 /* we converted 1 arg */
758 *argConverted = !info->fSkipArg;
759 return parsePos + skipped;
760}
761
762static int32_t
763u_scanf_uinteger_handler(UFILE *input,
764 u_scanf_spec_info *info,
765 ufmt_args *args,
766 const UChar *fmt,
767 int32_t *fmtConsumed,
768 int32_t *argConverted)
769{
770 /* TODO Fix this when Numberformat handles uint64_t */
771 return u_scanf_integer_handler(input, info, args, fmt, fmtConsumed, argConverted);
772}
773
774static int32_t
775u_scanf_percent_handler(UFILE *input,
776 u_scanf_spec_info *info,
777 ufmt_args *args,
778 const UChar *fmt,
779 int32_t *fmtConsumed,
780 int32_t *argConverted)
781{
Jungshik Shin87232d82017-05-13 21:10:13 -0700782 (void)fmt;
783 (void)fmtConsumed;
784
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000785 int32_t len;
786 double num;
787 UNumberFormat *format;
788 int32_t parsePos = 0;
789 UErrorCode status = U_ZERO_ERROR;
790
791
792 /* skip all ws in the input */
793 u_scanf_skip_leading_ws(input, info->fPadChar);
794
795 /* fill the input's internal buffer */
796 ufile_fill_uchar_buffer(input);
797
798 /* determine the size of the input's buffer */
799 len = (int32_t)(input->str.fLimit - input->str.fPos);
800
801 /* truncate to the width, if specified */
802 if(info->fWidth != -1)
803 len = ufmt_min(len, info->fWidth);
804
805 /* get the formatter */
806 format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_PERCENT);
807
808 /* handle error */
809 if(format == 0)
810 return 0;
811
812 /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
813 u_scanf_skip_leading_positive_sign(input, format, &status);
814
815 /* parse the number */
816 num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
817
818 if (!info->fSkipArg) {
819 *(double*)(args[0].ptrValue) = num;
820 }
821
822 /* mask off any necessary bits */
823 /* if(! info->fIsLong_double)
824 num &= DBL_MAX;*/
825
826 /* update the input's position to reflect consumed data */
827 input->str.fPos += parsePos;
828
829 /* we converted 1 arg */
830 *argConverted = !info->fSkipArg;
831 return parsePos;
832}
833
834static int32_t
835u_scanf_string_handler(UFILE *input,
836 u_scanf_spec_info *info,
837 ufmt_args *args,
838 const UChar *fmt,
839 int32_t *fmtConsumed,
840 int32_t *argConverted)
841{
Jungshik Shin87232d82017-05-13 21:10:13 -0700842 (void)fmt;
843 (void)fmtConsumed;
844
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000845 const UChar *source;
846 UConverter *conv;
847 char *arg = (char*)(args[0].ptrValue);
848 char *alias = arg;
849 char *limit;
850 UErrorCode status = U_ZERO_ERROR;
851 int32_t count;
852 int32_t skipped = 0;
853 UChar c;
Frank Tang1f164ee2022-11-08 12:31:27 -0800854 UBool isNotEOF = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000855
856 /* skip all ws in the input */
857 if (info->fIsString) {
858 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
859 }
860
861 /* get the string one character at a time, truncating to the width */
862 count = 0;
863
864 /* open the default converter */
865 conv = u_getDefaultConverter(&status);
866
867 if(U_FAILURE(status))
868 return -1;
869
870 while( (info->fWidth == -1 || count < info->fWidth)
Frank Tang1f164ee2022-11-08 12:31:27 -0800871 && ((isNotEOF = ufile_getch(input, &c)) == true)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000872 && (!info->fIsString || (c != info->fPadChar && !u_isWhitespace(c))))
873 {
874
875 if (!info->fSkipArg) {
876 /* put the character from the input onto the target */
877 source = &c;
878 /* Since we do this one character at a time, do it this way. */
879 if (info->fWidth > 0) {
880 limit = alias + info->fWidth - count;
881 }
882 else {
883 limit = alias + ucnv_getMaxCharSize(conv);
884 }
885
886 /* convert the character to the default codepage */
887 ucnv_fromUnicode(conv, &alias, limit, &source, source + 1,
Frank Tang1f164ee2022-11-08 12:31:27 -0800888 NULL, true, &status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000889
890 if(U_FAILURE(status)) {
891 /* clean up */
892 u_releaseDefaultConverter(conv);
893 return -1;
894 }
895 }
896
897 /* increment the count */
898 ++count;
899 }
900
901 /* put the final character we read back on the input */
902 if (!info->fSkipArg) {
903 if ((info->fWidth == -1 || count < info->fWidth) && isNotEOF)
904 u_fungetc(c, input);
905
906 /* add the terminator */
907 if (info->fIsString) {
908 *alias = 0x00;
909 }
910 }
911
912 /* clean up */
913 u_releaseDefaultConverter(conv);
914
915 /* we converted 1 arg */
916 *argConverted = !info->fSkipArg;
917 return count + skipped;
918}
919
920static int32_t
921u_scanf_char_handler(UFILE *input,
922 u_scanf_spec_info *info,
923 ufmt_args *args,
924 const UChar *fmt,
925 int32_t *fmtConsumed,
926 int32_t *argConverted)
927{
928 if (info->fWidth < 0) {
929 info->fWidth = 1;
930 }
Frank Tang1f164ee2022-11-08 12:31:27 -0800931 info->fIsString = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000932 return u_scanf_string_handler(input, info, args, fmt, fmtConsumed, argConverted);
933}
934
935static int32_t
936u_scanf_ustring_handler(UFILE *input,
937 u_scanf_spec_info *info,
938 ufmt_args *args,
939 const UChar *fmt,
940 int32_t *fmtConsumed,
941 int32_t *argConverted)
942{
Jungshik Shin87232d82017-05-13 21:10:13 -0700943 (void)fmt;
944 (void)fmtConsumed;
945
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000946 UChar *arg = (UChar*)(args[0].ptrValue);
947 UChar *alias = arg;
948 int32_t count;
949 int32_t skipped = 0;
950 UChar c;
Frank Tang1f164ee2022-11-08 12:31:27 -0800951 UBool isNotEOF = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000952
953 /* skip all ws in the input */
954 if (info->fIsString) {
955 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
956 }
957
958 /* get the string one character at a time, truncating to the width */
959 count = 0;
960
961 while( (info->fWidth == -1 || count < info->fWidth)
Frank Tang1f164ee2022-11-08 12:31:27 -0800962 && ((isNotEOF = ufile_getch(input, &c)) == true)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000963 && (!info->fIsString || (c != info->fPadChar && !u_isWhitespace(c))))
964 {
965
966 /* put the character from the input onto the target */
967 if (!info->fSkipArg) {
968 *alias++ = c;
969 }
970
971 /* increment the count */
972 ++count;
973 }
974
975 /* put the final character we read back on the input */
976 if (!info->fSkipArg) {
977 if((info->fWidth == -1 || count < info->fWidth) && isNotEOF) {
978 u_fungetc(c, input);
979 }
980
981 /* add the terminator */
982 if (info->fIsString) {
983 *alias = 0x0000;
984 }
985 }
986
987 /* we converted 1 arg */
988 *argConverted = !info->fSkipArg;
989 return count + skipped;
990}
991
992static int32_t
993u_scanf_uchar_handler(UFILE *input,
994 u_scanf_spec_info *info,
995 ufmt_args *args,
996 const UChar *fmt,
997 int32_t *fmtConsumed,
998 int32_t *argConverted)
999{
1000 if (info->fWidth < 0) {
1001 info->fWidth = 1;
1002 }
Frank Tang1f164ee2022-11-08 12:31:27 -08001003 info->fIsString = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001004 return u_scanf_ustring_handler(input, info, args, fmt, fmtConsumed, argConverted);
1005}
1006
1007static int32_t
1008u_scanf_spellout_handler(UFILE *input,
1009 u_scanf_spec_info *info,
1010 ufmt_args *args,
1011 const UChar *fmt,
1012 int32_t *fmtConsumed,
1013 int32_t *argConverted)
1014{
Jungshik Shin87232d82017-05-13 21:10:13 -07001015 (void)fmt;
1016 (void)fmtConsumed;
1017
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001018 int32_t len;
1019 double num;
1020 UNumberFormat *format;
1021 int32_t parsePos = 0;
1022 int32_t skipped;
1023 UErrorCode status = U_ZERO_ERROR;
1024
1025
1026 /* skip all ws in the input */
1027 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
1028
1029 /* fill the input's internal buffer */
1030 ufile_fill_uchar_buffer(input);
1031
1032 /* determine the size of the input's buffer */
1033 len = (int32_t)(input->str.fLimit - input->str.fPos);
1034
1035 /* truncate to the width, if specified */
1036 if(info->fWidth != -1)
1037 len = ufmt_min(len, info->fWidth);
1038
1039 /* get the formatter */
1040 format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SPELLOUT);
1041
1042 /* handle error */
1043 if(format == 0)
1044 return 0;
1045
1046 /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
1047 /* This is not applicable to RBNF. */
1048 /*skipped += u_scanf_skip_leading_positive_sign(input, format, &status);*/
1049
1050 /* parse the number */
1051 num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
1052
1053 if (!info->fSkipArg) {
1054 *(double*)(args[0].ptrValue) = num;
1055 }
1056
1057 /* mask off any necessary bits */
1058 /* if(! info->fIsLong_double)
1059 num &= DBL_MAX;*/
1060
1061 /* update the input's position to reflect consumed data */
1062 input->str.fPos += parsePos;
1063
1064 /* we converted 1 arg */
1065 *argConverted = !info->fSkipArg;
1066 return parsePos + skipped;
1067}
1068
1069static int32_t
1070u_scanf_hex_handler(UFILE *input,
1071 u_scanf_spec_info *info,
1072 ufmt_args *args,
1073 const UChar *fmt,
1074 int32_t *fmtConsumed,
1075 int32_t *argConverted)
1076{
Jungshik Shin87232d82017-05-13 21:10:13 -07001077 (void)fmt;
1078 (void)fmtConsumed;
1079
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001080 int32_t len;
1081 int32_t skipped;
1082 void *num = (void*) (args[0].ptrValue);
1083 int64_t result;
1084
1085 /* skip all ws in the input */
1086 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
1087
1088 /* fill the input's internal buffer */
1089 ufile_fill_uchar_buffer(input);
1090
1091 /* determine the size of the input's buffer */
1092 len = (int32_t)(input->str.fLimit - input->str.fPos);
1093
1094 /* truncate to the width, if specified */
1095 if(info->fWidth != -1)
1096 len = ufmt_min(len, info->fWidth);
1097
1098 /* check for alternate form */
1099 if( *(input->str.fPos) == 0x0030 &&
1100 (*(input->str.fPos + 1) == 0x0078 || *(input->str.fPos + 1) == 0x0058) ) {
1101
1102 /* skip the '0' and 'x' or 'X' if present */
1103 input->str.fPos += 2;
1104 len -= 2;
1105 }
1106
1107 /* parse the number */
1108 result = ufmt_uto64(input->str.fPos, &len, 16);
1109
1110 /* update the input's position to reflect consumed data */
1111 input->str.fPos += len;
1112
1113 /* mask off any necessary bits */
1114 if (!info->fSkipArg) {
1115 if (info->fIsShort)
1116 *(int16_t*)num = (int16_t)(UINT16_MAX & result);
1117 else if (info->fIsLongLong)
1118 *(int64_t*)num = result;
1119 else
1120 *(int32_t*)num = (int32_t)(UINT32_MAX & result);
1121 }
1122
1123 /* we converted 1 arg */
1124 *argConverted = !info->fSkipArg;
1125 return len + skipped;
1126}
1127
1128static int32_t
1129u_scanf_octal_handler(UFILE *input,
1130 u_scanf_spec_info *info,
1131 ufmt_args *args,
1132 const UChar *fmt,
1133 int32_t *fmtConsumed,
1134 int32_t *argConverted)
1135{
Jungshik Shin87232d82017-05-13 21:10:13 -07001136 (void)fmt;
1137 (void)fmtConsumed;
1138
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001139 int32_t len;
1140 int32_t skipped;
1141 void *num = (void*) (args[0].ptrValue);
1142 int64_t result;
1143
1144 /* skip all ws in the input */
1145 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
1146
1147 /* fill the input's internal buffer */
1148 ufile_fill_uchar_buffer(input);
1149
1150 /* determine the size of the input's buffer */
1151 len = (int32_t)(input->str.fLimit - input->str.fPos);
1152
1153 /* truncate to the width, if specified */
1154 if(info->fWidth != -1)
1155 len = ufmt_min(len, info->fWidth);
1156
1157 /* parse the number */
1158 result = ufmt_uto64(input->str.fPos, &len, 8);
1159
1160 /* update the input's position to reflect consumed data */
1161 input->str.fPos += len;
1162
1163 /* mask off any necessary bits */
1164 if (!info->fSkipArg) {
1165 if (info->fIsShort)
1166 *(int16_t*)num = (int16_t)(UINT16_MAX & result);
1167 else if (info->fIsLongLong)
1168 *(int64_t*)num = result;
1169 else
1170 *(int32_t*)num = (int32_t)(UINT32_MAX & result);
1171 }
1172
1173 /* we converted 1 arg */
1174 *argConverted = !info->fSkipArg;
1175 return len + skipped;
1176}
1177
1178static int32_t
1179u_scanf_pointer_handler(UFILE *input,
1180 u_scanf_spec_info *info,
1181 ufmt_args *args,
1182 const UChar *fmt,
1183 int32_t *fmtConsumed,
1184 int32_t *argConverted)
1185{
Jungshik Shin87232d82017-05-13 21:10:13 -07001186 (void)fmt;
1187 (void)fmtConsumed;
1188
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001189 int32_t len;
1190 int32_t skipped;
1191 void *result;
1192 void **p = (void**)(args[0].ptrValue);
1193
1194
1195 /* skip all ws in the input */
1196 skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
1197
1198 /* fill the input's internal buffer */
1199 ufile_fill_uchar_buffer(input);
1200
1201 /* determine the size of the input's buffer */
1202 len = (int32_t)(input->str.fLimit - input->str.fPos);
1203
1204 /* truncate to the width, if specified */
1205 if(info->fWidth != -1) {
1206 len = ufmt_min(len, info->fWidth);
1207 }
1208
1209 /* Make sure that we don't consume too much */
1210 if (len > (int32_t)(sizeof(void*)*2)) {
1211 len = (int32_t)(sizeof(void*)*2);
1212 }
1213
1214 /* parse the pointer - assign to temporary value */
1215 result = ufmt_utop(input->str.fPos, &len);
1216
1217 if (!info->fSkipArg) {
1218 *p = result;
1219 }
1220
1221 /* update the input's position to reflect consumed data */
1222 input->str.fPos += len;
1223
1224 /* we converted 1 arg */
1225 *argConverted = !info->fSkipArg;
1226 return len + skipped;
1227}
1228
1229static int32_t
1230u_scanf_scanset_handler(UFILE *input,
1231 u_scanf_spec_info *info,
1232 ufmt_args *args,
1233 const UChar *fmt,
1234 int32_t *fmtConsumed,
1235 int32_t *argConverted)
1236{
1237 USet *scanset;
1238 UErrorCode status = U_ZERO_ERROR;
1239 int32_t chLeft = INT32_MAX;
1240 UChar32 c;
1241 UChar *alias = (UChar*) (args[0].ptrValue);
Frank Tang1f164ee2022-11-08 12:31:27 -08001242 UBool isNotEOF = false;
1243 UBool readCharacter = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001244
1245 /* Create an empty set */
1246 scanset = uset_open(0, -1);
1247
1248 /* Back up one to get the [ */
1249 fmt--;
1250
1251 /* truncate to the width, if specified and alias the target */
1252 if(info->fWidth >= 0) {
1253 chLeft = info->fWidth;
1254 }
1255
1256 /* parse the scanset from the fmt string */
1257 *fmtConsumed = uset_applyPattern(scanset, fmt, -1, 0, &status);
1258
1259 /* verify that the parse was successful */
1260 if (U_SUCCESS(status)) {
1261 c=0;
1262
1263 /* grab characters one at a time and make sure they are in the scanset */
1264 while(chLeft > 0) {
Frank Tang1f164ee2022-11-08 12:31:27 -08001265 if ( ((isNotEOF = ufile_getch32(input, &c)) == true) && uset_contains(scanset, c) ) {
1266 readCharacter = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001267 if (!info->fSkipArg) {
1268 int32_t idx = 0;
Frank Tang1f164ee2022-11-08 12:31:27 -08001269 UBool isError = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001270
1271 U16_APPEND(alias, idx, chLeft, c, isError);
1272 if (isError) {
1273 break;
1274 }
1275 alias += idx;
1276 }
1277 chLeft -= (1 + U_IS_SUPPLEMENTARY(c));
1278 }
1279 else {
1280 /* if the character's not in the scanset, break out */
1281 break;
1282 }
1283 }
1284
1285 /* put the final character we read back on the input */
1286 if(isNotEOF && chLeft > 0) {
1287 u_fungetc(c, input);
1288 }
1289 }
1290
1291 uset_close(scanset);
1292
1293 /* if we didn't match at least 1 character, fail */
1294 if(!readCharacter)
1295 return -1;
1296 /* otherwise, add the terminator */
1297 else if (!info->fSkipArg) {
1298 *alias = 0x00;
1299 }
1300
1301 /* we converted 1 arg */
1302 *argConverted = !info->fSkipArg;
1303 return (info->fWidth >= 0 ? info->fWidth : INT32_MAX) - chLeft;
1304}
1305
1306/* Use US-ASCII characters only for formatting. Most codepages have
1307 characters 20-7F from Unicode. Using any other codepage specific
1308 characters will make it very difficult to format the string on
1309 non-Unicode machines */
1310static const u_scanf_info g_u_scanf_infos[USCANF_NUM_FMT_HANDLERS] = {
1311/* 0x20 */
1312 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1313 UFMT_EMPTY, UFMT_SIMPLE_PERCENT,UFMT_EMPTY, UFMT_EMPTY,
1314 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1315 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1316
1317/* 0x30 */
1318 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1319 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1320 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1321 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1322
1323/* 0x40 */
1324 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR,
1325 UFMT_EMPTY, UFMT_SCIENTIFIC, UFMT_EMPTY, UFMT_SCIDBL,
1326#ifdef U_USE_OBSOLETE_IO_FORMATTING
1327 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR/*deprecated*/,
1328#else
1329 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1330#endif
1331 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1332
1333/* 0x50 */
1334 UFMT_PERCENT, UFMT_EMPTY, UFMT_EMPTY, UFMT_USTRING,
1335#ifdef U_USE_OBSOLETE_IO_FORMATTING
1336 UFMT_EMPTY, UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT, UFMT_EMPTY,
1337#else
1338 UFMT_EMPTY, UFMT_EMPTY, UFMT_SPELLOUT, UFMT_EMPTY,
1339#endif
1340 UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_SCANSET,
1341 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1342
1343/* 0x60 */
1344 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_CHAR,
1345 UFMT_INT, UFMT_SCIENTIFIC, UFMT_DOUBLE, UFMT_SCIDBL,
1346 UFMT_EMPTY, UFMT_INT, UFMT_EMPTY, UFMT_EMPTY,
1347 UFMT_EMPTY, UFMT_EMPTY, UFMT_COUNT, UFMT_OCTAL,
1348
1349/* 0x70 */
1350 UFMT_POINTER, UFMT_EMPTY, UFMT_EMPTY, UFMT_STRING,
1351 UFMT_EMPTY, UFMT_UINT, UFMT_EMPTY, UFMT_EMPTY,
1352 UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1353 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
1354};
1355
1356U_CFUNC int32_t
1357u_scanf_parse(UFILE *f,
1358 const UChar *patternSpecification,
1359 va_list ap)
1360{
1361 const UChar *alias;
1362 int32_t count, converted, argConsumed, cpConsumed;
1363 uint16_t handlerNum;
1364
1365 ufmt_args args;
1366 u_scanf_spec spec;
1367 ufmt_type_info info;
1368 u_scanf_handler handler;
1369
1370 /* alias the pattern */
1371 alias = patternSpecification;
1372
1373 /* haven't converted anything yet */
1374 argConsumed = 0;
1375 converted = 0;
1376 cpConsumed = 0;
1377
1378 /* iterate through the pattern */
1379 for(;;) {
1380
1381 /* match any characters up to the next '%' */
1382 while(*alias != UP_PERCENT && *alias != 0x0000 && u_fgetc(f) == *alias) {
1383 alias++;
1384 }
1385
1386 /* if we aren't at a '%', or if we're at end of string, break*/
1387 if(*alias != UP_PERCENT || *alias == 0x0000)
1388 break;
1389
1390 /* parse the specifier */
1391 count = u_scanf_parse_spec(alias, &spec);
1392
1393 /* update the pointer in pattern */
1394 alias += count;
1395
1396 handlerNum = (uint16_t)(spec.fInfo.fSpec - USCANF_BASE_FMT_HANDLERS);
1397 if (handlerNum < USCANF_NUM_FMT_HANDLERS) {
1398 /* skip the argument, if necessary */
1399 /* query the info function for argument information */
1400 info = g_u_scanf_infos[ handlerNum ].info;
1401 if (info != ufmt_count && u_feof(f)) {
1402 break;
1403 }
1404 else if(spec.fInfo.fSkipArg) {
1405 args.ptrValue = NULL;
1406 }
1407 else {
1408 switch(info) {
1409 case ufmt_count:
1410 /* set the spec's width to the # of items converted */
1411 spec.fInfo.fWidth = cpConsumed;
Jungshik Shin5feb9ad2016-10-21 12:52:48 -07001412 U_FALLTHROUGH;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001413 case ufmt_char:
1414 case ufmt_uchar:
1415 case ufmt_int:
1416 case ufmt_string:
1417 case ufmt_ustring:
1418 case ufmt_pointer:
1419 case ufmt_float:
1420 case ufmt_double:
1421 args.ptrValue = va_arg(ap, void*);
1422 break;
1423
1424 default:
1425 /* else args is ignored */
1426 args.ptrValue = NULL;
1427 break;
1428 }
1429 }
1430
1431 /* call the handler function */
1432 handler = g_u_scanf_infos[ handlerNum ].handler;
1433 if(handler != 0) {
1434
1435 /* reset count to 1 so that += for alias works. */
1436 count = 1;
1437
1438 cpConsumed += (*handler)(f, &spec.fInfo, &args, alias, &count, &argConsumed);
1439
1440 /* if the handler encountered an error condition, break */
1441 if(argConsumed < 0) {
1442 converted = -1;
1443 break;
1444 }
1445
1446 /* add to the # of items converted */
1447 converted += argConsumed;
1448
1449 /* update the pointer in pattern */
1450 alias += count-1;
1451 }
1452 /* else do nothing */
1453 }
1454 /* else do nothing */
1455
1456 /* just ignore unknown tags */
1457 }
1458
1459 /* return # of items converted */
1460 return converted;
1461}
1462
1463#endif /* #if !UCONFIG_NO_FORMATTING */