update to current snapshot version
This commit is contained in:
@ -352,56 +352,85 @@ In input, the next byte or bytes must match the checksum.
|
|||||||
|
|
||||||
<h3>Implemented checksum functions</h3>
|
<h3>Implemented checksum functions</h3>
|
||||||
<dl>
|
<dl>
|
||||||
<dt><code>%<SUM></code> or <code>%<SUM8></code></dt>
|
<dt><code>%<sum></code> or <code>%<sum8></code></dt>
|
||||||
<dd>One byte. The sum of all characters modulo 2<sup>8</sup>.</dd>
|
<dd>One byte. The sum of all characters modulo 2<sup>8</sup>.</dd>
|
||||||
<dt><code>%<SUM16></code></dt>
|
<dt><code>%<sum16></code></dt>
|
||||||
<dd>Two bytes. The sum of all characters modulo 2<sup>16</sup>.</dd>
|
<dd>Two bytes. The sum of all characters modulo 2<sup>16</sup>.</dd>
|
||||||
<dt><code>%<SUM32></code></dt>
|
<dt><code>%<sum32></code></dt>
|
||||||
<dd>Four bytes. The sum of all characters modulo 2<sup>32</sup>.</dd>
|
<dd>Four bytes. The sum of all characters modulo 2<sup>32</sup>.</dd>
|
||||||
<dt><code>%<NEGSUM></code> or <code>%<NSUM></code> or <code>%<-SUM></code></dt>
|
<dt><code>%<negsum></code>, <code>%<nsum></code>, <code>%<-sum></code>, <code>%<negsum8></code>, <code>%<nsum8></code>, or <code>%<-sum8></code></dt>
|
||||||
<dd>One byte. The negative of the sum of all characters modulo 2<sup>8</sup>.</dd>
|
<dd>One byte. The negative of the sum of all characters modulo 2<sup>8</sup>.</dd>
|
||||||
<dt><code>%<NOTSUM></code> or <code>%<~SUM></code></dt>
|
<dt><code>%<negsum16></code>, <code>%<nsum16></code>, or <code>%<-sum16></code></dt>
|
||||||
|
<dd>Two bytes. The negative of the sum of all characters modulo 2<sup>16</sup>.</dd>
|
||||||
|
<dt><code>%<negsum32></code>, <code>%<nsum32></code>, or <code>%<-sum32></code></dt>
|
||||||
|
<dd>Four bytes. The negative of the sum of all characters modulo 2<sup>32</sup>.</dd>
|
||||||
|
<dt><code>%<notsum></code> or <code>%<~sum></code></dt>
|
||||||
<dd>One byte. The bitwise inverse of the sum of all characters modulo 2<sup>8</sup>.</dd>
|
<dd>One byte. The bitwise inverse of the sum of all characters modulo 2<sup>8</sup>.</dd>
|
||||||
<dt><code>%<XOR></code></dt>
|
<dt><code>%<xor></code></dt>
|
||||||
<dd>One byte. All characters xor'ed.</dd>
|
<dd>One byte. All characters xor'ed.</dd>
|
||||||
<dt><code>%<CRC8></code></dt>
|
<dt><code>%<xor7></code></dt>
|
||||||
<dd>One byte. An often used 8 bit CRC checksum
|
<dd>One byte. All characters xor'ed & 0x7F.</dd>
|
||||||
|
<dt><code>%<crc8></code></dt>
|
||||||
|
<dd>One byte. An often used 8 bit crc checksum
|
||||||
(poly=0x07, init=0x00, xorout=0x00).</dd>
|
(poly=0x07, init=0x00, xorout=0x00).</dd>
|
||||||
<dt><code>%<CCITT8></code></dt>
|
<dt><code>%<ccitt8></code></dt>
|
||||||
<dd>One byte. The CCITT standard 8 bit CRC checksum
|
<dd>One byte. The CCITT standard 8 bit crc checksum
|
||||||
(poly=0x31, init=0x00, xorout=0x00).</dd>
|
(poly=0x31, init=0x00, xorout=0x00).</dd>
|
||||||
<dt><code>%<CRC16></code></dt>
|
<dt><code>%<crc16></code></dt>
|
||||||
<dd>Two bytes. An often used 16 bit CRC checksum
|
<dd>Two bytes. An often used 16 bit crc checksum
|
||||||
(poly=0x8005, init=0x0000, xorout=0x0000).</dd>
|
(poly=0x8005, init=0x0000, xorout=0x0000).</dd>
|
||||||
<dt><code>%<CRC16R></code></dt>
|
<dt><code>%<crc16r></code></dt>
|
||||||
<dd>Two bytes. An often used reflected 16 bit CRC checksum
|
<dd>Two bytes. An often used reflected 16 bit crc checksum
|
||||||
(poly=0x8005, init=0x0000, xorout=0x0000).</dd>
|
(poly=0x8005, init=0x0000, xorout=0x0000).</dd>
|
||||||
<dt><code>%<CCITT16></code></dt>
|
<dt><code>%<ccitt16></code></dt>
|
||||||
<dd>Two bytes. The usual (but <a target="ex"
|
<dd>Two bytes. The usual (but <a target="ex"
|
||||||
href="http://www.joegeluso.com/software/articles/ccitt.htm">wrong?</a>)
|
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>
|
(poly=0x1021, init=0xFFFF, xorout=0x0000).</dd>
|
||||||
<dt><code>%<CCITT16A></code></dt>
|
<dt><code>%<ccitt16a></code></dt>
|
||||||
<dd>Two bytes. The unusual (but <a target="ex"
|
<dd>Two bytes. The unusual (but <a target="ex"
|
||||||
href="http://www.joegeluso.com/software/articles/ccitt.htm">correct?</a>)
|
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>
|
(poly=0x1021, init=0x1D0F, xorout=0x0000).</dd>
|
||||||
<dt><code>%<CRC32></code></dt>
|
<dt><code>%<crc32></code></dt>
|
||||||
<dd>Four bytes. The standard 32 bit CRC checksum.
|
<dd>Four bytes. The standard 32 bit crc checksum.
|
||||||
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0xFFFFFFFF).</dd>
|
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0xFFFFFFFF).</dd>
|
||||||
<dt><code>%<CRC32R></code></dt>
|
<dt><code>%<crc32r></code></dt>
|
||||||
<dd>Four bytes. The standard reflected 32 bit CRC checksum.
|
<dd>Four bytes. The standard reflected 32 bit crc checksum.
|
||||||
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0xFFFFFFFF).</dd>
|
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0xFFFFFFFF).</dd>
|
||||||
<dt><code>%<JAMCRC></code></dt>
|
<dt><code>%<jamcrc></code></dt>
|
||||||
<dd>Four bytes. Another reflected 32 bit CRC checksum.
|
<dd>Four bytes. Another reflected 32 bit crc checksum.
|
||||||
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0x00000000).</dd>
|
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0x00000000).</dd>
|
||||||
<dt><code>%<ADLER32></code></dt>
|
<dt><code>%<adler32></code></dt>
|
||||||
<dd>Four bytes. The Adler32 checksum according to <a target="ex"
|
<dd>Four bytes. The Adler32 checksum according to <a target="ex"
|
||||||
href="http://www.ietf.org/rfc/rfc1950.txt">RFC 1950</a>.</dd>
|
href="http://www.ietf.org/rfc/rfc1950.txt">RFC 1950</a>.</dd>
|
||||||
<dt><code>%<HEXSUM8></code></dt>
|
<dt><code>%<hexsum8></code></dt>
|
||||||
<dd>One byte. The sum of all hex digits. (Other characters are ignored.)</dd>
|
<dd>One byte. The sum of all hex digits. (Other characters are ignored.)</dd>
|
||||||
</dl>
|
</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/<title>(.*)<\/title>/</code> returns
|
||||||
|
the title of an HTML page, skipps anything before the
|
||||||
|
<code><title></code> tag and leaves anything after the
|
||||||
|
<code></title></code> tag in the input buffer.
|
||||||
|
</p>
|
||||||
<hr>
|
<hr>
|
||||||
<p align="right"><a href="processing.html">Next: Record Processing</a></p>
|
<p align="right"><a href="processing.html">Next: Record Processing</a></p>
|
||||||
<p><small>Dirk Zimoch, 2007</small></p>
|
<p><small>Dirk Zimoch, 2007</small></p>
|
||||||
|
@ -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#raw">%r</a></li>
|
||||||
<li><a target="text" href="formats.html#bcd">%D</a></li>
|
<li><a target="text" href="formats.html#bcd">%D</a></li>
|
||||||
<li><a target="text" href="formats.html#chksum">%<<em>checksum</em>></a></li>
|
<li><a target="text" href="formats.html#chksum">%<<em>checksum</em>></a></li>
|
||||||
|
<li><a target="text" href="formats.html#regex">%/<em>regex</em>/</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="top">
|
<div class="top">
|
||||||
|
@ -934,6 +934,7 @@ void intrCallbackOctet(void* /*pvt*/, asynUser *pasynUser,
|
|||||||
// 3. eomReason=ASYN_EOM_CNT when message was too long for
|
// 3. eomReason=ASYN_EOM_CNT when message was too long for
|
||||||
// internal buffer of asynDriver.
|
// internal buffer of asynDriver.
|
||||||
|
|
||||||
|
if (!interruptAccept) return; // too early to process records
|
||||||
if (interface->ioAction == AsyncRead ||
|
if (interface->ioAction == AsyncRead ||
|
||||||
interface->ioAction == AsyncReadMore)
|
interface->ioAction == AsyncReadMore)
|
||||||
{
|
{
|
||||||
@ -1181,6 +1182,9 @@ connectRequest(unsigned long connecttimeout_ms)
|
|||||||
double queueTimeout = connecttimeout_ms*0.001;
|
double queueTimeout = connecttimeout_ms*0.001;
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
ioAction = Connect;
|
ioAction = Connect;
|
||||||
|
|
||||||
|
debug("AsynDriverInterface::connectRequest %s\n",
|
||||||
|
clientName());
|
||||||
status = pasynManager->queueRequest(pasynUser,
|
status = pasynManager->queueRequest(pasynUser,
|
||||||
asynQueuePriorityConnect, queueTimeout);
|
asynQueuePriorityConnect, queueTimeout);
|
||||||
if (status != asynSuccess)
|
if (status != asynSuccess)
|
||||||
@ -1198,14 +1202,22 @@ connectRequest(unsigned long connecttimeout_ms)
|
|||||||
void AsynDriverInterface::
|
void AsynDriverInterface::
|
||||||
connectHandler()
|
connectHandler()
|
||||||
{
|
{
|
||||||
|
int connected;
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
status = pasynCommon->connect(pvtCommon, pasynUser);
|
|
||||||
if (status != asynSuccess)
|
pasynManager->isConnected(pasynUser, &connected);
|
||||||
|
debug("AsynDriverInterface::connectHandler %s is %s connected\n",
|
||||||
|
clientName(), connected ? "already" : "not yet");
|
||||||
|
if (!connected)
|
||||||
{
|
{
|
||||||
error("%s connectRequest: pasynCommon->connect() failed: %s\n",
|
status = pasynCommon->connect(pvtCommon, pasynUser);
|
||||||
clientName(), pasynUser->errorMessage);
|
if (status != asynSuccess)
|
||||||
connectCallback(StreamIoFault);
|
{
|
||||||
return;
|
error("%s connectRequest: pasynCommon->connect() failed: %s\n",
|
||||||
|
clientName(), pasynUser->errorMessage);
|
||||||
|
connectCallback(StreamIoFault);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
connectCallback(StreamIoSuccess);
|
connectCallback(StreamIoSuccess);
|
||||||
}
|
}
|
||||||
@ -1215,6 +1227,9 @@ disconnect()
|
|||||||
{
|
{
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
ioAction = Disconnect;
|
ioAction = Disconnect;
|
||||||
|
|
||||||
|
debug("AsynDriverInterface::disconnect %s\n",
|
||||||
|
clientName());
|
||||||
status = pasynManager->queueRequest(pasynUser,
|
status = pasynManager->queueRequest(pasynUser,
|
||||||
asynQueuePriorityConnect, 0.0);
|
asynQueuePriorityConnect, 0.0);
|
||||||
if (status != asynSuccess)
|
if (status != asynSuccess)
|
||||||
@ -1233,13 +1248,21 @@ disconnect()
|
|||||||
void AsynDriverInterface::
|
void AsynDriverInterface::
|
||||||
disconnectHandler()
|
disconnectHandler()
|
||||||
{
|
{
|
||||||
|
int connected;
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
status = pasynCommon->disconnect(pvtCommon, pasynUser);
|
|
||||||
if (status != asynSuccess)
|
pasynManager->isConnected(pasynUser, &connected);
|
||||||
|
debug("AsynDriverInterface::disconnectHandler %s is %s disconnected\n",
|
||||||
|
clientName(), !connected ? "already" : "not yet");
|
||||||
|
if (connected)
|
||||||
{
|
{
|
||||||
error("%s connectRequest: pasynCommon->disconnect() failed: %s\n",
|
status = pasynCommon->disconnect(pvtCommon, pasynUser);
|
||||||
clientName(), pasynUser->errorMessage);
|
if (status != asynSuccess)
|
||||||
return;
|
{
|
||||||
|
error("%s connectRequest: pasynCommon->disconnect() failed: %s\n",
|
||||||
|
clientName(), pasynUser->errorMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1312,6 +1335,8 @@ void handleTimeout(asynUser* pasynUser)
|
|||||||
interface->connectCallback(StreamIoTimeout);
|
interface->connectCallback(StreamIoTimeout);
|
||||||
break;
|
break;
|
||||||
case Disconnect:
|
case Disconnect:
|
||||||
|
debug ("AsynDriverInterface %s: disconnect timeout\n",
|
||||||
|
interface->clientName());
|
||||||
// not interested in callback
|
// not interested in callback
|
||||||
break;
|
break;
|
||||||
// No AsyncRead here because we don't use timeout when polling
|
// No AsyncRead here because we don't use timeout when polling
|
||||||
|
@ -41,6 +41,10 @@ FORMATS += Raw
|
|||||||
FORMATS += Binary
|
FORMATS += Binary
|
||||||
FORMATS += Checksum
|
FORMATS += Checksum
|
||||||
|
|
||||||
|
ifdef PCRE
|
||||||
|
FORMATS += Regexp
|
||||||
|
endif
|
||||||
|
|
||||||
# Want a loadable module?
|
# Want a loadable module?
|
||||||
# For Tornado 2.0.2, a fix is needed in the
|
# For Tornado 2.0.2, a fix is needed in the
|
||||||
# registerRecordDeviceDriver.pl script in base:
|
# registerRecordDeviceDriver.pl script in base:
|
||||||
|
@ -50,6 +50,11 @@ static ulong xor8(const uchar* data, ulong len, ulong sum)
|
|||||||
return 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)
|
static ulong crc_0x07(const uchar* data, ulong len, ulong crc)
|
||||||
{
|
{
|
||||||
// x^8 + x^2 + x^1 + x^0 (0x07)
|
// x^8 + x^2 + x^1 + x^0 (0x07)
|
||||||
@ -460,12 +465,23 @@ static checksum checksumMap[] =
|
|||||||
{"sum8", sum, 0x00, 0x00, 1}, // 0xDD
|
{"sum8", sum, 0x00, 0x00, 1}, // 0xDD
|
||||||
{"sum16", sum, 0x0000, 0x0000, 2}, // 0x01DD
|
{"sum16", sum, 0x0000, 0x0000, 2}, // 0x01DD
|
||||||
{"sum32", sum, 0x00000000, 0x00000000, 4}, // 0x000001DD
|
{"sum32", sum, 0x00000000, 0x00000000, 4}, // 0x000001DD
|
||||||
{"nsum", sum, 0xff, 0xff, 1}, // 0x23
|
{"nsum", sum, 0xFF, 0xFF, 1}, // 0x23
|
||||||
{"negsum", sum, 0xff, 0xff, 1}, // 0x23
|
{"negsum", sum, 0xFF, 0xFF, 1}, // 0x23
|
||||||
{"-sum", sum, 0xff, 0xff, 1}, // 0x23
|
{"-sum", sum, 0xFF, 0xFF, 1}, // 0x23
|
||||||
{"notsum", sum, 0x00, 0xff, 1}, // 0x22
|
{"nsum8", sum, 0xFF, 0xFF, 1}, // 0x23
|
||||||
{"~sum", sum, 0x00, 0xff, 1}, // 0x22
|
{"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
|
{"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
|
{"crc8", crc_0x07, 0x00, 0x00, 1}, // 0xF4
|
||||||
{"ccitt8", crc_0x31, 0x00, 0x00, 1}, // 0xA1
|
{"ccitt8", crc_0x31, 0x00, 0x00, 1}, // 0xA1
|
||||||
{"crc16", crc_0x8005, 0x0000, 0x0000, 2}, // 0xFEE8
|
{"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, '>');
|
const char* p = strchr(source, '>');
|
||||||
if (!p)
|
if (!p)
|
||||||
{
|
{
|
||||||
error ("Missing terminating '>' in checksum format.\n");
|
error ("Missing closing '>' in checksum format.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,10 @@ SRCS += $(FORMATS:%=%Converter.cc)
|
|||||||
SRCS += $(RECORDS:%=dev%Stream.c)
|
SRCS += $(RECORDS:%=dev%Stream.c)
|
||||||
SRCS += $(STREAM_SRCS)
|
SRCS += $(STREAM_SRCS)
|
||||||
|
|
||||||
|
ifneq ($(filter Regexp,$(FORMATS)),)
|
||||||
|
LIB_LIBS += pcre
|
||||||
|
endif
|
||||||
|
|
||||||
LIB_LIBS += Com dbIoc dbStaticIoc registryIoc iocsh
|
LIB_LIBS += Com dbIoc dbStaticIoc registryIoc iocsh
|
||||||
|
|
||||||
ifeq ($(USE_MEMGUARD),YES)
|
ifeq ($(USE_MEMGUARD),YES)
|
||||||
|
125
src/RegexpConverter.cc
Normal file
125
src/RegexpConverter.cc
Normal 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, "/");
|
@ -30,7 +30,7 @@ const char* commandStr[] = { "end", "in", "out", "wait", "event", "exec",
|
|||||||
|
|
||||||
inline const char* commandName(unsigned char i)
|
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 /////////////////////////////////////////////
|
/// debug functions /////////////////////////////////////////////
|
||||||
@ -1323,7 +1323,7 @@ scanValue(const StreamFormat& fmt, char* value, long maxlen)
|
|||||||
consumed > inputLine.length()-consumedInput) return -1;
|
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, consumed).expand()());
|
name(), StreamBuffer(value, maxlen).expand()());
|
||||||
#endif
|
#endif
|
||||||
flags |= GotValue;
|
flags |= GotValue;
|
||||||
return consumed;
|
return consumed;
|
||||||
|
@ -384,7 +384,7 @@ parse(const StreamFormat& fmt, StreamBuffer& info,
|
|||||||
fmt.prec, fmt.conv);
|
fmt.prec, fmt.conv);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
info.printf("%%%d[", fmt.width);
|
info.printf("%%%s%d[", fmt.flags & skip_flag ? "*" : "", fmt.width);
|
||||||
while (*source && *source != ']')
|
while (*source && *source != ']')
|
||||||
{
|
{
|
||||||
if (*source == esc) source++;
|
if (*source == esc) source++;
|
||||||
|
@ -1332,18 +1332,42 @@ compileString(StreamBuffer& buffer, const char*& source,
|
|||||||
// try constant token
|
// try constant token
|
||||||
struct {const char* name; char code;} codes [] =
|
struct {const char* name; char code;} codes [] =
|
||||||
{
|
{
|
||||||
{"skip", skip},
|
{"skip", skip},
|
||||||
{"?", skip},
|
{"?", skip},
|
||||||
{"eot", 4 },
|
{"nul", 0x00},
|
||||||
{"ack", 6 },
|
{"soh", 0x01},
|
||||||
{"bel", 7 },
|
{"stx", 0x02},
|
||||||
{"bs", 8 },
|
{"etx", 0x03},
|
||||||
{"ht", 9 },
|
{"eot", 0x04},
|
||||||
{"tab", 9 },
|
{"enq", 0x05},
|
||||||
{"lf", '\n' },
|
{"ack", 0x06},
|
||||||
{"nl", '\n' },
|
{"bel", 0x07},
|
||||||
{"cr", '\r' },
|
{"bs", 0x08},
|
||||||
{"esc", esc },
|
{"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}
|
{"del", 0x7f}
|
||||||
};
|
};
|
||||||
size_t i;
|
size_t i;
|
||||||
|
Reference in New Issue
Block a user