changed streamScanfN to return number of read bytes

This commit is contained in:
2018-06-06 15:52:55 +02:00
parent 0dfcc0f511
commit 9f6d4ab63f
19 changed files with 272 additions and 233 deletions

View File

@ -27,7 +27,7 @@ class BCDConverter : public StreamFormatConverter
{ {
int parse (const StreamFormat&, StreamBuffer&, const char*&, bool); int parse (const StreamFormat&, StreamBuffer&, const char*&, bool);
bool printLong(const StreamFormat&, StreamBuffer&, long); bool printLong(const StreamFormat&, StreamBuffer&, long);
int scanLong(const StreamFormat&, const char*, long&); long scanLong(const StreamFormat&, const char*, long&);
}; };
int BCDConverter:: int BCDConverter::
@ -39,64 +39,65 @@ parse(const StreamFormat& fmt, StreamBuffer&, const char*&, bool)
bool BCDConverter:: bool BCDConverter::
printLong(const StreamFormat& fmt, StreamBuffer& output, long value) printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
{ {
unsigned char bcd[6]={0,0,0,0,0,0}; // sufficient for 2^32 unsigned char bcd;
int i; bool neg = false;
int prec = fmt.prec; // number of nibbles long i;
if (prec == -1) unsigned long prec = fmt.prec < 0 ? 2 * sizeof(value) : fmt.prec; // number of nibbles
{ unsigned long width = (prec + (fmt.flags & sign_flag ? 2 : 1)) / 2;
prec = 2 * sizeof (value);
}
int width = (prec + (fmt.flags & sign_flag ? 2 : 1)) / 2;
if (fmt.width > width) width = fmt.width; if (fmt.width > width) width = fmt.width;
if (fmt.flags & sign_flag && value < 0) if (fmt.flags & sign_flag && value < 0 && prec > 0)
{ {
// negative BCD value, I hope "F" as "-" is OK neg = true;
bcd[5] = 0xF0;
value = -value; value = -value;
} }
if (prec > 10) prec = 10;
for (i = 0; i < prec; i++)
{
bcd[i/2] |= (value % 10) << (4 * (i & 1));
value /= 10;
}
if (fmt.flags & alt_flag) if (fmt.flags & alt_flag)
{ {
// least significant byte first (little endian) // least significant byte first (little endian)
for (i = 0; i < (prec + 1) / 2; i++) while (width-- && prec)
{ {
output.append(bcd[i]); bcd = value%10;
if (--prec)
{
--prec;
value /= 10;
bcd |= (value%10)<<4;
value /= 10;
}
output.append(bcd);
} }
for (; i < width; i++) if (width)
{ output.append('\0', width);
output.append('\0'); if (neg) output[-1] |= 0xf0;
}
output[-1] |= bcd[5];
} }
else else
{ {
// most significant byte first (big endian) // most significant byte first (big endian)
int firstbyte = output.length(); output.append('\0', width);
for (i = 0; i < width - (prec + 1) / 2; i++) if (neg) output[-width] |= 0xf0;
i = 0;
while (width-- && prec)
{ {
output.append('\0'); bcd = value%10;
if (--prec)
{
--prec;
value /= 10;
bcd |= (value%10)<<4;
value /= 10;
}
output[--i]=bcd;
} }
for (i = (prec - 1) / 2; i >= 0; i--)
{
output.append(bcd[i]);
}
output[firstbyte] |= bcd[5];
} }
return true; return true;
} }
int BCDConverter:: long BCDConverter::
scanLong(const StreamFormat& fmt, const char* input, long& value) scanLong(const StreamFormat& fmt, const char* input, long& value)
{ {
int length = 0; long length = 0;
int val = 0; long val = 0;
unsigned char bcd1, bcd10; unsigned char bcd1, bcd10;
int width = fmt.width; long width = fmt.width;
if (width == 0) width = 1; if (width == 0) width = 1;
if (fmt.flags & alt_flag) if (fmt.flags & alt_flag)
{ {

View File

@ -29,7 +29,7 @@ class BinaryConverter : public StreamFormatConverter
{ {
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool); int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
bool printLong(const StreamFormat&, StreamBuffer&, long); bool printLong(const StreamFormat&, StreamBuffer&, long);
int scanLong(const StreamFormat&, const char*, long&); long scanLong(const StreamFormat&, const char*, long&);
}; };
int BinaryConverter:: int BinaryConverter::
@ -77,7 +77,7 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
if (x <= 0x3FFFFFFF) { prec -= 2; x <<=2; } if (x <= 0x3FFFFFFF) { prec -= 2; x <<=2; }
if (x <= 0x7FFFFFFF) { prec -= 1; } if (x <= 0x7FFFFFFF) { prec -= 1; }
} }
int width = prec; unsigned long width = prec;
if (fmt.width > width) width = fmt.width; if (fmt.width > width) width = fmt.width;
char zero = fmt.info[0]; char zero = fmt.info[0];
char one = fmt.info[1]; char one = fmt.info[1];
@ -88,7 +88,7 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
if (!(fmt.flags & left_flag)) if (!(fmt.flags & left_flag))
{ {
// pad left // pad left
while (width > prec) while (width > (unsigned int)prec)
{ {
output.append(' '); output.append(' ');
width--; width--;
@ -112,7 +112,7 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
if (!(fmt.flags & left_flag)) if (!(fmt.flags & left_flag))
{ {
// pad left // pad left
while (width > prec) while (width > (unsigned int)prec)
{ {
output.append(fill); output.append(fill);
width--; width--;
@ -132,13 +132,13 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
return true; return true;
} }
int BinaryConverter:: long BinaryConverter::
scanLong(const StreamFormat& fmt, const char* input, long& value) scanLong(const StreamFormat& fmt, const char* input, long& value)
{ {
long val = 0; long val = 0;
int width = fmt.width; long width = fmt.width;
if (width == 0) width = -1; if (width == 0) width = -1;
int length = 0; long length = 0;
char zero = fmt.info[0]; char zero = fmt.info[0];
char one = fmt.info[1]; char one = fmt.info[1];
if (!isspace(zero) && !isspace(one)) if (!isspace(zero) && !isspace(one))

View File

@ -500,7 +500,7 @@ class ChecksumConverter : public StreamFormatConverter
{ {
int parse (const StreamFormat&, StreamBuffer&, const char*&, bool); int parse (const StreamFormat&, StreamBuffer&, const char*&, bool);
bool printPseudo(const StreamFormat&, StreamBuffer&); bool printPseudo(const StreamFormat&, StreamBuffer&);
int scanPseudo(const StreamFormat&, StreamBuffer&, long& cursor); long scanPseudo(const StreamFormat&, StreamBuffer&, long& cursor);
}; };
int ChecksumConverter:: int ChecksumConverter::
@ -535,7 +535,7 @@ parse(const StreamFormat&, StreamBuffer& info, const char*& source, bool)
source+=3; source+=3;
notflag = true; notflag = true;
} }
unsigned fnum; unsigned char fnum;
int len = p-source; int len = p-source;
unsigned int init, xorout; unsigned int init, xorout;
for (fnum = 0; fnum < sizeof(checksumMap)/sizeof(checksum); fnum++) for (fnum = 0; fnum < sizeof(checksumMap)/sizeof(checksum); fnum++)
@ -573,7 +573,7 @@ printPseudo(const StreamFormat& format, StreamBuffer& output)
const char* info = format.info; const char* info = format.info;
unsigned int init = extract<unsigned int>(info); unsigned int init = extract<unsigned int>(info);
unsigned int xorout = extract<unsigned int>(info); unsigned int xorout = extract<unsigned int>(info);
int fnum = extract<char>(info); unsigned char fnum = extract<unsigned char>(info);
int start = format.width; int start = format.width;
int length = output.length()-format.width; int length = output.length()-format.width;
@ -641,7 +641,7 @@ printPseudo(const StreamFormat& format, StreamBuffer& output)
return true; return true;
} }
int ChecksumConverter:: long ChecksumConverter::
scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor) scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
{ {
unsigned int sum; unsigned int sum;
@ -649,8 +649,8 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, long& cursor)
unsigned int init = extract<unsigned int>(info); unsigned int init = extract<unsigned int>(info);
unsigned int xorout = extract<unsigned int>(info); unsigned int xorout = extract<unsigned int>(info);
int start = format.width; int start = format.width;
int fnum = extract<char>(info); unsigned char fnum = extract<unsigned char>(info);
int length = cursor-format.width; long length = cursor-format.width;
if (format.prec > 0) length -= format.prec; if (format.prec > 0) length -= format.prec;

View File

@ -29,7 +29,7 @@ class EnumConverter : public StreamFormatConverter
{ {
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool); int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
bool printLong(const StreamFormat&, StreamBuffer&, long); bool printLong(const StreamFormat&, StreamBuffer&, long);
int scanLong(const StreamFormat&, const char*, long&); long scanLong(const StreamFormat&, const char*, long&);
}; };
// info format: <numEnums><index><string>0<index><string>0... // info format: <numEnums><index><string>0<index><string>0...
@ -148,7 +148,7 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
return true; return true;
} }
int EnumConverter:: long EnumConverter::
scanLong(const StreamFormat& fmt, const char* input, long& value) scanLong(const StreamFormat& fmt, const char* input, long& value)
{ {
debug("EnumConverter::scanLong(%%%c, \"%s\")\n", debug("EnumConverter::scanLong(%%%c, \"%s\")\n",
@ -156,7 +156,7 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
const char* s = fmt.info; const char* s = fmt.info;
long numEnums = extract<long>(s); long numEnums = extract<long>(s);
long index; long index;
int length; long length;
bool match; bool match;
while (numEnums--) while (numEnums--)

View File

@ -39,7 +39,7 @@
class MantissaExponentConverter : public StreamFormatConverter class MantissaExponentConverter : public StreamFormatConverter
{ {
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool); virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
virtual int scanDouble(const StreamFormat&, const char*, double&); virtual long scanDouble(const StreamFormat&, const char*, double&);
virtual bool printDouble(const StreamFormat&, StreamBuffer&, double); virtual bool printDouble(const StreamFormat&, StreamBuffer&, double);
}; };
@ -50,7 +50,7 @@ parse(const StreamFormat&, StreamBuffer&,
return double_format; return double_format;
} }
int MantissaExponentConverter:: long MantissaExponentConverter::
scanDouble(const StreamFormat& fmt, const char* input, double& value) scanDouble(const StreamFormat& fmt, const char* input, double& value)
{ {
int mantissa; int mantissa;

View File

@ -27,7 +27,7 @@ class RawConverter : public StreamFormatConverter
{ {
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool); int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
bool printLong(const StreamFormat&, StreamBuffer&, long); bool printLong(const StreamFormat&, StreamBuffer&, long);
int scanLong(const StreamFormat&, const char*, long&); long scanLong(const StreamFormat&, const char*, long&);
}; };
int RawConverter:: int RawConverter::
@ -40,10 +40,9 @@ parse(const StreamFormat& fmt, StreamBuffer&,
bool RawConverter:: bool RawConverter::
printLong(const StreamFormat& fmt, StreamBuffer& output, long value) printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
{ {
int prec = fmt.prec; // number of bytes from value unsigned int prec = fmt.prec < 0 ? 1 : fmt.prec; // number of bytes from value, default 1
if (prec == -1) prec = 1; // default: 1 byte unsigned long width = prec; // number of bytes in output
int width = prec; // number of bytes in output if (prec > sizeof(long)) prec=sizeof(long);
if (prec > (int)sizeof(long)) prec=sizeof(long);
if (fmt.width > width) width = fmt.width; if (fmt.width > width) width = fmt.width;
char byte = 0; char byte = 0;
@ -96,12 +95,12 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
return true; return true;
} }
int RawConverter:: long RawConverter::
scanLong(const StreamFormat& fmt, const char* input, long& value) scanLong(const StreamFormat& fmt, const char* input, long& value)
{ {
long length = 0; long length = 0;
long val = 0; long val = 0;
int width = fmt.width; unsigned long width = fmt.width;
if (width == 0) width = 1; // default: 1 byte if (width == 0) width = 1; // default: 1 byte
if (fmt.flags & skip_flag) if (fmt.flags & skip_flag)
{ {

View File

@ -29,7 +29,7 @@ class RawFloatConverter : public StreamFormatConverter
{ {
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool); int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
bool printDouble(const StreamFormat&, StreamBuffer&, double); bool printDouble(const StreamFormat&, StreamBuffer&, double);
int scanDouble(const StreamFormat&, const char*, double&); long scanDouble(const StreamFormat&, const char*, double&);
}; };
int RawFloatConverter:: int RawFloatConverter::
@ -90,7 +90,7 @@ printDouble(const StreamFormat& format, StreamBuffer& output, double value)
return true; return true;
} }
int RawFloatConverter:: long RawFloatConverter::
scanDouble(const StreamFormat& format, const char* input, double& value) scanDouble(const StreamFormat& format, const char* input, double& value)
{ {
int nbOfBytes; int nbOfBytes;

View File

@ -38,8 +38,8 @@
class RegexpConverter : public StreamFormatConverter class RegexpConverter : public StreamFormatConverter
{ {
int parse (const StreamFormat& fmt, StreamBuffer&, const char*&, bool); int parse (const StreamFormat& fmt, StreamBuffer&, const char*&, bool);
int scanString(const StreamFormat& fmt, const char*, char*, size_t); long scanString(const StreamFormat& fmt, const char*, char*, unsigned long&);
int scanPseudo(const StreamFormat& fmt, StreamBuffer& input, long& cursor); long scanPseudo(const StreamFormat& fmt, StreamBuffer& input, long& cursor);
bool printPseudo(const StreamFormat& fmt, StreamBuffer& output); bool printPseudo(const StreamFormat& fmt, StreamBuffer& output);
}; };
@ -54,7 +54,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
} }
if (fmt.prec > 9) if (fmt.prec > 9)
{ {
error("Subexpression index %d too big (>9)\n", fmt.prec); error("Subexpression index %ld too big (>9)\n", fmt.prec);
return false; return false;
} }
@ -115,14 +115,13 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
return string_format; return string_format;
} }
int RegexpConverter:: long RegexpConverter::
scanString(const StreamFormat& fmt, const char* input, scanString(const StreamFormat& fmt, const char* input,
char* value, size_t maxlen) char* value, unsigned long& size)
{ {
int ovector[30]; int ovector[30];
int rc; int rc;
unsigned int l; unsigned int l;
const char* info = fmt.info; const char* info = fmt.info;
pcre* code = extract<pcre*>(info); pcre* code = extract<pcre*>(info);
int length = fmt.width > 0 ? fmt.width : strlen(input); int length = fmt.width > 0 ? fmt.width : strlen(input);
@ -141,17 +140,18 @@ scanString(const StreamFormat& fmt, const char* input,
if (fmt.flags & skip_flag) return ovector[subexpr*2+1]; if (fmt.flags & skip_flag) return ovector[subexpr*2+1];
l = ovector[subexpr*2+1] - ovector[subexpr*2]; l = ovector[subexpr*2+1] - ovector[subexpr*2];
if (l >= maxlen) { if (l >= size) {
if (!(fmt.flags & sign_flag)) { if (!(fmt.flags & sign_flag)) {
error("Regexp: Matching string \"%s\" too long (%d>%ld bytes). You may want to try the + flag: \"%%+/.../\"\n", error("Regexp: Matching string \"%s\" too long (%d>%ld bytes). You may want to try the + flag: \"%%+/.../\"\n",
StreamBuffer(input + ovector[subexpr*2],l).expand()(), StreamBuffer(input + ovector[subexpr*2],l).expand()(),
l, (long)maxlen-1); l, (long)size-1);
return -1; return -1;
} }
l = maxlen-1; l = size-1;
} }
memcpy(value, input + ovector[subexpr*2], l); memcpy(value, input + ovector[subexpr*2], l);
value[l] = '\0'; value[l] = '\0';
size = l+1; // update number of bytes written to value
return ovector[1]; // consume input until end of match return ovector[1]; // consume input until end of match
} }
@ -159,8 +159,8 @@ static void regsubst(const StreamFormat& fmt, StreamBuffer& buffer, long start)
{ {
const char* subst = fmt.info; const char* subst = fmt.info;
pcre* code = extract<pcre*>(subst); pcre* code = extract<pcre*>(subst);
long length; unsigned long length, c;
int rc, l, c, r, rl, n; int rc, l, r, rl, n;
int ovector[30]; int ovector[30];
StreamBuffer s; StreamBuffer s;
@ -176,7 +176,7 @@ static void regsubst(const StreamFormat& fmt, StreamBuffer& buffer, long start)
for (c = 0, n = 1; c < length; n++) for (c = 0, n = 1; c < length; n++)
{ {
rc = pcre_exec(code, NULL, buffer(start+c), length-c, 0, 0, ovector, 30); rc = pcre_exec(code, NULL, buffer(start+c), length-c, 0, 0, ovector, 30);
debug("pcre_exec match \"%.*s\" result = %d\n", (int)length-c, buffer(start+c), rc); debug("pcre_exec match \"%.*s\" result = %d\n", (int)(length-c), buffer(start+c), rc);
if (rc < 0) // no match if (rc < 0) // no match
return; return;
@ -229,7 +229,7 @@ static void regsubst(const StreamFormat& fmt, StreamBuffer& buffer, long start)
} }
} }
int RegexpConverter:: long RegexpConverter::
scanPseudo(const StreamFormat& fmt, StreamBuffer& input, long& cursor) scanPseudo(const StreamFormat& fmt, StreamBuffer& input, long& cursor)
{ {
/* re-write input buffer */ /* re-write input buffer */

View File

@ -1215,6 +1215,7 @@ normal_format:
{ {
long ldummy; long ldummy;
double ddummy; double ddummy;
long unsigned size=0;
switch (fmt.type) switch (fmt.type)
{ {
case unsigned_format: case unsigned_format:
@ -1229,7 +1230,7 @@ normal_format:
break; break;
case string_format: case string_format:
consumed = StreamFormatConverter::find(fmt.conv)-> consumed = StreamFormatConverter::find(fmt.conv)->
scanString(fmt, inputLine(consumedInput), NULL, 0); scanString(fmt, inputLine(consumedInput), NULL, size);
break; break;
case pseudo_format: case pseudo_format:
// pass complete input // pass complete input
@ -1482,7 +1483,7 @@ scanValue(const StreamFormat& fmt, long& value)
} }
else return -1; else return -1;
} }
if (fmt.flags & fix_width_flag && consumed != fmt.width) return -1; if (fmt.flags & fix_width_flag && (unsigned long)consumed != fmt.width) return -1;
if (consumed > inputLine.length()-consumedInput) return -1; if (consumed > inputLine.length()-consumedInput) return -1;
debug("StreamCore::scanValue(%s) scanned %li\n", debug("StreamCore::scanValue(%s) scanned %li\n",
name(), value); name(), value);
@ -1514,7 +1515,7 @@ scanValue(const StreamFormat& fmt, double& value)
} }
else return -1; else return -1;
} }
if (fmt.flags & fix_width_flag && (consumed != (fmt.width + fmt.prec + 1))) return -1; if (fmt.flags & fix_width_flag && ((unsigned long)consumed != (fmt.width + fmt.prec + 1))) return -1;
if (consumed > inputLine.length()-consumedInput) return -1; if (consumed > inputLine.length()-consumedInput) return -1;
debug("StreamCore::scanValue(%s) scanned %#g\n", debug("StreamCore::scanValue(%s) scanned %#g\n",
name(), value); name(), value);
@ -1523,7 +1524,7 @@ scanValue(const StreamFormat& fmt, double& value)
} }
long StreamCore:: long StreamCore::
scanValue(const StreamFormat& fmt, char* value, long maxlen) scanValue(const StreamFormat& fmt, char* value, unsigned long& size)
{ {
if (fmt.type != string_format) if (fmt.type != string_format)
{ {
@ -1531,13 +1532,12 @@ scanValue(const StreamFormat& fmt, char* value, long maxlen)
name(), fmt.conv); name(), fmt.conv);
return -1; return -1;
} }
if (maxlen < 0) maxlen = 0;
flags |= ScanTried; flags |= ScanTried;
if (!matchSeparator()) return -1; if (!matchSeparator()) return -1;
long consumed = StreamFormatConverter::find(fmt.conv)-> long consumed = StreamFormatConverter::find(fmt.conv)->
scanString(fmt, inputLine(consumedInput), value, maxlen); scanString(fmt, inputLine(consumedInput), value, size);
debug("StreamCore::scanValue(%s, format=%%%c, char*, maxlen=%ld) input=\"%s\"\n", debug("StreamCore::scanValue(%s, format=%%%c, char*, size=%ld) input=\"%s\"\n",
name(), fmt.conv, maxlen, inputLine.expand(consumedInput)()); name(), fmt.conv, size, inputLine.expand(consumedInput)());
if (consumed < 0) if (consumed < 0)
{ {
if (fmt.flags & default_flag) if (fmt.flags & default_flag)
@ -1547,11 +1547,11 @@ scanValue(const StreamFormat& fmt, char* value, long maxlen)
} }
else return -1; else return -1;
} }
if (fmt.flags & fix_width_flag && consumed != fmt.width) return -1; if (fmt.flags & fix_width_flag && (unsigned long)consumed != fmt.width) return -1;
if (consumed > inputLine.length()-consumedInput) return -1; if (consumed > inputLine.length()-consumedInput) return -1;
#ifndef NO_TEMPORARY #ifndef NO_TEMPORARY
debug("StreamCore::scanValue(%s) scanned \"%s\"\n", debug("StreamCore::scanValue(%s) scanned \"%s\"\n",
name(), StreamBuffer(value, maxlen).expand()()); name(), StreamBuffer(value, size).expand()());
#endif #endif
flags |= GotValue; flags |= GotValue;
return consumed; return consumed;

