Index: icu46/source/io/uscanf_p.c |
=================================================================== |
--- icu46/source/io/uscanf_p.c (revision 0) |
+++ icu46/source/io/uscanf_p.c (revision 0) |
@@ -0,0 +1,1407 @@ |
+/* |
+******************************************************************************* |
+* |
+* Copyright (C) 1998-2010, International Business Machines |
+* Corporation and others. All Rights Reserved. |
+* |
+******************************************************************************* |
+* |
+* File uscnnf_p.c |
+* |
+* Modification History: |
+* |
+* Date Name Description |
+* 12/02/98 stephen Creation. |
+* 03/13/99 stephen Modified for new C API. |
+******************************************************************************* |
+*/ |
+ |
+#include "unicode/utypes.h" |
+ |
+#if !UCONFIG_NO_FORMATTING |
+ |
+#include "unicode/uchar.h" |
+#include "unicode/ustring.h" |
+#include "unicode/unum.h" |
+#include "unicode/udat.h" |
+#include "unicode/uset.h" |
+#include "uscanf.h" |
+#include "ufmt_cmn.h" |
+#include "ufile.h" |
+#include "locbund.h" |
+ |
+#include "cmemory.h" |
+#include "ustr_cnv.h" |
+ |
+/* flag characters for u_scanf */ |
+#define FLAG_ASTERISK 0x002A |
+#define FLAG_PAREN 0x0028 |
+ |
+#define ISFLAG(s) (s) == FLAG_ASTERISK || \ |
+ (s) == FLAG_PAREN |
+ |
+/* special characters for u_scanf */ |
+#define SPEC_DOLLARSIGN 0x0024 |
+ |
+/* unicode digits */ |
+#define DIGIT_ZERO 0x0030 |
+#define DIGIT_ONE 0x0031 |
+#define DIGIT_TWO 0x0032 |
+#define DIGIT_THREE 0x0033 |
+#define DIGIT_FOUR 0x0034 |
+#define DIGIT_FIVE 0x0035 |
+#define DIGIT_SIX 0x0036 |
+#define DIGIT_SEVEN 0x0037 |
+#define DIGIT_EIGHT 0x0038 |
+#define DIGIT_NINE 0x0039 |
+ |
+#define ISDIGIT(s) (s) == DIGIT_ZERO || \ |
+ (s) == DIGIT_ONE || \ |
+ (s) == DIGIT_TWO || \ |
+ (s) == DIGIT_THREE || \ |
+ (s) == DIGIT_FOUR || \ |
+ (s) == DIGIT_FIVE || \ |
+ (s) == DIGIT_SIX || \ |
+ (s) == DIGIT_SEVEN || \ |
+ (s) == DIGIT_EIGHT || \ |
+ (s) == DIGIT_NINE |
+ |
+/* u_scanf modifiers */ |
+#define MOD_H 0x0068 |
+#define MOD_LOWERL 0x006C |
+#define MOD_L 0x004C |
+ |
+#define ISMOD(s) (s) == MOD_H || \ |
+ (s) == MOD_LOWERL || \ |
+ (s) == MOD_L |
+ |
+/** |
+ * Struct encapsulating a single uscanf format specification. |
+ */ |
+typedef struct u_scanf_spec_info { |
+ int32_t fWidth; /* Width */ |
+ |
+ UChar fSpec; /* Format specification */ |
+ |
+ UChar fPadChar; /* Padding character */ |
+ |
+ UBool fSkipArg; /* TRUE if arg should be skipped */ |
+ UBool fIsLongDouble; /* L flag */ |
+ UBool fIsShort; /* h flag */ |
+ UBool fIsLong; /* l flag */ |
+ UBool fIsLongLong; /* ll flag */ |
+ UBool fIsString; /* TRUE if this is a NULL-terminated string. */ |
+} u_scanf_spec_info; |
+ |
+ |
+/** |
+ * Struct encapsulating a single u_scanf format specification. |
+ */ |
+typedef struct u_scanf_spec { |
+ u_scanf_spec_info fInfo; /* Information on this spec */ |
+ int32_t fArgPos; /* Position of data in arg list */ |
+} u_scanf_spec; |
+ |
+/** |
+ * Parse a single u_scanf format specifier in Unicode. |
+ * @param fmt A pointer to a '%' character in a u_scanf format specification. |
+ * @param spec A pointer to a <TT>u_scanf_spec</TT> to receive the parsed |
+ * format specifier. |
+ * @return The number of characters contained in this specifier. |
+ */ |
+static int32_t |
+u_scanf_parse_spec (const UChar *fmt, |
+ u_scanf_spec *spec) |
+{ |
+ const UChar *s = fmt; |
+ const UChar *backup; |
+ u_scanf_spec_info *info = &(spec->fInfo); |
+ |
+ /* initialize spec to default values */ |
+ spec->fArgPos = -1; |
+ |
+ info->fWidth = -1; |
+ info->fSpec = 0x0000; |
+ info->fPadChar = 0x0020; |
+ info->fSkipArg = FALSE; |
+ info->fIsLongDouble = FALSE; |
+ info->fIsShort = FALSE; |
+ info->fIsLong = FALSE; |
+ info->fIsLongLong = FALSE; |
+ info->fIsString = TRUE; |
+ |
+ |
+ /* skip over the initial '%' */ |
+ s++; |
+ |
+ /* Check for positional argument */ |
+ if(ISDIGIT(*s)) { |
+ |
+ /* Save the current position */ |
+ backup = s; |
+ |
+ /* handle positional parameters */ |
+ if(ISDIGIT(*s)) { |
+ spec->fArgPos = (int) (*s++ - DIGIT_ZERO); |
+ |
+ while(ISDIGIT(*s)) { |
+ spec->fArgPos *= 10; |
+ spec->fArgPos += (int) (*s++ - DIGIT_ZERO); |
+ } |
+ } |
+ |
+ /* if there is no '$', don't read anything */ |
+ if(*s != SPEC_DOLLARSIGN) { |
+ spec->fArgPos = -1; |
+ s = backup; |
+ } |
+ /* munge the '$' */ |
+ else |
+ s++; |
+ } |
+ |
+ /* Get any format flags */ |
+ while(ISFLAG(*s)) { |
+ switch(*s++) { |
+ |
+ /* skip argument */ |
+ case FLAG_ASTERISK: |
+ info->fSkipArg = TRUE; |
+ break; |
+ |
+ /* pad character specified */ |
+ case FLAG_PAREN: |
+ |
+ /* first four characters are hex values for pad char */ |
+ info->fPadChar = (UChar)ufmt_digitvalue(*s++); |
+ info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++)); |
+ info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++)); |
+ info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++)); |
+ |
+ /* final character is ignored */ |
+ s++; |
+ |
+ break; |
+ } |
+ } |
+ |
+ /* Get the width */ |
+ if(ISDIGIT(*s)){ |
+ info->fWidth = (int) (*s++ - DIGIT_ZERO); |
+ |
+ while(ISDIGIT(*s)) { |
+ info->fWidth *= 10; |
+ info->fWidth += (int) (*s++ - DIGIT_ZERO); |
+ } |
+ } |
+ |
+ /* Get any modifiers */ |
+ if(ISMOD(*s)) { |
+ switch(*s++) { |
+ |
+ /* short */ |
+ case MOD_H: |
+ info->fIsShort = TRUE; |
+ break; |
+ |
+ /* long or long long */ |
+ case MOD_LOWERL: |
+ if(*s == MOD_LOWERL) { |
+ info->fIsLongLong = TRUE; |
+ /* skip over the next 'l' */ |
+ s++; |
+ } |
+ else |
+ info->fIsLong = TRUE; |
+ break; |
+ |
+ /* long double */ |
+ case MOD_L: |
+ info->fIsLongDouble = TRUE; |
+ break; |
+ } |
+ } |
+ |
+ /* finally, get the specifier letter */ |
+ info->fSpec = *s++; |
+ |
+ /* return # of characters in this specifier */ |
+ return (int32_t)(s - fmt); |
+} |
+ |
+#define UP_PERCENT 0x0025 |
+ |
+ |
+/* ANSI style formatting */ |
+/* Use US-ASCII characters only for formatting */ |
+ |
+/* % */ |
+#define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_scanf_simple_percent_handler} |
+/* s */ |
+#define UFMT_STRING {ufmt_string, u_scanf_string_handler} |
+/* c */ |
+#define UFMT_CHAR {ufmt_string, u_scanf_char_handler} |
+/* d, i */ |
+#define UFMT_INT {ufmt_int, u_scanf_integer_handler} |
+/* u */ |
+#define UFMT_UINT {ufmt_int, u_scanf_uinteger_handler} |
+/* o */ |
+#define UFMT_OCTAL {ufmt_int, u_scanf_octal_handler} |
+/* x, X */ |
+#define UFMT_HEX {ufmt_int, u_scanf_hex_handler} |
+/* f */ |
+#define UFMT_DOUBLE {ufmt_double, u_scanf_double_handler} |
+/* e, E */ |
+#define UFMT_SCIENTIFIC {ufmt_double, u_scanf_scientific_handler} |
+/* g, G */ |
+#define UFMT_SCIDBL {ufmt_double, u_scanf_scidbl_handler} |
+/* n */ |
+#define UFMT_COUNT {ufmt_count, u_scanf_count_handler} |
+/* [ */ |
+#define UFMT_SCANSET {ufmt_string, u_scanf_scanset_handler} |
+ |
+/* non-ANSI extensions */ |
+/* Use US-ASCII characters only for formatting */ |
+ |
+/* p */ |
+#define UFMT_POINTER {ufmt_pointer, u_scanf_pointer_handler} |
+/* V */ |
+#define UFMT_SPELLOUT {ufmt_double, u_scanf_spellout_handler} |
+/* P */ |
+#define UFMT_PERCENT {ufmt_double, u_scanf_percent_handler} |
+/* C K is old format */ |
+#define UFMT_UCHAR {ufmt_uchar, u_scanf_uchar_handler} |
+/* S U is old format */ |
+#define UFMT_USTRING {ufmt_ustring, u_scanf_ustring_handler} |
+ |
+ |
+#define UFMT_EMPTY {ufmt_empty, NULL} |
+ |
+/** |
+ * A u_scanf handler function. |
+ * A u_scanf handler is responsible for handling a single u_scanf |
+ * format specification, for example 'd' or 's'. |
+ * @param stream The UFILE to which to write output. |
+ * @param info A pointer to a <TT>u_scanf_spec_info</TT> struct containing |
+ * information on the format specification. |
+ * @param args A pointer to the argument data |
+ * @param fmt A pointer to the first character in the format string |
+ * following the spec. |
+ * @param fmtConsumed On output, set to the number of characters consumed |
+ * in <TT>fmt</TT>. Do nothing, if the argument isn't variable width. |
+ * @param argConverted The number of arguments converted and assigned, or -1 if an |
+ * error occurred. |
+ * @return The number of code points consumed during reading. |
+ */ |
+typedef int32_t (*u_scanf_handler) (UFILE *stream, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted); |
+ |
+typedef struct u_scanf_info { |
+ ufmt_type_info info; |
+ u_scanf_handler handler; |
+} u_scanf_info; |
+ |
+#define USCANF_NUM_FMT_HANDLERS 108 |
+#define USCANF_SYMBOL_BUFFER_SIZE 8 |
+ |
+/* We do not use handlers for 0-0x1f */ |
+#define USCANF_BASE_FMT_HANDLERS 0x20 |
+ |
+ |
+static int32_t |
+u_scanf_skip_leading_ws(UFILE *input, |
+ UChar pad) |
+{ |
+ UChar c; |
+ int32_t count = 0; |
+ UBool isNotEOF; |
+ |
+ /* skip all leading ws in the input */ |
+ while( (isNotEOF = ufile_getch(input, &c)) && (c == pad || u_isWhitespace(c)) ) |
+ { |
+ count++; |
+ } |
+ |
+ /* put the final character back on the input */ |
+ if(isNotEOF) |
+ u_fungetc(c, input); |
+ |
+ return count; |
+} |
+ |
+/* TODO: Is always skipping the prefix symbol as a positive sign a good idea in all locales? */ |
+static int32_t |
+u_scanf_skip_leading_positive_sign(UFILE *input, |
+ UNumberFormat *format, |
+ UErrorCode *status) |
+{ |
+ UChar c; |
+ int32_t count = 0; |
+ UBool isNotEOF; |
+ UChar plusSymbol[USCANF_SYMBOL_BUFFER_SIZE]; |
+ int32_t symbolLen; |
+ UErrorCode localStatus = U_ZERO_ERROR; |
+ |
+ if (U_SUCCESS(*status)) { |
+ symbolLen = unum_getSymbol(format, |
+ UNUM_PLUS_SIGN_SYMBOL, |
+ plusSymbol, |
+ sizeof(plusSymbol)/sizeof(*plusSymbol), |
+ &localStatus); |
+ |
+ if (U_SUCCESS(localStatus)) { |
+ /* skip all leading ws in the input */ |
+ while( (isNotEOF = ufile_getch(input, &c)) && (count < symbolLen && c == plusSymbol[count]) ) |
+ { |
+ count++; |
+ } |
+ |
+ /* put the final character back on the input */ |
+ if(isNotEOF) { |
+ u_fungetc(c, input); |
+ } |
+ } |
+ } |
+ |
+ return count; |
+} |
+ |
+static int32_t |
+u_scanf_simple_percent_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ /* make sure the next character in the input is a percent */ |
+ *argConverted = 0; |
+ if(u_fgetc(input) != 0x0025) { |
+ *argConverted = -1; |
+ } |
+ return 1; |
+} |
+ |
+static int32_t |
+u_scanf_count_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ /* in the special case of count, the u_scanf_spec_info's width */ |
+ /* will contain the # of items converted thus far */ |
+ if (!info->fSkipArg) { |
+ if (info->fIsShort) |
+ *(int16_t*)(args[0].ptrValue) = (int16_t)(UINT16_MAX & info->fWidth); |
+ else if (info->fIsLongLong) |
+ *(int64_t*)(args[0].ptrValue) = info->fWidth; |
+ else |
+ *(int32_t*)(args[0].ptrValue) = (int32_t)(UINT32_MAX & info->fWidth); |
+ } |
+ *argConverted = 0; |
+ |
+ /* we converted 0 args */ |
+ return 0; |
+} |
+ |
+static int32_t |
+u_scanf_double_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ int32_t len; |
+ double num; |
+ UNumberFormat *format; |
+ int32_t parsePos = 0; |
+ int32_t skipped; |
+ UErrorCode status = U_ZERO_ERROR; |
+ |
+ |
+ /* skip all ws in the input */ |
+ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); |
+ |
+ /* fill the input's internal buffer */ |
+ ufile_fill_uchar_buffer(input); |
+ |
+ /* determine the size of the input's buffer */ |
+ len = (int32_t)(input->str.fLimit - input->str.fPos); |
+ |
+ /* truncate to the width, if specified */ |
+ if(info->fWidth != -1) |
+ len = ufmt_min(len, info->fWidth); |
+ |
+ /* get the formatter */ |
+ format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL); |
+ |
+ /* handle error */ |
+ if(format == 0) |
+ return 0; |
+ |
+ /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */ |
+ skipped += u_scanf_skip_leading_positive_sign(input, format, &status); |
+ |
+ /* parse the number */ |
+ num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status); |
+ |
+ if (!info->fSkipArg) { |
+ if (info->fIsLong) |
+ *(double*)(args[0].ptrValue) = num; |
+ else if (info->fIsLongDouble) |
+ *(long double*)(args[0].ptrValue) = num; |
+ else |
+ *(float*)(args[0].ptrValue) = (float)num; |
+ } |
+ |
+ /* mask off any necessary bits */ |
+ /* if(! info->fIsLong_double) |
+ num &= DBL_MAX;*/ |
+ |
+ /* update the input's position to reflect consumed data */ |
+ input->str.fPos += parsePos; |
+ |
+ /* we converted 1 arg */ |
+ *argConverted = !info->fSkipArg; |
+ return parsePos + skipped; |
+} |
+ |
+#define UPRINTF_SYMBOL_BUFFER_SIZE 8 |
+ |
+static int32_t |
+u_scanf_scientific_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ int32_t len; |
+ double num; |
+ UNumberFormat *format; |
+ int32_t parsePos = 0; |
+ int32_t skipped; |
+ UErrorCode status = U_ZERO_ERROR; |
+ UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE]; |
+ int32_t srcLen, expLen; |
+ UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE]; |
+ |
+ |
+ /* skip all ws in the input */ |
+ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); |
+ |
+ /* fill the input's internal buffer */ |
+ ufile_fill_uchar_buffer(input); |
+ |
+ /* determine the size of the input's buffer */ |
+ len = (int32_t)(input->str.fLimit - input->str.fPos); |
+ |
+ /* truncate to the width, if specified */ |
+ if(info->fWidth != -1) |
+ len = ufmt_min(len, info->fWidth); |
+ |
+ /* get the formatter */ |
+ format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SCIENTIFIC); |
+ |
+ /* handle error */ |
+ if(format == 0) |
+ return 0; |
+ |
+ /* set the appropriate flags on the formatter */ |
+ |
+ srcLen = unum_getSymbol(format, |
+ UNUM_EXPONENTIAL_SYMBOL, |
+ srcExpBuf, |
+ sizeof(srcExpBuf), |
+ &status); |
+ |
+ /* Upper/lower case the e */ |
+ if (info->fSpec == (UChar)0x65 /* e */) { |
+ expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf), |
+ srcExpBuf, srcLen, |
+ input->str.fBundle.fLocale, |
+ &status); |
+ } |
+ else { |
+ expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf), |
+ srcExpBuf, srcLen, |
+ input->str.fBundle.fLocale, |
+ &status); |
+ } |
+ |
+ unum_setSymbol(format, |
+ UNUM_EXPONENTIAL_SYMBOL, |
+ expBuf, |
+ expLen, |
+ &status); |
+ |
+ |
+ |
+ |
+ /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */ |
+ skipped += u_scanf_skip_leading_positive_sign(input, format, &status); |
+ |
+ /* parse the number */ |
+ num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status); |
+ |
+ if (!info->fSkipArg) { |
+ if (info->fIsLong) |
+ *(double*)(args[0].ptrValue) = num; |
+ else if (info->fIsLongDouble) |
+ *(long double*)(args[0].ptrValue) = num; |
+ else |
+ *(float*)(args[0].ptrValue) = (float)num; |
+ } |
+ |
+ /* mask off any necessary bits */ |
+ /* if(! info->fIsLong_double) |
+ num &= DBL_MAX;*/ |
+ |
+ /* update the input's position to reflect consumed data */ |
+ input->str.fPos += parsePos; |
+ |
+ /* we converted 1 arg */ |
+ *argConverted = !info->fSkipArg; |
+ return parsePos + skipped; |
+} |
+ |
+static int32_t |
+u_scanf_scidbl_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ int32_t len; |
+ double num; |
+ UNumberFormat *scientificFormat, *genericFormat; |
+ /*int32_t scientificResult, genericResult;*/ |
+ double scientificResult, genericResult; |
+ int32_t scientificParsePos = 0, genericParsePos = 0, parsePos = 0; |
+ int32_t skipped; |
+ UErrorCode scientificStatus = U_ZERO_ERROR; |
+ UErrorCode genericStatus = U_ZERO_ERROR; |
+ |
+ |
+ /* since we can't determine by scanning the characters whether */ |
+ /* a number was formatted in the 'f' or 'g' styles, parse the */ |
+ /* string with both formatters, and assume whichever one */ |
+ /* parsed the most is the correct formatter to use */ |
+ |
+ |
+ /* skip all ws in the input */ |
+ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); |
+ |
+ /* fill the input's internal buffer */ |
+ ufile_fill_uchar_buffer(input); |
+ |
+ /* determine the size of the input's buffer */ |
+ len = (int32_t)(input->str.fLimit - input->str.fPos); |
+ |
+ /* truncate to the width, if specified */ |
+ if(info->fWidth != -1) |
+ len = ufmt_min(len, info->fWidth); |
+ |
+ /* get the formatters */ |
+ scientificFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SCIENTIFIC); |
+ genericFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL); |
+ |
+ /* handle error */ |
+ if(scientificFormat == 0 || genericFormat == 0) |
+ return 0; |
+ |
+ /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */ |
+ skipped += u_scanf_skip_leading_positive_sign(input, genericFormat, &genericStatus); |
+ |
+ /* parse the number using each format*/ |
+ |
+ scientificResult = unum_parseDouble(scientificFormat, input->str.fPos, len, |
+ &scientificParsePos, &scientificStatus); |
+ |
+ genericResult = unum_parseDouble(genericFormat, input->str.fPos, len, |
+ &genericParsePos, &genericStatus); |
+ |
+ /* determine which parse made it farther */ |
+ if(scientificParsePos > genericParsePos) { |
+ /* stash the result in num */ |
+ num = scientificResult; |
+ /* update the input's position to reflect consumed data */ |
+ parsePos += scientificParsePos; |
+ } |
+ else { |
+ /* stash the result in num */ |
+ num = genericResult; |
+ /* update the input's position to reflect consumed data */ |
+ parsePos += genericParsePos; |
+ } |
+ input->str.fPos += parsePos; |
+ |
+ if (!info->fSkipArg) { |
+ if (info->fIsLong) |
+ *(double*)(args[0].ptrValue) = num; |
+ else if (info->fIsLongDouble) |
+ *(long double*)(args[0].ptrValue) = num; |
+ else |
+ *(float*)(args[0].ptrValue) = (float)num; |
+ } |
+ |
+ /* mask off any necessary bits */ |
+ /* if(! info->fIsLong_double) |
+ num &= DBL_MAX;*/ |
+ |
+ /* we converted 1 arg */ |
+ *argConverted = !info->fSkipArg; |
+ return parsePos + skipped; |
+} |
+ |
+static int32_t |
+u_scanf_integer_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ int32_t len; |
+ void *num = (void*) (args[0].ptrValue); |
+ UNumberFormat *format; |
+ int32_t parsePos = 0; |
+ int32_t skipped; |
+ UErrorCode status = U_ZERO_ERROR; |
+ int64_t result; |
+ |
+ |
+ /* skip all ws in the input */ |
+ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); |
+ |
+ /* fill the input's internal buffer */ |
+ ufile_fill_uchar_buffer(input); |
+ |
+ /* determine the size of the input's buffer */ |
+ len = (int32_t)(input->str.fLimit - input->str.fPos); |
+ |
+ /* truncate to the width, if specified */ |
+ if(info->fWidth != -1) |
+ len = ufmt_min(len, info->fWidth); |
+ |
+ /* get the formatter */ |
+ format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL); |
+ |
+ /* handle error */ |
+ if(format == 0) |
+ return 0; |
+ |
+ /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */ |
+ skipped += u_scanf_skip_leading_positive_sign(input, format, &status); |
+ |
+ /* parse the number */ |
+ result = unum_parseInt64(format, input->str.fPos, len, &parsePos, &status); |
+ |
+ /* mask off any necessary bits */ |
+ if (!info->fSkipArg) { |
+ if (info->fIsShort) |
+ *(int16_t*)num = (int16_t)(UINT16_MAX & result); |
+ else if (info->fIsLongLong) |
+ *(int64_t*)num = result; |
+ else |
+ *(int32_t*)num = (int32_t)(UINT32_MAX & result); |
+ } |
+ |
+ /* update the input's position to reflect consumed data */ |
+ input->str.fPos += parsePos; |
+ |
+ /* we converted 1 arg */ |
+ *argConverted = !info->fSkipArg; |
+ return parsePos + skipped; |
+} |
+ |
+static int32_t |
+u_scanf_uinteger_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ /* TODO Fix this when Numberformat handles uint64_t */ |
+ return u_scanf_integer_handler(input, info, args, fmt, fmtConsumed, argConverted); |
+} |
+ |
+static int32_t |
+u_scanf_percent_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ int32_t len; |
+ double num; |
+ UNumberFormat *format; |
+ int32_t parsePos = 0; |
+ int32_t skipped; |
+ UErrorCode status = U_ZERO_ERROR; |
+ |
+ |
+ /* skip all ws in the input */ |
+ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); |
+ |
+ /* fill the input's internal buffer */ |
+ ufile_fill_uchar_buffer(input); |
+ |
+ /* determine the size of the input's buffer */ |
+ len = (int32_t)(input->str.fLimit - input->str.fPos); |
+ |
+ /* truncate to the width, if specified */ |
+ if(info->fWidth != -1) |
+ len = ufmt_min(len, info->fWidth); |
+ |
+ /* get the formatter */ |
+ format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_PERCENT); |
+ |
+ /* handle error */ |
+ if(format == 0) |
+ return 0; |
+ |
+ /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */ |
+ skipped += u_scanf_skip_leading_positive_sign(input, format, &status); |
+ |
+ /* parse the number */ |
+ num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status); |
+ |
+ if (!info->fSkipArg) { |
+ *(double*)(args[0].ptrValue) = num; |
+ } |
+ |
+ /* mask off any necessary bits */ |
+ /* if(! info->fIsLong_double) |
+ num &= DBL_MAX;*/ |
+ |
+ /* update the input's position to reflect consumed data */ |
+ input->str.fPos += parsePos; |
+ |
+ /* we converted 1 arg */ |
+ *argConverted = !info->fSkipArg; |
+ return parsePos; |
+} |
+ |
+static int32_t |
+u_scanf_string_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ const UChar *source; |
+ UConverter *conv; |
+ char *arg = (char*)(args[0].ptrValue); |
+ char *alias = arg; |
+ char *limit; |
+ UErrorCode status = U_ZERO_ERROR; |
+ int32_t count; |
+ int32_t skipped = 0; |
+ UChar c; |
+ UBool isNotEOF = FALSE; |
+ |
+ /* skip all ws in the input */ |
+ if (info->fIsString) { |
+ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); |
+ } |
+ |
+ /* get the string one character at a time, truncating to the width */ |
+ count = 0; |
+ |
+ /* open the default converter */ |
+ conv = u_getDefaultConverter(&status); |
+ |
+ if(U_FAILURE(status)) |
+ return -1; |
+ |
+ while( (info->fWidth == -1 || count < info->fWidth) |
+ && (isNotEOF = ufile_getch(input, &c)) |
+ && (!info->fIsString || (c != info->fPadChar && !u_isWhitespace(c)))) |
+ { |
+ |
+ if (!info->fSkipArg) { |
+ /* put the character from the input onto the target */ |
+ source = &c; |
+ /* Since we do this one character at a time, do it this way. */ |
+ if (info->fWidth > 0) { |
+ limit = alias + info->fWidth - count; |
+ } |
+ else { |
+ limit = alias + ucnv_getMaxCharSize(conv); |
+ } |
+ |
+ /* convert the character to the default codepage */ |
+ ucnv_fromUnicode(conv, &alias, limit, &source, source + 1, |
+ NULL, TRUE, &status); |
+ |
+ if(U_FAILURE(status)) { |
+ /* clean up */ |
+ u_releaseDefaultConverter(conv); |
+ return -1; |
+ } |
+ } |
+ |
+ /* increment the count */ |
+ ++count; |
+ } |
+ |
+ /* put the final character we read back on the input */ |
+ if (!info->fSkipArg) { |
+ if ((info->fWidth == -1 || count < info->fWidth) && isNotEOF) |
+ u_fungetc(c, input); |
+ |
+ /* add the terminator */ |
+ if (info->fIsString) { |
+ *alias = 0x00; |
+ } |
+ } |
+ |
+ /* clean up */ |
+ u_releaseDefaultConverter(conv); |
+ |
+ /* we converted 1 arg */ |
+ *argConverted = !info->fSkipArg; |
+ return count + skipped; |
+} |
+ |
+static int32_t |
+u_scanf_char_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ if (info->fWidth < 0) { |
+ info->fWidth = 1; |
+ } |
+ info->fIsString = FALSE; |
+ return u_scanf_string_handler(input, info, args, fmt, fmtConsumed, argConverted); |
+} |
+ |
+static int32_t |
+u_scanf_ustring_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ UChar *arg = (UChar*)(args[0].ptrValue); |
+ UChar *alias = arg; |
+ int32_t count; |
+ int32_t skipped = 0; |
+ UChar c; |
+ UBool isNotEOF = FALSE; |
+ |
+ /* skip all ws in the input */ |
+ if (info->fIsString) { |
+ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); |
+ } |
+ |
+ /* get the string one character at a time, truncating to the width */ |
+ count = 0; |
+ |
+ while( (info->fWidth == -1 || count < info->fWidth) |
+ && (isNotEOF = ufile_getch(input, &c)) |
+ && (!info->fIsString || (c != info->fPadChar && !u_isWhitespace(c)))) |
+ { |
+ |
+ /* put the character from the input onto the target */ |
+ if (!info->fSkipArg) { |
+ *alias++ = c; |
+ } |
+ |
+ /* increment the count */ |
+ ++count; |
+ } |
+ |
+ /* put the final character we read back on the input */ |
+ if (!info->fSkipArg) { |
+ if((info->fWidth == -1 || count < info->fWidth) && isNotEOF) { |
+ u_fungetc(c, input); |
+ } |
+ |
+ /* add the terminator */ |
+ if (info->fIsString) { |
+ *alias = 0x0000; |
+ } |
+ } |
+ |
+ /* we converted 1 arg */ |
+ *argConverted = !info->fSkipArg; |
+ return count + skipped; |
+} |
+ |
+static int32_t |
+u_scanf_uchar_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ if (info->fWidth < 0) { |
+ info->fWidth = 1; |
+ } |
+ info->fIsString = FALSE; |
+ return u_scanf_ustring_handler(input, info, args, fmt, fmtConsumed, argConverted); |
+} |
+ |
+static int32_t |
+u_scanf_spellout_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ int32_t len; |
+ double num; |
+ UNumberFormat *format; |
+ int32_t parsePos = 0; |
+ int32_t skipped; |
+ UErrorCode status = U_ZERO_ERROR; |
+ |
+ |
+ /* skip all ws in the input */ |
+ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); |
+ |
+ /* fill the input's internal buffer */ |
+ ufile_fill_uchar_buffer(input); |
+ |
+ /* determine the size of the input's buffer */ |
+ len = (int32_t)(input->str.fLimit - input->str.fPos); |
+ |
+ /* truncate to the width, if specified */ |
+ if(info->fWidth != -1) |
+ len = ufmt_min(len, info->fWidth); |
+ |
+ /* get the formatter */ |
+ format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SPELLOUT); |
+ |
+ /* handle error */ |
+ if(format == 0) |
+ return 0; |
+ |
+ /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */ |
+ /* This is not applicable to RBNF. */ |
+ /*skipped += u_scanf_skip_leading_positive_sign(input, format, &status);*/ |
+ |
+ /* parse the number */ |
+ num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status); |
+ |
+ if (!info->fSkipArg) { |
+ *(double*)(args[0].ptrValue) = num; |
+ } |
+ |
+ /* mask off any necessary bits */ |
+ /* if(! info->fIsLong_double) |
+ num &= DBL_MAX;*/ |
+ |
+ /* update the input's position to reflect consumed data */ |
+ input->str.fPos += parsePos; |
+ |
+ /* we converted 1 arg */ |
+ *argConverted = !info->fSkipArg; |
+ return parsePos + skipped; |
+} |
+ |
+static int32_t |
+u_scanf_hex_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ int32_t len; |
+ int32_t skipped; |
+ void *num = (void*) (args[0].ptrValue); |
+ int64_t result; |
+ |
+ /* skip all ws in the input */ |
+ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); |
+ |
+ /* fill the input's internal buffer */ |
+ ufile_fill_uchar_buffer(input); |
+ |
+ /* determine the size of the input's buffer */ |
+ len = (int32_t)(input->str.fLimit - input->str.fPos); |
+ |
+ /* truncate to the width, if specified */ |
+ if(info->fWidth != -1) |
+ len = ufmt_min(len, info->fWidth); |
+ |
+ /* check for alternate form */ |
+ if( *(input->str.fPos) == 0x0030 && |
+ (*(input->str.fPos + 1) == 0x0078 || *(input->str.fPos + 1) == 0x0058) ) { |
+ |
+ /* skip the '0' and 'x' or 'X' if present */ |
+ input->str.fPos += 2; |
+ len -= 2; |
+ } |
+ |
+ /* parse the number */ |
+ result = ufmt_uto64(input->str.fPos, &len, 16); |
+ |
+ /* update the input's position to reflect consumed data */ |
+ input->str.fPos += len; |
+ |
+ /* mask off any necessary bits */ |
+ if (!info->fSkipArg) { |
+ if (info->fIsShort) |
+ *(int16_t*)num = (int16_t)(UINT16_MAX & result); |
+ else if (info->fIsLongLong) |
+ *(int64_t*)num = result; |
+ else |
+ *(int32_t*)num = (int32_t)(UINT32_MAX & result); |
+ } |
+ |
+ /* we converted 1 arg */ |
+ *argConverted = !info->fSkipArg; |
+ return len + skipped; |
+} |
+ |
+static int32_t |
+u_scanf_octal_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ int32_t len; |
+ int32_t skipped; |
+ void *num = (void*) (args[0].ptrValue); |
+ int64_t result; |
+ |
+ /* skip all ws in the input */ |
+ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); |
+ |
+ /* fill the input's internal buffer */ |
+ ufile_fill_uchar_buffer(input); |
+ |
+ /* determine the size of the input's buffer */ |
+ len = (int32_t)(input->str.fLimit - input->str.fPos); |
+ |
+ /* truncate to the width, if specified */ |
+ if(info->fWidth != -1) |
+ len = ufmt_min(len, info->fWidth); |
+ |
+ /* parse the number */ |
+ result = ufmt_uto64(input->str.fPos, &len, 8); |
+ |
+ /* update the input's position to reflect consumed data */ |
+ input->str.fPos += len; |
+ |
+ /* mask off any necessary bits */ |
+ if (!info->fSkipArg) { |
+ if (info->fIsShort) |
+ *(int16_t*)num = (int16_t)(UINT16_MAX & result); |
+ else if (info->fIsLongLong) |
+ *(int64_t*)num = result; |
+ else |
+ *(int32_t*)num = (int32_t)(UINT32_MAX & result); |
+ } |
+ |
+ /* we converted 1 arg */ |
+ *argConverted = !info->fSkipArg; |
+ return len + skipped; |
+} |
+ |
+static int32_t |
+u_scanf_pointer_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ int32_t len; |
+ int32_t skipped; |
+ void *result; |
+ void **p = (void**)(args[0].ptrValue); |
+ |
+ |
+ /* skip all ws in the input */ |
+ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); |
+ |
+ /* fill the input's internal buffer */ |
+ ufile_fill_uchar_buffer(input); |
+ |
+ /* determine the size of the input's buffer */ |
+ len = (int32_t)(input->str.fLimit - input->str.fPos); |
+ |
+ /* truncate to the width, if specified */ |
+ if(info->fWidth != -1) { |
+ len = ufmt_min(len, info->fWidth); |
+ } |
+ |
+ /* Make sure that we don't consume too much */ |
+ if (len > (int32_t)(sizeof(void*)*2)) { |
+ len = (int32_t)(sizeof(void*)*2); |
+ } |
+ |
+ /* parse the pointer - assign to temporary value */ |
+ result = ufmt_utop(input->str.fPos, &len); |
+ |
+ if (!info->fSkipArg) { |
+ *p = result; |
+ } |
+ |
+ /* update the input's position to reflect consumed data */ |
+ input->str.fPos += len; |
+ |
+ /* we converted 1 arg */ |
+ *argConverted = !info->fSkipArg; |
+ return len + skipped; |
+} |
+ |
+static int32_t |
+u_scanf_scanset_handler(UFILE *input, |
+ u_scanf_spec_info *info, |
+ ufmt_args *args, |
+ const UChar *fmt, |
+ int32_t *fmtConsumed, |
+ int32_t *argConverted) |
+{ |
+ USet *scanset; |
+ UErrorCode status = U_ZERO_ERROR; |
+ int32_t chLeft = INT32_MAX; |
+ UChar32 c; |
+ UChar *alias = (UChar*) (args[0].ptrValue); |
+ UBool isNotEOF = FALSE; |
+ UBool readCharacter = FALSE; |
+ |
+ /* Create an empty set */ |
+ scanset = uset_open(0, -1); |
+ |
+ /* Back up one to get the [ */ |
+ fmt--; |
+ |
+ /* truncate to the width, if specified and alias the target */ |
+ if(info->fWidth >= 0) { |
+ chLeft = info->fWidth; |
+ } |
+ |
+ /* parse the scanset from the fmt string */ |
+ *fmtConsumed = uset_applyPattern(scanset, fmt, -1, 0, &status); |
+ |
+ /* verify that the parse was successful */ |
+ if (U_SUCCESS(status)) { |
+ c=0; |
+ |
+ /* grab characters one at a time and make sure they are in the scanset */ |
+ while(chLeft > 0) { |
+ if ((isNotEOF = ufile_getch32(input, &c)) && uset_contains(scanset, c)) { |
+ readCharacter = TRUE; |
+ if (!info->fSkipArg) { |
+ int32_t idx = 0; |
+ UBool isError = FALSE; |
+ |
+ U16_APPEND(alias, idx, chLeft, c, isError); |
+ if (isError) { |
+ break; |
+ } |
+ alias += idx; |
+ } |
+ chLeft -= (1 + U_IS_SUPPLEMENTARY(c)); |
+ } |
+ else { |
+ /* if the character's not in the scanset, break out */ |
+ break; |
+ } |
+ } |
+ |
+ /* put the final character we read back on the input */ |
+ if(isNotEOF && chLeft > 0) { |
+ u_fungetc(c, input); |
+ } |
+ } |
+ |
+ uset_close(scanset); |
+ |
+ /* if we didn't match at least 1 character, fail */ |
+ if(!readCharacter) |
+ return -1; |
+ /* otherwise, add the terminator */ |
+ else if (!info->fSkipArg) { |
+ *alias = 0x00; |
+ } |
+ |
+ /* we converted 1 arg */ |
+ *argConverted = !info->fSkipArg; |
+ return (info->fWidth >= 0 ? info->fWidth : INT32_MAX) - chLeft; |
+} |
+ |
+/* Use US-ASCII characters only for formatting. Most codepages have |
+ characters 20-7F from Unicode. Using any other codepage specific |
+ characters will make it very difficult to format the string on |
+ non-Unicode machines */ |
+static const u_scanf_info g_u_scanf_infos[USCANF_NUM_FMT_HANDLERS] = { |
+/* 0x20 */ |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, |
+ UFMT_EMPTY, UFMT_SIMPLE_PERCENT,UFMT_EMPTY, UFMT_EMPTY, |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, |
+ |
+/* 0x30 */ |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, |
+ |
+/* 0x40 */ |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR, |
+ UFMT_EMPTY, UFMT_SCIENTIFIC, UFMT_EMPTY, UFMT_SCIDBL, |
+#ifdef U_USE_OBSOLETE_IO_FORMATTING |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR/*deprecated*/, |
+#else |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, |
+#endif |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, |
+ |
+/* 0x50 */ |
+ UFMT_PERCENT, UFMT_EMPTY, UFMT_EMPTY, UFMT_USTRING, |
+#ifdef U_USE_OBSOLETE_IO_FORMATTING |
+ UFMT_EMPTY, UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT, UFMT_EMPTY, |
+#else |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_SPELLOUT, UFMT_EMPTY, |
+#endif |
+ UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_SCANSET, |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, |
+ |
+/* 0x60 */ |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_CHAR, |
+ UFMT_INT, UFMT_SCIENTIFIC, UFMT_DOUBLE, UFMT_SCIDBL, |
+ UFMT_EMPTY, UFMT_INT, UFMT_EMPTY, UFMT_EMPTY, |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_COUNT, UFMT_OCTAL, |
+ |
+/* 0x70 */ |
+ UFMT_POINTER, UFMT_EMPTY, UFMT_EMPTY, UFMT_STRING, |
+ UFMT_EMPTY, UFMT_UINT, UFMT_EMPTY, UFMT_EMPTY, |
+ UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, |
+ UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, |
+}; |
+ |
+U_CFUNC int32_t |
+u_scanf_parse(UFILE *f, |
+ const UChar *patternSpecification, |
+ va_list ap) |
+{ |
+ const UChar *alias; |
+ int32_t count, converted, argConsumed, cpConsumed; |
+ uint16_t handlerNum; |
+ |
+ ufmt_args args; |
+ u_scanf_spec spec; |
+ ufmt_type_info info; |
+ u_scanf_handler handler; |
+ |
+ /* alias the pattern */ |
+ alias = patternSpecification; |
+ |
+ /* haven't converted anything yet */ |
+ argConsumed = 0; |
+ converted = 0; |
+ cpConsumed = 0; |
+ |
+ /* iterate through the pattern */ |
+ for(;;) { |
+ |
+ /* match any characters up to the next '%' */ |
+ while(*alias != UP_PERCENT && *alias != 0x0000 && u_fgetc(f) == *alias) { |
+ alias++; |
+ } |
+ |
+ /* if we aren't at a '%', or if we're at end of string, break*/ |
+ if(*alias != UP_PERCENT || *alias == 0x0000) |
+ break; |
+ |
+ /* parse the specifier */ |
+ count = u_scanf_parse_spec(alias, &spec); |
+ |
+ /* update the pointer in pattern */ |
+ alias += count; |
+ |
+ handlerNum = (uint16_t)(spec.fInfo.fSpec - USCANF_BASE_FMT_HANDLERS); |
+ if (handlerNum < USCANF_NUM_FMT_HANDLERS) { |
+ /* skip the argument, if necessary */ |
+ /* query the info function for argument information */ |
+ info = g_u_scanf_infos[ handlerNum ].info; |
+ if (info != ufmt_count && u_feof(f)) { |
+ break; |
+ } |
+ else if(spec.fInfo.fSkipArg) { |
+ args.ptrValue = NULL; |
+ } |
+ else { |
+ switch(info) { |
+ case ufmt_count: |
+ /* set the spec's width to the # of items converted */ |
+ spec.fInfo.fWidth = cpConsumed; |
+ /* fall through to next case */ |
+ case ufmt_char: |
+ case ufmt_uchar: |
+ case ufmt_int: |
+ case ufmt_string: |
+ case ufmt_ustring: |
+ case ufmt_pointer: |
+ case ufmt_float: |
+ case ufmt_double: |
+ args.ptrValue = va_arg(ap, void*); |
+ break; |
+ |
+ default: |
+ /* else args is ignored */ |
+ args.ptrValue = NULL; |
+ break; |
+ } |
+ } |
+ |
+ /* call the handler function */ |
+ handler = g_u_scanf_infos[ handlerNum ].handler; |
+ if(handler != 0) { |
+ |
+ /* reset count to 1 so that += for alias works. */ |
+ count = 1; |
+ |
+ cpConsumed += (*handler)(f, &spec.fInfo, &args, alias, &count, &argConsumed); |
+ |
+ /* if the handler encountered an error condition, break */ |
+ if(argConsumed < 0) { |
+ converted = -1; |
+ break; |
+ } |
+ |
+ /* add to the # of items converted */ |
+ converted += argConsumed; |
+ |
+ /* update the pointer in pattern */ |
+ alias += count-1; |
+ } |
+ /* else do nothing */ |
+ } |
+ /* else do nothing */ |
+ |
+ /* just ignore unknown tags */ |
+ } |
+ |
+ /* return # of items converted */ |
+ return converted; |
+} |
+ |
+#endif /* #if !UCONFIG_NO_FORMATTING */ |
Property changes on: icu46/source/io/uscanf_p.c |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |