Compare commits

..

17 Commits

Author SHA1 Message Date
d5dc15e321 version updated 2018-07-12 16:16:34 +02:00
cfa777d718 added missing output convertion from ULONG in waveform record 2018-07-12 16:11:38 +02:00
54bc78f7c7 fix bug that leads to infinite callback loop when first command (typically 'out') fails 2018-07-12 16:07:48 +02:00
77d110de70 fix for 'skip' and '?' in 'in' command 2018-07-11 18:00:08 +02:00
19467bd5d5 allow literal \0 - \9 in regsub if there is no matching sub-expression 2018-07-10 11:08:36 +02:00
d69c74bc8f update version 2018-07-06 17:03:40 +02:00
e09506c2bb always enable error messages when loading protocol files 2018-07-06 17:02:34 +02:00
343eef324b bugfix: in quoted strings do not mis-interpret double backslash before quote or $ as escape char 2018-07-06 16:48:15 +02:00
a798cf2f21 buxfix: in regsub continue scanning only after last substitution 2018-07-06 14:37:18 +02:00
23f3e806e2 removed unfiltered debug message 2018-06-08 10:54:21 +02:00
56b6c9a627 fix for 3.16+ 2018-06-06 10:51:18 +02:00
2830f07324 update version number 2017-11-03 13:46:08 +01:00
abd8daafc3 escape all non-ascii chars to avoid problems with UTF terminals 2017-11-03 13:41:38 +01:00
489e783872 Don't change EOS if not necessary. And some improved diagnostics 2017-11-03 13:40:47 +01:00
10d1fa8b02 do not run exceprion handlers from @init 2017-11-02 09:18:24 +01:00
c8bffebfc6 fix version number 2017-11-02 09:17:47 +01:00
0a90eb3d9c fix ai/ao conversion when using LINR=NO CONVERSION together with ASLO or AOFF 2017-01-18 16:03:02 +01:00
13 changed files with 139 additions and 87 deletions

View File

@ -44,7 +44,7 @@ ifneq (${EPICS_BASETYPE},3.13)
RECORDTYPES += calcout RECORDTYPES += calcout
endif endif
StreamCore.o: streamReferences StreamCore.o StreamCore.d: streamReferences
streamReferences: streamReferences:
perl ../src/makeref.pl Interface $(BUSSES) > $@ perl ../src/makeref.pl Interface $(BUSSES) > $@

View File

@ -564,8 +564,8 @@ in architecture specific RELEASE.Common.<em>arch</em> files.
If the regular expression is not anchored, i.e. does not start with If the regular expression is not anchored, i.e. does not start with
<code>^</code>, leading non-matching input is skipped. <code>^</code>, leading non-matching input is skipped.
A maximum of <em>width</em> bytes is matched, if specified. A maximum of <em>width</em> bytes is matched, if specified.
If <em>precision</em> is given, it specifies the sub-expression whose match If <em>precision</em> is given, it specifies the sub-expression in <code>()</code>
is retuned. whose match is retuned.
Otherwise the complete match is returned. Otherwise the complete match is returned.
In any case, the complete match is consumed from the input buffer. In any case, the complete match is consumed from the input buffer.
If the expression contains a <code>/</code> it must be escaped like <code>\/</code>. If the expression contains a <code>/</code> it must be escaped like <code>\/</code>.
@ -586,12 +586,19 @@ as a post-processor for output.
</p> </p>
<p> <p>
Matches of the <em>regex</em> are replaced by the string <em>subst</em> with all Matches of the <em>regex</em> are replaced by the string <em>subst</em> with all
<code>&</code> or <code>\0</code> in <em>subst</em> replaced with the match itself and all <code>&</code> in <em>subst</em> replaced with the match itself and all
<code>\1</code> through <code>\9</code> replaced with the match of the corresponding sub-expression. <code>\1</code> through <code>\9</code> replaced with the match of the corresponding
sub-expression <span class="new"> if such a sub-expression exists.
Due to limitations of the parser, <code>\1</code> and <code>\x01</code> are the same
which makes it difficult to use literal bytes with values lower than 10 in <em>subst</em>.
Therefore <code>\0</code> aways means a literal byte (incompatible change from earlier version!)
and <code>\1</code> through <code>\9</code> mean literal bytes if they are larger than
the number of sub-expressions.
</span>
To get a literal <code>&</code> or <code>\</code> or <code>/</code> in the substitution write To get a literal <code>&</code> or <code>\</code> or <code>/</code> in the substitution write
<code>\&</code> or <code>\\</code> or <code>\/</code>. <code>\&</code> or <code>\\</code> or <code>\/</code>.
There is no way to specify literal bytes with values less or equal to 9 in the
substitution!
</p> </p>
<p> <p>
If <em>width</em> is specified, it limits the number of characters processed. If <em>width</em> is specified, it limits the number of characters processed.

