sscanf removed from %c and %[]
This commit is contained in:
@ -238,7 +238,7 @@ static void copyFormatString(StreamBuffer& info, const char* source)
|
|||||||
// A word on sscanf
|
// A word on sscanf
|
||||||
// GNU's sscanf implementation sucks. It calls strlen on the buffer.
|
// GNU's sscanf implementation sucks. It calls strlen on the buffer.
|
||||||
// That leads to a time consumption proportional to the buffer size.
|
// That leads to a time consumption proportional to the buffer size.
|
||||||
// When reading huge arrays element wise by repeatedly calling sscanf,
|
// When reading huge arrays element-wise by repeatedly calling sscanf,
|
||||||
// the performance drops to O(n^2).
|
// the performance drops to O(n^2).
|
||||||
// The vxWorks implementation sucks, too. When all parsed values are skipped
|
// The vxWorks implementation sucks, too. When all parsed values are skipped
|
||||||
// with %*, it returns -1 instead of 0 even though it was successful.
|
// with %*, it returns -1 instead of 0 even though it was successful.
|
||||||
@ -433,8 +433,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
if (fmt.flags & (sign_flag|zero_flag))
|
if (fmt.flags & (sign_flag|zero_flag))
|
||||||
{
|
{
|
||||||
error("Use of modifiers '+', '0'"
|
error("Use of modifiers '+', '0'"
|
||||||
"not allowed with %%%c conversion\n",
|
"not allowed with %%s conversion\n");
|
||||||
fmt.conv);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (scanFormat && fmt.prec >= 0)
|
if (scanFormat && fmt.prec >= 0)
|
||||||
@ -477,7 +476,7 @@ scanString(const StreamFormat& fmt, const char* input,
|
|||||||
{
|
{
|
||||||
// normally leading whitespace does not count to width
|
// normally leading whitespace does not count to width
|
||||||
// but do so if space flag is present
|
// but do so if space flag is present
|
||||||
if (fmt.flags & space_flag || fmt.conv == 'c')
|
if (fmt.flags & space_flag)
|
||||||
{
|
{
|
||||||
if (maxlen > 1)
|
if (maxlen > 1)
|
||||||
{
|
{
|
||||||
@ -493,7 +492,7 @@ scanString(const StreamFormat& fmt, const char* input,
|
|||||||
{
|
{
|
||||||
// normally whitespace ends string
|
// normally whitespace ends string
|
||||||
// but don't end if # flag is present
|
// but don't end if # flag is present
|
||||||
if (fmt.conv == 's' && !(fmt.flags & alt_flag) && isspace(*input)) break;
|
if (!(fmt.flags & alt_flag) && isspace(*input)) break;
|
||||||
if (maxlen > 1)
|
if (maxlen > 1)
|
||||||
{
|
{
|
||||||
*value++ = *input;
|
*value++ = *input;
|
||||||
@ -514,11 +513,11 @@ RegisterConverter (StdStringConverter, "s");
|
|||||||
|
|
||||||
// Standard Characters Converter for 'c'
|
// Standard Characters Converter for 'c'
|
||||||
|
|
||||||
class StdCharsConverter : public StdStringConverter
|
class StdCharsConverter : public StreamFormatConverter
|
||||||
{
|
{
|
||||||
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||||
virtual bool printLong(const StreamFormat&, StreamBuffer&, long);
|
virtual bool printLong(const StreamFormat&, StreamBuffer&, long);
|
||||||
// scanString is inherited from %s format
|
virtual int scanString(const StreamFormat&, const char*, char*, size_t);
|
||||||
};
|
};
|
||||||
|
|
||||||
int StdCharsConverter::
|
int StdCharsConverter::
|
||||||
@ -528,8 +527,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
if (fmt.flags & (sign_flag|space_flag|zero_flag|alt_flag))
|
if (fmt.flags & (sign_flag|space_flag|zero_flag|alt_flag))
|
||||||
{
|
{
|
||||||
error("Use of modifiers '+', ' ', '0', '#' "
|
error("Use of modifiers '+', ' ', '0', '#' "
|
||||||
"not allowed with %%%c conversion\n",
|
"not allowed with %%c conversion\n");
|
||||||
fmt.conv);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (scanFormat && fmt.prec >= 0)
|
if (scanFormat && fmt.prec >= 0)
|
||||||
@ -555,6 +553,37 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int StdCharsConverter::
|
||||||
|
scanString(const StreamFormat& fmt, const char* input,
|
||||||
|
char* value, size_t maxlen)
|
||||||
|
{
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
|
int width = fmt.width;
|
||||||
|
|
||||||
|
if ((fmt.flags & skip_flag) || value == NULL) maxlen = 0;
|
||||||
|
|
||||||
|
// if user does not specify width assume 1
|
||||||
|
if (width == 0) width = 1;
|
||||||
|
|
||||||
|
while (*input && width)
|
||||||
|
{
|
||||||
|
if (maxlen > 1)
|
||||||
|
{
|
||||||
|
*value++ = *input;
|
||||||
|
maxlen--;
|
||||||
|
}
|
||||||
|
length++;
|
||||||
|
width--;
|
||||||
|
input++;
|
||||||
|
}
|
||||||
|
if (maxlen > 0)
|
||||||
|
{
|
||||||
|
*value = '\0';
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
RegisterConverter (StdCharsConverter, "c");
|
RegisterConverter (StdCharsConverter, "c");
|
||||||
|
|
||||||
// Standard Charset Converter for '['
|
// Standard Charset Converter for '['
|
||||||
@ -566,6 +595,16 @@ class StdCharsetConverter : public StreamFormatConverter
|
|||||||
// no print method, %[ is readonly
|
// no print method, %[ is readonly
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void markbit(StreamBuffer& info, bool notflag, char c)
|
||||||
|
{
|
||||||
|
const char mask [8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
|
||||||
|
|
||||||
|
if (notflag)
|
||||||
|
info[c>>3] |= mask[c&7];
|
||||||
|
else
|
||||||
|
info[c>>3] &= ~mask[c&7];
|
||||||
|
}
|
||||||
|
|
||||||
int StdCharsetConverter::
|
int StdCharsetConverter::
|
||||||
parse(const StreamFormat& fmt, StreamBuffer& info,
|
parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||||
const char*& source, bool scanFormat)
|
const char*& source, bool scanFormat)
|
||||||
@ -578,8 +617,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
if (fmt.flags & (left_flag|sign_flag|space_flag|zero_flag|alt_flag))
|
if (fmt.flags & (left_flag|sign_flag|space_flag|zero_flag|alt_flag))
|
||||||
{
|
{
|
||||||
error("Use of modifiers '-', '+', ' ', '0', '#'"
|
error("Use of modifiers '-', '+', ' ', '0', '#'"
|
||||||
"not allowed with %%%c conversion\n",
|
"not allowed with %%[ conversion\n");
|
||||||
fmt.conv);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (scanFormat && fmt.prec >= 0)
|
if (scanFormat && fmt.prec >= 0)
|
||||||
@ -588,18 +626,46 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
fmt.prec, fmt.conv);
|
fmt.prec, fmt.conv);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
info.printf("%%%s%d[", fmt.flags & skip_flag ? "*" : "", fmt.width);
|
|
||||||
while (*source && *source != ']')
|
int notflag = 0;
|
||||||
|
char c = 0;
|
||||||
|
|
||||||
|
info.clear().reserve(32);
|
||||||
|
if (*source == '^')
|
||||||
{
|
{
|
||||||
if (*source == esc) source++;
|
notflag = 1;
|
||||||
info.append(*source++);
|
source++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset(info(1), 255, 32);
|
||||||
|
}
|
||||||
|
if (*source == ']')
|
||||||
|
{
|
||||||
|
markbit(info, notflag, *source++);
|
||||||
|
}
|
||||||
|
for (; *source && *source != ']'; source++)
|
||||||
|
{
|
||||||
|
if (*source == esc)
|
||||||
|
{
|
||||||
|
markbit(info, notflag, *++source);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*source == '-' && c && source[1] && source[1] != ']')
|
||||||
|
{
|
||||||
|
source++;
|
||||||
|
while (c < *source) markbit(info, notflag, c++);
|
||||||
|
while (c > *source) markbit(info, notflag, c--);
|
||||||
|
}
|
||||||
|
c = *source;
|
||||||
|
markbit(info, notflag, c);
|
||||||
}
|
}
|
||||||
if (!*source) {
|
if (!*source) {
|
||||||
error("Missing ']' after %%[ format conversion\n");
|
error("Missing ']' after %%[ format conversion\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
source++; // consume ']'
|
source++; // consume ']'
|
||||||
info.append("]%n");
|
|
||||||
return string_format;
|
return string_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,33 +673,31 @@ int StdCharsetConverter::
|
|||||||
scanString(const StreamFormat& fmt, const char* input,
|
scanString(const StreamFormat& fmt, const char* input,
|
||||||
char* value, size_t maxlen)
|
char* value, size_t maxlen)
|
||||||
{
|
{
|
||||||
int length = -1;
|
int length = 0;
|
||||||
if (fmt.flags & skip_flag)
|
|
||||||
|
int width = fmt.width;
|
||||||
|
const char mask [8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
|
||||||
|
|
||||||
|
if ((fmt.flags & skip_flag) || value == NULL) maxlen = 0;
|
||||||
|
|
||||||
|
// if user does not specify width assume "ininity" (-1)
|
||||||
|
if (width == 0) width = -1;
|
||||||
|
|
||||||
|
while (*input && width)
|
||||||
{
|
{
|
||||||
/* can't use return value on vxWorks: sscanf with %* format
|
if (fmt.info[*input>>3] & mask[*input&7]) break;
|
||||||
returns -1 at end of string whether value is found or not */
|
if (maxlen > 1)
|
||||||
sscanf(input, fmt.info, &length);
|
{
|
||||||
|
*value++ = *input;
|
||||||
|
maxlen--;
|
||||||
|
}
|
||||||
|
length++;
|
||||||
|
width--;
|
||||||
|
input++;
|
||||||
}
|
}
|
||||||
else
|
if (maxlen > 0)
|
||||||
{
|
{
|
||||||
char tmpformat[256];
|
*value = '\0';
|
||||||
const char* f;
|
|
||||||
if (maxlen <= fmt.width || fmt.width == 0)
|
|
||||||
{
|
|
||||||
const char *p = strchr (fmt.info, '[');
|
|
||||||
// assure not to read too much
|
|
||||||
sprintf(tmpformat, "%%%ld%s", (long)maxlen-1, p);
|
|
||||||
f = tmpformat;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
f = fmt.info;
|
|
||||||
}
|
|
||||||
if (sscanf(input, f, value, &length) < 1) return -1;
|
|
||||||
if (length < 0) return -1;
|
|
||||||
value[length] = '\0';
|
|
||||||
debug("StdCharsetConverter::scanString: length=%d, value=%s\n",
|
|
||||||
length, value);
|
|
||||||
}
|
}
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user