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
// GNU's sscanf implementation sucks. It calls strlen on the buffer.
// 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 vxWorks implementation sucks, too. When all parsed values are skipped
// 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))
{
error("Use of modifiers '+', '0'"
"not allowed with %%%c conversion\n",
fmt.conv);
"not allowed with %%s conversion\n");
return false;
}
if (scanFormat && fmt.prec >= 0)
@ -477,7 +476,7 @@ scanString(const StreamFormat& fmt, const char* input,
{
// normally leading whitespace does not count to width
// but do so if space flag is present
if (fmt.flags & space_flag || fmt.conv == 'c')
if (fmt.flags & space_flag)
{
if (maxlen > 1)
{
@ -493,7 +492,7 @@ scanString(const StreamFormat& fmt, const char* input,
{
// normally whitespace ends string
// 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)
{
*value++ = *input;
@ -514,11 +513,11 @@ RegisterConverter (StdStringConverter, "s");
// Standard Characters Converter for 'c'
class StdCharsConverter : public StdStringConverter
class StdCharsConverter : public StreamFormatConverter
{
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
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::
@ -528,8 +527,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
if (fmt.flags & (sign_flag|space_flag|zero_flag|alt_flag))
{
error("Use of modifiers '+', ' ', '0', '#' "
"not allowed with %%%c conversion\n",
fmt.conv);
"not allowed with %%c conversion\n");
return false;
}
if (scanFormat && fmt.prec >= 0)
@ -555,6 +553,37 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
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");
// Standard Charset Converter for '['
@ -566,6 +595,16 @@ class StdCharsetConverter : public StreamFormatConverter
// 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::
parse(const StreamFormat& fmt, StreamBuffer& info,
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))
{
error("Use of modifiers '-', '+', ' ', '0', '#'"
"not allowed with %%%c conversion\n",
fmt.conv);
"not allowed with %%[ conversion\n");
return false;
}
if (scanFormat && fmt.prec >= 0)
@ -588,18 +626,46 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
fmt.prec, fmt.conv);
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++;
info.append(*source++);
notflag = 1;
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) {
error("Missing ']' after %%[ format conversion\n");
return false;
}
source++; // consume ']'
info.append("]%n");
return string_format;
}
@ -607,33 +673,31 @@ int StdCharsetConverter::
scanString(const StreamFormat& fmt, const char* input,
char* value, size_t maxlen)
{
int length = -1;
if (fmt.flags & skip_flag)
int length = 0;
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
returns -1 at end of string whether value is found or not */
sscanf(input, fmt.info, &length);
if (fmt.info[*input>>3] & mask[*input&7]) break;
if (maxlen > 1)
{
*value++ = *input;
maxlen--;
}
length++;
width--;
input++;
}
else
if (maxlen > 0)
{
char tmpformat[256];
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);
*value = '\0';
}
return length;
}