View File

@ -137,7 +137,7 @@ protected:
bool printValue(const StreamFormat& format, char* value); bool printValue(const StreamFormat& format, char* value);
long scanValue(const StreamFormat& format, long& value); long scanValue(const StreamFormat& format, long& value);
long scanValue(const StreamFormat& format, double& value); long scanValue(const StreamFormat& format, double& value);
long scanValue(const StreamFormat& format, char* value, long maxlen); long scanValue(const StreamFormat& format, char* value, unsigned long& size);
long scanValue(const StreamFormat& format); long scanValue(const StreamFormat& format);
StreamBuffer protocolname; StreamBuffer protocolname;

View File

@ -157,7 +157,7 @@ class Stream : protected StreamCore
long initRecord(const char* filename, const char* protocol, long initRecord(const char* filename, const char* protocol,
const char* busname, int addr, const char* busparam); const char* busname, int addr, const char* busparam);
bool print(format_t *format, va_list ap); bool print(format_t *format, va_list ap);
bool scan(format_t *format, void* pvalue, size_t maxStringSize); long scan(format_t *format, void* pvalue, size_t maxStringSize);
bool process(); bool process();
// device support functions // device support functions
@ -554,19 +554,21 @@ long streamPrintf(dbCommon *record, format_t *format, ...)
long streamScanfN(dbCommon* record, format_t *format, long streamScanfN(dbCommon* record, format_t *format,
void* value, size_t maxStringSize) void* value, size_t maxStringSize)
{ {
long size;
debug("streamScanfN(%s,format=%%%c,maxStringSize=%ld)\n", debug("streamScanfN(%s,format=%%%c,maxStringSize=%ld)\n",
record->name, format->priv->conv, (long)maxStringSize); record->name, format->priv->conv, (long)maxStringSize);
Stream* pstream = (Stream*)record->dpvt; Stream* pstream = (Stream*)record->dpvt;
if (!pstream) return ERROR; if (!pstream) return ERROR;
if (!pstream->scan(format, value, maxStringSize)) size = pstream->scan(format, value, maxStringSize);
if (size == ERROR)
{ {
return ERROR; debug("streamScanfN(%s) failed\n", record->name);
} }
#ifndef NO_TEMPORARY #ifndef NO_TEMPORARY
debug("streamScanfN(%s) success, value=\"%s\"\n", debug("streamScanfN(%s) success, value=\"%s\"\n",
record->name, StreamBuffer((char*)value).expand()()); record->name, StreamBuffer((char*)value).expand()());
#endif #endif
return OK; return size;
} }
// Stream methods //////////////////////////////////////////////////////// // Stream methods ////////////////////////////////////////////////////////
@ -800,11 +802,12 @@ print(format_t *format, va_list ap)
return false; return false;
} }
bool Stream:: long Stream::
scan(format_t *format, void* value, size_t maxStringSize) scan(format_t *format, void* value, size_t maxStringSize)
{ {
// called by streamScanfN // called by streamScanfN
unsigned long size = maxStringSize;
// first remove old value from inputLine (if we are scanning arrays) // first remove old value from inputLine (if we are scanning arrays)
consumedInput += currentValueLength; consumedInput += currentValueLength;
currentValueLength = 0; currentValueLength = 0;
@ -820,20 +823,17 @@ scan(format_t *format, void* value, size_t maxStringSize)
break; break;
case DBF_STRING: case DBF_STRING:
currentValueLength = scanValue(*format->priv, (char*)value, currentValueLength = scanValue(*format->priv, (char*)value,
maxStringSize); size);
break; break;
default: default:
error("INTERNAL ERROR (%s): Illegal format type\n", name()); error("INTERNAL ERROR (%s): Illegal format type\n", name());
return false; return ERROR;
}
if (currentValueLength < 0)
{
currentValueLength = 0;
return false;
} }
// Don't remove scanned value from inputLine yet, because // Don't remove scanned value from inputLine yet, because
// we might need the string in a later error message. // we might need the string in a later error message.
return true; if (currentValueLength == ERROR) return ERROR;
if (format->type == DBF_STRING) return size;
return OK;
} }
// epicsTimerNotify virtual method /////////////////////////////////////// // epicsTimerNotify virtual method ///////////////////////////////////////
@ -1163,6 +1163,7 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
int status; int status;
const char* putfunc; const char* putfunc;
format_s fmt; format_s fmt;
unsigned long stringsize = MAX_STRING_SIZE;
fmt.type = dbfMapping[format.type]; fmt.type = dbfMapping[format.type];
fmt.priv = &format; fmt.priv = &format;
@ -1172,10 +1173,18 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
// to field of this or other record. // to field of this or other record.
StreamBuffer fieldBuffer; StreamBuffer fieldBuffer;
DBADDR* pdbaddr = (DBADDR*)fieldaddress; DBADDR* pdbaddr = (DBADDR*)fieldaddress;
long nord; size_t size;
long nelem = pdbaddr->no_elements; unsigned long nord;
size_t size = nelem * dbValueSize(fmt.type); unsigned long nelem = pdbaddr->no_elements;
buffer = fieldBuffer.clear().reserve(size); if (format.type == string_format &&
(pdbaddr->field_type == DBF_CHAR || pdbaddr->field_type == DBF_UCHAR))
{
// string to char array
size = nelem;
}
else
size = nelem * dbValueSize(fmt.type);
buffer = fieldBuffer.clear().reserve(size); // maybe write to field directly in case types match?
for (nord = 0; nord < nelem; nord++) for (nord = 0; nord < nelem; nord++)
{ {
debug("Stream::matchValue(%s): buffer before: %s\n", debug("Stream::matchValue(%s): buffer before: %s\n",
@ -1232,24 +1241,27 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
} }
case string_format: case string_format:
{ {
if (pdbaddr->field_type == DBF_CHAR) if (pdbaddr->field_type == DBF_CHAR ||
pdbaddr->field_type == DBF_UCHAR)
{ {
// string to char array // string to char array
consumed = scanValue(format, buffer, nelem); stringsize = nelem;
consumed = scanValue(format, buffer, stringsize);
debug("Stream::matchValue(%s): %s.%s = \"%.*s\"\n", debug("Stream::matchValue(%s): %s.%s = \"%.*s\"\n",
name(), pdbaddr->precord->name, name(), pdbaddr->precord->name,
((dbFldDes*)pdbaddr->pfldDes)->name, ((dbFldDes*)pdbaddr->pfldDes)->name,
(int)consumed, buffer); (int)consumed, buffer);
nord = nelem; nord = nelem; // this shortcuts the loop
} }
else else
{ {
stringsize = MAX_STRING_SIZE;
consumed = scanValue(format, consumed = scanValue(format,
buffer+MAX_STRING_SIZE*nord, MAX_STRING_SIZE); buffer+MAX_STRING_SIZE*nord, stringsize);
debug("Stream::matchValue(%s): %s.%s[%li] = \"%.*s\"\n", debug("Stream::matchValue(%s): %s.%s[%li] = \"%.*s\"\n",
name(), pdbaddr->precord->name, name(), pdbaddr->precord->name,
((dbFldDes*)pdbaddr->pfldDes)->name, ((dbFldDes*)pdbaddr->pfldDes)->name,
nord, MAX_STRING_SIZE, buffer+MAX_STRING_SIZE*nord); nord, (int)stringsize, buffer+MAX_STRING_SIZE*nord);
} }
break; break;
} }
@ -1290,7 +1302,7 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
/* convert from Unix epoch (1 Jan 1970) to EPICS epoch (1 Jan 1990) */ /* convert from Unix epoch (1 Jan 1970) to EPICS epoch (1 Jan 1990) */
dval = dval-631152000u; dval = dval-631152000u;
pdbaddr->precord->time.secPastEpoch = (long)dval; pdbaddr->precord->time.secPastEpoch = (long)dval;
// rouding: we don't have 9 digits precision // rounding: we don't have 9 digits precision
// in a double of today's number of seconds // in a double of today's number of seconds
pdbaddr->precord->time.nsec = (long)((dval-(long)dval)*1e6)*1000; pdbaddr->precord->time.nsec = (long)((dval-(long)dval)*1e6)*1000;
debug("Stream::matchValue(%s): writing %i.%i to %s.TIME field\n", debug("Stream::matchValue(%s): writing %i.%i to %s.TIME field\n",
@ -1307,10 +1319,11 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
#endif #endif
} }
if (format.type == string_format && if (format.type == string_format &&
(pdbaddr->field_type == DBF_CHAR || pdbaddr->field_type == DBF_UCHAR)) (pdbaddr->field_type == DBF_CHAR ||
pdbaddr->field_type == DBF_UCHAR))
{ {
/* write strings to [U]CHAR arrays */ /* write strings to [U]CHAR arrays */
nord = consumed; nord = stringsize;
fmt.type = DBF_CHAR; fmt.type = DBF_CHAR;
} }
if (pdbaddr->precord == record || INIT_RUN) if (pdbaddr->precord == record || INIT_RUN)
@ -1349,25 +1362,26 @@ matchValue(const StreamFormat& format, const void* fieldaddress)
case DBF_ULONG: case DBF_ULONG:
case DBF_LONG: case DBF_LONG:
case DBF_ENUM: case DBF_ENUM:
error("%s: %s(%s.%s, %s, %li) failed\n", error("%s: %s(%s.%s, %s, %li, %lu) failed\n",
name(), putfunc, pdbaddr->precord->name, name(), putfunc, pdbaddr->precord->name,
((dbFldDes*)pdbaddr->pfldDes)->name, ((dbFldDes*)pdbaddr->pfldDes)->name,
pamapdbfType[fmt.type].strvalue, pamapdbfType[fmt.type].strvalue,
lval); lval, nord);
return false; return false;
case DBF_DOUBLE: case DBF_DOUBLE:
error("%s: %s(%s.%s, %s, %#g) failed\n", error("%s: %s(%s.%s, %s, %#g, %lu) failed\n",
name(), putfunc, pdbaddr->precord->name, name(), putfunc, pdbaddr->precord->name,
((dbFldDes*)pdbaddr->pfldDes)->name, ((dbFldDes*)pdbaddr->pfldDes)->name,
pamapdbfType[fmt.type].strvalue, pamapdbfType[fmt.type].strvalue,
dval); dval, nord);
return false; return false;
case DBF_STRING: case DBF_STRING:
error("%s: %s(%s.%s, %s, \"%.*s\") failed\n", case DBF_CHAR:
error("%s: %s(%s.%s, %s, \"%.*s\", %lu) failed\n",
name(), putfunc, pdbaddr->precord->name, name(), putfunc, pdbaddr->precord->name,
((dbFldDes*)pdbaddr->pfldDes)->name, ((dbFldDes*)pdbaddr->pfldDes)->name,
pamapdbfType[fmt.type].strvalue, pamapdbfType[fmt.type].strvalue,
(int)consumed, buffer); (int)consumed, buffer, nord);
return false; return false;
default: default:
return false; return false;

View File

@ -50,9 +50,9 @@ typedef struct StreamFormat
char conv; char conv;
StreamFormatType type; StreamFormatType type;
unsigned short flags; unsigned short flags;
short prec; long prec;
unsigned short width; unsigned long width;
unsigned short infolen; unsigned long infolen;
const char* info; const char* info;
} StreamFormat; } StreamFormat;

