Compare commits

...

7 Commits

Author SHA1 Message Date
Andrew Johnson
ed37ace27e R3.15.1 2014-12-01 15:07:38 -06:00
Andrew Johnson
bc15875bfb Merge changes from 3.14 branch, revno 12507 2014-12-01 12:29:30 -06:00
Andrew Johnson
69eaaa17ba Fix xsubpp for RHEL 7 and derivatives.
It got moved. This might not be the final fix for those using an
add-on version of Perl though...
2014-12-01 12:12:09 -06:00
Andrew Johnson
30b789aa49 Fix epicsStrnEscapedFromRaw() and epicsStrnRawFromEscaped()
Major rewrites; the original epicsStrnRawFromEscaped() could read
beyond the end of the input buffer if the input count ended in the
middle of an octal or hex escape sequence. Zero termination did not
always match the return count, and hex escapes were always 2 digits,
contrary to the C standard.

New versions don't use epicsSnprintf() or sscanf() for hex and octal
conversions, so should be slightly faster.

Added 81 new tests to check the above issues.
2014-12-01 11:34:58 -06:00
Ralph Lange
1a94ea1045 libCom/osi: fix - do not set the main thread's Linux name to _main_ (linux) 2014-12-01 13:48:10 +01:00
Andrew Johnson
f1dec35c5c Update KnownProblems list 2014-11-19 16:00:31 -06:00
Andrew Johnson
6e8a3fcd6d Set version snapshot to -rc1-DEV 2014-11-19 15:35:12 -06:00
7 changed files with 334 additions and 156 deletions

View File

@@ -41,11 +41,11 @@ EPICS_PATCH_LEVEL = 0
#EPICS_DEV_SNAPSHOT=-pre1-DEV
#EPICS_DEV_SNAPSHOT=-pre2
#EPICS_DEV_SNAPSHOT=-pre2-DEV
EPICS_DEV_SNAPSHOT=-rc1
#EPICS_DEV_SNAPSHOT=-rc1
#EPICS_DEV_SNAPSHOT=-rc1-DEV
#EPICS_DEV_SNAPSHOT=-rc2
#EPICS_DEV_SNAPSHOT=-rc2-DEV
#EPICS_DEV_SNAPSHOT=
EPICS_DEV_SNAPSHOT=
# No changes should be needed below here

View File

@@ -4,30 +4,27 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Known Problems in R3.15.0.2</title>
<title>Known Problems in R3.15.1</title>
</head>
<body>
<h1 style="text-align: center">EPICS Base R3.15.0.2: Known Problems</h1>
<h1 style="text-align: center">EPICS Base R3.15.1: Known Problems</h1>
<p>Any patch files linked below should be applied at the root of the
base-3.15.0.2 tree. Download them, then use the GNU Patch program as
base-3.15.1 tree. Download them, then use the GNU Patch program as
follows:</p>
<blockquote><pre>% <b>cd <i>/path/to/</i>base-3.15.0.2</b>
<blockquote><pre>% <b>cd <i>/path/to/</i>base-3.15.1</b>
% <b>patch -p0 &lt; <i>/path/to/</i>file.patch</b></pre></blockquote>
<p>The following significant problems have been reported with this
version of EPICS Base:</p>
<ul>
<li>64-bit Windows builds may not work with some tool-sets, the code in
<tt>src/legacy/gdd</tt> is not comptible with the LLP64 model that Windows
uses for its 64-bit ABI.</li>
<li>The <tt>-x</tt> option to the softIoc program loads a standard database
that is supposed to be able to exit the running IOC. In this release that
causes an assertion failure which prints a stack trace and suspends the
program wihout exiting.</li>
<li>64-bit Windows builds of the CAS library may not work with some compilers.
The code in <tt>src/legacy/gdd</tt> is currently incompatible with the LLP64
model that Windows uses for its 64-bit ABI.</li>
</ul>

View File

