sscanf removed from %c and %[]

This commit is contained in:
zimoch
2010-11-29 15:26:05 +00:00
parent 7836af6423
commit 29ac760f0e

View File

@ -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;
} }