View File

@ -113,12 +113,12 @@ parseFormat(const char*& source, FormatType formatType, StreamFormat& streamForm
char* p; char* p;
val = strtoul (source, &p, 10); val = strtoul (source, &p, 10);
source = p; source = p;
if (val > 0xFFFF) if (val > LONG_MAX)
{ {
error("Field width %ld out of range\n", val); error("Field width %ld out of range\n", val);
return false; return false;
} }
streamFormat.width = (unsigned short)val; streamFormat.width = val;
// look for prec // look for prec
streamFormat.prec = -1; streamFormat.prec = -1;
if (*source == '.') if (*source == '.')
@ -132,7 +132,7 @@ parseFormat(const char*& source, FormatType formatType, StreamFormat& streamForm
return false; return false;
} }
source = p; source = p;
if (val > 0x7FFF) if (val > SHRT_MAX)
{ {
error("Precision %ld out of range\n", val); error("Precision %ld out of range\n", val);
return false; return false;
@ -205,7 +205,7 @@ printPseudo(const StreamFormat& fmt, StreamBuffer&)
return false; return false;
} }
int StreamFormatConverter:: long StreamFormatConverter::
scanLong(const StreamFormat& fmt, const char*, long&) scanLong(const StreamFormat& fmt, const char*, long&)
{ {
error("Unimplemented scanLong method for %%%c format\n", error("Unimplemented scanLong method for %%%c format\n",
@ -213,7 +213,7 @@ scanLong(const StreamFormat& fmt, const char*, long&)
return -1; return -1;
} }
int StreamFormatConverter:: long StreamFormatConverter::
scanDouble(const StreamFormat& fmt, const char*, double&) scanDouble(const StreamFormat& fmt, const char*, double&)
{ {
error("Unimplemented scanDouble method for %%%c format\n", error("Unimplemented scanDouble method for %%%c format\n",
@ -221,15 +221,15 @@ scanDouble(const StreamFormat& fmt, const char*, double&)
return -1; return -1;
} }
int StreamFormatConverter:: long StreamFormatConverter::
scanString(const StreamFormat& fmt, const char*, char*, size_t) scanString(const StreamFormat& fmt, const char*, char*, unsigned long&)
{ {
error("Unimplemented scanString method for %%%c format\n", error("Unimplemented scanString method for %%%c format\n",
fmt.conv); fmt.conv);
return -1; return -1;
} }
int StreamFormatConverter:: long StreamFormatConverter::
scanPseudo(const StreamFormat& fmt, StreamBuffer&, long&) scanPseudo(const StreamFormat& fmt, StreamBuffer&, long&)
{ {
error("Unimplemented scanPseudo method for %%%c format\n", error("Unimplemented scanPseudo method for %%%c format\n",
@ -255,11 +255,11 @@ static void copyFormatString(StreamBuffer& info, const char* source)
// Standard Long Converter for 'diouxX' // Standard Long Converter for 'diouxX'
static int prepareval(const StreamFormat& fmt, const char*& input, bool& neg) static long prepareval(const StreamFormat& fmt, const char*& input, bool& neg)
{ {
int length = 0; long consumed = 0;
neg = false; neg = false;
while (isspace(*input)) { input++; length++; } while (isspace(*input)) { input++; consumed++; }
if (fmt.width) if (fmt.width)
{ {
// take local copy because strto* don't have width parameter // take local copy because strto* don't have width parameter
@ -268,7 +268,7 @@ static int prepareval(const StreamFormat& fmt, const char*& input, bool& neg)
{ {
// normally whitespace does not count to width // normally whitespace does not count to width
// but do so if space flag is present // but do so if space flag is present
width -= length; width -= consumed;
} }
strncpy((char*)fmt.info, input, width); strncpy((char*)fmt.info, input, width);
((char*)fmt.info)[width] = 0; ((char*)fmt.info)[width] = 0;
@ -283,21 +283,21 @@ static int prepareval(const StreamFormat& fmt, const char*& input, bool& neg)
neg = true; neg = true;
skipsign: skipsign:
input++; input++;
length++; consumed++;
} }
if (isspace(*input)) if (isspace(*input))
{ {
// allow space after sign only if # flag is set // allow space after sign only if # flag is set
if (!(fmt.flags & alt_flag)) return -1; if (!(fmt.flags & alt_flag)) return -1;
} }
return length; return consumed;
} }
class StdLongConverter : public StreamFormatConverter class StdLongConverter : public StreamFormatConverter
{ {
int parse(const StreamFormat& fmt, StreamBuffer& output, const char*& value, bool scanFormat); int parse(const StreamFormat& fmt, StreamBuffer& output, const char*& value, bool scanFormat);
bool printLong(const StreamFormat& fmt, StreamBuffer& output, long value); bool printLong(const StreamFormat& fmt, StreamBuffer& output, long value);
int scanLong(const StreamFormat& fmt, const char* input, long& value); long scanLong(const StreamFormat& fmt, const char* input, long& value);
}; };
int StdLongConverter:: int StdLongConverter::
@ -306,7 +306,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
{ {
if (scanFormat && fmt.prec >= 0) if (scanFormat && fmt.prec >= 0)
{ {
error("Use of precision field '.%d' not allowed with %%%c input conversion\n", error("Use of precision field '.%ld' not allowed with %%%c input conversion\n",
fmt.prec, fmt.conv); fmt.prec, fmt.conv);
return false; return false;
} }
@ -334,17 +334,17 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
return true; return true;
} }
int StdLongConverter:: long StdLongConverter::
scanLong(const StreamFormat& fmt, const char* input, long& value) scanLong(const StreamFormat& fmt, const char* input, long& value)
{ {
char* end; char* end;
int length; long consumed;
bool neg; bool neg;
int base; int base;
long v; long v;
length = prepareval(fmt, input, neg); consumed = prepareval(fmt, input, neg);
if (length < 0) return -1; if (consumed < 0) return -1;
switch (fmt.conv) switch (fmt.conv)
{ {
case 'd': case 'd':
@ -366,9 +366,9 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
} }
v = strtoul(input, &end, base); v = strtoul(input, &end, base);
if (end == input) return -1; if (end == input) return -1;
length += end-input; consumed += end-input;
value = neg ? -v : v; value = neg ? -v : v;
return length; return consumed;
} }
RegisterConverter (StdLongConverter, "diouxX"); RegisterConverter (StdLongConverter, "diouxX");
@ -379,7 +379,7 @@ class StdDoubleConverter : public StreamFormatConverter
{ {
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool); virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
virtual bool printDouble(const StreamFormat&, StreamBuffer&, double); virtual bool printDouble(const StreamFormat&, StreamBuffer&, double);
virtual int scanDouble(const StreamFormat&, const char*, double&); virtual long scanDouble(const StreamFormat&, const char*, double&);
}; };
int StdDoubleConverter:: int StdDoubleConverter::
@ -388,7 +388,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
{ {
if (scanFormat && fmt.prec >= 0) if (scanFormat && fmt.prec >= 0)
{ {
error("Use of precision field '.%d' not allowed with %%%c input conversion\n", error("Use of precision field '.%ld' not allowed with %%%c input conversion\n",
fmt.prec, fmt.conv); fmt.prec, fmt.conv);
return false; return false;
} }
@ -411,20 +411,20 @@ printDouble(const StreamFormat& fmt, StreamBuffer& output, double value)
return true; return true;
} }
int StdDoubleConverter:: long StdDoubleConverter::
scanDouble(const StreamFormat& fmt, const char* input, double& value) scanDouble(const StreamFormat& fmt, const char* input, double& value)
{ {
char* end; char* end;
int length; long consumed;
bool neg; bool neg;
length = prepareval(fmt, input, neg); consumed = prepareval(fmt, input, neg);
if (length < 0) return -1; if (consumed < 0) return -1;
value = strtod(input, &end); value = strtod(input, &end);
if (neg) value = -value; if (neg) value = -value;
if (end == input) return -1; if (end == input) return -1;
length += end-input; consumed += end-input;
return length; return consumed;
} }
RegisterConverter (StdDoubleConverter, "feEgG"); RegisterConverter (StdDoubleConverter, "feEgG");
@ -435,7 +435,7 @@ class StdStringConverter : public StreamFormatConverter
{ {
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool); virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
virtual bool printString(const StreamFormat&, StreamBuffer&, const char*); virtual bool printString(const StreamFormat&, StreamBuffer&, const char*);
virtual int scanString(const StreamFormat&, const char*, char*, size_t); virtual long scanString(const StreamFormat&, const char*, char*, unsigned long&);
}; };
int StdStringConverter:: int StdStringConverter::
@ -451,7 +451,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
} }
if (scanFormat && fmt.prec >= 0) if (scanFormat && fmt.prec >= 0)
{ {
error("Use of precision field '.%d' not allowed with %%%c input conversion\n", error("Use of precision field '.%ld' not allowed with %%%c input conversion\n",
fmt.prec, fmt.conv); fmt.prec, fmt.conv);
return false; return false;
} }
@ -483,17 +483,17 @@ printString(const StreamFormat& fmt, StreamBuffer& output, const char* value)
return true; return true;
} }
int StdStringConverter:: long StdStringConverter::
scanString(const StreamFormat& fmt, const char* input, scanString(const StreamFormat& fmt, const char* input,
char* value, size_t maxlen) char* value, unsigned long &size)
{ {
int length = 0; long consumed = 0;
long space_left = size;
int width = fmt.width; int width = fmt.width;
if ((fmt.flags & skip_flag) || value == NULL) maxlen = 0; if ((fmt.flags & skip_flag) || value == NULL) space_left = 0;
// if user does not specify width assume "ininity" (-1) // if user does not specify width assume "infinity" (-1)
if (width == 0) if (width == 0)
{ {
if (fmt.conv == 'c') width = 1; if (fmt.conv == 'c') width = 1;
@ -506,14 +506,14 @@ scanString(const StreamFormat& fmt, const char* input,
// but do so if space flag is present // but do so if space flag is present
if (fmt.flags & space_flag) if (fmt.flags & space_flag)
{ {
if (maxlen > 1) if (space_left > 1) // keep space for terminal null byte
{ {
*value++ = *input; *value++ = *input;
maxlen--; space_left--;
} }
width--; width--;
} }
length++; consumed++;
input++; input++;
} }
while (*input && width) while (*input && width)
@ -521,20 +521,22 @@ 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.flags & alt_flag) && isspace(*input)) break; if (!(fmt.flags & alt_flag) && isspace(*input)) break;
if (maxlen > 1) if (space_left > 1)
{ {
*value++ = *input; *value++ = *input;
maxlen--; space_left--;
} }
length++; consumed++;
width--; width--;
input++; input++;
} }
if (maxlen > 0) if (space_left)
{ {
*value = '\0'; *value = '\0';
space_left--;
size -= space_left; // update number of bytes copied to value
} }
return length; return consumed;
} }
RegisterConverter (StdStringConverter, "s"); RegisterConverter (StdStringConverter, "s");
@ -545,7 +547,7 @@ 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);
virtual int scanString(const StreamFormat&, const char*, char*, size_t); virtual long scanString(const StreamFormat&, const char*, char*, unsigned long&);
}; };
int StdCharsConverter:: int StdCharsConverter::
@ -560,7 +562,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
} }
if (scanFormat && fmt.prec >= 0) if (scanFormat && fmt.prec >= 0)
{ {
error("Use of precision field '.%d' not allowed with %%%c input conversion\n", error("Use of precision field '.%ld' not allowed with %%%c input conversion\n",
fmt.prec, fmt.conv); fmt.prec, fmt.conv);
return false; return false;
} }
@ -581,35 +583,37 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
return true; return true;
} }
int StdCharsConverter:: long StdCharsConverter::
scanString(const StreamFormat& fmt, const char* input, scanString(const StreamFormat& fmt, const char* input,
char* value, size_t maxlen) char* value, unsigned long& size)
{ {
int length = 0; long consumed = 0;
long width = fmt.width;
long space_left = size;
int width = fmt.width; if ((fmt.flags & skip_flag) || value == NULL) space_left = 0;
if ((fmt.flags & skip_flag) || value == NULL) maxlen = 0;
// if user does not specify width assume 1 // if user does not specify width assume 1
if (width == 0) width = 1; if (width == 0) width = 1;
while (*input && width) while (*input && width)
{ {
if (maxlen > 1) if (space_left > 1) // keep space for terminal null byte
{ {
*value++ = *input; *value++ = *input;
maxlen--; space_left--;
} }
length++; consumed++;
width--; width--;
input++; input++;
} }
if (maxlen > 0) if (space_left)
{ {
*value = '\0'; *value = '\0';
space_left--;
size -= space_left; // update number of bytes written to value
} }
return length; return consumed; // return number of bytes consumed from input
} }
RegisterConverter (StdCharsConverter, "c"); RegisterConverter (StdCharsConverter, "c");
@ -619,7 +623,7 @@ RegisterConverter (StdCharsConverter, "c");
class StdCharsetConverter : public StreamFormatConverter class StdCharsetConverter : public StreamFormatConverter
{ {
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool); virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
virtual int scanString(const StreamFormat&, const char*, char*, size_t); virtual long scanString(const StreamFormat&, const char*, char*, unsigned long&);
// no print method, %[ is readonly // no print method, %[ is readonly
}; };
@ -651,7 +655,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
} }
if (scanFormat && fmt.prec >= 0) if (scanFormat && fmt.prec >= 0)
{ {
error("Use of precision field '.%d' not allowed with %%%c input conversion\n", error("Use of precision field '.%ld' not allowed with %%%c input conversion\n",
fmt.prec, fmt.conv); fmt.prec, fmt.conv);
return false; return false;
} }
@ -698,35 +702,38 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
return string_format; return string_format;
} }
int StdCharsetConverter:: long StdCharsetConverter::
scanString(const StreamFormat& fmt, const char* input, scanString(const StreamFormat& fmt, const char* input,
char* value, size_t maxlen) char* value, unsigned long& size)
{ {
int length = 0; long consumed = 0;
int width = fmt.width; long width = fmt.width;
long space_left = size;
if ((fmt.flags & skip_flag) || value == NULL) maxlen = 0; if ((fmt.flags & skip_flag) || value == NULL) space_left = 0;
// if user does not specify width assume "ininity" (-1) // if user does not specify width assume "infinity" (-1)
if (width == 0) width = -1; if (width == 0) width = -1;
while (*input && width) while (*input && width)
{ {
if (fmt.info[*input>>3] & 1<<(*input&7)) break; if (fmt.info[*input>>3] & 1<<(*input&7)) break;
if (maxlen > 1) if (space_left > 1) // keep space for terminal null byte
{ {
*value++ = *input; *value++ = *input;
maxlen--; space_left--;
} }
length++; consumed++;
width--; width--;
input++; input++;
} }
if (maxlen > 0) if (space_left)
{ {
*value = '\0'; *value = '\0';
space_left--;
size -= space_left; // update number of bytes written to value
} }
return length; return consumed;
} }
RegisterConverter (StdCharsetConverter, "["); RegisterConverter (StdCharsetConverter, "[");

