Compare commits
18 Commits
stream_2_3
...
stream_2_4
Author | SHA1 | Date | |
---|---|---|---|
2cd969d643 | |||
0c9d4dc4c0 | |||
ef3b2ec9fd | |||
1fb402e838 | |||
eae987e7f1 | |||
93906dd022 | |||
7e717c564d | |||
14b60c210a | |||
8dae0afa30 | |||
95bf2c78c2 | |||
8c10e5395c | |||
69de0b9f31 | |||
22ae510dca | |||
5fdf3912c8 | |||
b50aec424f | |||
4a1033b6dc | |||
68e178d41b | |||
e83ceda41c |
5
MODULE
Normal file
5
MODULE
Normal file
@ -0,0 +1,5 @@
|
||||
# Please change the following email with yours.
|
||||
Email: dirk.zimoch@psi.ch
|
||||
Module-Name: StreamDevice2
|
||||
Description: StreamDevice2
|
||||
Project-Name:
|
7
Makefile
7
Makefile
@ -15,7 +15,7 @@ FORMATS += RawFloat
|
||||
FORMATS += Binary
|
||||
FORMATS += Checksum
|
||||
FORMATS += Regexp
|
||||
FORMATS += Exponential
|
||||
FORMATS += MantissaExponent
|
||||
RECORDTYPES += aai aao
|
||||
RECORDTYPES += ao ai
|
||||
RECORDTYPES += bo bi
|
||||
@ -32,6 +32,11 @@ SOURCES += $(wildcard src/Stream*.cc)
|
||||
SOURCES += src/StreamVersion.c
|
||||
SOURCES_3.14 += src/devcalcoutStream.c
|
||||
|
||||
HEADERS += StreamFormat.h
|
||||
HEADERS += StreamFormatConverter.h
|
||||
HEADERS += StreamBuffer.h
|
||||
HEADERS += StreamError.h
|
||||
|
||||
ifeq (${EPICS_BASETYPE},3.13)
|
||||
USR_INCLUDES += -include $(INSTALL_INCLUDE)/compat3_13.h
|
||||
endif
|
||||
|
@ -59,12 +59,12 @@ writeRequest()
|
||||
pasynManager->queueRequest()
|
||||
when request is handled
|
||||
pasynOctet->flush()
|
||||
pasynOctet->writeRaw()
|
||||
if writeRaw() times out
|
||||
pasynOctet->write()
|
||||
if write() times out
|
||||
writeCallback(StreamIoTimeout)
|
||||
if writeRaw fails otherwise
|
||||
if write fails otherwise
|
||||
writeCallback(StreamIoFault)
|
||||
if writeRaw succeeds and all bytes have been written
|
||||
if write succeeds and all bytes have been written
|
||||
writeCallback(StreamIoSuccess)
|
||||
if not all bytes can be written
|
||||
pasynManager->queueRequest() to write next part
|
||||
@ -605,15 +605,27 @@ writeHandler()
|
||||
|
||||
size_t streameoslen;
|
||||
const char* streameos = getOutTerminator(streameoslen);
|
||||
if (streameos) // stream has added eos
|
||||
int oldeoslen = -1;
|
||||
char oldeos[16];
|
||||
if (streameos) // stream has already added eos, don't do it again in asyn
|
||||
{
|
||||
status = pasynOctet->writeRaw(pvtOctet, pasynUser,
|
||||
outputBuffer, outputSize, &written);
|
||||
// clear terminator for asyn
|
||||
status = pasynOctet->getOutputEos(pvtOctet,
|
||||
pasynUser, oldeos, sizeof(oldeos)-1, &oldeoslen);
|
||||
if (status != asynSuccess)
|
||||
{
|
||||
oldeoslen = -1;
|
||||
// No EOS support?
|
||||
}
|
||||
pasynOctet->setOutputEos(pvtOctet, pasynUser,
|
||||
NULL, 0);
|
||||
}
|
||||
else // asyn should add eos
|
||||
status = pasynOctet->write(pvtOctet, pasynUser,
|
||||
outputBuffer, outputSize, &written);
|
||||
if (oldeoslen >= 0) // restore asyn terminator
|
||||
{
|
||||
status = pasynOctet->write(pvtOctet, pasynUser,
|
||||
outputBuffer, outputSize, &written);
|
||||
pasynOctet->setOutputEos(pvtOctet, pasynUser,
|
||||
oldeos, oldeoslen);
|
||||
}
|
||||
switch (status)
|
||||
{
|
||||
@ -773,7 +785,7 @@ readHandler()
|
||||
pasynUser->timeout = replyTimeout;
|
||||
}
|
||||
bool waitForReply = true;
|
||||
int received;
|
||||
size_t received;
|
||||
int eomReason;
|
||||
asynStatus status;
|
||||
long readMore;
|
||||
@ -785,7 +797,7 @@ readHandler()
|
||||
eomReason = 0;
|
||||
|
||||
status = pasynOctet->read(pvtOctet, pasynUser,
|
||||
buffer, bytesToRead, (size_t*)&received, &eomReason);
|
||||
buffer, bytesToRead, &received, &eomReason);
|
||||
if (ioAction == Read || status != asynTimeout)
|
||||
{
|
||||
debug("AsynDriverInterface::readHandler(%s): "
|
||||
@ -804,8 +816,8 @@ readHandler()
|
||||
debug("AsynDriverInterface::readHandler(%s): "
|
||||
"AsyncRead poll: received %d of %d bytes \"%s\" "
|
||||
"eomReason=%s [data ignored]\n",
|
||||
clientName(), received, bytesToRead,
|
||||
StreamBuffer(buffer, received).expand()(),
|
||||
clientName(), (int)received, bytesToRead,
|
||||
StreamBuffer(buffer, (int)received).expand()(),
|
||||
eomReasonStr[eomReason&0x7]);
|
||||
#endif
|
||||
// ignore what we got from here.
|
||||
@ -818,8 +830,8 @@ readHandler()
|
||||
debug("AsynDriverInterface::readHandler(%s): "
|
||||
"received %d of %d bytes \"%s\" "
|
||||
"eomReason=%s\n",
|
||||
clientName(), received, bytesToRead,
|
||||
StreamBuffer(buffer, received).expand()(),
|
||||
clientName(), (int)received, bytesToRead,
|
||||
StreamBuffer(buffer, (int)received).expand()(),
|
||||
eomReasonStr[eomReason&0x7]);
|
||||
#endif
|
||||
// asynOctet->read() cuts off terminator, but:
|
||||
@ -839,7 +851,7 @@ readHandler()
|
||||
size_t i;
|
||||
for (i = 0; i < deveoslen; i++, received++)
|
||||
{
|
||||
if (received >= 0) buffer[received] = deveos[i];
|
||||
if ((int)received >= 0) buffer[received] = deveos[i];
|
||||
// It is safe to add to buffer here, because
|
||||
// the terminator was already there before
|
||||
// asynOctet->read() had cut it.
|
||||
@ -877,7 +889,7 @@ readHandler()
|
||||
debug("AsynDriverInterface::readHandler(%s): "
|
||||
"ioAction=%s, timeout after %d of %d bytes \"%s\"\n",
|
||||
clientName(), ioActionStr[ioAction],
|
||||
received, bytesToRead,
|
||||
(int)received, bytesToRead,
|
||||
StreamBuffer(buffer, received).expand()());
|
||||
#endif
|
||||
if (ioAction == AsyncRead || ioAction == AsyncReadMore)
|
||||
@ -944,28 +956,11 @@ void intrCallbackOctet(void* /*pvt*/, asynUser *pasynUser,
|
||||
// Problems here:
|
||||
// 1. We get this message too when we are the poller.
|
||||
// Thus we have to ignore what we got from polling.
|
||||
// 2. We get this message multiple times when original reader
|
||||
// reads in chunks.
|
||||
// 3. eomReason=ASYN_EOM_CNT when message was too long for
|
||||
// 2. eomReason=ASYN_EOM_CNT when message was too long for
|
||||
// internal buffer of asynDriver.
|
||||
|
||||
if (!interruptAccept) return; // too early to process records
|
||||
debug("AsynDriverInterface::intrCallbackOctet(%s) ioAction = %s\n",
|
||||
interface->clientName(), ioActionStr[interface->ioAction]);
|
||||
if (interface->ioAction == AsyncRead ||
|
||||
interface->ioAction == AsyncReadMore)
|
||||
{
|
||||
interface->asynReadHandler(data, numchars, eomReason);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef NO_TEMPORARY
|
||||
debug("AsynDriverInterface::intrCallbackOctet(%s, buffer=\"%s\", "
|
||||
"received=%d eomReason=%s) ioAction=%s\n",
|
||||
interface->clientName(), StreamBuffer(data, numchars).expand()(),
|
||||
numchars, eomReasonStr[eomReason&0x7], ioActionStr[interface->ioAction]);
|
||||
#endif
|
||||
}
|
||||
interface->asynReadHandler(data, numchars, eomReason);
|
||||
}
|
||||
|
||||
// get asynchronous input
|
||||
|
@ -65,7 +65,7 @@ printLong(const StreamFormat& format, StreamBuffer& output, long value)
|
||||
{
|
||||
// find number of significant bits
|
||||
prec = sizeof (value) * 8;
|
||||
while (prec && (value & (1 << (prec - 1))) == 0) prec--;
|
||||
while (prec && (value & (1L << (prec - 1))) == 0) prec--;
|
||||
}
|
||||
if (prec == 0) prec++; // print at least one bit
|
||||
int width = prec;
|
||||
@ -75,7 +75,7 @@ printLong(const StreamFormat& format, StreamBuffer& output, long value)
|
||||
char fill = (format.flags & zero_flag) ? zero : ' ';
|
||||
if (format.flags & alt_flag)
|
||||
{
|
||||
// little endian (least significan bit first)
|
||||
// little endian (least significant bit first)
|
||||
if (!(format.flags & left_flag))
|
||||
{
|
||||
// pad left
|
||||
@ -99,7 +99,7 @@ printLong(const StreamFormat& format, StreamBuffer& output, long value)
|
||||
}
|
||||
else
|
||||
{
|
||||
// big endian (most significan bit first)
|
||||
// big endian (most significant bit first)
|
||||
if (!(format.flags & left_flag))
|
||||
{
|
||||
// pad left
|
||||
@ -111,7 +111,7 @@ printLong(const StreamFormat& format, StreamBuffer& output, long value)
|
||||
}
|
||||
while (prec--)
|
||||
{
|
||||
output.append((value & (1 << prec)) ? one : zero);
|
||||
output.append((value & (1L << prec)) ? one : zero);
|
||||
width--;
|
||||
}
|
||||
while (width--)
|
||||
|
@ -38,10 +38,10 @@ SYNAPPS_RECORDS += scalcout
|
||||
FORMATS += Enum
|
||||
FORMATS += BCD
|
||||
FORMATS += Raw
|
||||
FORMATS += RawFloat
|
||||
FORMATS += Binary
|
||||
FORMATS += Checksum
|
||||
FORMATS += Exponential
|
||||
FORMATS += RawFloat
|
||||
FORMATS += MantissaExponent
|
||||
|
||||
# Want Perl regular expression matching?
|
||||
# If PCRE is installed at the same location for all
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "StreamFormatConverter.h"
|
||||
#include "StreamError.h"
|
||||
#include "StreamProtocol.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
// Enum %{string0|string1|...}
|
||||
|
||||
@ -31,44 +32,62 @@ class EnumConverter : public StreamFormatConverter
|
||||
int scanLong(const StreamFormat&, const char*, long&);
|
||||
};
|
||||
|
||||
// info format: <numEnums><index><string>0<index><string>0...
|
||||
|
||||
int EnumConverter::
|
||||
parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
const char*& source, bool)
|
||||
{
|
||||
if (fmt.flags & (left_flag|sign_flag|space_flag|zero_flag|alt_flag))
|
||||
if (fmt.flags & (left_flag|sign_flag|space_flag|zero_flag))
|
||||
{
|
||||
error("Use of modifiers '-', '+', ' ', '0', '#'"
|
||||
error("Use of modifiers '-', '+', ' ', '0' "
|
||||
"not allowed with %%{ conversion\n");
|
||||
return false;
|
||||
}
|
||||
int i = info.length(); // put maxValue here later
|
||||
info.append('\0');
|
||||
int maxValue = 0;
|
||||
long numEnums = 0;
|
||||
int n = info.length(); // put numEnums here later
|
||||
info.append(&numEnums, sizeof(numEnums));
|
||||
long index = 0;
|
||||
int i = 0;
|
||||
i = info.length(); // put index here later
|
||||
info.append(&index, sizeof(index));
|
||||
while (*source)
|
||||
{
|
||||
switch (*source)
|
||||
if (*source == '=' && (fmt.flags & alt_flag))
|
||||
{
|
||||
case '|':
|
||||
info.append('\0');
|
||||
if (++maxValue > 255)
|
||||
{
|
||||
error("Too many enums (max 256)\n");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case '}':
|
||||
source++;
|
||||
info.append('\0');
|
||||
info[i] = maxValue;
|
||||
debug("EnumConverter::parse %d choices: %s\n",
|
||||
maxValue+1, info.expand(i+1)());
|
||||
return enum_format;
|
||||
case esc:
|
||||
info.append(*source++);
|
||||
default:
|
||||
info.append(*source);
|
||||
char* p;
|
||||
index = strtol(++source, &p, 0);
|
||||
if (p == source || (*p != '|' && *p != '}'))
|
||||
{
|
||||
error("Integer expected after '=' "
|
||||
"in %%{ format conversion\n");
|
||||
return false;
|
||||
}
|
||||
memcpy(info(i), &index, sizeof(index));
|
||||
source = p;
|
||||
}
|
||||
if (*source == '|' || *source == '}')
|
||||
{
|
||||
numEnums++;
|
||||
info.append('\0');
|
||||
|
||||
if (*source++ == '}')
|
||||
{
|
||||
memcpy(info(n), &numEnums, sizeof(numEnums));
|
||||
debug("EnumConverter::parse %ld choices: %s\n",
|
||||
numEnums, info.expand()());
|
||||
return enum_format;
|
||||
}
|
||||
index ++;
|
||||
i = info.length();
|
||||
info.append(&index, sizeof(index));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*source == esc)
|
||||
info.append(*source++);
|
||||
info.append(*source++);
|
||||
}
|
||||
source++;
|
||||
}
|
||||
error("Missing '}' after %%{ format conversion\n");
|
||||
return false;
|
||||
@ -77,14 +96,10 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
bool EnumConverter::
|
||||
printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
||||
{
|
||||
long maxValue = fmt.info[0]; // number of enums
|
||||
const char* s = fmt.info+1; // first enum string
|
||||
if (value < 0 || value > maxValue)
|
||||
{
|
||||
error("Value %li out of range [0...%li]\n", value, maxValue);
|
||||
return false;
|
||||
}
|
||||
while (value--)
|
||||
const char* s = fmt.info;
|
||||
long numEnums = extract<long>(s);
|
||||
long index = extract<long>(s);
|
||||
while (numEnums-- && (value != index))
|
||||
{
|
||||
while(*s)
|
||||
{
|
||||
@ -92,6 +107,12 @@ printLong(const StreamFormat& fmt, StreamBuffer& output, long value)
|
||||
s++;
|
||||
}
|
||||
s++;
|
||||
index = extract<long>(s);
|
||||
}
|
||||
if (numEnums == -1)
|
||||
{
|
||||
error("Value %li not found in enum set\n", value);
|
||||
return false;
|
||||
}
|
||||
while(*s)
|
||||
{
|
||||
@ -106,14 +127,16 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||
{
|
||||
debug("EnumConverter::scanLong(%%%c, \"%s\")\n",
|
||||
fmt.conv, input);
|
||||
long maxValue = fmt.info[0]; // number of enums
|
||||
const char* s = fmt.info+1; // first enum string
|
||||
const char* s = fmt.info;
|
||||
long numEnums = extract<long>(s);
|
||||
long index;
|
||||
int length;
|
||||
long val;
|
||||
|
||||
bool match;
|
||||
for (val = 0; val <= maxValue; val++)
|
||||
while (numEnums--)
|
||||
{
|
||||
debug("EnumConverter::scanLong: check #%ld \"%s\"\n", val, s);
|
||||
index = extract<long>(s);
|
||||
debug("EnumConverter::scanLong: check #%ld \"%s\"\n", index, s);
|
||||
length = 0;
|
||||
match = true;
|
||||
while(*s)
|
||||
@ -129,8 +152,8 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||
}
|
||||
if (match)
|
||||
{
|
||||
debug("EnumConverter::scanLong: value %ld matches\n", val);
|
||||
value = val;
|
||||
debug("EnumConverter::scanLong: value %ld matches\n", index);
|
||||
value = index;
|
||||
return length;
|
||||
}
|
||||
s++;
|
||||
|
@ -70,7 +70,7 @@ SHRLIB_DEPLIB_DIRS += $(PCRE_LIB)
|
||||
endif
|
||||
endif
|
||||
|
||||
LIB_LIBS += Com dbIoc dbStaticIoc registryIoc iocsh
|
||||
LIB_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
ifeq ($(USE_MEMGUARD),YES)
|
||||
# memguard looks for memory leaks (gcc only)
|
||||
|
@ -1,8 +1,7 @@
|
||||
/***************************************************************
|
||||
* StreamDevice Support *
|
||||
* *
|
||||
* (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) *
|
||||
* (C) 2007 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* (C) 2008 Dirk Zimoch (dirk.zimoch@psi.ch) *
|
||||
* *
|
||||
* This is a custom exponential format converter for *
|
||||
* StreamDevice. *
|
||||
@ -32,26 +31,26 @@
|
||||
// But why not +11000-04 ?
|
||||
// For writing, I chose the following convention:
|
||||
// Format precision defines number of digits in mantissa
|
||||
// Number of digits in exponent is at least 2
|
||||
// No leading '0' in mantissa (except for 0.0 of course)
|
||||
// Number of digits in exponent is at least 2
|
||||
// Format flags +, -, and space are supported in the usual way
|
||||
// Flags #, 0 are not supported
|
||||
|
||||
class ExponentialConverter : public StreamFormatConverter
|
||||
class MantissaExponentConverter : public StreamFormatConverter
|
||||
{
|
||||
virtual int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
|
||||
virtual int scanDouble(const StreamFormat&, const char*, double&);
|
||||
virtual bool printDouble(const StreamFormat&, StreamBuffer&, double);
|
||||
};
|
||||
|
||||
int ExponentialConverter::
|
||||
int MantissaExponentConverter::
|
||||
parse(const StreamFormat& fmt, StreamBuffer& info,
|
||||
const char*& source, bool scanFormat)
|
||||
{
|
||||
return double_format;
|
||||
}
|
||||
|
||||
int ExponentialConverter::
|
||||
int MantissaExponentConverter::
|
||||
scanDouble(const StreamFormat& fmt, const char* input, double& value)
|
||||
{
|
||||
int mantissa;
|
||||
@ -61,11 +60,11 @@ scanDouble(const StreamFormat& fmt, const char* input, double& value)
|
||||
sscanf(input, "%d%d%n", &mantissa, &exponent, &length);
|
||||
if (fmt.flags & skip_flag) return length;
|
||||
if (length == -1) return -1;
|
||||
value = (double)(mantissa) * pow(10, exponent);
|
||||
value = (double)(mantissa) * pow(10.0, exponent);
|
||||
return length;
|
||||
}
|
||||
|
||||
bool ExponentialConverter::
|
||||
bool MantissaExponentConverter::
|
||||
printDouble(const StreamFormat& fmt, StreamBuffer& output, double value)
|
||||
{
|
||||
// Have to divide value into mantissa and exponent
|
||||
@ -73,21 +72,23 @@ printDouble(const StreamFormat& fmt, StreamBuffer& output, double value)
|
||||
// number of characters in exponent is at least 2
|
||||
int spaces;
|
||||
StreamBuffer buf;
|
||||
int prec = fmt.prec;
|
||||
|
||||
buf.printf("%.*e", fmt.prec-1, fabs(value));
|
||||
if (prec < 1) prec = 6;
|
||||
buf.printf("%.*e", prec-1, fabs(value)/pow(10.0, prec-1));
|
||||
buf.remove(1,1);
|
||||
buf.remove(buf.find('e'),1);
|
||||
|
||||
spaces = fmt.width-buf.length();
|
||||
if (fmt.flags & (space_flag|sign_flag) || value < 0) spaces--;
|
||||
if (fmt.flags & (space_flag|sign_flag) || value < 0.0) spaces--;
|
||||
if (spaces < 0) spaces = 0;
|
||||
if (!(fmt.flags & left_flag))
|
||||
output.append(' ', spaces);
|
||||
if (fmt.flags & (space_flag|sign_flag) == space_flag && value >= 0)
|
||||
if ((fmt.flags & (space_flag|sign_flag)) == space_flag && value >= 0.0)
|
||||
output.append(' ');
|
||||
if (fmt.flags & sign_flag && value >= 0)
|
||||
if (fmt.flags & sign_flag && value >= 0.0)
|
||||
output.append('+');
|
||||
if (value <= 0)
|
||||
if (value < 0.0)
|
||||
output.append('-');
|
||||
output.append(buf);
|
||||
if (fmt.flags & left_flag)
|
||||
@ -95,5 +96,5 @@ printDouble(const StreamFormat& fmt, StreamBuffer& output, double value)
|
||||
return true;
|
||||
}
|
||||
|
||||
RegisterConverter (ExponentialConverter, "m");
|
||||
RegisterConverter (MantissaExponentConverter, "m");
|
||||
|
@ -40,10 +40,12 @@ parse(const StreamFormat&, StreamBuffer&,
|
||||
bool RawConverter::
|
||||
printLong(const StreamFormat& format, StreamBuffer& output, long value)
|
||||
{
|
||||
int prec = format.prec; // number of bytes from value
|
||||
if (prec == -1) prec = 1; // default: 1 byte
|
||||
int width = prec; // number of bytes in output
|
||||
int prec = format.prec; // number of bytes from value
|
||||
if (prec == -1) prec = 1; // default: 1 byte
|
||||
int width = prec; // number of bytes in output
|
||||
if (prec > (int)sizeof(long)) prec=sizeof(long);
|
||||
if (format.width > width) width = format.width;
|
||||
|
||||
char byte = 0;
|
||||
if (format.flags & alt_flag) // little endian (lsb first)
|
||||
{
|
||||
|
@ -21,21 +21,7 @@
|
||||
#include "StreamFormatConverter.h"
|
||||
#include "StreamError.h"
|
||||
|
||||
#ifdef vxWorks
|
||||
#include "vxWorks.h"
|
||||
#define __BYTE_ORDER _BYTE_ORDER
|
||||
#define __LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
#define __BIG_ENDIAN _BIG_ENDIAN
|
||||
#else
|
||||
// Let's hope all other architectures have endian.h
|
||||
#include "endian.h"
|
||||
#endif
|
||||
|
||||
#ifndef __BYTE_ORDER
|
||||
#error define __BYTE_ORDER as __LITTLE_ENDIAN or __BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#if (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
|
||||
static int endian = 0;
|
||||
|
||||
// Raw Float Converter %R
|
||||
|
||||
@ -50,6 +36,17 @@ int RawFloatConverter::
|
||||
parse(const StreamFormat& format, StreamBuffer&,
|
||||
const char*&, bool)
|
||||
{
|
||||
// Find out byte order
|
||||
if (!endian) {
|
||||
union {long l; char c [sizeof(long)];} u;
|
||||
u.l=1;
|
||||
if (u.c[0]) { endian = 1234;} // little endian
|
||||
else if (u.c[sizeof(long)-1]) { endian = 4321;} // big endian
|
||||
else {
|
||||
error ("Cannot find out byte order for %%R format.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Assume IEEE formats with 4 or 8 bytes (default: 4)
|
||||
if (format.width==0 || format.width==4 || format.width==8)
|
||||
return double_format;
|
||||
@ -76,15 +73,10 @@ printDouble(const StreamFormat& format, StreamBuffer& output, double value)
|
||||
buffer.fval = value;
|
||||
else
|
||||
buffer.dval = value;
|
||||
|
||||
#if (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
bool swap = format.flags & alt_flag;
|
||||
#else
|
||||
bool swap = !(format.flags & alt_flag);
|
||||
#endif
|
||||
|
||||
if (swap)
|
||||
if (!(format.flags & alt_flag) ^ (endian == 4321))
|
||||
{
|
||||
// swap if byte orders differ
|
||||
for (n = nbOfBytes-1; n >= 0; n--)
|
||||
{
|
||||
output.append(buffer.bytes[n]);
|
||||
@ -119,14 +111,9 @@ scanDouble(const StreamFormat& format, const char* input, double& value)
|
||||
return(nbOfBytes); // just skip input
|
||||
}
|
||||
|
||||
#if (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
bool swap = format.flags & alt_flag;
|
||||
#else
|
||||
bool swap = !(format.flags & alt_flag);
|
||||
#endif
|
||||
|
||||
if (swap)
|
||||
if (!(format.flags & alt_flag) ^ (endian == 4321))
|
||||
{
|
||||
// swap if byte orders differ
|
||||
for (n = nbOfBytes-1, i = 0; n >= 0; n--, i++)
|
||||
{
|
||||
buffer.bytes[n] = input[i];
|
||||
@ -147,5 +134,3 @@ scanDouble(const StreamFormat& format, const char* input, double& value)
|
||||
}
|
||||
|
||||
RegisterConverter (RawFloatConverter, "R");
|
||||
|
||||
#endif /* known byte order */
|
||||
|
@ -112,7 +112,7 @@ scanString(const StreamFormat& fmt, const char* input,
|
||||
if (!(fmt.flags & sign_flag)) {
|
||||
debug("Matching string \"%s\" too long (%d>%d bytes)\n",
|
||||
StreamBuffer(input+ovector[subexpr*2], len).expand()(),
|
||||
len, maxlen-1);
|
||||
(int)len, (int)maxlen-1);
|
||||
return -1;
|
||||
}
|
||||
len = maxlen-1;
|
||||
|
@ -135,7 +135,7 @@ find(const void* m, long size, long start) const
|
||||
start += len;
|
||||
if (start < 0) start = 0;
|
||||
}
|
||||
if (start >= len-size+1) return -1; // find nothing after end
|
||||
if (start+size > len) return -1; // find nothing after end
|
||||
if (!m || size <= 0) return start; // find empty string at start
|
||||
const char* s = static_cast<const char*>(m);
|
||||
char* b = buffer+offs;
|
||||
@ -143,12 +143,12 @@ find(const void* m, long size, long start) const
|
||||
long i;
|
||||
while ((p = static_cast<char*>(memchr(p, s[0], b-p+len-size+1))))
|
||||
{
|
||||
i = 1;
|
||||
while (p[i] == s[i])
|
||||
for (i = 1; i < size; i++)
|
||||
{
|
||||
if (++i >= size) return p-b;
|
||||
if (p[i] != s[i]) goto next;
|
||||
}
|
||||
p++;
|
||||
return p-b;
|
||||
next: p++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ public:
|
||||
StreamBuffer& replace(long pos, long length, const StreamBuffer& s)
|
||||
{return replace(pos, length, s.buffer+s.offs, s.len);}
|
||||
|
||||
// replace: delete part of buffer
|
||||
// remove: delete from start/pos
|
||||
StreamBuffer& remove(long pos, long length)
|
||||
{return replace(pos, length, NULL, 0);}
|
||||
|
||||
@ -152,7 +152,7 @@ public:
|
||||
{if (length>len) length=len;
|
||||
offs+=length; len-=length; return *this;}
|
||||
|
||||
// replace: delete end of buffer
|
||||
// truncate: delete end of buffer
|
||||
StreamBuffer& truncate(long pos)
|
||||
{return replace(pos, len, NULL, 0);}
|
||||
|
||||
|
@ -360,7 +360,7 @@ compileCommand(StreamProtocolParser::Protocol* protocol,
|
||||
{
|
||||
buffer.append(exec_cmd);
|
||||
if (!protocol->compileString(buffer, args,
|
||||
NoFormat, this))
|
||||
PrintFormat, this))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -390,6 +390,22 @@ compileCommand(StreamProtocolParser::Protocol* protocol,
|
||||
|
||||
// Run the protocol
|
||||
|
||||
// Input and events may come asynchonously from the bus driver
|
||||
// Especially in the sequence 'out "request"; in "reply";' the
|
||||
// reply can come before the 'in' command has actually started.
|
||||
// For asyncronous protocols, input can come at any time.
|
||||
// Thus, we must always accept input and event while the protocol
|
||||
// is running or when asyncronous mode is active.
|
||||
// Early input and event must be buffered until 'in' or 'event'
|
||||
// start. An 'out' command must discard any early input to avoid
|
||||
// problems with late input from aborted protocols.
|
||||
// Async mode ends on Abort or Error or if another command comes
|
||||
// after the asynchronous 'in' command.
|
||||
// Input can be discarded when it is not accepted any more, i.e.
|
||||
// at the end of syncronous protocols and when an asynchronous
|
||||
// mode ends (but not when 'in'-only protocol finishes normally).
|
||||
|
||||
|
||||
bool StreamCore::
|
||||
startProtocol(StartMode startMode)
|
||||
{
|
||||
@ -443,7 +459,7 @@ finishProtocol(ProtocolResult status)
|
||||
flags & WaitPending ? "timerCallback()" : "");
|
||||
status = Fault;
|
||||
}
|
||||
flags &= ~(AcceptInput|AcceptEvent);
|
||||
//// flags &= ~(AcceptInput|AcceptEvent);
|
||||
if (runningHandler)
|
||||
{
|
||||
// get original error status
|
||||
@ -518,6 +534,7 @@ finishProtocol(ProtocolResult status)
|
||||
flags &= ~BusOwner;
|
||||
}
|
||||
busFinish();
|
||||
flags &= ~(AcceptInput|AcceptEvent);
|
||||
protocolFinishHook(status);
|
||||
}
|
||||
|
||||
@ -539,16 +556,16 @@ evalCommand()
|
||||
switch (*commandIndex++)
|
||||
{
|
||||
case out_cmd:
|
||||
flags &= ~(AcceptInput|AcceptEvent);
|
||||
//// flags &= ~(AcceptInput|AcceptEvent);
|
||||
return evalOut();
|
||||
case in_cmd:
|
||||
flags &= ~AcceptEvent;
|
||||
//// flags &= ~AcceptEvent;
|
||||
return evalIn();
|
||||
case wait_cmd:
|
||||
flags &= ~(AcceptInput|AcceptEvent);
|
||||
//// flags &= ~(AcceptInput|AcceptEvent);
|
||||
return evalWait();
|
||||
case event_cmd:
|
||||
flags &= ~AcceptInput;
|
||||
//// flags &= ~AcceptInput;
|
||||
return evalEvent();
|
||||
case exec_cmd:
|
||||
return evalExec();
|
||||
@ -787,6 +804,8 @@ lockCallback(StreamIoStatus status)
|
||||
flags |= BusOwner;
|
||||
if (status != StreamIoSuccess)
|
||||
{
|
||||
error("%s: Lock timeout\n",
|
||||
name());
|
||||
finishProtocol(LockTimeout);
|
||||
return;
|
||||
}
|
||||
@ -907,7 +926,7 @@ readCallback(StreamIoStatus status,
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
flags &= ~AcceptInput;
|
||||
//// flags &= ~AcceptInput;
|
||||
unparsedInput = false;
|
||||
switch (status)
|
||||
{
|
||||
@ -966,9 +985,15 @@ readCallback(StreamIoStatus status,
|
||||
{
|
||||
// look for terminator
|
||||
end = inputBuffer.find(inTerminator);
|
||||
if (end >= 0) termlen = inTerminator.length();
|
||||
debug("StreamCore::readCallback(%s) inTerminator %sfound\n",
|
||||
name(), end >= 0 ? "" : "not ");
|
||||
if (end >= 0)
|
||||
{
|
||||
termlen = inTerminator.length();
|
||||
debug("StreamCore::readCallback(%s) inTerminator %s at position %ld\n",
|
||||
name(), inTerminator.expand()(), end);
|
||||
} else {
|
||||
debug("StreamCore::readCallback(%s) inTerminator %s not found\n",
|
||||
name(), inTerminator.expand()());
|
||||
}
|
||||
}
|
||||
if (status == StreamIoEnd && end < 0)
|
||||
{
|
||||
@ -990,6 +1015,12 @@ readCallback(StreamIoStatus status,
|
||||
end = maxInput;
|
||||
termlen = 0;
|
||||
}
|
||||
if (end >= 0)
|
||||
{
|
||||
// be forgiving with timeout because end is found
|
||||
if (status == StreamIoTimeout)
|
||||
status = StreamIoEnd;
|
||||
}
|
||||
if (end < 0)
|
||||
{
|
||||
// no end found
|
||||
@ -1006,23 +1037,22 @@ readCallback(StreamIoStatus status,
|
||||
}
|
||||
// try to parse what we got
|
||||
end = inputBuffer.length();
|
||||
if (!(flags & AsyncMode))
|
||||
if (flags & AsyncMode)
|
||||
{
|
||||
debug("StreamCore::readCallback(%s) async timeout: just restart\n",
|
||||
name());
|
||||
inputBuffer.clear();
|
||||
commandIndex = commandStart;
|
||||
evalIn();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
error("%s: Timeout after reading %ld byte%s \"%s%s\"\n",
|
||||
name(), end, end==1 ? "" : "s", end > 20 ? "..." : "",
|
||||
inputBuffer.expand(-20)());
|
||||
}
|
||||
}
|
||||
|
||||
if (status == StreamIoTimeout && (flags & AsyncMode))
|
||||
{
|
||||
debug("StreamCore::readCallback(%s) async timeout: just restart\n",
|
||||
name());
|
||||
inputBuffer.clear();
|
||||
commandIndex = commandStart;
|
||||
evalIn();
|
||||
return 0;
|
||||
}
|
||||
|
||||
inputLine.set(inputBuffer(), end);
|
||||
debug("StreamCore::readCallback(%s) input line: \"%s\"\n",
|
||||
@ -1063,7 +1093,7 @@ readCallback(StreamIoStatus status,
|
||||
return 0;
|
||||
}
|
||||
// end input mode and do next command
|
||||
flags &= ~(AsyncMode|AcceptInput);
|
||||
//// flags &= ~(AsyncMode|AcceptInput);
|
||||
// -- should we tell someone that input has finished? --
|
||||
evalCommand();
|
||||
return 0;
|
||||
@ -1136,14 +1166,21 @@ matchInput()
|
||||
}
|
||||
if (consumed < 0)
|
||||
{
|
||||
if (!(flags & AsyncMode) && onMismatch[0] != in_cmd)
|
||||
if (fmt.flags & default_flag)
|
||||
{
|
||||
error("%s: Input \"%s%s\" does not match format %%%s\n",
|
||||
name(), inputLine.expand(consumedInput, 20)(),
|
||||
inputLine.length()-consumedInput > 20 ? "..." : "",
|
||||
formatstring);
|
||||
consumed = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(flags & AsyncMode) && onMismatch[0] != in_cmd)
|
||||
{
|
||||
error("%s: Input \"%s%s\" does not match format %%%s\n",
|
||||
name(), inputLine.expand(consumedInput, 20)(),
|
||||
inputLine.length()-consumedInput > 20 ? "..." : "",
|
||||
formatstring);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
consumedInput += consumed;
|
||||
break;
|
||||
@ -1293,8 +1330,16 @@ scanValue(const StreamFormat& fmt, long& value)
|
||||
scanLong(fmt, inputLine(consumedInput), value);
|
||||
debug("StreamCore::scanValue(%s, format=%%%c, long) input=\"%s\"\n",
|
||||
name(), fmt.conv, inputLine.expand(consumedInput)());
|
||||
if (consumed < 0 ||
|
||||
consumed > inputLine.length()-consumedInput) return -1;
|
||||
if (consumed < 0)
|
||||
{
|
||||
if (fmt.flags & default_flag)
|
||||
{
|
||||
value = 0;
|
||||
consumed = 0;
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
if (consumed > inputLine.length()-consumedInput) return -1;
|
||||
debug("StreamCore::scanValue(%s) scanned %li\n",
|
||||
name(), value);
|
||||
flags |= GotValue;
|
||||
@ -1316,8 +1361,16 @@ scanValue(const StreamFormat& fmt, double& value)
|
||||
scanDouble(fmt, inputLine(consumedInput), value);
|
||||
debug("StreamCore::scanValue(%s, format=%%%c, double) input=\"%s\"\n",
|
||||
name(), fmt.conv, inputLine.expand(consumedInput)());
|
||||
if (consumed < 0 ||
|
||||
consumed > inputLine.length()-consumedInput) return -1;
|
||||
if (consumed < 0)
|
||||
{
|
||||
if (fmt.flags & default_flag)
|
||||
{
|
||||
value = 0.0;
|
||||
consumed = 0;
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
if (consumed > inputLine.length()-consumedInput) return -1;
|
||||
debug("StreamCore::scanValue(%s) scanned %#g\n",
|
||||
name(), value);
|
||||
flags |= GotValue;
|
||||
@ -1340,8 +1393,16 @@ scanValue(const StreamFormat& fmt, char* value, long maxlen)
|
||||
scanString(fmt, inputLine(consumedInput), value, maxlen);
|
||||
debug("StreamCore::scanValue(%s, format=%%%c, char*, maxlen=%ld) input=\"%s\"\n",
|
||||
name(), fmt.conv, maxlen, inputLine.expand(consumedInput)());
|
||||
if (consumed < 0 ||
|
||||
consumed > inputLine.length()-consumedInput) return -1;
|
||||
if (consumed < 0)
|
||||
{
|
||||
if (fmt.flags & default_flag)
|
||||
{
|
||||
value[0] = 0;
|
||||
consumed = 0;
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
if (consumed > inputLine.length()-consumedInput) return -1;
|
||||
#ifndef NO_TEMPORARY
|
||||
debug("StreamCore::scanValue(%s) scanned \"%s\"\n",
|
||||
name(), StreamBuffer(value, maxlen).expand()());
|
||||
|
@ -501,8 +501,8 @@ long streamScanSep(dbCommon* record)
|
||||
long streamScanfN(dbCommon* record, format_t *format,
|
||||
void* value, size_t maxStringSize)
|
||||
{
|
||||
debug("streamScanfN(%s,format=%%%c,maxStringSize=%d)\n",
|
||||
record->name, format->priv->conv, maxStringSize);
|
||||
debug("streamScanfN(%s,format=%%%c,maxStringSize=%ld)\n",
|
||||
record->name, format->priv->conv, (long)maxStringSize);
|
||||
Stream* pstream = (Stream*)record->dpvt;
|
||||
if (!pstream) return ERROR;
|
||||
if (!pstream->scan(format, value, maxStringSize))
|
||||
|
@ -23,12 +23,13 @@
|
||||
#define StreamFormat_h
|
||||
|
||||
typedef enum {
|
||||
left_flag = 0x01,
|
||||
sign_flag = 0x02,
|
||||
space_flag = 0x04,
|
||||
alt_flag = 0x08,
|
||||
zero_flag = 0x10,
|
||||
skip_flag = 0x20
|
||||
left_flag = 0x01,
|
||||
sign_flag = 0x02,
|
||||
space_flag = 0x04,
|
||||
alt_flag = 0x08,
|
||||
zero_flag = 0x10,
|
||||
skip_flag = 0x20,
|
||||
default_flag = 0x40
|
||||
} StreamFormatFlag;
|
||||
|
||||
typedef enum {
|
||||
|
@ -112,7 +112,7 @@ static void copyFormatString(StreamBuffer& info, const char* source)
|
||||
const char* p = source - 1;
|
||||
while (*p != '%' && *p != ')') p--;
|
||||
info.append('%');
|
||||
while (++p != source-1) info.append(*p);
|
||||
while (++p != source-1) if (*p != '?') info.append(*p);
|
||||
}
|
||||
|
||||
// Standard Long Converter for 'diouxX'
|
||||
@ -160,7 +160,8 @@ scanLong(const StreamFormat& fmt, const char* input, long& value)
|
||||
int length = -1;
|
||||
if (fmt.flags & skip_flag)
|
||||
{
|
||||
/* on vxWorks, return value of sscanf with %*... is buggy */
|
||||
/* 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);
|
||||
}
|
||||
else
|
||||
@ -217,7 +218,8 @@ scanDouble(const StreamFormat& fmt, const char* input, double& value)
|
||||
int length = -1;
|
||||
if (fmt.flags & skip_flag)
|
||||
{
|
||||
/* on vxWorks, return value of sscanf with %*... is buggy */
|
||||
/* 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);
|
||||
}
|
||||
else
|
||||
@ -276,12 +278,13 @@ scanString(const StreamFormat& fmt, const char* input,
|
||||
if (*input == '\0')
|
||||
{
|
||||
// match empty string
|
||||
value[0] = '\0';
|
||||
if (value) value[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
if (fmt.flags & skip_flag)
|
||||
{
|
||||
/* on vxWorks, return value of sscanf with %*... is buggy */
|
||||
/* 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);
|
||||
}
|
||||
else
|
||||
@ -291,7 +294,7 @@ scanString(const StreamFormat& fmt, const char* input,
|
||||
if (maxlen <= fmt.width || fmt.width == 0)
|
||||
{
|
||||
// assure not to read too much
|
||||
sprintf(tmpformat, "%%%d%c%%n", maxlen-1, fmt.conv);
|
||||
sprintf(tmpformat, "%%%ld%c%%n", (long)maxlen-1, fmt.conv);
|
||||
f = tmpformat;
|
||||
}
|
||||
else
|
||||
@ -409,7 +412,8 @@ scanString(const StreamFormat& fmt, const char* input,
|
||||
int length = -1;
|
||||
if (fmt.flags & skip_flag)
|
||||
{
|
||||
/* on vxWorks, return value of sscanf with %*... is buggy */
|
||||
/* 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);
|
||||
}
|
||||
else
|
||||
@ -420,7 +424,7 @@ scanString(const StreamFormat& fmt, const char* input,
|
||||
{
|
||||
const char *p = strchr (fmt.info, '[');
|
||||
// assure not to read too much
|
||||
sprintf(tmpformat, "%%%d%s", maxlen-1, p);
|
||||
sprintf(tmpformat, "%%%ld%s", (long)maxlen-1, p);
|
||||
f = tmpformat;
|
||||
}
|
||||
else
|
||||
|
@ -1504,6 +1504,16 @@ compileFormat(StreamBuffer& buffer, const char*& formatstr,
|
||||
}
|
||||
streamFormat.flags |= skip_flag;
|
||||
break;
|
||||
case '?':
|
||||
if (formatType != ScanFormat)
|
||||
{
|
||||
errorMsg(line,
|
||||
"Use of default modifier '?' "
|
||||
"only allowed in input formats\n");
|
||||
return false;
|
||||
}
|
||||
streamFormat.flags |= default_flag;
|
||||
break;
|
||||
default:
|
||||
loop = false;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
#define devStream_h
|
||||
|
||||
#define STREAM_MAJOR 2
|
||||
#define STREAM_MINOR 3
|
||||
#define STREAM_MINOR 4
|
||||
|
||||
#if defined(__vxworks) || defined(vxWorks)
|
||||
#include <vxWorks.h>
|
||||
|
@ -25,12 +25,12 @@
|
||||
static long readData (dbCommon *record, format_t *format)
|
||||
{
|
||||
aiRecord *ai = (aiRecord *) record;
|
||||
double val;
|
||||
|
||||
switch (format->type)
|
||||
{
|
||||
case DBF_DOUBLE:
|
||||
{
|
||||
double val;
|
||||
if (streamScanf (record, format, &val)) return ERROR;
|
||||
if (ai->aslo != 0.0) val *= ai->aslo;
|
||||
val += ai->aoff;
|
||||
@ -43,7 +43,10 @@ static long readData (dbCommon *record, format_t *format)
|
||||
}
|
||||
case DBF_LONG:
|
||||
{
|
||||
return streamScanf (record, format, &ai->rval);
|
||||
long rval;
|
||||
if (streamScanf (record, format, &rval)) return ERROR;
|
||||
ai->rval = rval;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
return ERROR;
|
||||
@ -64,7 +67,7 @@ static long writeData (dbCommon *record, format_t *format)
|
||||
}
|
||||
case DBF_LONG:
|
||||
{
|
||||
return streamPrintf (record, format, ai->rval);
|
||||
return streamPrintf (record, format, (long) ai->rval);
|
||||
}
|
||||
}
|
||||
return ERROR;
|
||||
|
@ -51,12 +51,12 @@ static long readData (dbCommon *record, format_t *format)
|
||||
static long writeData (dbCommon *record, format_t *format)
|
||||
{
|
||||
aoRecord *ao = (aoRecord *) record;
|
||||
double val;
|
||||
|
||||
switch (format->type)
|
||||
{
|
||||
case DBF_DOUBLE:
|
||||
{
|
||||
double val;
|
||||
if (INIT_RUN) val = ao->val;
|
||||
else val = ao->oval;
|
||||
val -= ao->aoff;
|
||||
@ -65,7 +65,7 @@ static long writeData (dbCommon *record, format_t *format)
|
||||
}
|
||||
case DBF_LONG:
|
||||
{
|
||||
return streamPrintf (record, format, ao->rval);
|
||||
return streamPrintf (record, format, (long) ao->rval);
|
||||
}
|
||||
}
|
||||
return ERROR;
|
||||
|
@ -28,7 +28,10 @@ static long readData (dbCommon *record, format_t *format)
|
||||
|
||||
if (format->type == DBF_LONG || format->type == DBF_ENUM)
|
||||
{
|
||||
return streamScanf (record, format, &li->val);
|
||||
long val;
|
||||
if (streamScanf (record, format, &val)) return ERROR;
|
||||
li->val = val;
|
||||
return OK;
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
@ -39,7 +42,7 @@ static long writeData (dbCommon *record, format_t *format)
|
||||
|
||||
if (format->type == DBF_LONG || format->type == DBF_ENUM)
|
||||
{
|
||||
return streamPrintf (record, format, li->val);
|
||||
return streamPrintf (record, format, (long) li->val);
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
|
@ -29,7 +29,10 @@ static long readData (dbCommon *record, format_t *format)
|
||||
|
||||
if (format->type == DBF_LONG || format->type == DBF_ENUM)
|
||||
{
|
||||
return streamScanf (record, format, &lo->val);
|
||||
long val;
|
||||
if (streamScanf (record, format, &val)) return ERROR;
|
||||
lo->val = val;
|
||||
return OK;
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
@ -40,7 +43,7 @@ static long writeData (dbCommon *record, format_t *format)
|
||||
|
||||
if (format->type == DBF_LONG || format->type == DBF_ENUM)
|
||||
{
|
||||
return streamPrintf (record, format, lo->val);
|
||||
return streamPrintf (record, format, (long) lo->val);
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
|
Reference in New Issue
Block a user