View File

@ -562,13 +562,7 @@ connectToAsynPort()
clientName(), connected ? "already" : "not yet"); clientName(), connected ? "already" : "not yet");
if (!connected) if (!connected)
{ {
printf ("%s: AsynDriverInterface::connectToAsynPort: "
"pasynCommon->connect(%p, %p)\n",
clientName(), pvtCommon, pasynUser);
status = pasynCommon->connect(pvtCommon, pasynUser); status = pasynCommon->connect(pvtCommon, pasynUser);
printf ("%s: AsynDriverInterface::connectToAsynPort: "
"pasynCommon->connect(%p, %p) = %s\n",
clientName(), pvtCommon, pasynUser, asynStatusStr[status]);
debug("AsynDriverInterface::connectToAsynPort(%s): " debug("AsynDriverInterface::connectToAsynPort(%s): "
"status=%s\n", "status=%s\n",
clientName(), asynStatusStr[status]); clientName(), asynStatusStr[status]);
@ -718,13 +712,19 @@ writeHandler()
pasynOctet->setOutputEos(pvtOctet, pasynUser, pasynOctet->setOutputEos(pvtOctet, pasynUser,
NULL, 0); NULL, 0);
} }
pasynUser->errorMessage[0] = 0;
status = pasynOctet->write(pvtOctet, pasynUser, status = pasynOctet->write(pvtOctet, pasynUser,
outputBuffer, outputSize, &written); outputBuffer, outputSize, &written);
#ifndef NO_TEMPORARY
debug("AsynDriverInterface::writeHandler(%s): " debug("AsynDriverInterface::writeHandler(%s): "
"write(..., outputSize=%ld, written=%ld) " "write(..., \"%s\", outputSize=%ld, written=%ld) "
"[timeout=%g sec] = %s\n", "[timeout=%g sec] = %s (%s)\n",
clientName(), (long)outputSize, (long)written, clientName(),
pasynUser->timeout, asynStatusStr[status]); StreamBuffer(outputBuffer, outputSize).expand()(),
(long)outputSize, (long)written,
pasynUser->timeout, asynStatusStr[status],
pasynUser->errorMessage);
#endif
if (oldeoslen >= 0) // restore asyn terminator if (oldeoslen >= 0) // restore asyn terminator
{ {
@ -769,34 +769,34 @@ writeHandler()
writeCallback(StreamIoSuccess); writeCallback(StreamIoSuccess);
return; return;
case asynTimeout: case asynTimeout:
error("%s: asynTimeout (%g sec) in write. Asyn says: %s\n", error("%s: asynTimeout (%g sec) in write. Asyn driver says: \"%s\"\n",
clientName(), pasynUser->timeout, pasynUser->errorMessage); clientName(), pasynUser->timeout, pasynUser->errorMessage);
writeCallback(StreamIoTimeout); writeCallback(StreamIoTimeout);
return; return;
case asynOverflow: case asynOverflow:
error("%s: asynOverflow in write. Asyn driver says: %s\n", error("%s: asynOverflow in write. Asyn driver says: \"%s\"\n",
clientName(), pasynUser->errorMessage); clientName(), pasynUser->errorMessage);
writeCallback(StreamIoFault); writeCallback(StreamIoFault);
return; return;
case asynError: case asynError:
error("%s: asynError in write. Asyn driver says: %s\n", error("%s: asynError in write. Asyn driver says: \"%s\"\n",
clientName(), pasynUser->errorMessage); clientName(), pasynUser->errorMessage);
writeCallback(StreamIoFault); writeCallback(StreamIoFault);
return; return;
#ifdef ASYN_VERSION // asyn >= 4.14 #ifdef ASYN_VERSION // asyn >= 4.14
case asynDisconnected: case asynDisconnected:
error("%s: asynDisconnected in write. Asyn driver says: %s\n", error("%s: asynDisconnected in write. Asyn driver says: \"%s\"\n",
clientName(), pasynUser->errorMessage); clientName(), pasynUser->errorMessage);
writeCallback(StreamIoFault); writeCallback(StreamIoFault);
return; return;
case asynDisabled: case asynDisabled:
error("%s: asynDisconnected in write. Asyn driver says: %s\n", error("%s: asynDisconnected in write. Asyn driver says: \"%s\"\n",
clientName(), pasynUser->errorMessage); clientName(), pasynUser->errorMessage);
writeCallback(StreamIoFault); writeCallback(StreamIoFault);
return; return;
#endif #endif
default: default:
error("%s: unknown asyn error in write. Asyn driver says: %s\n", error("%s: unknown asyn error in write. Asyn driver says: \"%s\"\n",
clientName(), pasynUser->errorMessage); clientName(), pasynUser->errorMessage);
writeCallback(StreamIoFault); writeCallback(StreamIoFault);
return; return;
@ -887,6 +887,11 @@ readHandler()
oldeoslen = -1; oldeoslen = -1;
} else do { } else do {
// device (e.g. GPIB) might not accept full eos length // device (e.g. GPIB) might not accept full eos length
if ((int)deveoslen == oldeoslen && strcmp(deveos, oldeos) == 0)
{
// nothing to do: old and new eos are the same
break;
}
if (pasynOctet->setInputEos(pvtOctet, pasynUser, if (pasynOctet->setInputEos(pvtOctet, pasynUser,
deveos, deveoslen) == asynSuccess) deveos, deveoslen) == asynSuccess)
{ {
@ -894,8 +899,9 @@ readHandler()
if (ioAction != AsyncRead) if (ioAction != AsyncRead)
{ {
debug("AsynDriverInterface::readHandler(%s) " debug("AsynDriverInterface::readHandler(%s) "
"input EOS set to %s\n", "input EOS changed from \"%s\" to \"%s\"\n",
clientName(), clientName(),
StreamBuffer(oldeos, oldeoslen).expand()(),
StreamBuffer(deveos, deveoslen).expand()()); StreamBuffer(deveos, deveoslen).expand()());
} }
#endif #endif
@ -951,6 +957,7 @@ readHandler()
readMore = 0; readMore = 0;
received = 0; received = 0;
eomReason = 0; eomReason = 0;
pasynUser->errorMessage[0] = 0;
debug("AsynDriverInterface::readHandler(%s): ioAction=%s " debug("AsynDriverInterface::readHandler(%s): ioAction=%s "
"read(..., bytesToRead=%ld, ...) " "read(..., bytesToRead=%ld, ...) "
@ -959,12 +966,13 @@ readHandler()
bytesToRead, pasynUser->timeout); bytesToRead, pasynUser->timeout);
status = pasynOctet->read(pvtOctet, pasynUser, status = pasynOctet->read(pvtOctet, pasynUser,
buffer, bytesToRead, &received, &eomReason); buffer, bytesToRead, &received, &eomReason);
#ifndef NO_TEMPORARY
debug("AsynDriverInterface::readHandler(%s): " debug("AsynDriverInterface::readHandler(%s): "
"read returned %s: ioAction=%s received=%ld, eomReason=%s, buffer=\"%s\"\n", "read returned %s: ioAction=%s received=%ld, eomReason=%s, buffer=\"%s\"\n",
clientName(), asynStatusStr[status], ioActionStr[ioAction], clientName(), asynStatusStr[status], ioActionStr[ioAction],
(long)received,eomReasonStr[eomReason&0x7], (long)received,eomReasonStr[eomReason&0x7],
StreamBuffer(buffer, received).expand()()); StreamBuffer(buffer, received).expand()());
#endif
pasynManager->isConnected(pasynUser, &connected); pasynManager->isConnected(pasynUser, &connected);
debug("AsynDriverInterface::readHandler(%s): " debug("AsynDriverInterface::readHandler(%s): "
"device is now %sconnected\n", "device is now %sconnected\n",
@ -1094,29 +1102,29 @@ readHandler()
} }
peeksize = inputBuffer.capacity(); peeksize = inputBuffer.capacity();
// deliver whatever we could save // deliver whatever we could save
error("%s: asynOverflow in read. Asyn driver says: %s\n", error("%s: asynOverflow in read. Asyn driver says: \"%s\"\n",
clientName(), pasynUser->errorMessage); clientName(), pasynUser->errorMessage);
readCallback(StreamIoFault, buffer, received); readCallback(StreamIoFault, buffer, received);
break; break;
case asynError: case asynError:
error("%s: asynError in read. Asyn driver says: %s\n", error("%s: asynError in read. Asyn driver says: \"%s\"\n",
clientName(), pasynUser->errorMessage); clientName(), pasynUser->errorMessage);
readCallback(StreamIoFault, buffer, received); readCallback(StreamIoFault, buffer, received);
break; break;
#ifdef ASYN_VERSION // asyn >= 4.14 #ifdef ASYN_VERSION // asyn >= 4.14
case asynDisconnected: case asynDisconnected:
error("%s: asynDisconnected in read. Asyn driver says: %s\n", error("%s: asynDisconnected in read. Asyn driver says: \"%s\"\n",
clientName(), pasynUser->errorMessage); clientName(), pasynUser->errorMessage);
readCallback(StreamIoFault); readCallback(StreamIoFault);
return; return;
case asynDisabled: case asynDisabled:
error("%s: asynDisconnected in read. Asyn driver says: %s\n", error("%s: asynDisconnected in read. Asyn driver says: \"%s\"\n",
clientName(), pasynUser->errorMessage); clientName(), pasynUser->errorMessage);
readCallback(StreamIoFault); readCallback(StreamIoFault);
return; return;
#endif #endif
default: default:
error("%s: unknown asyn error in read. Asyn driver says: %s\n", error("%s: unknown asyn error in read. Asyn driver says: \"%s\"\n",
clientName(), pasynUser->errorMessage); clientName(), pasynUser->errorMessage);
readCallback(StreamIoFault); readCallback(StreamIoFault);
return; return;
@ -1138,10 +1146,16 @@ readHandler()
} }
// restore original EOS // restore original EOS
if (oldeoslen >= 0) if (oldeoslen >= 0 && oldeoslen != (int)deveoslen && strcmp(deveos, oldeos) != 0)
{ {
pasynOctet->setInputEos(pvtOctet, pasynUser, pasynOctet->setInputEos(pvtOctet, pasynUser,
oldeos, oldeoslen); oldeos, oldeoslen);
#ifndef NO_TEMPORARY
debug("AsynDriverInterface::readHandler(%s) "
"input EOS restored to \"%s\"\n",
clientName(),
StreamBuffer(oldeos, oldeoslen).expand()());
#endif
} }
} }

