ICU-3499 Fix flaws found while testing %n, %c and %C

X-SVN-Rev: 15596
This commit is contained in:
George Rhoten 2004-05-27 22:54:41 +00:00
parent b2697fc485
commit 326ab9c4b0
2 changed files with 263 additions and 229 deletions

View File

@ -85,11 +85,12 @@ typedef struct u_scanf_spec_info {
UChar fPadChar; /* Padding character */ UChar fPadChar; /* Padding character */
UBool fSkipArg; /* TRUE if arg should be skipped */
UBool fIsLongDouble; /* L flag */ UBool fIsLongDouble; /* L flag */
UBool fIsShort; /* h flag */ UBool fIsShort; /* h flag */
UBool fIsLong; /* l flag */ UBool fIsLong; /* l flag */
UBool fIsLongLong; /* ll flag */ UBool fIsLongLong; /* ll flag */
UBool fSkipArg; /* TRUE if arg should be skipped */ UBool fIsString; /* TRUE if this is a NULL-terminated string. */
} u_scanf_spec_info; } u_scanf_spec_info;
@ -119,14 +120,15 @@ u_scanf_parse_spec (const UChar *fmt,
/* initialize spec to default values */ /* initialize spec to default values */
spec->fArgPos = -1; spec->fArgPos = -1;
info->fSkipArg = FALSE;
info->fSpec = 0x0000;
info->fWidth = -1; info->fWidth = -1;
info->fSpec = 0x0000;
info->fPadChar = 0x0020; info->fPadChar = 0x0020;
info->fSkipArg = FALSE;
info->fIsLongDouble = FALSE; info->fIsLongDouble = FALSE;
info->fIsShort = FALSE; info->fIsShort = FALSE;
info->fIsLong = FALSE; info->fIsLong = FALSE;
info->fIsLongLong = FALSE; info->fIsLongLong = FALSE;
info->fIsString = TRUE;
/* skip over the initial '%' */ /* skip over the initial '%' */
@ -285,16 +287,18 @@ u_scanf_parse_spec (const UChar *fmt,
* @param args A pointer to the argument data * @param args A pointer to the argument data
* @param fmt A pointer to the first character in the format string * @param fmt A pointer to the first character in the format string
* following the spec. * following the spec.
* @param consumed On output, set to the number of characters consumed * @param fmtConsumed On output, set to the number of characters consumed
* in <TT>fmt</TT>. * in <TT>fmt</TT>. Do nothing, if the argument isn't variable width.
* @return The number of arguments converted and assigned, or -1 if an * @param argConverted The number of arguments converted and assigned, or -1 if an
* error occurred. * error occurred.
* @return The number of code points consumed during reading.
*/ */
typedef int32_t (*u_scanf_handler) (UFILE *stream, typedef int32_t (*u_scanf_handler) (UFILE *stream,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed); int32_t *fmtConsumed,
int32_t *argConverted);
typedef struct u_scanf_info { typedef struct u_scanf_info {
ufmt_type_info info; ufmt_type_info info;
@ -330,147 +334,37 @@ u_scanf_skip_leading_ws(UFILE *input,
static int32_t static int32_t
u_scanf_simple_percent_handler(UFILE *input, u_scanf_simple_percent_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
/* make sure the next character in the input is a percent */ /* make sure the next character in the input is a percent */
*argConverted = 0;
if(u_fgetc(input) != 0x0025) { if(u_fgetc(input) != 0x0025) {
return -1; *argConverted = -1;
} }
return 0; return 1;
}
static int32_t
u_scanf_string_handler(UFILE *input,
const u_scanf_spec_info *info,
ufmt_args *args,
const UChar *fmt,
int32_t *consumed)
{
UChar c;
UBool isNotEOF;
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 input */
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))
&& (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. */
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(isNotEOF && (info->fWidth == -1 || count < info->fWidth) )
u_fungetc(c, input);
/* add the terminator */
*alias = 0x00;
}
/* clean up */
u_releaseDefaultConverter(conv);
/* we converted 1 arg */
return !info->fSkipArg;
}
static int32_t
u_scanf_ustring_handler(UFILE *input,
const u_scanf_spec_info *info,
ufmt_args *args,
const UChar *fmt,
int32_t *consumed)
{
UChar c;
UBool isNotEOF;
int32_t count;
UChar *arg = (UChar*)(args[0].ptrValue);
UChar *alias = arg;
/* skip all ws in the input */
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))
&& (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(isNotEOF && (info->fWidth == -1 || count < info->fWidth)) {
u_fungetc(c, input);
}
/* add the terminator */
*alias = 0x0000;
}
/* we converted 1 arg */
return !info->fSkipArg;
} }
static int32_t static int32_t
u_scanf_count_handler(UFILE *input, u_scanf_count_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
/* in the special case of count, the u_scanf_spec_info's width */ /* in the special case of count, the u_scanf_spec_info's width */
/* will contain the # of items converted thus far */ /* will contain the # of items converted thus far */
if (!info->fSkipArg) { if (!info->fSkipArg) {
*(int*)(args[0].ptrValue) = info->fWidth; 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);
} }
/* we converted 0 args */ /* we converted 0 args */
@ -479,10 +373,11 @@ u_scanf_count_handler(UFILE *input,
static int32_t static int32_t
u_scanf_double_handler(UFILE *input, u_scanf_double_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
int32_t len; int32_t len;
double num; double num;
@ -526,15 +421,17 @@ u_scanf_double_handler(UFILE *input,
input->str.fPos += parsePos; input->str.fPos += parsePos;
/* we converted 1 arg */ /* we converted 1 arg */
return !info->fSkipArg; *argConverted = !info->fSkipArg;
return parsePos;
} }
static int32_t static int32_t
u_scanf_scientific_handler(UFILE *input, u_scanf_scientific_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
int32_t len; int32_t len;
double num; double num;
@ -578,22 +475,24 @@ u_scanf_scientific_handler(UFILE *input,
input->str.fPos += parsePos; input->str.fPos += parsePos;
/* we converted 1 arg */ /* we converted 1 arg */
return !info->fSkipArg; *argConverted = !info->fSkipArg;
return parsePos;
} }
static int32_t static int32_t
u_scanf_scidbl_handler(UFILE *input, u_scanf_scidbl_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
int32_t len; int32_t len;
double num; double num;
UNumberFormat *scientificFormat, *genericFormat; UNumberFormat *scientificFormat, *genericFormat;
/*int32_t scientificResult, genericResult;*/ /*int32_t scientificResult, genericResult;*/
double scientificResult, genericResult; double scientificResult, genericResult;
int32_t scientificParsePos = 0, genericParsePos = 0; int32_t scientificParsePos = 0, genericParsePos = 0, parsePos = 0;
UErrorCode scientificStatus = U_ZERO_ERROR; UErrorCode scientificStatus = U_ZERO_ERROR;
UErrorCode genericStatus = U_ZERO_ERROR; UErrorCode genericStatus = U_ZERO_ERROR;
@ -638,14 +537,15 @@ u_scanf_scidbl_handler(UFILE *input,
/* stash the result in num */ /* stash the result in num */
num = scientificResult; num = scientificResult;
/* update the input's position to reflect consumed data */ /* update the input's position to reflect consumed data */
input->str.fPos += scientificParsePos; parsePos += scientificParsePos;
} }
else { else {
/* stash the result in num */ /* stash the result in num */
num = genericResult; num = genericResult;
/* update the input's position to reflect consumed data */ /* update the input's position to reflect consumed data */
input->str.fPos += genericParsePos; parsePos += genericParsePos;
} }
input->str.fPos += parsePos;
if (!info->fSkipArg) { if (!info->fSkipArg) {
*(double*)(args[0].ptrValue) = num; *(double*)(args[0].ptrValue) = num;
@ -656,15 +556,17 @@ u_scanf_scidbl_handler(UFILE *input,
num &= DBL_MAX;*/ num &= DBL_MAX;*/
/* we converted 1 arg */ /* we converted 1 arg */
return !info->fSkipArg; *argConverted = !info->fSkipArg;
return parsePos;
} }
static int32_t static int32_t
u_scanf_integer_handler(UFILE *input, u_scanf_integer_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
int32_t len; int32_t len;
void *num = (void*) (args[0].ptrValue); void *num = (void*) (args[0].ptrValue);
@ -711,36 +613,29 @@ u_scanf_integer_handler(UFILE *input,
input->str.fPos += parsePos; input->str.fPos += parsePos;
/* we converted 1 arg */ /* we converted 1 arg */
return !info->fSkipArg; *argConverted = !info->fSkipArg;
return parsePos;
} }
static int32_t static int32_t
u_scanf_uinteger_handler(UFILE *input, u_scanf_uinteger_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
ufmt_args uint_args; /* TODO Fix this when Numberformat handles uint64_t */
int32_t converted_args; return u_scanf_integer_handler(input, info, args, fmt, fmtConsumed, argConverted);
double currDouble;
uint_args.ptrValue = &currDouble;
converted_args = u_scanf_double_handler(input, info, &uint_args, fmt, consumed);
if (!info->fSkipArg) {
*(uint32_t*)(args[0].ptrValue) = (uint32_t)currDouble;
}
return converted_args;
} }
static int32_t static int32_t
u_scanf_percent_handler(UFILE *input, u_scanf_percent_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
int32_t len; int32_t len;
double num; double num;
@ -784,74 +679,177 @@ u_scanf_percent_handler(UFILE *input,
input->str.fPos += parsePos; input->str.fPos += parsePos;
/* we converted 1 arg */ /* we converted 1 arg */
return !info->fSkipArg; *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)
{
UChar c;
UBool isNotEOF;
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 input */
if (info->fIsString) {
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. */
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(isNotEOF && (info->fWidth == -1 || count < info->fWidth) )
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;
} }
static int32_t static int32_t
u_scanf_char_handler(UFILE *input, u_scanf_char_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
UChar uc = 0; if (info->fWidth < 0) {
char *result; info->fWidth = 1;
char *c = (char*)(args[0].ptrValue); }
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 c;
UBool isNotEOF;
int32_t count;
UChar *arg = (UChar*)(args[0].ptrValue);
UChar *alias = arg;
/* skip all ws in the input */ /* skip all ws in the input */
u_scanf_skip_leading_ws(input, info->fPadChar); if (info->fIsString) {
u_scanf_skip_leading_ws(input, info->fPadChar);
/* get the character from the input, truncating to the width */
if(info->fWidth == -1 || info->fWidth > 1)
if (!ufile_getch(input, &uc))
return -1; /* no character */
/* convert the character to the default codepage */
result = ufmt_unicodeToDefaultCP(&uc, 1);
if (!info->fSkipArg) {
*c = result[0];
} }
/* clean up */ /* get the string one character at a time, truncating to the width */
uprv_free(result); 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(isNotEOF && (info->fWidth == -1 || count < info->fWidth)) {
u_fungetc(c, input);
}
/* add the terminator */
if (info->fIsString) {
*alias = 0x0000;
}
}
/* we converted 1 arg */ /* we converted 1 arg */
return !info->fSkipArg; *argConverted = !info->fSkipArg;
return count;
} }
static int32_t static int32_t
u_scanf_uchar_handler(UFILE *input, u_scanf_uchar_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
UChar *c = (UChar*)(args[0].ptrValue); if (info->fWidth < 0) {
UChar skippedChar; info->fWidth = 1;
if (info->fSkipArg) {
c = &skippedChar;
} }
info->fIsString = FALSE;
/* skip all ws in the input */ return u_scanf_ustring_handler(input, info, args, fmt, fmtConsumed, argConverted);
u_scanf_skip_leading_ws(input, info->fPadChar);
/* get the character from the input, truncating to the width */
if(info->fWidth == -1 || info->fWidth > 1)
if (!ufile_getch(input, c))
return -1; /* no character */
/* we converted 1 arg */
return !info->fSkipArg;
} }
static int32_t static int32_t
u_scanf_spellout_handler(UFILE *input, u_scanf_spellout_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
int32_t len; int32_t len;
double num; double num;
@ -895,15 +893,17 @@ u_scanf_spellout_handler(UFILE *input,
input->str.fPos += parsePos; input->str.fPos += parsePos;
/* we converted 1 arg */ /* we converted 1 arg */
return !info->fSkipArg; *argConverted = !info->fSkipArg;
return parsePos;
} }
static int32_t static int32_t
u_scanf_hex_handler(UFILE *input, u_scanf_hex_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
int32_t len; int32_t len;
void *num = (void*) (args[0].ptrValue); void *num = (void*) (args[0].ptrValue);
@ -948,15 +948,17 @@ u_scanf_hex_handler(UFILE *input,
} }
/* we converted 1 arg */ /* we converted 1 arg */
return !info->fSkipArg; *argConverted = !info->fSkipArg;
return len;
} }
static int32_t static int32_t
u_scanf_octal_handler(UFILE *input, u_scanf_octal_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
int32_t len; int32_t len;
void *num = (void*) (args[0].ptrValue); void *num = (void*) (args[0].ptrValue);
@ -992,15 +994,17 @@ u_scanf_octal_handler(UFILE *input,
} }
/* we converted 1 arg */ /* we converted 1 arg */
return !info->fSkipArg; *argConverted = !info->fSkipArg;
return len;
} }
static int32_t static int32_t
u_scanf_pointer_handler(UFILE *input, u_scanf_pointer_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
int32_t len; int32_t len;
void *result; void *result;
@ -1031,15 +1035,17 @@ u_scanf_pointer_handler(UFILE *input,
input->str.fPos += len; input->str.fPos += len;
/* we converted 1 arg */ /* we converted 1 arg */
return !info->fSkipArg; *argConverted = !info->fSkipArg;
return len;
} }
static int32_t static int32_t
u_scanf_scanset_handler(UFILE *input, u_scanf_scanset_handler(UFILE *input,
const u_scanf_spec_info *info, u_scanf_spec_info *info,
ufmt_args *args, ufmt_args *args,
const UChar *fmt, const UChar *fmt,
int32_t *consumed) int32_t *fmtConsumed,
int32_t *argConverted)
{ {
USet *scanset; USet *scanset;
UErrorCode status = U_ZERO_ERROR; UErrorCode status = U_ZERO_ERROR;
@ -1061,7 +1067,7 @@ u_scanf_scanset_handler(UFILE *input,
} }
/* parse the scanset from the fmt string */ /* parse the scanset from the fmt string */
*consumed = uset_applyPattern(scanset, fmt, -1, 0, &status); *fmtConsumed = uset_applyPattern(scanset, fmt, -1, 0, &status);
/* verify that the parse was successful */ /* verify that the parse was successful */
if (U_SUCCESS(status)) { if (U_SUCCESS(status)) {
@ -1106,7 +1112,8 @@ u_scanf_scanset_handler(UFILE *input,
} }
/* we converted 1 arg */ /* we converted 1 arg */
return !info->fSkipArg; *argConverted = !info->fSkipArg;
return (info->fWidth >= 0 ? info->fWidth : INT32_MAX) - chLeft;
} }
/* Use US-ASCII characters only for formatting. Most codepages have /* Use US-ASCII characters only for formatting. Most codepages have
@ -1165,7 +1172,7 @@ u_scanf_parse(UFILE *f,
va_list ap) va_list ap)
{ {
const UChar *alias; const UChar *alias;
int32_t count, converted, temp; int32_t count, converted, argConsumed, cpConsumed;
uint16_t handlerNum; uint16_t handlerNum;
ufmt_args args; ufmt_args args;
@ -1177,7 +1184,9 @@ u_scanf_parse(UFILE *f,
alias = patternSpecification; alias = patternSpecification;
/* haven't converted anything yet */ /* haven't converted anything yet */
argConsumed = 0;
converted = 0; converted = 0;
cpConsumed = 0;
/* iterate through the pattern */ /* iterate through the pattern */
for(;;) { for(;;) {
@ -1209,6 +1218,10 @@ u_scanf_parse(UFILE *f,
if(info > ufmt_simple_percent) { if(info > ufmt_simple_percent) {
switch(info) { 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_char:
case ufmt_uchar: case ufmt_uchar:
case ufmt_int: case ufmt_int:
@ -1220,12 +1233,6 @@ u_scanf_parse(UFILE *f,
args.ptrValue = va_arg(ap, void*); args.ptrValue = va_arg(ap, void*);
break; break;
case ufmt_count:
args.int64Value = va_arg(ap, int);
/* set the spec's width to the # of items converted */
spec.fInfo.fWidth = converted;
break;
default: default:
break; /* Should never get here */ break; /* Should never get here */
} }
@ -1238,14 +1245,14 @@ u_scanf_parse(UFILE *f,
/* reset count to 1 so that += for alias works. */ /* reset count to 1 so that += for alias works. */
count = 1; count = 1;
temp = (*handler)(f, &spec.fInfo, &args, alias, &count); cpConsumed += (*handler)(f, &spec.fInfo, &args, alias, &count, &argConsumed);
/* if the handler encountered an error condition, break */ /* if the handler encountered an error condition, break */
if(temp == -1) if(argConsumed < 0)
break; break;
/* add to the # of items converted */ /* add to the # of items converted */
converted += temp; converted += argConsumed;
/* update the pointer in pattern */ /* update the pointer in pattern */
alias += count-1; alias += count-1;

View File

@ -691,6 +691,32 @@ static void TestVargs(void) {
Test_u_vfprintf("8 9 a B 8.9", "%d %u %x %X %.1f", 8, 9, 10, 11, 8.9); Test_u_vfprintf("8 9 a B 8.9", "%d %u %x %X %.1f", 8, 9, 10, 11, 8.9);
} }
static void TestCount(void) {
UChar testStr[16];
int16_t i16 = -1;
int32_t i32 = -1;
int64_t i64 = -1;
u_uastrcpy(testStr, "1233456789");
if (u_sscanf(testStr, "%*3[123]%n%*[1-9]", &i32) != 0) {
log_err("test 1: scanf did not return 0\n");
}
if (i32 != 3) {
log_err("test 1: scanf returned %hd instead of 3\n", i32);
}
if (u_sscanf(testStr, "%*4[123]%hn%*[1-9]", &i16) != 0) {
log_err("test 2: scanf did not return 0\n");
}
if (i16 != 4) {
log_err("test 2: scanf returned %d instead of 4\n", i16);
}
if (u_sscanf(testStr, "%*[123]%*[1-9]%lln", &i64) != 0) {
log_err("test 3: scanf did not return 0\n");
}
if (i64 != 10) {
log_err("test 3: scanf did not return 10\n", i64);
}
}
U_CFUNC void U_CFUNC void
addStringTest(TestNode** root) { addStringTest(TestNode** root) {
addTest(root, &TestString, "string/TestString"); addTest(root, &TestString, "string/TestString");
@ -701,6 +727,7 @@ addStringTest(TestNode** root) {
addTest(root, &TestStringCompatibility, "string/TestStringCompatibility"); addTest(root, &TestStringCompatibility, "string/TestStringCompatibility");
addTest(root, &TestBadScanfFormat, "string/TestBadScanfFormat"); addTest(root, &TestBadScanfFormat, "string/TestBadScanfFormat");
addTest(root, &TestVargs, "string/TestVargs"); addTest(root, &TestVargs, "string/TestVargs");
addTest(root, &TestCount, "string/TestCount");
} }