update to current snapshot version

This commit is contained in:
zimoch
2007-08-27 12:49:48 +00:00
parent 13d1b6a42b
commit c3979f766f
10 changed files with 286 additions and 58 deletions

View File

@ -352,56 +352,85 @@ In input, the next byte or bytes must match the checksum.
<h3>Implemented checksum functions</h3>
<dl>
<dt><code>%&lt;SUM&gt;</code> or <code>%&lt;SUM8&gt;</code></dt>
<dt><code>%&lt;sum&gt;</code> or <code>%&lt;sum8&gt;</code></dt>
<dd>One byte. The sum of all characters modulo 2<sup>8</sup>.</dd>
<dt><code>%&lt;SUM16&gt;</code></dt>
<dt><code>%&lt;sum16&gt;</code></dt>
<dd>Two bytes. The sum of all characters modulo 2<sup>16</sup>.</dd>
<dt><code>%&lt;SUM32&gt;</code></dt>
<dt><code>%&lt;sum32&gt;</code></dt>
<dd>Four bytes. The sum of all characters modulo 2<sup>32</sup>.</dd>
<dt><code>%&lt;NEGSUM&gt;</code> or <code>%&lt;NSUM&gt;</code> or <code>%&lt;-SUM&gt;</code></dt>
<dt><code>%&lt;negsum&gt;</code>, <code>%&lt;nsum&gt;</code>, <code>%&lt;-sum&gt;</code>, <code>%&lt;negsum8&gt;</code>, <code>%&lt;nsum8&gt;</code>, or <code>%&lt;-sum8&gt;</code></dt>
<dd>One byte. The negative of the sum of all characters modulo 2<sup>8</sup>.</dd>
<dt><code>%&lt;NOTSUM&gt;</code> or <code>%&lt;~SUM&gt;</code></dt>
<dt><code>%&lt;negsum16&gt;</code>, <code>%&lt;nsum16&gt;</code>, or <code>%&lt;-sum16&gt;</code></dt>
<dd>Two bytes. The negative of the sum of all characters modulo 2<sup>16</sup>.</dd>
<dt><code>%&lt;negsum32&gt;</code>, <code>%&lt;nsum32&gt;</code>, or <code>%&lt;-sum32&gt;</code></dt>
<dd>Four bytes. The negative of the sum of all characters modulo 2<sup>32</sup>.</dd>
<dt><code>%&lt;notsum&gt;</code> or <code>%&lt;~sum&gt;</code></dt>
<dd>One byte. The bitwise inverse of the sum of all characters modulo 2<sup>8</sup>.</dd>
<dt><code>%&lt;XOR&gt;</code></dt>
<dt><code>%&lt;xor&gt;</code></dt>
<dd>One byte. All characters xor'ed.</dd>
<dt><code>%&lt;CRC8&gt;</code></dt>
<dd>One byte. An often used 8 bit CRC checksum
<dt><code>%&lt;xor7&gt;</code></dt>
<dd>One byte. All characters xor'ed &amp; 0x7F.</dd>
<dt><code>%&lt;crc8&gt;</code></dt>
<dd>One byte. An often used 8 bit crc checksum
(poly=0x07, init=0x00, xorout=0x00).</dd>
<dt><code>%&lt;CCITT8&gt;</code></dt>
<dd>One byte. The CCITT standard 8 bit CRC checksum
<dt><code>%&lt;ccitt8&gt;</code></dt>
<dd>One byte. The CCITT standard 8 bit crc checksum
(poly=0x31, init=0x00, xorout=0x00).</dd>
<dt><code>%&lt;CRC16&gt;</code></dt>
<dd>Two bytes. An often used 16 bit CRC checksum
<dt><code>%&lt;crc16&gt;</code></dt>
<dd>Two bytes. An often used 16 bit crc checksum
(poly=0x8005, init=0x0000, xorout=0x0000).</dd>
<dt><code>%&lt;CRC16R&gt;</code></dt>
<dd>Two bytes. An often used reflected 16 bit CRC checksum
<dt><code>%&lt;crc16r&gt;</code></dt>
<dd>Two bytes. An often used reflected 16 bit crc checksum
(poly=0x8005, init=0x0000, xorout=0x0000).</dd>
<dt><code>%&lt;CCITT16&gt;</code></dt>
<dt><code>%&lt;ccitt16&gt;</code></dt>
<dd>Two bytes. The usual (but <a target="ex"
href="http://www.joegeluso.com/software/articles/ccitt.htm">wrong?</a>)
implementation of the CCITT standard 16 bit CRC checksum
implementation of the CCITT standard 16 bit crc checksum
(poly=0x1021, init=0xFFFF, xorout=0x0000).</dd>
<dt><code>%&lt;CCITT16A&gt;</code></dt>
<dt><code>%&lt;ccitt16a&gt;</code></dt>
<dd>Two bytes. The unusual (but <a target="ex"
href="http://www.joegeluso.com/software/articles/ccitt.htm">correct?</a>)
implementation of the CCITT standard 16 bit CRC checksum with augment.
implementation of the CCITT standard 16 bit crc checksum with augment.
(poly=0x1021, init=0x1D0F, xorout=0x0000).</dd>
<dt><code>%&lt;CRC32&gt;</code></dt>
<dd>Four bytes. The standard 32 bit CRC checksum.
<dt><code>%&lt;crc32&gt;</code></dt>
<dd>Four bytes. The standard 32 bit crc checksum.
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0xFFFFFFFF).</dd>
<dt><code>%&lt;CRC32R&gt;</code></dt>
<dd>Four bytes. The standard reflected 32 bit CRC checksum.
<dt><code>%&lt;crc32r&gt;</code></dt>
<dd>Four bytes. The standard reflected 32 bit crc checksum.
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0xFFFFFFFF).</dd>
<dt><code>%&lt;JAMCRC&gt;</code></dt>
<dd>Four bytes. Another reflected 32 bit CRC checksum.
<dt><code>%&lt;jamcrc&gt;</code></dt>
<dd>Four bytes. Another reflected 32 bit crc checksum.
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0x00000000).</dd>
<dt><code>%&lt;ADLER32&gt;</code></dt>
<dt><code>%&lt;adler32&gt;</code></dt>
<dd>Four bytes. The Adler32 checksum according to <a target="ex"
href="http://www.ietf.org/rfc/rfc1950.txt">RFC 1950</a>.</dd>
<dt><code>%&lt;HEXSUM8&gt;</code></dt>
<dt><code>%&lt;hexsum8&gt;</code></dt>
<dd>One byte. The sum of all hex digits. (Other characters are ignored.)</dd>
</dl>
<a name="regex"></a>
<h2>12. Regular Expresion STRING Converter (<code>%/<em>regex</em>/</code>)</h2>
<p>
This input-only format matches <a target="ex"
href="http://www.pcre.org/" >Perl compatible regular expressions (PCRE)</a>.
It is only available if a PCRE library is installed and the RELEASE
file contains the variable <code>PCRE</code> which should point to the
install location.
If the regular expression is not anchored, i.e. does not start with
<code>^</code>, leading non-matching input is skipped.
A maximum of <em>width</em> bytes is matched, if specified.
If <em>prec</em> is given, it specifies the sub-expression whose match
is retuned.
Otherwise the complete match is returned.
In any case, the complete match is consumed from the input buffer.
If the expression contains a <code>/</code> is must be escaped.
</p>
<p>
Example: <code>%.1/&lt;title&gt;(.*)&lt;\/title&gt;/</code> returns
the title of an HTML page, skipps anything before the
<code>&lt;title&gt</code> tag and leaves anything after the
<code>&lt;/title&gt;</code> tag in the input buffer.
</p>
<hr>
<p align="right"><a href="processing.html">Next: Record Processing</a></p>
<p><small>Dirk Zimoch, 2007</small></p>