View File

@ -32,7 +32,6 @@
run-time leak. run-time leak.
- A maximum of 9 subexpressions is supported. Only one of them can - A maximum of 9 subexpressions is supported. Only one of them can
be the result of the match. be the result of the match.
- vxWorks and maybe other OS don't have a PCRE library. Provide one?
*/ */
class RegexpConverter : public StreamFormatConverter class RegexpConverter : public StreamFormatConverter
@ -54,7 +53,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("Sub-expression index %d too big (>9)\n", fmt.prec);
return false; return false;
} }
@ -84,18 +83,26 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
const char* errormsg; const char* errormsg;
int eoffset; int eoffset;
pcre* code = pcre_compile(pattern(), 0, int nsubexpr;
&errormsg, &eoffset, NULL);
pcre* code = pcre_compile(pattern(), 0, &errormsg, &eoffset, NULL);
if (!code) if (!code)
{ {
error("%s after \"%s\"\n", errormsg, pattern.expand(0, eoffset)()); error("%s after \"%s\"\n", errormsg, pattern.expand(0, eoffset)());
return false; return false;
} }
pcre_fullinfo(code, NULL, PCRE_INFO_CAPTURECOUNT, &nsubexpr);
if (fmt.prec > nsubexpr)
{
error("Sub-expression index is %d but pattern has only %d sub-expression\n", fmt.prec, nsubexpr);
return false;
}
info.append(&code, sizeof(code)); info.append(&code, sizeof(code));
if (fmt.flags & alt_flag) if (fmt.flags & alt_flag)
{ {
StreamBuffer subst; StreamBuffer subst;
debug("check for subst in \"%s\"\n", StreamBuffer(source).expand()()); debug("check for subst in \"%s\"\n", StreamBuffer(source).expand()());
while (*source != '/') while (*source != '/')
{ {
@ -167,16 +174,16 @@ static void regsubst(const StreamFormat& fmt, StreamBuffer& buffer, long start)
length = buffer.length() - start; length = buffer.length() - start;
if (fmt.width && fmt.width < length) if (fmt.width && fmt.width < length)
length = fmt.width; length = fmt.width;
if (fmt.flags & sign_flag) if (fmt.flags & left_flag)
start = buffer.length() - length; start = buffer.length() - length;
debug("regsubst buffer=\"%s\", start=%ld, length=%ld, subst = \"%s\"\n", debug("regsubst buffer=\"%s\", start=%ld, length=%ld, subst = \"%s\"\n",
buffer.expand()(), start, length, subst); buffer.expand()(), start, length, StreamBuffer(subst).expand()());
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", buffer.expand(start+c, length-c)(), rc);
if (rc < 0) // no match if (rc < 0) // no match
return; return;
@ -188,11 +195,11 @@ static void regsubst(const StreamFormat& fmt, StreamBuffer& buffer, long start)
} }
// replace & by match in subst // replace & by match in subst
l = ovector[1] - ovector[0]; l = ovector[1] - ovector[0];
debug("start = \"%s\"\n", buffer(start+c)); debug("before [%d]= \"%s\"\n", ovector[0], buffer.expand(start+c,ovector[0])());
debug("match = \"%.*s\"\n", l, buffer(start+c+ovector[0])); debug("match [%d]= \"%s\"\n", l, buffer.expand(start+c+ovector[0],l)());
for (r = 1; r < rc; r++) for (r = 1; r < rc; r++)
debug("sub%d = \"%.*s\"\n", r, ovector[r*2+1]-ovector[r*2], buffer(start+c+ovector[r*2])); debug("sub%d = \"%s\"\n", r, buffer.expand(start+c+ovector[r*2], ovector[r*2+1]-ovector[r*2])());
debug("rest = \"%s\"\n", buffer(start+c+ovector[1])); debug("after = \"%s\"\n", buffer.expand(start+c+ovector[1])());
s = subst; s = subst;
debug("subs = \"%s\"\n", s.expand()()); debug("subs = \"%s\"\n", s.expand()());
for (r = 0; r < s.length(); r++) for (r = 0; r < s.length(); r++)
@ -201,11 +208,11 @@ static void regsubst(const StreamFormat& fmt, StreamBuffer& buffer, long start)
if (s[r] == esc) if (s[r] == esc)
{ {
unsigned char ch = s[r+1]; unsigned char ch = s[r+1];
if (ch < 9) // escaped 0 - 9 : replace with subexpr if (c != 0 && ch < rc) // escaped 1 - 9 : replace with subexpr
{ {
ch *= 2; ch *= 2;
rl = ovector[ch+1] - ovector[ch]; rl = ovector[ch+1] - ovector[ch];
debug("replace \\%d: \"%.*s\"\n", ch/2, rl, buffer(start+c+ovector[ch])); debug("replace \\%d: \"%s\"\n", ch/2, buffer.expand(start+c+ovector[ch], rl)());
s.replace(r, 2, buffer(start+c+ovector[ch]), rl); s.replace(r, 2, buffer(start+c+ovector[ch]), rl);
r += rl - 1; r += rl - 1;
} }
@ -214,16 +221,16 @@ static void regsubst(const StreamFormat& fmt, StreamBuffer& buffer, long start)
} }
else if (s[r] == '&') // unescaped & : replace with match else if (s[r] == '&') // unescaped & : replace with match
{ {
debug("replace &: \"%.*s\"\n", l, buffer(start+c+ovector[0])); debug("replace &: \"%s\"\n", buffer.expand(start+c+ovector[0], l)());
s.replace(r, 1, buffer(start+c+ovector[0]), l); s.replace(r, 1, buffer(start+c+ovector[0]), l);
r += l - 1; r += l - 1;
} }
else continue; else continue;
debug("subs = \"%s\"\n", s()); debug("subs = \"%s\"\n", s.expand()());
} }
buffer.replace(start+c+ovector[0], l, s); buffer.replace(start+c+ovector[0], l, s);
length += s.length() - l; length += s.length() - l;
c += s.length(); c += ovector[0] + s.length();
if (n == fmt.prec) // max match reached if (n == fmt.prec) // max match reached
return; return;
} }