View File

@ -56,13 +56,13 @@ public:
StreamBuffer& output, const char* value); StreamBuffer& output, const char* value);
virtual bool printPseudo(const StreamFormat& fmt, virtual bool printPseudo(const StreamFormat& fmt,
StreamBuffer& output); StreamBuffer& output);
virtual int scanLong(const StreamFormat& fmt, virtual long scanLong(const StreamFormat& fmt,
const char* input, long& value); const char* input, long& value);
virtual int scanDouble(const StreamFormat& fmt, virtual long scanDouble(const StreamFormat& fmt,
const char* input, double& value); const char* input, double& value);
virtual int scanString(const StreamFormat& fmt, virtual long scanString(const StreamFormat& fmt,
const char* input, char* value, size_t maxlen); const char* input, char* value, unsigned long& size);
virtual int scanPseudo(const StreamFormat& fmt, virtual long scanPseudo(const StreamFormat& fmt,
StreamBuffer& inputLine, long& cursor); StreamBuffer& inputLine, long& cursor);
}; };
@ -130,8 +130,8 @@ void* ref_##converter = &registrar_##converter\
* You only need to implement the flavour of print and/or scan suitable for * You only need to implement the flavour of print and/or scan suitable for
* the datatype returned by parse(). * the datatype returned by parse().
* *
* Now, fmt.type contains the value returned by parse(). With fmt.info() * Now, fmt.type contains the value returned by parse(). With fmt.info() you
* you will get the string you have written to info in parse() (null terminated). * will get the string you have written to info in parse() (null terminated).
* The length of the info string can be found in fmt.infolen. * The length of the info string can be found in fmt.infolen.
* *
* In print*(), append the converted value to output. Do not modify what is * In print*(), append the converted value to output. Do not modify what is
@ -139,9 +139,14 @@ void* ref_##converter = &registrar_##converter\
* Return true on success, false on failure. * Return true on success, false on failure.
* *
* In scan*(), read the value from input and return the number of consumed * In scan*(), read the value from input and return the number of consumed
* bytes. In the string version, don't write more bytes than maxlen! If the * bytes.
* skip_flag is set, you don't need to write to value, since the value will be * In the string version, don't write more bytes than size including a
* discarded anyway. Return -1 on failure. * mandatory terminating null byte. Update size with the number of bytes
* written into the value, wich may differ from the number of bytes consumed
* from the input (e.g. due to leading space). If the skip_flag is set, the
* input will be discarded. Thus, don't write to value. You also don't need
* to update size.
* Return -1 on failure.
* *
* *
* Register your class * Register your class