View File

@ -120,6 +120,7 @@ h1 {font-size:120%;
<li><a target="text" href="formats.html#raw">%r</a></li>
<li><a target="text" href="formats.html#bcd">%D</a></li>
<li><a target="text" href="formats.html#chksum">%&lt;<em>checksum</em>&gt;</a></li>
<li><a target="text" href="formats.html#regex">%/<em>regex</em>/</a></li>
</ul>
</div>
<div class="top">

View File

@ -934,6 +934,7 @@ void intrCallbackOctet(void* /*pvt*/, asynUser *pasynUser,
// 3. eomReason=ASYN_EOM_CNT when message was too long for
// internal buffer of asynDriver.
if (!interruptAccept) return; // too early to process records
if (interface->ioAction == AsyncRead ||
interface->ioAction == AsyncReadMore)
{
@ -1181,6 +1182,9 @@ connectRequest(unsigned long connecttimeout_ms)
double queueTimeout = connecttimeout_ms*0.001;
asynStatus status;
ioAction = Connect;
debug("AsynDriverInterface::connectRequest %s\n",
clientName());
status = pasynManager->queueRequest(pasynUser,
asynQueuePriorityConnect, queueTimeout);
if (status != asynSuccess)
@ -1198,7 +1202,14 @@ connectRequest(unsigned long connecttimeout_ms)
void AsynDriverInterface::
connectHandler()
{
int connected;
asynStatus status;
pasynManager->isConnected(pasynUser, &connected);
debug("AsynDriverInterface::connectHandler %s is %s connected\n",
clientName(), connected ? "already" : "not yet");
if (!connected)
{
status = pasynCommon->connect(pvtCommon, pasynUser);
if (status != asynSuccess)
{
@ -1207,6 +1218,7 @@ connectHandler()
connectCallback(StreamIoFault);
return;
}
}
connectCallback(StreamIoSuccess);
}
@ -1215,6 +1227,9 @@ disconnect()
{
asynStatus status;
ioAction = Disconnect;
debug("AsynDriverInterface::disconnect %s\n",
clientName());
status = pasynManager->queueRequest(pasynUser,
asynQueuePriorityConnect, 0.0);
if (status != asynSuccess)
@ -1233,7 +1248,14 @@ disconnect()
void AsynDriverInterface::
disconnectHandler()
{
int connected;
asynStatus status;
pasynManager->isConnected(pasynUser, &connected);
debug("AsynDriverInterface::disconnectHandler %s is %s disconnected\n",
clientName(), !connected ? "already" : "not yet");
if (connected)
{
status = pasynCommon->disconnect(pvtCommon, pasynUser);
if (status != asynSuccess)
{
@ -1241,6 +1263,7 @@ disconnectHandler()
clientName(), pasynUser->errorMessage);
return;
}
}
}
void AsynDriverInterface::
@ -1312,6 +1335,8 @@ void handleTimeout(asynUser* pasynUser)
interface->connectCallback(StreamIoTimeout);
break;
case Disconnect:
debug ("AsynDriverInterface %s: disconnect timeout\n",
interface->clientName());
// not interested in callback
break;
// No AsyncRead here because we don't use timeout when polling

View File

@ -41,6 +41,10 @@ FORMATS += Raw
FORMATS += Binary
FORMATS += Checksum
ifdef PCRE
FORMATS += Regexp
endif
# Want a loadable module?
# For Tornado 2.0.2, a fix is needed in the
# registerRecordDeviceDriver.pl script in base:

View File

@ -50,6 +50,11 @@ static ulong xor8(const uchar* data, ulong len, ulong sum)
return sum;
}
static ulong xor7(const uchar* data, ulong len, ulong sum)
{
return xor8(data, len, sum) & 0x7F;
}
static ulong crc_0x07(const uchar* data, ulong len, ulong crc)
{
// x^8 + x^2 + x^1 + x^0 (0x07)
@ -460,12 +465,23 @@ static checksum checksumMap[] =
{"sum8", sum, 0x00, 0x00, 1}, // 0xDD
{"sum16", sum, 0x0000, 0x0000, 2}, // 0x01DD
{"sum32", sum, 0x00000000, 0x00000000, 4}, // 0x000001DD
{"nsum", sum, 0xff, 0xff, 1}, // 0x23
{"negsum", sum, 0xff, 0xff, 1}, // 0x23
{"-sum", sum, 0xff, 0xff, 1}, // 0x23
{"notsum", sum, 0x00, 0xff, 1}, // 0x22
{"~sum", sum, 0x00, 0xff, 1}, // 0x22
{"nsum", sum, 0xFF, 0xFF, 1}, // 0x23
{"negsum", sum, 0xFF, 0xFF, 1}, // 0x23
{"-sum", sum, 0xFF, 0xFF, 1}, // 0x23
{"nsum8", sum, 0xFF, 0xFF, 1}, // 0x23
{"negsum8", sum, 0xFF, 0xFF, 1}, // 0x23
{"-sum8", sum, 0xFF, 0xFF, 1}, // 0x23
{"nsum16", sum, 0xFFFF, 0xFFFF, 2}, // 0xFE23
{"negsum16",sum, 0xFFFF, 0xFFFF, 2}, // 0xFE23
{"-sum16", sum, 0xFFFF, 0xFFFF, 2}, // 0xFE23
{"nsum32", sum, 0xFFFFFFFF, 0xFFFFFFFF, 4}, // 0xFFFFFE23
{"negsum32",sum, 0xFFFFFFFF, 0xFFFFFFFF, 4}, // 0xFFFFFE23
{"-sum32", sum, 0xFFFFFFFF, 0xFFFFFFFF, 4}, // 0xFFFFFE23
{"notsum", sum, 0x00, 0xFF, 1}, // 0x22
{"~sum", sum, 0x00, 0xFF, 1}, // 0x22
{"xor", xor8, 0x00, 0x00, 1}, // 0x31
{"xor8", xor8, 0x00, 0x00, 1}, // 0x31
{"xor7", xor7, 0x00, 0x00, 1}, // 0x31
{"crc8", crc_0x07, 0x00, 0x00, 1}, // 0xF4
{"ccitt8", crc_0x31, 0x00, 0x00, 1}, // 0xA1
{"crc16", crc_0x8005, 0x0000, 0x0000, 2}, // 0xFEE8
@ -494,7 +510,7 @@ parse(const StreamFormat&, StreamBuffer& info, const char*& source, bool)
const char* p = strchr(source, '>');
if (!p)
{
error ("Missing terminating '>' in checksum format.\n");
error ("Missing closing '>' in checksum format.\n");
return false;
}

View File

@ -57,6 +57,10 @@ SRCS += $(FORMATS:%=%Converter.cc)
SRCS += $(RECORDS:%=dev%Stream.c)
SRCS += $(STREAM_SRCS)
ifneq ($(filter Regexp,$(FORMATS)),)
LIB_LIBS += pcre
endif
LIB_LIBS += Com dbIoc dbStaticIoc registryIoc iocsh
ifeq ($(USE_MEMGUARD),YES)

125
src/RegexpConverter.cc Normal file
View File

@ -0,0 +1,125 @@
/***************************************************************
* StreamDevice Support *
* *
* (C) 1999 Dirk Zimoch (zimoch@delta.uni-dortmund.de) *
* (C) 2007 Dirk Zimoch (dirk.zimoch@psi.ch) *
* *
* This is the regexp format converter of StreamDevice. *
* Please refer to the HTML files in ../doc/ for a detailed *
* documentation. *
* *
* If you do any changes in this file, you are not allowed to *
* redistribute it any more. If there is a bug or a missing *
* feature, send me an email and/or your patch. If I accept *
* your changes, they will go to the next release. *
* *
* DISCLAIMER: If this software breaks something or harms *
* someone, it's your problem. *
* *
***************************************************************/
#include "StreamFormatConverter.h"
#include "StreamError.h"
#include "string.h"
#include "pcre.h"
// Perl regular expressions (PCRE) %/regexp/
/* Notes:
- Memory for compiled regexp is allocated in parse but never freed.
This should not be too much of a problem unless streamReload is
called really often before the IOC is restarted. It is not a
run-time leak.
- A maximum of 9 subexpressions is supported. Only one of them can
be the result of the match.
- vxWorks and maybe other OS don't have a PCRE library. Provide one?
*/
class RegexpConverter : public StreamFormatConverter
{
int parse (const StreamFormat&, StreamBuffer&, const char*&, bool);
int scanString(const StreamFormat&, const char*, char*, size_t);
};
int RegexpConverter::
parse(const StreamFormat& fmt, StreamBuffer& info,
const char*& source, bool scanFormat)
{
if (!scanFormat)
{
error("Format conversion %%/regexp/ is only allowed in input formats\n");
return false;
}
if (fmt.prec > 9)
{
error("Subexpression index %d too big (>9)\n", fmt.prec);
return false;
}
if (fmt.flags & (left_flag|space_flag|zero_flag|alt_flag))
{
error("Use of modifiers '-', ' ', '0', '#'"
"not allowed with %%/regexp/ conversion\n");
return false;
}
StreamBuffer pattern;
while (*source != '/')
{
if (!*source) {
error("Missing closing '/' after %%/ format conversion\n");
return false;
}
if (*source == esc) {
source++;
pattern.printf("\\x%02x", *source++ & 0xFF);
continue;
}
pattern.append(*source++);
}
source++;
debug("regexp = \"%s\"\n", pattern());
const char* errormsg;
int eoffset;
pcre* code = pcre_compile(pattern(), 0,
&errormsg, &eoffset, NULL);
if (!code)
{
error("%s after \"%s\"\n", errormsg, pattern.expand(0, eoffset)());
return false;
}
info.append(&code, sizeof(code));
return string_format;
}
int RegexpConverter::
scanString(const StreamFormat& fmt, const char* input,
char* value, size_t maxlen)
{
pcre* code;
size_t len;
int ovector[30];
int rc;
int subexpr = 0;
memcpy (&code, fmt.info, sizeof(code));
len = fmt.width > 0 ? fmt.width : strlen(input);
subexpr = fmt.prec > 0 ? fmt.prec : 0;
rc = pcre_exec(code, NULL, input, len, 0, 0, ovector, 30);
if (rc < 1) return -1;
if (fmt.flags & skip_flag) return ovector[1];
len = ovector[subexpr*2+1] - ovector[subexpr*2];
if (len >= maxlen) {
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);
return -1;
}
len = maxlen-1;
}
memcpy(value, input+ovector[subexpr*2], len);
value[len]=0;
return ovector[1];
}
RegisterConverter (RegexpConverter, "/");

View File

@ -30,7 +30,7 @@ const char* commandStr[] = { "end", "in", "out", "wait", "event", "exec",
inline const char* commandName(unsigned char i)
{
return i > exec_cmd ? "invalid" : commandStr[i];
return i >= sizeof(commandStr)/sizeof(char*) ? "invalid" : commandStr[i];
}
/// debug functions /////////////////////////////////////////////
@ -1323,7 +1323,7 @@ scanValue(const StreamFormat& fmt, char* value, long maxlen)
consumed > inputLine.length()-consumedInput) return -1;
#ifndef NO_TEMPORARY
debug("StreamCore::scanValue(%s) scanned \"%s\"\n",
name(), StreamBuffer(value, consumed).expand()());
name(), StreamBuffer(value, maxlen).expand()());
#endif
flags |= GotValue;
return consumed;

