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