View File

@ -296,7 +296,7 @@ StreamBuffer StreamBuffer::expand(ssize_t start, ssize_t length) const
for (i = start; i < end; i++) for (i = start; i < end; i++)
{ {
c = buffer[i]; c = buffer[i];
if ((c & 0x7f) < 0x20 || (c & 0x7f) == 0x7f) if (c < 0x20 || c >= 0x7f)
{ {
result.print("<%02x>", c & 0xff); result.print("<%02x>", c & 0xff);
} }

View File

@ -460,7 +460,7 @@ finishProtocol(ProtocolResult status)
status = Fault; status = Fault;
} }
//// flags &= ~(AcceptInput|AcceptEvent); //// flags &= ~(AcceptInput|AcceptEvent);
if (runningHandler) if (runningHandler || flags & InitRun)
{ {
// get original error status // get original error status
if (status == Success) status = runningHandler; if (status == Success) status = runningHandler;

View File

@ -196,8 +196,12 @@ extern "C" long streamReload(char* recordname)
dbCommon* record; dbCommon* record;
long status; long status;
int oldStreamError = streamError;
streamError = 1;
if(!pdbbase) { if(!pdbbase) {
error("No database has been loaded\n"); error("No database has been loaded\n");
streamError = oldStreamError;
return ERROR; return ERROR;
} }
debug("streamReload(%s)\n", recordname); debug("streamReload(%s)\n", recordname);
@ -234,6 +238,7 @@ extern "C" long streamReload(char* recordname)
} }
dbFinishEntry(&dbentry); dbFinishEntry(&dbentry);
StreamProtocolParser::free(); StreamProtocolParser::free();
streamError = oldStreamError;
return OK; return OK;
} }
@ -408,6 +413,7 @@ long streamInit(int after)
{ {
if (after) if (after)
{ {
streamError = 0; // Switch off errors after init in order not to spam messages when a device is down.
StreamProtocolParser::free(); StreamProtocolParser::free();
} }
return OK; return OK;
@ -735,16 +741,15 @@ process()
debug("Stream::process(%s) start\n", name()); debug("Stream::process(%s) start\n", name());
status = NO_ALARM; status = NO_ALARM;
convert = OK; convert = OK;
record->pact = true;
if (!startProtocol(StreamCore::StartNormal)) if (!startProtocol(StreamCore::StartNormal))
{ {
debug("Stream::process(%s): could not start, status=%d\n", debug("Stream::process(%s): could not start, status=%d\n",
name(), status); name(), status);
(void) recGblSetSevr(record, status, INVALID_ALARM); (void) recGblSetSevr(record, status, INVALID_ALARM);
record->pact = false;
return false; return false;
} }
debug("Stream::process(%s): protocol started\n", name()); debug("Stream::process(%s): protocol started\n", name());
record->pact = true;
return true; return true;
} }

