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>
|
||||
<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>
|
||||
<dt><code>%<SUM16></code></dt>
|
||||
<dt><code>%<sum16></code></dt>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<dt><code>%<XOR></code></dt>
|
||||
<dt><code>%<xor></code></dt>
|
||||
<dd>One byte. All characters xor'ed.</dd>
|
||||
<dt><code>%<CRC8></code></dt>
|
||||
<dd>One byte. An often used 8 bit CRC checksum
|
||||
<dt><code>%<xor7></code></dt>
|
||||
<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>
|
||||
<dt><code>%<CCITT8></code></dt>
|
||||
<dd>One byte. The CCITT standard 8 bit CRC checksum
|
||||
<dt><code>%<ccitt8></code></dt>
|
||||
<dd>One byte. The CCITT standard 8 bit crc checksum
|
||||
(poly=0x31, init=0x00, xorout=0x00).</dd>
|
||||
<dt><code>%<CRC16></code></dt>
|
||||
<dd>Two bytes. An often used 16 bit CRC checksum
|
||||
<dt><code>%<crc16></code></dt>
|
||||
<dd>Two bytes. An often used 16 bit crc checksum
|
||||
(poly=0x8005, init=0x0000, xorout=0x0000).</dd>
|
||||
<dt><code>%<CRC16R></code></dt>
|
||||
<dd>Two bytes. An often used reflected 16 bit CRC checksum
|
||||
<dt><code>%<crc16r></code></dt>
|
||||
<dd>Two bytes. An often used reflected 16 bit crc checksum
|
||||
(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"
|
||||
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>%<CCITT16A></code></dt>
|
||||
<dt><code>%<ccitt16a></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>%<CRC32></code></dt>
|
||||
<dd>Four bytes. The standard 32 bit CRC checksum.
|
||||
<dt><code>%<crc32></code></dt>
|
||||
<dd>Four bytes. The standard 32 bit crc checksum.
|
||||
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0xFFFFFFFF).</dd>
|
||||
<dt><code>%<CRC32R></code></dt>
|
||||
<dd>Four bytes. The standard reflected 32 bit CRC checksum.
|
||||
<dt><code>%<crc32r></code></dt>
|
||||
<dd>Four bytes. The standard reflected 32 bit crc checksum.
|
||||
(poly=0x04C11DB7, init=0xFFFFFFFF, xorout=0xFFFFFFFF).</dd>
|
||||
<dt><code>%<JAMCRC></code></dt>
|
||||
<dd>Four bytes. Another reflected 32 bit CRC checksum.
|
||||
<dt><code>%<jamcrc></code></dt>
|
||||
<dd>Four bytes. Another reflected 32 bit crc checksum.
|
||||
(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"
|
||||
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>
|
||||
</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>
|
||||
<p align="right"><a href="processing.html">Next: Record Processing</a></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#bcd">%D</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>
|
||||
</div>
|
||||
<div class="top">
|
||||
|
@ -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,14 +1202,22 @@ connectRequest(unsigned long connecttimeout_ms)
|
||||
void AsynDriverInterface::
|
||||
connectHandler()
|
||||
{
|
||||
int connected;
|
||||
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",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
connectCallback(StreamIoFault);
|
||||
return;
|
||||
status = pasynCommon->connect(pvtCommon, pasynUser);
|
||||
if (status != asynSuccess)
|
||||
{
|
||||
error("%s connectRequest: pasynCommon->connect() failed: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
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,13 +1248,21 @@ disconnect()
|
||||
void AsynDriverInterface::
|
||||
disconnectHandler()
|
||||
{
|
||||
int connected;
|
||||
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",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
return;
|
||||
status = pasynCommon->disconnect(pvtCommon, pasynUser);
|
||||
if (status != asynSuccess)
|
||||
{
|
||||
error("%s connectRequest: pasynCommon->disconnect() failed: %s\n",
|
||||
clientName(), pasynUser->errorMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
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)
|
||||
{
|
||||
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;
|
||||
|
@ -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++;
|
||||
|
@ -1332,18 +1332,42 @@ compileString(StreamBuffer& buffer, const char*& source,
|
||||
// try constant token
|
||||
struct {const char* name; char code;} codes [] =
|
||||
{
|
||||
{"skip", skip},
|
||||
{"?", skip},
|
||||
{"eot", 4 },
|
||||
{"ack", 6 },
|
||||
{"bel", 7 },
|
||||
{"bs", 8 },
|
||||
{"ht", 9 },
|
||||
{"tab", 9 },
|
||||
{"lf", '\n' },
|
||||
{"nl", '\n' },
|
||||
{"cr", '\r' },
|
||||
{"esc", esc },
|
||||
{"skip", skip},
|
||||
{"?", skip},
|
||||
{"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;
|
||||
|
Reference in New Issue
Block a user