69ba12f77c
X-SVN-Rev: 1410
1519 lines
37 KiB
C
1519 lines
37 KiB
C
/*
|
|
*******************************************************************************
|
|
*
|
|
* 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 <string.h>
|
|
#include <stdlib.h>
|
|
#include <float.h>
|
|
#include <limits.h>
|
|
|
|
u_scanf_handler g_u_scanf_handlers [256];
|
|
u_scanf_info g_u_scanf_infos [256];
|
|
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;
|
|
}
|
|
|