View File

@ -23,7 +23,7 @@
#include <stdio.h> #include <stdio.h>
int streamDebug = 0; int streamDebug = 0;
int streamError = 0; int streamError = 1;
extern "C" { extern "C" {
#ifdef _WIN32 #ifdef _WIN32
__declspec(dllexport) __declspec(dllexport)

View File

@ -512,7 +512,16 @@ Each time newline is read, line is incremented.
buffer(token)); buffer(token));
return false; return false;
} }
if (c == '$' && buffer[-1] == '\\') buffer.append(c);
if (c == quote)
{
quote = false;
break;
}
if (c == '\\')
{
c = getc(file);
if (c == '$')
{ {
// quoted variable reference // quoted variable reference
// terminate string here and do variable in next pass // terminate string here and do variable in next pass
@ -520,11 +529,13 @@ Each time newline is read, line is incremented.
ungetc(c, file); ungetc(c, file);
break; break;
} }
buffer.append(c); if (c == EOF || c == '\n')
if (c == quote && buffer[-2] != '\\')
{ {
quote = false; error(line, filename(), "Backslash at end of line: %s\n",
break; buffer(token));
return false;
}
buffer.append(c);
} }
c = getc(file); c = getc(file);
} }
@ -1348,7 +1359,8 @@ compileString(StreamBuffer& buffer, const char*& source,
source); source);
return false; return false;
} }
if (formatType != NoFormat) if (formatType != NoFormat &&
i > 2 /* do not escape skip */)
{ {
buffer.append(esc); buffer.append(esc);
} }