View File

@ -384,7 +384,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
fmt.prec, fmt.conv);
return false;
}
info.printf("%%%d[", fmt.width);
info.printf("%%%s%d[", fmt.flags & skip_flag ? "*" : "", fmt.width);
while (*source && *source != ']')
{
if (*source == esc) source++;

View File

@ -1334,16 +1334,40 @@ compileString(StreamBuffer& buffer, const char*& source,
{
{"skip", skip},
{"?", skip},
{"eot", 4 },
{"ack", 6 },
{"bel", 7 },
{"bs", 8 },
{"ht", 9 },
{"tab", 9 },
{"lf", '\n' },
{"nl", '\n' },
{"cr", '\r' },
{"esc", esc },
{"nul", 0x00},
{"soh", 0x01},
{"stx", 0x02},
{"etx", 0x03},
{"eot", 0x04},
{"enq", 0x05},
{"ack", 0x06},
{"bel", 0x07},
{"bs", 0x08},
{"ht", 0x09},
{"tab", 0x09},
{"lf", 0x0A},
{"nl", 0x0A},
{"vt", 0x0B},
{"ff", 0x0C},
{"cr", 0x0D},
{"so", 0x0E},
{"si", 0x0F},
{"dle", 0x10},
{"dc1", 0x11},
{"dc2", 0x12},
{"dc3", 0x13},
{"dc4", 0x14},
{"nak", 0x15},
{"syn", 0x16},
{"etb", 0x17},
{"can", 0x18},
{"em", 0x19},
{"sub", 0x1A},
{"esc", 0x1B},
{"fs", 0x1C},
{"gs", 0x1D},
{"rs", 0x1E},
{"us", 0x1F},
{"del", 0x7f}
};
size_t i;