@@ -7,12 +7,14 @@
</head>
<body lang="en">
<h1 align="center">EPICS Base Release 3.15.1-rc1</h1>
<p style="color:red">This version of EPICS Base has not been released yet.</p>
<h1 align="center">EPICS Base Release 3.15.1</h1>
<h2 align="center">Changes between 3.15.0.2 and 3.15.1</h2>
<!-- Insert new items immediately below here ... -->
<h3>epicsStrnEscapedFromRaw() and epicsStrnRawFromEscaped()</h3>
<p>These routines have been rewritten; the previous implementations did not
always behave exactly as specified.</p>
<h3>Shared Library Versions</h3>

View File

@@ -54,10 +54,11 @@ include $(TOP)/configure/RULES
ifdef T_A
EXTUTILS = $(shell $(PERL) ../perlConfig.pl privlib)/ExtUtils
XSUBPP = $(firstword $(wildcard /usr/bin/xsubpp $(EXTUTILS)/xsubpp))
%.c: ../%.xs
$(RM) $@ $@_new
$(PERL) $(EXTUTILS)/xsubpp -typemap $(EXTUTILS)/typemap $< > $@_new && $(MV) $@_new $@
$(PERL) $(XSUBPP) -typemap $(EXTUTILS)/typemap $< > $@_new && $(MV) $@_new $@
$(INSTALL_PERL_MODULES)/$(PERL_ARCHPATH)/%: %
$(ECHO) "Installing loadable shared library $@"

View File