View File

@ -1484,7 +1484,7 @@ compileFormat(StreamBuffer& buffer, const char*& formatstr,
buffer.append(infoString); buffer.append(infoString);
debug("StreamProtocolParser::Protocol::compileFormat: format.type=%s, " debug("StreamProtocolParser::Protocol::compileFormat: format.type=%s, "
"infolen=%d infostring=\"%s\"\n", "infolen=%ld infostring=\"%s\"\n",
StreamFormatTypeStr[streamFormat.type], StreamFormatTypeStr[streamFormat.type],
streamFormat.infolen, infoString.expand()()); streamFormat.infolen, infoString.expand()());
formatstr = source; // move pointer after parsed format formatstr = source; // move pointer after parsed format

View File

@ -75,7 +75,7 @@ class TimestampConverter : public StreamFormatConverter
{ {
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool); int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
bool printDouble(const StreamFormat&, StreamBuffer&, double); bool printDouble(const StreamFormat&, StreamBuffer&, double);
int scanDouble(const StreamFormat&, const char*, double&); long scanDouble(const StreamFormat&, const char*, double&);
}; };
int TimestampConverter:: int TimestampConverter::
@ -516,9 +516,7 @@ startover:
return input; return input;
} }
long TimestampConverter::
int TimestampConverter::
scanDouble(const StreamFormat& format, const char* input, double& value) scanDouble(const StreamFormat& format, const char* input, double& value)
{ {
struct tm brokenDownTime; struct tm brokenDownTime;

View File

@ -114,18 +114,23 @@ static long readData(dbCommon *record, format_t *format)
break; break;
case DBF_CHAR: case DBF_CHAR:
case DBF_UCHAR: case DBF_UCHAR:
memset(aai->bptr, 0, aai->nelm);
aai->nord = 0; aai->nord = 0;
if (streamScanfN(record, format, if ((lval = streamScanfN(record, format,
(char *)aai->bptr, aai->nelm) == ERROR) (char *)aai->bptr, aai->nelm)) == ERROR)
{ {
memset(aai->bptr, 0, aai->nelm);
return ERROR; return ERROR;
} }
((char*)aai->bptr)[aai->nelm-1] = 0; if ((size_t)lval < aai->nelm)
for (lval = aai->nelm-2; {
lval >= 0 && ((char*)aai->bptr)[lval] == 0; memset(((char*)aai->bptr)+lval , 0, aai->nelm-lval);
lval--); lval++;
aai->nord = lval+1; }
else
{
((char*)aai->bptr)[aai->nelm-1] = 0;
}
aai->nord = lval;
return OK; return OK;
default: default:
errlogSevPrintf(errlogFatal, errlogSevPrintf(errlogFatal,

View File

@ -114,18 +114,23 @@ static long readData(dbCommon *record, format_t *format)
break; break;
case DBF_CHAR: case DBF_CHAR:
case DBF_UCHAR: case DBF_UCHAR:
memset(aao->bptr, 0, aao->nelm);
aao->nord = 0; aao->nord = 0;
if (streamScanfN(record, format, if ((lval = streamScanfN(record, format,
(char *)aao->bptr, aao->nelm) == ERROR) (char *)aao->bptr, aao->nelm)) == ERROR)
{ {
memset(aao->bptr, 0, aao->nelm);
return ERROR; return ERROR;
} }
((char*)aao->bptr)[aao->nelm-1] = 0; if ((size_t)lval < aao->nelm)
for (lval = aao->nelm-2; {
lval >= 0 && ((char*)aao->bptr)[lval] == 0; memset(((char*)aao->bptr)+lval , 0, aao->nelm-lval);
lval--); lval++;
aao->nord = lval+1; }
else
{
((char*)aao->bptr)[aao->nelm-1] = 0;
}
aao->nord = lval;
return OK; return OK;
default: default:
errlogSevPrintf(errlogFatal, errlogSevPrintf(errlogFatal,

View File

@ -114,18 +114,23 @@ static long readData(dbCommon *record, format_t *format)
break; break;
case DBF_CHAR: case DBF_CHAR:
case DBF_UCHAR: case DBF_UCHAR:
memset(wf->bptr, 0, wf->nelm);
wf->nord = 0; wf->nord = 0;
if (streamScanfN(record, format, if ((lval = streamScanfN(record, format,
(char *)wf->bptr, wf->nelm) == ERROR) (char *)wf->bptr, wf->nelm)) == ERROR)
{ {
memset(wf->bptr, 0, wf->nelm);
return ERROR; return ERROR;
} }
((char*)wf->bptr)[wf->nelm-1] = 0; if ((size_t)lval < wf->nelm)
for (lval = wf->nelm-2; {
lval >= 0 && ((char*)wf->bptr)[lval] == 0; memset(((char*)wf->bptr)+lval , 0, wf->nelm-lval);
lval--); lval++;
wf->nord = lval+1; }
else
{
((char*)wf->bptr)[wf->nelm-1] = 0;
}
wf->nord = lval;
return OK; return OK;
default: default:
errlogSevPrintf(errlogFatal, errlogSevPrintf(errlogFatal,