/* ******************************************************************************* * * Copyright (C) 1998-1999, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* * * File uscanf.c * * Modification History: * * Date Name Description * 12/02/98 stephen Creation. * 03/13/99 stephen Modified for new C API. ******************************************************************************* */ #include "unicode/utypes.h" #include "unicode/uchar.h" #include "uscanf.h" #include "uscanf_p.h" #include "uscanset.h" #include "unicode/ustdio.h" #include "ufile.h" #include "unicode/ustring.h" #include "locbund.h" #include "umutex.h" #include "unicode/unum.h" #include "unicode/udat.h" #include #include #include #include static u_scanf_handler g_u_scanf_handlers [256]; static u_scanf_info g_u_scanf_infos [256]; static UBool g_u_scanf_inited = FALSE; int32_t u_fscanf( UFILE *f, const char *patternSpecification, ... ) { va_list ap; int32_t converted; va_start(ap, patternSpecification); converted = u_vfscanf(f, patternSpecification, ap); va_end(ap); return converted; } int32_t u_fscanf_u( UFILE *f, const UChar *patternSpecification, ... ) { va_list ap; int32_t converted; va_start(ap, patternSpecification); converted = u_vfscanf_u(f, patternSpecification, ap); va_end(ap); return converted; } int32_t u_vfscanf( UFILE *f, const char *patternSpecification, va_list ap) { int32_t converted; UChar *pattern; /* convert from the default codepage to Unicode */ pattern = ufmt_defaultCPToUnicode(patternSpecification, strlen(patternSpecification)); if(pattern == 0) { return 0; } /* do the work */ converted = u_vfscanf_u(f, pattern, ap); /* clean up */ free(pattern); return converted; } int32_t u_scanf_register_handler (UChar spec, u_scanf_info info, u_scanf_handler handler) { /* lock the cache */ umtx_lock(0); /* add to our list of function pointers */ g_u_scanf_infos[ (unsigned char) spec ] = info; g_u_scanf_handlers[ (unsigned char) spec ] = handler; /* unlock the cache */ umtx_unlock(0); return 0; } int32_t u_scanf_skip_leading_ws(UFILE *stream, UChar pad) { UChar c; int32_t count = 0; /* skip all leading ws in the stream */ while( ((c = u_fgetc(stream)) != 0xFFFF) && (c == pad || ufmt_isws(c)) ) ++count; /* put the final character back on the stream */ if(c != 0xFFFF) u_fungetc(c, stream); return count; } int32_t u_scanf_simple_percent_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* we don't need any arguments */ return 0; } int32_t u_scanf_simple_percent_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { /* make sure the next character in the stream is a percent */ if(u_fgetc(stream) != 0x0025) return -1; else return 0; } int32_t u_scanf_string_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type string */ argtypes[0] = ufmt_string; return 1; } int32_t u_scanf_string_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { UChar c; int32_t count; const UChar *source; UConverter *conv; UErrorCode status = U_ZERO_ERROR; char *arg = (char*)(args[0].ptrValue); char *alias = arg; char *limit; /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* get the string one character at a time, truncating to the width */ count = 0; /* open the default converter */ conv = ucnv_open(ucnv_getDefaultName(), &status); if(U_FAILURE(status)) return -1; /* since there is no real limit, just use a reasonable value */ limit = alias + 2048; while( ((c = u_fgetc(stream)) != 0xFFFF) && (c != info->fPadChar && ! ufmt_isws(c)) && (info->fWidth == -1 || count < info->fWidth) ) { /* put the character from the stream onto the target */ source = &c; /* convert the character to the default codepage */ ucnv_fromUnicode(conv, &alias, limit, &source, source + 1, NULL, TRUE, &status); if(U_FAILURE(status)) return -1; /* increment the count */ ++count; } /* put the final character we read back on the stream */ if(c != 0xFFFF) u_fungetc(c, stream); /* add the terminator */ *alias = 0x00; /* clean up */ ucnv_close(conv); /* we converted 1 arg */ return 1; } int32_t u_scanf_ustring_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type ustring */ argtypes[0] = ufmt_ustring; return 1; } int32_t u_scanf_ustring_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { UChar c; int32_t count; UChar *arg = (UChar*)(args[0].ptrValue); UChar *alias = arg; /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* get the string one character at a time, truncating to the width */ count = 0; while( ((c = u_fgetc(stream)) != 0xFFFF) && (c != info->fPadChar && ! ufmt_isws(c)) && (info->fWidth == -1 || count < info->fWidth) ) { /* put the character from the stream onto the target */ *alias++ = c; /* increment the count */ ++count; } /* put the final character we read back on the stream */ if(c != 0xFFFF) u_fungetc(c, stream); /* add the terminator */ *alias = 0x0000; /* we converted 1 arg */ return 1; } int32_t u_scanf_count_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type count */ argtypes[0] = ufmt_count; return 1; } int32_t u_scanf_count_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { int *converted = (int*)(args[0].ptrValue); /* in the special case of count, the u_scanf_spec_info's width */ /* will contain the # of items converted thus far */ *converted = info->fWidth; /* we converted 0 args */ return 0; } int32_t u_scanf_integer_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type int */ argtypes[0] = ufmt_int; return 1; } int32_t u_scanf_integer_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { int32_t len; long *num = (long*) (args[0].ptrValue); UNumberFormat *format; int32_t parsePos = 0; UErrorCode status = U_ZERO_ERROR; /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* fill the stream's internal buffer */ ufile_fill_uchar_buffer(stream); /* determine the size of the stream's buffer */ len = stream->fUCLimit - stream->fUCPos; /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* get the formatter */ format = u_locbund_getNumberFormat(stream->fBundle); /* handle error */ if(format == 0) return 0; /* parse the number */ *num = unum_parse(format, stream->fUCPos, len, &parsePos, &status); /* mask off any necessary bits */ if(info->fIsShort) *num &= SHRT_MAX; else if(! info->fIsLong || ! info->fIsLongLong) *num &= INT_MAX; /* update the stream's position to reflect consumed data */ stream->fUCPos += parsePos; /* we converted 1 arg */ return 1; } int32_t u_scanf_double_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type double */ argtypes[0] = ufmt_double; return 1; } int32_t u_scanf_double_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { int32_t len; double *num = (double*) (args[0].ptrValue); UNumberFormat *format; int32_t parsePos = 0; UErrorCode status = U_ZERO_ERROR; /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* fill the stream's internal buffer */ ufile_fill_uchar_buffer(stream); /* determine the size of the stream's buffer */ len = stream->fUCLimit - stream->fUCPos; /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* get the formatter */ format = u_locbund_getNumberFormat(stream->fBundle); /* handle error */ if(format == 0) return 0; /* parse the number */ *num = unum_parseDouble(format, stream->fUCPos, len, &parsePos, &status); /* mask off any necessary bits */ /* if(! info->fIsLong_double) num &= DBL_MAX;*/ /* update the stream's position to reflect consumed data */ stream->fUCPos += parsePos; /* we converted 1 arg */ return 1; } int32_t u_scanf_scientific_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type double */ argtypes[0] = ufmt_double; return 1; } int32_t u_scanf_scientific_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { int32_t len; double *num = (double*) (args[0].ptrValue); UNumberFormat *format; int32_t parsePos = 0; UErrorCode status = U_ZERO_ERROR; /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* fill the stream's internal buffer */ ufile_fill_uchar_buffer(stream); /* determine the size of the stream's buffer */ len = stream->fUCLimit - stream->fUCPos; /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* get the formatter */ format = u_locbund_getScientificFormat(stream->fBundle); /* handle error */ if(format == 0) return 0; /* parse the number */ *num = unum_parseDouble(format, stream->fUCPos, len, &parsePos, &status); /* mask off any necessary bits */ /* if(! info->fIsLong_double) num &= DBL_MAX;*/ /* update the stream's position to reflect consumed data */ stream->fUCPos += parsePos; /* we converted 1 arg */ return 1; } int32_t u_scanf_scidbl_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type double */ argtypes[0] = ufmt_double; return 1; } int32_t u_scanf_scidbl_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { int32_t len; double *num = (double*) (args[0].ptrValue); UNumberFormat *scientificFormat, *genericFormat; /*int32_t scientificResult, genericResult;*/ double scientificResult, genericResult; int32_t scientificParsePos = 0, genericParsePos = 0; UErrorCode scientificStatus = U_ZERO_ERROR; UErrorCode genericStatus = U_ZERO_ERROR; UBool useScientific; /* 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 stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* fill the stream's internal buffer */ ufile_fill_uchar_buffer(stream); /* determine the size of the stream's buffer */ len = stream->fUCLimit - stream->fUCPos; /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* get the formatters */ scientificFormat = u_locbund_getScientificFormat(stream->fBundle); genericFormat = u_locbund_getNumberFormat(stream->fBundle); /* handle error */ if(scientificFormat == 0 || genericFormat == 0) return 0; /* parse the number using each format*/ scientificResult = unum_parseDouble(scientificFormat, stream->fUCPos, len, &scientificParsePos, &scientificStatus); genericResult = unum_parseDouble(genericFormat, stream->fUCPos, len, &genericParsePos, &genericStatus); /* determine which parse made it farther */ useScientific = scientificParsePos > genericParsePos; /* stash the result in num */ *num = useScientific ? scientificResult : genericResult; /* mask off any necessary bits */ /* if(! info->fIsLong_double) num &= DBL_MAX;*/ /* update the stream's position to reflect consumed data */ stream->fUCPos += useScientific ? scientificParsePos : genericParsePos; /* we converted 1 arg */ return 1; } int32_t u_scanf_currency_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type double */ argtypes[0] = ufmt_double; return 1; } int32_t u_scanf_currency_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { int32_t len; double *num = (double*) (args[0].ptrValue); UNumberFormat *format; int32_t parsePos = 0; UErrorCode status = U_ZERO_ERROR; /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* fill the stream's internal buffer */ ufile_fill_uchar_buffer(stream); /* determine the size of the stream's buffer */ len = stream->fUCLimit - stream->fUCPos; /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* get the formatter */ format = u_locbund_getCurrencyFormat(stream->fBundle); /* handle error */ if(format == 0) return 0; /* parse the number */ *num = unum_parseDouble(format, stream->fUCPos, len, &parsePos, &status); /* mask off any necessary bits */ /* if(! info->fIsLong_double) num &= DBL_MAX;*/ /* update the stream's position to reflect consumed data */ stream->fUCPos += parsePos; /* we converted 1 arg */ return 1; } int32_t u_scanf_percent_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type double */ argtypes[0] = ufmt_double; return 1; } int32_t u_scanf_percent_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { int32_t len; double *num = (double*) (args[0].ptrValue); UNumberFormat *format; int32_t parsePos = 0; UErrorCode status = U_ZERO_ERROR; /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* fill the stream's internal buffer */ ufile_fill_uchar_buffer(stream); /* determine the size of the stream's buffer */ len = stream->fUCLimit - stream->fUCPos; /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* get the formatter */ format = u_locbund_getPercentFormat(stream->fBundle); /* handle error */ if(format == 0) return 0; /* parse the number */ *num = unum_parseDouble(format, stream->fUCPos, len, &parsePos, &status); /* mask off any necessary bits */ /* if(! info->fIsLong_double) num &= DBL_MAX;*/ /* update the stream's position to reflect consumed data */ stream->fUCPos += parsePos; /* we converted 1 arg */ return 1; } int32_t u_scanf_date_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type Date */ argtypes[0] = ufmt_date; return 1; } int32_t u_scanf_date_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { int32_t len; UDate *date = (UDate*) (args[0].ptrValue); UDateFormat *format; int32_t parsePos = 0; UErrorCode status = U_ZERO_ERROR; /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* fill the stream's internal buffer */ ufile_fill_uchar_buffer(stream); /* determine the size of the stream's buffer */ len = stream->fUCLimit - stream->fUCPos; /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* get the formatter */ format = u_locbund_getDateFormat(stream->fBundle); /* handle error */ if(format == 0) return 0; /* parse the number */ *date = udat_parse(format, stream->fUCPos, len, &parsePos, &status); /* update the stream's position to reflect consumed data */ stream->fUCPos += parsePos; /* we converted 1 arg */ return 1; } int32_t u_scanf_time_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type Date */ argtypes[0] = ufmt_date; return 1; } int32_t u_scanf_time_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { int32_t len; UDate *time = (UDate*) (args[0].ptrValue); UDateFormat *format; int32_t parsePos = 0; UErrorCode status = U_ZERO_ERROR; /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* fill the stream's internal buffer */ ufile_fill_uchar_buffer(stream); /* determine the size of the stream's buffer */ len = stream->fUCLimit - stream->fUCPos; /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* get the formatter */ format = u_locbund_getTimeFormat(stream->fBundle); /* handle error */ if(format == 0) return 0; /* parse the number */ *time = udat_parse(format, stream->fUCPos, len, &parsePos, &status); /* update the stream's position to reflect consumed data */ stream->fUCPos += parsePos; /* we converted 1 arg */ return 1; } int32_t u_scanf_char_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type char */ argtypes[0] = ufmt_char; return 1; } int32_t u_scanf_char_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { UChar uc; char *result; char *c = (char*)(args[0].ptrValue); /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* get the character from the stream, truncating to the width */ if(info->fWidth == -1 || info->fWidth > 1) uc = u_fgetc(stream); /* handle EOF */ if(uc == 0xFFFF) return -1; /* convert the character to the default codepage */ result = ufmt_unicodeToDefaultCP(&uc, 1); *c = result[0]; /* clean up */ free(result); /* we converted 1 arg */ return 1; } int32_t u_scanf_uchar_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type uchar */ argtypes[0] = ufmt_uchar; return 1; } int32_t u_scanf_uchar_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { UChar *c = (UChar*)(args[0].ptrValue); /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* get the character from the stream, truncating to the width */ if(info->fWidth == -1 || info->fWidth > 1) *c = u_fgetc(stream); /* handle EOF */ if(*c == 0xFFFF) return -1; /* we converted 1 arg */ return 1; } int32_t u_scanf_spellout_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type double */ argtypes[0] = ufmt_double; return 1; } int32_t u_scanf_spellout_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { int32_t len; double *num = (double*) (args[0].ptrValue); UNumberFormat *format; int32_t parsePos = 0; UErrorCode status = U_ZERO_ERROR; /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* fill the stream's internal buffer */ ufile_fill_uchar_buffer(stream); /* determine the size of the stream's buffer */ len = stream->fUCLimit - stream->fUCPos; /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* get the formatter */ format = u_locbund_getSpelloutFormat(stream->fBundle); /* handle error */ if(format == 0) return 0; /* parse the number */ *num = unum_parseDouble(format, stream->fUCPos, len, &parsePos, &status); /* mask off any necessary bits */ /* if(! info->fIsLong_double) num &= DBL_MAX;*/ /* update the stream's position to reflect consumed data */ stream->fUCPos += parsePos; /* we converted 1 arg */ return 1; } int32_t u_scanf_hex_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type int */ argtypes[0] = ufmt_int; return 1; } int32_t u_scanf_hex_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { int32_t len; long *num = (long*) (args[0].ptrValue); /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* fill the stream's internal buffer */ ufile_fill_uchar_buffer(stream); /* determine the size of the stream's buffer */ len = stream->fUCLimit - stream->fUCPos; /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* check for alternate form */ if( *(stream->fUCPos) == 0x0030 && (*(stream->fUCPos + 1) == 0x0078 || *(stream->fUCPos + 1) == 0x0058) ) { /* skip the '0' and 'x' or 'X' if present */ stream->fUCPos += 2; len -= 2; } /* parse the number */ *num = ufmt_utol(stream->fUCPos, &len, 16); /* update the stream's position to reflect consumed data */ stream->fUCPos += len; /* mask off any necessary bits */ if(info->fIsShort) *num &= SHRT_MAX; else if(! info->fIsLong || ! info->fIsLongLong) *num &= INT_MAX; /* we converted 1 arg */ return 1; } int32_t u_scanf_octal_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type int */ argtypes[0] = ufmt_int; return 1; } int32_t u_scanf_octal_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { int32_t len; long *num = (long*) (args[0].ptrValue); /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* fill the stream's internal buffer */ ufile_fill_uchar_buffer(stream); /* determine the size of the stream's buffer */ len = stream->fUCLimit - stream->fUCPos; /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* parse the number */ *num = ufmt_utol(stream->fUCPos, &len, 8); /* update the stream's position to reflect consumed data */ stream->fUCPos += len; /* mask off any necessary bits */ if(info->fIsShort) *num &= SHRT_MAX; else if(! info->fIsLong || ! info->fIsLongLong) *num &= INT_MAX; /* we converted 1 arg */ return 1; } int32_t u_scanf_pointer_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type void* */ argtypes[0] = ufmt_pointer; return 1; } int32_t u_scanf_pointer_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { int32_t len; void *p = (void*)(args[0].ptrValue); /* skip all ws in the stream */ u_scanf_skip_leading_ws(stream, info->fPadChar); /* fill the stream's internal buffer */ ufile_fill_uchar_buffer(stream); /* determine the size of the stream's buffer */ len = stream->fUCLimit - stream->fUCPos; /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* parse the pointer - cast to void** to assign to *p */ *(void**)p = (void*) ufmt_utol(stream->fUCPos, &len, 16); /* update the stream's position to reflect consumed data */ stream->fUCPos += len; /* we converted 1 arg */ return 1; } int32_t u_scanf_scanset_info(const u_scanf_spec_info *info, int32_t *argtypes, int32_t n) { /* handle error */ if(n < 1) return 0; /* we need 1 argument of type char* */ argtypes[0] = ufmt_string; return 1; } int32_t u_scanf_scanset_handler(UFILE *stream, const u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *consumed) { u_scanf_scanset scanset; int32_t len; UBool success; UChar c; const UChar *source; UConverter *conv; UErrorCode status = U_ZERO_ERROR; char *s = (char*) (args[0].ptrValue); char *alias, *limit; /* fill the stream's internal buffer */ ufile_fill_uchar_buffer(stream); /* determine the size of the stream's buffer */ len = stream->fUCLimit - stream->fUCPos; /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* alias the target */ alias = s; limit = alias + len; /* parse the scanset from the fmt string */ *consumed = u_strlen(fmt); success = u_scanf_scanset_init(&scanset, fmt, consumed); /* increment consumed by one to eat the final ']' */ ++(*consumed); /* open the default converter */ conv = ucnv_open(ucnv_getDefaultName(), &status); /* verify that the parse was successful and the converter opened */ if(! success || U_FAILURE(status)) return -1; /* grab characters one at a time and make sure they are in the scanset */ while( (c = u_fgetc(stream)) != 0xFFFF && alias < limit) { if(u_scanf_scanset_in(&scanset, c)) { source = &c; /* convert the character to the default codepage */ ucnv_fromUnicode(conv, &alias, limit, &source, source + 1, NULL, TRUE, &status); if(U_FAILURE(status)) return -1; } /* if the character's not in the scanset, break out */ else { break; } } /* put the final character we read back on the stream */ if(c != 0xFFFF) u_fungetc(c, stream); /* if we didn't match at least 1 character, fail */ if(alias == s) return -1; /* otherwise, add the terminator */ else *alias = 0x00; /* clean up */ ucnv_close(conv); /* we converted 1 arg */ return 1; } void u_scanf_init(void) { int32_t i; /*Mutex *lock;*/ /* if we're already inited, do nothing */ if(g_u_scanf_inited) return; /* lock the cache */ umtx_lock(0); /* if we're already inited, do nothing */ if(g_u_scanf_inited) { umtx_unlock(0); return; } /* initialize all handlers and infos to 0 */ for(i = 0; i < 256; ++i) { g_u_scanf_infos[i] = 0; g_u_scanf_handlers[i] = 0; } /* register the handlers for standard specifiers */ /* don't use u_scanf_register_handler to avoid mutex creation */ /* handle '%' */ g_u_scanf_infos[ 0x0025 ] = u_scanf_simple_percent_info; g_u_scanf_handlers[ 0x0025 ] = u_scanf_simple_percent_handler; /* handle 's' */ g_u_scanf_infos[ 0x0073 ] = u_scanf_string_info; g_u_scanf_handlers[ 0x0073 ] = u_scanf_string_handler; /* handle 'U' */ g_u_scanf_infos[ 0x0055 ] = u_scanf_ustring_info; g_u_scanf_handlers[ 0x0055 ] = u_scanf_ustring_handler; /* handle 'n' */ g_u_scanf_infos[ 0x006E ] = u_scanf_count_info; g_u_scanf_handlers[ 0x006E ] = u_scanf_count_handler; /* handle 'd' */ g_u_scanf_infos[ 0x0064 ] = u_scanf_integer_info; g_u_scanf_handlers[ 0x0064 ] = u_scanf_integer_handler; /* handle 'i' */ g_u_scanf_infos[ 0x0069 ] = u_scanf_integer_info; g_u_scanf_handlers[ 0x0069 ] = u_scanf_integer_handler; /* handle 'u' */ g_u_scanf_infos[ 0x0075 ] = u_scanf_integer_info; g_u_scanf_handlers[ 0x0075 ] = u_scanf_integer_handler; /* handle 'f' */ g_u_scanf_infos[ 0x0066 ] = u_scanf_double_info; g_u_scanf_handlers[ 0x0066 ] = u_scanf_double_handler; /* handle 'e' */ g_u_scanf_infos[ 0x0065 ] = u_scanf_scientific_info; g_u_scanf_handlers[ 0x0065 ] = u_scanf_scientific_handler; /* handle 'E' */ g_u_scanf_infos[ 0x0045 ] = u_scanf_scientific_info; g_u_scanf_handlers[ 0x0045 ] = u_scanf_scientific_handler; /* handle 'g' */ g_u_scanf_infos[ 0x0067 ] = u_scanf_scidbl_info; g_u_scanf_handlers[ 0x0067 ] = u_scanf_scidbl_handler; /* handle 'G' */ g_u_scanf_infos[ 0x0047 ] = u_scanf_scidbl_info; g_u_scanf_handlers[ 0x0047 ] = u_scanf_scidbl_handler; /* handle 'M' */ g_u_scanf_infos[ 0x004D ] = u_scanf_currency_info; g_u_scanf_handlers[ 0x004D ] = u_scanf_currency_handler; /* handle 'P' */ g_u_scanf_infos[ 0x0050 ] = u_scanf_percent_info; g_u_scanf_handlers[ 0x0050 ] = u_scanf_percent_handler; /* handle 'D' */ g_u_scanf_infos[ 0x0044 ] = u_scanf_date_info; g_u_scanf_handlers[ 0x0044 ] = u_scanf_date_handler; /* handle 'T' */ g_u_scanf_infos[ 0x0054 ] = u_scanf_time_info; g_u_scanf_handlers[ 0x0054 ] = u_scanf_time_handler; /* handle 'c' */ g_u_scanf_infos[ 0x0063 ] = u_scanf_char_info; g_u_scanf_handlers[ 0x0063 ] = u_scanf_char_handler; /* handle 'K' */ g_u_scanf_infos[ 0x004B ] = u_scanf_uchar_info; g_u_scanf_handlers[ 0x004B ] = u_scanf_uchar_handler; /* handle 'V' */ g_u_scanf_infos[ 0x0056 ] = u_scanf_spellout_info; g_u_scanf_handlers[ 0x0056 ] = u_scanf_spellout_handler; /* handle 'x' */ g_u_scanf_infos[ 0x0078 ] = u_scanf_hex_info; g_u_scanf_handlers[ 0x0078 ] = u_scanf_hex_handler; /* handle 'X' */ g_u_scanf_infos[ 0x0058 ] = u_scanf_hex_info; g_u_scanf_handlers[ 0x0058 ] = u_scanf_hex_handler; /* handle 'o' */ g_u_scanf_infos[ 0x006F ] = u_scanf_octal_info; g_u_scanf_handlers[ 0x006F ] = u_scanf_octal_handler; /* handle 'p' */ g_u_scanf_infos[ 0x0070 ] = u_scanf_pointer_info; g_u_scanf_handlers[ 0x0070 ] = u_scanf_pointer_handler; /* handle '[' */ g_u_scanf_infos[ 0x005B ] = u_scanf_scanset_info; g_u_scanf_handlers[ 0x005B ] = u_scanf_scanset_handler; /* we're finished */ g_u_scanf_inited = TRUE; /* unlock the cache */ umtx_unlock(0); } #define U_SCANF_MAX_ARGS 32 #define UP_PERCENT 0x0025 int32_t u_vfscanf_u( UFILE *f, const UChar *patternSpecification, va_list ap) { u_scanf_spec spec; const UChar *alias; int32_t count, converted, temp; int32_t num_args_wanted; int32_t ufmt_types [U_SCANF_MAX_ARGS]; ufmt_args args [U_SCANF_MAX_ARGS]; u_scanf_info info; u_scanf_handler handler; int32_t cur_arg; /* init our function tables */ if(! g_u_scanf_inited) u_scanf_init(); /* alias the pattern */ alias = patternSpecification; /* haven't converted anything yet */ converted = 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; /* skip the argument, if necessary */ if(spec.fSkipArg) va_arg(ap, int); /* query the info function for argument information */ info = g_u_scanf_infos[ (unsigned char) spec.fInfo.fSpec ]; if(info != 0) { num_args_wanted = (*info)(&spec.fInfo, ufmt_types, U_SCANF_MAX_ARGS); } else num_args_wanted = 0; /* fill in the requested arguments */ for(cur_arg = 0; cur_arg < num_args_wanted && cur_arg < U_SCANF_MAX_ARGS; ++cur_arg) { switch(ufmt_types[cur_arg]) { case ufmt_count: args[cur_arg].intValue = va_arg(ap, int); /* set the spec's width to the # of items converted */ spec.fInfo.fWidth = converted; break; case ufmt_int: args[cur_arg].ptrValue = va_arg(ap, int*); break; case ufmt_char: args[cur_arg].ptrValue = va_arg(ap, int*); break; case ufmt_wchar: args[cur_arg].ptrValue = va_arg(ap, wchar_t*); break; case ufmt_string: args[cur_arg].ptrValue = va_arg(ap, char*); break; case ufmt_wstring: args[cur_arg].ptrValue = va_arg(ap, wchar_t*); break; case ufmt_pointer: args[cur_arg].ptrValue = va_arg(ap, void*); break; case ufmt_float: args[cur_arg].ptrValue = va_arg(ap, float*); break; case ufmt_double: args[cur_arg].ptrValue = va_arg(ap, double*); break; case ufmt_date: args[cur_arg].ptrValue = va_arg(ap, UDate*); break; case ufmt_ustring: args[cur_arg].ptrValue = va_arg(ap, UChar*); break; case ufmt_uchar: args[cur_arg].ptrValue = va_arg(ap, int*); break; } } /* call the handler function */ handler = g_u_scanf_handlers[ (unsigned char) spec.fInfo.fSpec ]; if(handler != 0) { /* reset count */ count = 0; temp = (*handler)(f, &spec.fInfo, args, alias, &count); /* if the handler encountered an error condition, break */ if(temp == -1) break; /* add to the # of items converted */ converted += temp; /* update the pointer in pattern */ alias += count; } /* just ignore unknown tags */ } /* return # of items converted */ return converted; }