@@ -29,148 +29,165 @@
#include "epicsString.h"
/* Deprecated, use epicsStrnRawFromEscaped() instead */
int dbTranslateEscape(char *to, const char *from)
int dbTranslateEscape(char *dst, const char *src)
{
size_t big_enough = strlen(from)+1;
return epicsStrnRawFromEscaped(to, big_enough, from, big_enough);
size_t big_enough = strlen(src) + 1;
return epicsStrnRawFromEscaped(dst, big_enough, src, big_enough);
}
int epicsStrnRawFromEscaped(char *to, size_t outsize, const char *from,
size_t inlen)
int epicsStrnRawFromEscaped(char *dst, size_t dstlen, const char *src,
size_t srclen)
{
const char *pfrom = from;
char *pto = to;
char c;
size_t nto = 0, nfrom = 0;
int rem = dstlen;
int ndst = 0;
if (outsize == 0)
return 0;
while (srclen--) {
int c = *src++;
#define OUT(chr) if (--rem > 0) ndst++, *dst++ = chr
while ((c = *pfrom++) && nto < outsize && nfrom < inlen) {
nfrom++;
if (c == '\\') {
if (nfrom >= inlen || *pfrom == '\0') break;
switch (*pfrom) {
case 'a': pfrom++; nfrom++; *pto++ = '\a' ; nto++; break;
case 'b': pfrom++; nfrom++; *pto++ = '\b' ; nto++; break;
case 'f': pfrom++; nfrom++; *pto++ = '\f' ; nto++; break;
case 'n': pfrom++; nfrom++; *pto++ = '\n' ; nto++; break;
case 'r': pfrom++; nfrom++; *pto++ = '\r' ; nto++; break;
case 't': pfrom++; nfrom++; *pto++ = '\t' ; nto++; break;
case 'v': pfrom++; nfrom++; *pto++ = '\v' ; nto++; break;
case '\\': pfrom++; nfrom++; *pto++ = '\\' ; nto++; break;
case '\?': pfrom++; nfrom++; *pto++ = '\?' ; nto++; break;
case '\'': pfrom++; nfrom++; *pto++ = '\'' ; nto++; break;
case '\"': pfrom++; nfrom++; *pto++ = '\"' ; nto++; break;
case '0' :case '1' :case '2' :case '3' :
case '4' :case '5' :case '6' :case '7' :
{
int i;
char strval[4] = {0,0,0,0};
unsigned int ival;
unsigned char *pchar;
if (!c) break;
for (i=0; i<3; i++) {
if ((*pfrom < '0') || (*pfrom > '7')) break;
strval[i] = *pfrom++; nfrom++;
}
sscanf(strval,"%o",&ival);
pchar = (unsigned char *)(pto++); nto++;
*pchar = (unsigned char)(ival);
}
break;
case 'x' :
{
int i;
char strval[3] = {0,0,0};
unsigned int ival;
unsigned char *pchar;
pfrom++; /*skip the x*/
for (i=0; i<2; i++) {
if (!isxdigit((int)*pfrom)) break;
strval[i] = *pfrom++; nfrom++;
}
sscanf(strval,"%x",&ival);
pchar = (unsigned char *)(pto++); nto++;
*pchar = (unsigned char)(ival);
}
break;
default:
*pto++ = *pfrom++; nfrom++; nto++;
}
} else {
*pto++ = c; nto++;
input:
if (c != '\\') {
OUT(c);
continue;
}
}
if (nto == outsize)
pto--;
*pto = '\0';
return nto;
}
int epicsStrnEscapedFromRaw(char *outbuf, size_t outsize, const char *inbuf,
size_t inlen)
{
int maxout = outsize;
int nout = 0;
int len;
char *outpos = outbuf;
if (!srclen-- || !(c = *src++)) break;
while (inlen--) {
char c = *inbuf++;
switch (c) {
case '\a': len = epicsSnprintf(outpos, maxout, "\\a"); break;
case '\b': len = epicsSnprintf(outpos, maxout, "\\b"); break;
case '\f': len = epicsSnprintf(outpos, maxout, "\\f"); break;
case '\n': len = epicsSnprintf(outpos, maxout, "\\n"); break;
case '\r': len = epicsSnprintf(outpos, maxout, "\\r"); break;
case '\t': len = epicsSnprintf(outpos, maxout, "\\t"); break;
case '\v': len = epicsSnprintf(outpos, maxout, "\\v"); break;
case '\\': len = epicsSnprintf(outpos, maxout, "\\\\"); ; break;
case '\'': len = epicsSnprintf(outpos, maxout, "\\'"); break;
case '\"': len = epicsSnprintf(outpos, maxout, "\\\""); break;
default:
if (isprint((int)c))
len = epicsSnprintf(outpos, maxout, "%c", c);
else
len = epicsSnprintf(outpos, maxout, "\\%03o",
(unsigned char)c);
break;
}
if (len<0) return -1;
nout += len;
if (nout < outsize) {
maxout -= len;
outpos += len;
} else {
outpos = outpos + maxout -1;
maxout = 1;
case 'a': OUT('\a'); break;
case 'b': OUT('\b'); break;
case 'f': OUT('\f'); break;
case 'n': OUT('\n'); break;
case 'r': OUT('\r'); break;
case 't': OUT('\t'); break;
case 'v': OUT('\v'); break;
case '\\': OUT('\\'); break;
case '\'': OUT('\''); break;
case '\"': OUT('\"'); break;
case '0' :case '1' :case '2' :case '3' :
case '4' :case '5' :case '6' :case '7' :
{ /* \ooo */
unsigned int u = c - '0';
if (!srclen-- || !(c = *src++)) {
OUT(u); goto done;
}
if (c < '0' || c > '7') {
OUT(u); goto input;
}
u = u << 3 | (c - '0');
if (!srclen-- || !(c = *src++)) {
OUT(u); goto done;
}
if (c < '0' || c > '7') {
OUT(u); goto input;
}
u = u << 3 | (c - '0');
if (u > 0377) {
/* Undefined behaviour! */
}
OUT(u);
}
break;
case 'x' :
{ /* \xXXX... */
unsigned int u = 0;
if (!srclen-- || !(c = *src++))
goto done;
while (isxdigit(c)) {
u = u << 4 | ((c > '9') ? toupper(c) - 'A' + 10 : c - '0');
if (u > 0xff) {
/* Undefined behaviour! */
}
if (!srclen-- || !(c = *src++)) {
OUT(u);
goto done;
}
}
OUT(u);
goto input;
}
default:
OUT(c);
}
#undef OUT
}
*outpos = '\0';
return nout;
done:
if (dstlen)
*dst = '\0';
return ndst;
}
size_t epicsStrnEscapedFromRawSize(const char *inbuf, size_t inlen)
int epicsStrnEscapedFromRaw(char *dst, size_t dstlen, const char *src,
size_t srclen)
{
size_t nout = inlen;
int rem = dstlen;
int ndst = 0;
while (inlen--) {
char c = *inbuf++;
if (dst == src)
return -1;
while (srclen--) {
int c = *src++;
#define OUT(chr) ndst++; if (--rem > 0) *dst++ = chr
switch (c) {
case '\a': OUT('\\'); OUT('a'); break;
case '\b': OUT('\\'); OUT('b'); break;
case '\f': OUT('\\'); OUT('f'); break;
case '\n': OUT('\\'); OUT('n'); break;
case '\r': OUT('\\'); OUT('r'); break;
case '\t': OUT('\\'); OUT('t'); break;
case '\v': OUT('\\'); OUT('v'); break;
case '\\': OUT('\\'); OUT('\\'); break;
case '\'': OUT('\\'); OUT('\''); break;
case '\"': OUT('\\'); OUT('\"'); break;
default:
if (isprint(c)) {
OUT(c);
break;
}
OUT('\\');
OUT('0' + ((c & 0300) >> 6));
OUT('0' + ((c & 0070) >> 3));
OUT('0' + (c & 0007));
}
#undef OUT
}
if (dstlen)
*dst = '\0';
return ndst;
}
size_t epicsStrnEscapedFromRawSize(const char *src, size_t srclen)
{
size_t ndst = srclen;
while (srclen--) {
int c = *src++;
switch (c) {
case '\a': case '\b': case '\f': case '\n':
case '\r': case '\t': case '\v': case '\\':
case '\'': case '\"':
nout++;
ndst++;
break;
default:
if (!isprint((int)c))
nout += 3;
if (!isprint(c))
ndst += 3;
}
}
return nout;
return ndst;
}
int epicsStrCaseCmp(const char *s1, const char *s2)

View File

@@ -17,6 +17,7 @@
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/prctl.h>
@@ -57,8 +58,10 @@ static void thread_hook(epicsThreadId pthreadInfo)
/* Set the name of the thread's process. Limited to 16 characters. */
char comm[16];
snprintf(comm, sizeof(comm), "%s", pthreadInfo->name);
prctl(PR_SET_NAME, comm, 0l, 0l, 0l);
if (strcmp(pthreadInfo->name, "_main_")) {
snprintf(comm, sizeof(comm), "%s", pthreadInfo->name);
prctl(PR_SET_NAME, comm, 0l, 0l, 0l);
}
pthreadInfo->lwpId = syscall(SYS_gettid);
}

View File

@@ -88,7 +88,7 @@ MAIN(epicsStringTest)
char *s;
int status;
testPlan(323);
testPlan(402);
testChars();
@@ -125,41 +125,199 @@ MAIN(epicsStringTest)
testGlob();
memset(result, 'x', sizeof(result));
status = epicsStrnEscapedFromRaw(result, 0, ABCD, 4);
testOk(status == 4, "epicsStrnEscapedFromRaw(out, 0) -> %d (exp. 4)", status);
testOk(result[0] == 'x', " No output");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 0, ABCD, 4);
testOk(status == 0, "epicsStrnRawFromEscaped(out, 0) -> %d (exp. 0)", status);
testOk(result[0] == 'x', " No output");
memset(result, 'x', sizeof(result));
status = epicsStrnEscapedFromRaw(result, 1, ABCD, 4);
testOk(status == 4, "epicsStrnEscapedFromRaw(out, 1) -> %d (exp. 4)", status);
testOk(result[0] == 0, " 0-terminated");
testOk(result[1] == 'x', " No overrun");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 1, ABCD, 4);
testOk(status == 0, "epicsStrnRawFromEscaped(out, 1) -> %d (exp. 0)", status);
testOk(result[0] == 0, " 0-terminated");
testOk(result[1] == 'x', " No overrun");
testDiag("Testing size = epicsStrnEscapedFromRawSize");
status = epicsStrnEscapedFromRawSize(ABCD, 3);
testOk(status == 3, "size(\"ABCD\", 3) -> %d (exp. 3)", status);
status = epicsStrnEscapedFromRawSize(ABCD, 4);
testOk(status == 4, "size(\"ABCD\", 4) -> %d (exp. 4)", status);
status = epicsStrnEscapedFromRawSize(ABCD, 5);
testOk(status == 8, "size(\"ABCD\", 5) -> %d (exp. 8)", status);
testDiag("Testing esc = epicsStrnEscapedFromRaw(out, 4, ...)");
memset(result, 'x', sizeof(result));
status = epicsStrnEscapedFromRaw(result, 4, ABCD, 3);
testOk(status == 3, "epicsStrnEscapedFromRaw returned %d (exp. 3)", status);
testOk(result[4] == 'x', "epicsStrnEscapedFromRaw no buffer overrun");
testOk(result[3] == 0, "epicsStrnEscapedFromRaw 0-terminated");
testOk(status == 3, "esc(\"ABCD\", 3) -> %d (exp. 3)", status);
testOk(result[3] == 0, " 0-terminated");
testOk(result[4] == 'x', " No overrun");
memset(result, 'x', sizeof(result));
status = epicsStrnEscapedFromRaw(result, 4, ABCD, 4);
testOk(status == 4, "epicsStrnEscapedFromRaw returned %d (exp. 4)", status);
testOk(result[4] == 'x', "epicsStrnEscapedFromRaw no buffer overrun");
testOk(result[3] == 0, "epicsStrnEscapedFromRaw 0-terminated");
testOk(status == 4, "esc(\"ABCD\", 4) -> %d (exp. 4)", status);
testOk(result[3] == 0, " 0-terminated");
testOk(result[4] == 'x', " No overrun");
memset(result, 'x', sizeof(result));
status = epicsStrnEscapedFromRaw(result, 4, ABCDE, 5);
testOk(status == 5, "epicsStrnEscapedFromRaw returned %d (exp. 5)", status);
testOk(result[4] == 'x', "epicsStrnEscapedFromRaw no buffer overrun");
testOk(result[3] == 0, "epicsStrnEscapedFromRaw 0-terminated");
status = epicsStrnEscapedFromRaw(result, 4, ABCD, 5);
testOk(status == 8, "esc(\"ABCD\", 5) -> %d (exp. 8)", status);
testOk(result[3] == 0, " 0-terminated");
testOk(result[4] == 'x', " No overrun");
testDiag("Testing raw = epicsStrnRawFromEscaped(out, 4, ...)");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, ABCD, 0);
testOk(status == 0, "raw(\"ABCD\", 0) -> %d (exp. 0)", status);
testOk(result[0] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, ABCD, 1);
testOk(status == 1, "raw(\"ABCD\", 1) -> %d (exp. 1)", status);
testOk(result[0] == 'A', " Char '%c' (exp. 'A')", result[0]);
testOk(result[1] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, ABCD, 2);
testOk(status == 2, "raw(\"ABCD\", 2) -> %d (exp. 2)", status);
testOk(result[0] == 'A', " Char '%c' (exp. 'A')", result[0]);
testOk(result[1] == 'B', " Char '%c' (exp. 'B')", result[1]);
testOk(result[2] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, ABCD, 3);
testOk(status == 3, "epicsStrnRawFromEscaped returned %d (exp. 3)", status);
testOk(result[4] == 'x', "epicsStrnRawFromEscaped no buffer overrun");
testOk(result[3] == 0, "epicsStrnRawFromEscaped 0-terminated");
testOk(status == 3, "raw(\"ABCD\", 3) -> %d (exp. 3)", status);
testOk(result[0] == 'A', " Char '%c' (exp. 'A')", result[0]);
testOk(result[1] == 'B', " Char '%c' (exp. 'B')", result[1]);
testOk(result[2] == 'C', " Char '%c' (exp. 'C')", result[2]);
testOk(result[3] == 0, " 0-terminated");
testOk(result[4] == 'x', " No write outside buffer");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, ABCD, 4);
testOk(status == 4, "epicsStrnRawFromEscaped returned %d (exp. 4)", status);
testOk(result[4] == 'x', "epicsStrnRawFromEscaped no buffer overrun");
testOk(result[3] == 0, "epicsStrnRawFromEscaped 0-terminated");
testOk(status == 3, "raw(\"ABCD\", 4) -> %d (exp. 3)", status);
testOk(result[0] == 'A', " Char '%c' (exp. 'A')", result[0]);
testOk(result[1] == 'B', " Char '%c' (exp. 'B')", result[1]);
testOk(result[2] == 'C', " Char '%c' (exp. 'C')", result[2]);
testOk(result[3] == 0, " 0-terminated");
testOk(result[4] == 'x', " No write outside buffer");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, ABCDE, 5);
testOk(status == 4, "epicsStrnRawFromEscaped returned %d (exp. 4)", status);
testOk(result[4] == 'x', "epicsStrnRawFromEscaped no buffer overrun");
testOk(result[3] == 0, "epicsStrnRawFromEscaped 0-terminated");
testOk(status == 3, "raw(\"ABCDE\", 5) -> %d (exp. 3)", status);
testOk(result[0] == 'A', " Char '%c' (exp. 'A')", result[0]);
testOk(result[1] == 'B', " Char '%c' (exp. 'B')", result[1]);
testOk(result[2] == 'C', " Char '%c' (exp. 'C')", result[2]);
testOk(result[3] == 0, " 0-terminated");
testOk(result[4] == 'x', " No write outside buffer");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "A", 2);
testOk(status == 1, "raw(\"A\", 2) -> %d (exp. 1)", status);
testOk(result[0] == 'A', " Char '%c' (exp. 'A')", result[0]);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\123", 1);
testOk(status == 0, "raw(\"\\123\", 1) -> %d (exp. 0)", status);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\123", 2);
testOk(status == 1, "raw(\"\\123\", 2) -> %d (exp. 1)", status);
testOk(result[0] == 1, " Octal escape (got \\%03o)", result[0]);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\123", 3);
testOk(status == 1, "raw(\"\\123\", 3) -> %d (exp. 1)", status);
testOk(result[0] == 012, " Octal escape (got \\%03o)", result[0]);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\123", 4);
testOk(status == 1, "raw(\"\\123\", 4) -> %d (exp. 1)", status);
testOk(result[0] == 0123, " Octal escape (got \\%03o)", result[0]);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\812", 2);
testOk(status == 1, "raw(\"\\812\", 2) -> %d (exp. 1)", status);
testOk(result[0] == '8', " Escaped '%c')", result[0]);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\182", 3);
testOk(status == 2, "raw(\"\\182\", 3) -> %d (exp. 2)", status);
testOk(result[0] == 1, " Octal escape (got \\%03o)", result[0]);
testOk(result[1] == '8', " Terminated with '%c'", result[1]);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\128", 4);
testOk(status == 2, "raw(\"\\128\", 4) -> %d (exp. 2)", status);
testOk(result[0] == 012, " Octal escape (got \\%03o)", result[0]);
testOk(result[1] == '8', " Terminator char got '%c'", result[1]);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\x12", 1);
testOk(status == 0, "raw(\"\\x12\", 1) -> %d (exp. 0)", status);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\x12", 2);
testOk(status == 0, "raw(\"\\x12\", 2) -> %d (exp. 0)", status);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\x12", 3);
testOk(status == 1, "raw(\"\\x12\", 3) -> %d (exp. 1)", status);
testOk(result[0] == 1, " Hex escape (got \\x%x)", result[0]);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\x12", 4);
testOk(status == 1, "raw(\"\\x12\", 4) -> %d (exp. 1)", status);
testOk(result[0] == 0x12," Hex escape (got \\x%x)", result[0]);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\xaF", 4);
testOk(status == 1, "raw(\"\\xaF\", 4) -> %d (exp. 1)", status);
testOk(result[0] == '\xaF'," Hex escape (got \\x%x)", result[0] & 0xFF);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\x012", 5);
testOk(status == 1, "raw(\"\\x012\", 5) -> %d (exp. 1)", status);
testOk(result[0] == 0x12," Hex escape (got \\x%x)", result[0]);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\x0012", 6);
testOk(status == 1, "raw(\"\\x0012\", 6) -> %d (exp. 1)", status);
testOk(result[0] == 0x12," Hex escape (got \\x%x)", result[0]);
testOk(result[status] == 0, " 0-terminated");
memset(result, 'x', sizeof(result));
status = epicsStrnRawFromEscaped(result, 4, "\\x1g", 4);
testOk(status == 2, "raw(\"\\x1g\", 4) -> %d (exp. 2)", status);
testOk(result[0] == 1, " Hex escape (got \\x%x)", result[0]);
testOk(result[1] == 'g', " Terminator char got '%c'", result[1]);
testOk(result[status] == 0, " 0-terminated");
return testDone();
}