ICU-3499 Fix flaws found while testing %n, %c and %C
X-SVN-Rev: 15596
This commit is contained in:
parent
b2697fc485
commit
326ab9c4b0
@ -85,11 +85,12 @@ typedef struct u_scanf_spec_info {
|
||||
|
||||
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 fSkipArg; /* TRUE if arg should be skipped */
|
||||
UBool fIsString; /* TRUE if this is a NULL-terminated string. */
|
||||
} u_scanf_spec_info;
|
||||
|
||||
|
||||
@ -119,14 +120,15 @@ u_scanf_parse_spec (const UChar *fmt,
|
||||
/* initialize spec to default values */
|
||||
spec->fArgPos = -1;
|
||||
|
||||
info->fSkipArg = FALSE;
|
||||
info->fSpec = 0x0000;
|
||||
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 '%' */
|
||||
@ -285,16 +287,18 @@ u_scanf_parse_spec (const UChar *fmt,
|
||||
* @param args A pointer to the argument data
|
||||
* @param fmt A pointer to the first character in the format string
|
||||
* following the spec.
|
||||
* @param consumed On output, set to the number of characters consumed
|
||||
* in <TT>fmt</TT>.
|
||||
* @return The number of arguments converted and assigned, or -1 if an
|
||||
* @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,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed);
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted);
|
||||
|
||||
typedef struct u_scanf_info {
|
||||
ufmt_type_info info;
|
||||
@ -330,147 +334,37 @@ u_scanf_skip_leading_ws(UFILE *input,
|
||||
|
||||
static int32_t
|
||||
u_scanf_simple_percent_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted)
|
||||
{
|
||||
/* make sure the next character in the input is a percent */
|
||||
*argConverted = 0;
|
||||
if(u_fgetc(input) != 0x0025) {
|
||||
return -1;
|
||||
*argConverted = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
u_scanf_count_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
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 */
|
||||
/* will contain the # of items converted thus far */
|
||||
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 */
|
||||
@ -479,10 +373,11 @@ u_scanf_count_handler(UFILE *input,
|
||||
|
||||
static int32_t
|
||||
u_scanf_double_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted)
|
||||
{
|
||||
int32_t len;
|
||||
double num;
|
||||
@ -526,15 +421,17 @@ u_scanf_double_handler(UFILE *input,
|
||||
input->str.fPos += parsePos;
|
||||
|
||||
/* we converted 1 arg */
|
||||
return !info->fSkipArg;
|
||||
*argConverted = !info->fSkipArg;
|
||||
return parsePos;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
u_scanf_scientific_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted)
|
||||
{
|
||||
int32_t len;
|
||||
double num;
|
||||
@ -578,22 +475,24 @@ u_scanf_scientific_handler(UFILE *input,
|
||||
input->str.fPos += parsePos;
|
||||
|
||||
/* we converted 1 arg */
|
||||
return !info->fSkipArg;
|
||||
*argConverted = !info->fSkipArg;
|
||||
return parsePos;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
u_scanf_scidbl_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
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;
|
||||
int32_t scientificParsePos = 0, genericParsePos = 0, parsePos = 0;
|
||||
UErrorCode scientificStatus = U_ZERO_ERROR;
|
||||
UErrorCode genericStatus = U_ZERO_ERROR;
|
||||
|
||||
@ -638,14 +537,15 @@ u_scanf_scidbl_handler(UFILE *input,
|
||||
/* stash the result in num */
|
||||
num = scientificResult;
|
||||
/* update the input's position to reflect consumed data */
|
||||
input->str.fPos += scientificParsePos;
|
||||
parsePos += scientificParsePos;
|
||||
}
|
||||
else {
|
||||
/* stash the result in num */
|
||||
num = genericResult;
|
||||
/* update the input's position to reflect consumed data */
|
||||
input->str.fPos += genericParsePos;
|
||||
parsePos += genericParsePos;
|
||||
}
|
||||
input->str.fPos += parsePos;
|
||||
|
||||
if (!info->fSkipArg) {
|
||||
*(double*)(args[0].ptrValue) = num;
|
||||
@ -656,15 +556,17 @@ u_scanf_scidbl_handler(UFILE *input,
|
||||
num &= DBL_MAX;*/
|
||||
|
||||
/* we converted 1 arg */
|
||||
return !info->fSkipArg;
|
||||
*argConverted = !info->fSkipArg;
|
||||
return parsePos;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
u_scanf_integer_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted)
|
||||
{
|
||||
int32_t len;
|
||||
void *num = (void*) (args[0].ptrValue);
|
||||
@ -711,36 +613,29 @@ u_scanf_integer_handler(UFILE *input,
|
||||
input->str.fPos += parsePos;
|
||||
|
||||
/* we converted 1 arg */
|
||||
return !info->fSkipArg;
|
||||
*argConverted = !info->fSkipArg;
|
||||
return parsePos;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
u_scanf_uinteger_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted)
|
||||
{
|
||||
ufmt_args uint_args;
|
||||
int32_t converted_args;
|
||||
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;
|
||||
/* 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,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted)
|
||||
{
|
||||
int32_t len;
|
||||
double num;
|
||||
@ -784,74 +679,177 @@ u_scanf_percent_handler(UFILE *input,
|
||||
input->str.fPos += parsePos;
|
||||
|
||||
/* 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
|
||||
u_scanf_char_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted)
|
||||
{
|
||||
UChar uc = 0;
|
||||
char *result;
|
||||
char *c = (char*)(args[0].ptrValue);
|
||||
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 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 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];
|
||||
if (info->fIsString) {
|
||||
u_scanf_skip_leading_ws(input, info->fPadChar);
|
||||
}
|
||||
|
||||
/* clean up */
|
||||
uprv_free(result);
|
||||
/* 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(isNotEOF && (info->fWidth == -1 || count < info->fWidth)) {
|
||||
u_fungetc(c, input);
|
||||
}
|
||||
|
||||
/* add the terminator */
|
||||
if (info->fIsString) {
|
||||
*alias = 0x0000;
|
||||
}
|
||||
}
|
||||
|
||||
/* we converted 1 arg */
|
||||
return !info->fSkipArg;
|
||||
*argConverted = !info->fSkipArg;
|
||||
return count;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
u_scanf_uchar_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted)
|
||||
{
|
||||
UChar *c = (UChar*)(args[0].ptrValue);
|
||||
UChar skippedChar;
|
||||
|
||||
if (info->fSkipArg) {
|
||||
c = &skippedChar;
|
||||
if (info->fWidth < 0) {
|
||||
info->fWidth = 1;
|
||||
}
|
||||
|
||||
/* skip all ws in the input */
|
||||
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;
|
||||
info->fIsString = FALSE;
|
||||
return u_scanf_ustring_handler(input, info, args, fmt, fmtConsumed, argConverted);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
u_scanf_spellout_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted)
|
||||
{
|
||||
int32_t len;
|
||||
double num;
|
||||
@ -895,15 +893,17 @@ u_scanf_spellout_handler(UFILE *input,
|
||||
input->str.fPos += parsePos;
|
||||
|
||||
/* we converted 1 arg */
|
||||
return !info->fSkipArg;
|
||||
*argConverted = !info->fSkipArg;
|
||||
return parsePos;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
u_scanf_hex_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted)
|
||||
{
|
||||
int32_t len;
|
||||
void *num = (void*) (args[0].ptrValue);
|
||||
@ -948,15 +948,17 @@ u_scanf_hex_handler(UFILE *input,
|
||||
}
|
||||
|
||||
/* we converted 1 arg */
|
||||
return !info->fSkipArg;
|
||||
*argConverted = !info->fSkipArg;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
u_scanf_octal_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted)
|
||||
{
|
||||
int32_t len;
|
||||
void *num = (void*) (args[0].ptrValue);
|
||||
@ -992,15 +994,17 @@ u_scanf_octal_handler(UFILE *input,
|
||||
}
|
||||
|
||||
/* we converted 1 arg */
|
||||
return !info->fSkipArg;
|
||||
*argConverted = !info->fSkipArg;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
u_scanf_pointer_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted)
|
||||
{
|
||||
int32_t len;
|
||||
void *result;
|
||||
@ -1031,15 +1035,17 @@ u_scanf_pointer_handler(UFILE *input,
|
||||
input->str.fPos += len;
|
||||
|
||||
/* we converted 1 arg */
|
||||
return !info->fSkipArg;
|
||||
*argConverted = !info->fSkipArg;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
u_scanf_scanset_handler(UFILE *input,
|
||||
const u_scanf_spec_info *info,
|
||||
u_scanf_spec_info *info,
|
||||
ufmt_args *args,
|
||||
const UChar *fmt,
|
||||
int32_t *consumed)
|
||||
int32_t *fmtConsumed,
|
||||
int32_t *argConverted)
|
||||
{
|
||||
USet *scanset;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
@ -1061,7 +1067,7 @@ u_scanf_scanset_handler(UFILE *input,
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if (U_SUCCESS(status)) {
|
||||
@ -1106,7 +1112,8 @@ u_scanf_scanset_handler(UFILE *input,
|
||||
}
|
||||
|
||||
/* 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
|
||||
@ -1165,7 +1172,7 @@ u_scanf_parse(UFILE *f,
|
||||
va_list ap)
|
||||
{
|
||||
const UChar *alias;
|
||||
int32_t count, converted, temp;
|
||||
int32_t count, converted, argConsumed, cpConsumed;
|
||||
uint16_t handlerNum;
|
||||
|
||||
ufmt_args args;
|
||||
@ -1177,7 +1184,9 @@ u_scanf_parse(UFILE *f,
|
||||
alias = patternSpecification;
|
||||
|
||||
/* haven't converted anything yet */
|
||||
argConsumed = 0;
|
||||
converted = 0;
|
||||
cpConsumed = 0;
|
||||
|
||||
/* iterate through the pattern */
|
||||
for(;;) {
|
||||
@ -1209,6 +1218,10 @@ u_scanf_parse(UFILE *f,
|
||||
if(info > ufmt_simple_percent) {
|
||||
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:
|
||||
@ -1220,12 +1233,6 @@ u_scanf_parse(UFILE *f,
|
||||
args.ptrValue = va_arg(ap, void*);
|
||||
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:
|
||||
break; /* Should never get here */
|
||||
}
|
||||
@ -1238,14 +1245,14 @@ u_scanf_parse(UFILE *f,
|
||||
/* reset count to 1 so that += for alias works. */
|
||||
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(temp == -1)
|
||||
if(argConsumed < 0)
|
||||
break;
|
||||
|
||||
/* add to the # of items converted */
|
||||
converted += temp;
|
||||
converted += argConsumed;
|
||||
|
||||
/* update the pointer in pattern */
|
||||
alias += count-1;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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
|
||||
addStringTest(TestNode** root) {
|
||||
addTest(root, &TestString, "string/TestString");
|
||||
@ -701,6 +727,7 @@ addStringTest(TestNode** root) {
|
||||
addTest(root, &TestStringCompatibility, "string/TestStringCompatibility");
|
||||
addTest(root, &TestBadScanfFormat, "string/TestBadScanfFormat");
|
||||
addTest(root, &TestVargs, "string/TestVargs");
|
||||
addTest(root, &TestCount, "string/TestCount");
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user