View File

@ -23,7 +23,7 @@
#define STREAM_MAJOR 2 #define STREAM_MAJOR 2
#define STREAM_MINOR 7 #define STREAM_MINOR 7
#define STREAM_PATCHLEVEL 8 #define STREAM_PATCHLEVEL 14
#if defined(__vxworks) || defined(vxWorks) #if defined(__vxworks) || defined(vxWorks)
#include <vxWorks.h> #include <vxWorks.h>
@ -58,7 +58,6 @@ extern "C" {
#include <dbCommon.h> #include <dbCommon.h>
#include <dbScan.h> #include <dbScan.h>
#include <devSup.h> #include <devSup.h>
/* #include <dbFldTypes.h> */
#include <dbAccess.h> #include <dbAccess.h>
#ifdef devStream_epicsExportSharedSymbols #ifdef devStream_epicsExportSharedSymbols

View File

@ -55,11 +55,14 @@ static long readData (dbCommon *record, format_t *format)
ai->rval = rval; ai->rval = rval;
if (ai->linr == menuConvertNO_CONVERSION) if (ai->linr == menuConvertNO_CONVERSION)
{ {
/* allow more bits than 32 */ /* allow integers with more than 32 bits */
double val;
if (format->type == DBF_ULONG) if (format->type == DBF_ULONG)
ai->val = (unsigned long)rval; val = (unsigned long)rval;
else else
ai->val = rval; val = rval;
if (ai->aslo != 0.0 && ai->aslo != 1.0) val *= ai->aslo;
ai->val = val + ai->aoff;
return DO_NOT_CONVERT; return DO_NOT_CONVERT;
} }
return OK; return OK;

View File

@ -46,11 +46,14 @@ static long readData (dbCommon *record, format_t *format)
ao->rval = rval; ao->rval = rval;
if (ao->linr == menuConvertNO_CONVERSION) if (ao->linr == menuConvertNO_CONVERSION)
{ {
/* allow more bits than 32 */ /* allow integers with more than 32 bits */
double val;
if (format->type == DBF_ULONG) if (format->type == DBF_ULONG)
ao->val = (unsigned long)rval; val = (unsigned long)rval;
else else
ao->val = rval; val = rval;
if (ao->aslo != 0.0 && ao->aslo != 1.0) val *= ao->aslo;
ao->val = val + ao->aoff;
return DO_NOT_CONVERT; return DO_NOT_CONVERT;
} }
return OK; return OK;
@ -63,20 +66,21 @@ static long writeData (dbCommon *record, format_t *format)
{ {
aoRecord *ao = (aoRecord *) record; aoRecord *ao = (aoRecord *) record;
double val = (INIT_RUN ? ao->val : ao->oval) - ao->aoff;
if (ao->aslo != 0.0 && ao->aslo != 1.0) val /= ao->aslo;
switch (format->type) switch (format->type)
{ {
case DBF_DOUBLE: case DBF_DOUBLE:
{ {
double val = (INIT_RUN ? ao->val : ao->oval) - ao->aoff;
if (ao->aslo != 0.0 && ao->aslo != 1.0) val /= ao->aslo;
return streamPrintf (record, format, val); return streamPrintf (record, format, val);
} }
case DBF_ULONG: case DBF_ULONG:
{ {
if (ao->linr == menuConvertNO_CONVERSION) if (ao->linr == menuConvertNO_CONVERSION)
{ {
/* allow more bits than 32 */ /* allow integers with more than 32 bits */
return streamPrintf (record, format, (unsigned long)(INIT_RUN ? ao->val : ao->oval)); return streamPrintf (record, format, (unsigned long)val);
} }
return streamPrintf (record, format, (unsigned long)ao->rval); return streamPrintf (record, format, (unsigned long)ao->rval);
} }
@ -84,8 +88,8 @@ static long writeData (dbCommon *record, format_t *format)
{ {
if (ao->linr == menuConvertNO_CONVERSION) if (ao->linr == menuConvertNO_CONVERSION)
{ {
/* allow more bits than 32 */ /* allow integers with more than 32 bits */
return streamPrintf (record, format, (long)(INIT_RUN ? ao->val : ao->oval)); return streamPrintf (record, format, (long)val);
} }
return streamPrintf (record, format, (long)ao->rval); return streamPrintf (record, format, (long)ao->rval);
} }

View File

@ -192,6 +192,7 @@ static long writeData (dbCommon *record, format_t *format)
return ERROR; return ERROR;
break; break;
} }
case DBF_ULONG:
case DBF_LONG: case DBF_LONG:
case DBF_ENUM: case DBF_ENUM:
{ {