Merge ~dougmurray/epics-base:fix-1943245 into ~epics-core/epics-base/+git/epics-base:7.0

Proposed by Doug Murray
Status: Needs review
Proposed branch: ~dougmurray/epics-base:fix-1943245
Merge into: ~epics-core/epics-base/+git/epics-base:7.0
Diff against target: 168 lines (+94/-35)
2 files modified
modules/libcom/src/misc/epicsString.c (+85/-33)
modules/libcom/test/epicsStringTest.c (+9/-2)
Reviewer Review Type Date Requested Status
Andrew Johnson Needs Fixing
Review via email: mp+422030@code.launchpad.net

Commit message

Fixes lp: #1943245

To post a comment you must log in.
Revision history for this message
Andrew Johnson (anj) wrote :

See comments inline below...

review: Needs Fixing
~dougmurray/epics-base:fix-1943245 updated
ccba97b... by Doug Murray

Fix up previous commit with added comment
Remove older routine, replaced by new version; added
comment from updated routine description.

Unmerged commits

ccba97b... by Doug Murray

Fix up previous commit with added comment
Remove older routine, replaced by new version; added
comment from updated routine description.

7abe056... by Doug Murray

#1943245 epicsStrnEscapedFromRaw may print inclomplete escape sequences
Fixed a problem where a partial escape sequence could be added to
a string. Rather than checking for the limit when adding each
character, the check is made for the entire sequence.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/modules/libcom/src/misc/epicsString.c b/modules/libcom/src/misc/epicsString.c
2index ca61d9b..1854874 100644
3--- a/modules/libcom/src/misc/epicsString.c
4+++ b/modules/libcom/src/misc/epicsString.c
5@@ -117,46 +117,98 @@ done:
6 return ndst;
7 }
8
9-int epicsStrnEscapedFromRaw(char *dst, size_t dstlen, const char *src,
10- size_t srclen)
11+/*
12+ * expand the given character.
13+ * Place the expansion in *dest, which
14+ * must be at least 5 characters long
15+ *
16+ * Returns: number of characters produced.
17+ */
18+static int translateEscapedChar( char c, char *dest)
19 {
20- int rem = dstlen;
21- int ndst = 0;
22+ static const char hex[] = "0123456789abcdef";
23+ char *ptr = dest;
24+ int ret = 0;
25
26- if (dst == src)
27- return -1;
28+ if( ptr == NULL)
29+ return 0;
30
31- while (srclen--) {
32- static const char hex[] = "0123456789abcdef";
33- int c = *src++;
34- #define OUT(chr) ndst++; if (--rem > 0) *dst++ = chr
35-
36- switch (c) {
37- case '\a': OUT('\\'); OUT('a'); break;
38- case '\b': OUT('\\'); OUT('b'); break;
39- case '\f': OUT('\\'); OUT('f'); break;
40- case '\n': OUT('\\'); OUT('n'); break;
41- case '\r': OUT('\\'); OUT('r'); break;
42- case '\t': OUT('\\'); OUT('t'); break;
43- case '\v': OUT('\\'); OUT('v'); break;
44- case '\\': OUT('\\'); OUT('\\'); break;
45- case '\'': OUT('\\'); OUT('\''); break;
46- case '\"': OUT('\\'); OUT('\"'); break;
47- case '\0': OUT('\\'); OUT('0'); break;
48+ *ptr++ = '\\';
49+ switch( c) {
50 default:
51- if (isprint(c & 0xff)) {
52- OUT(c);
53- break;
54+ if( isprint( c & 0xff)) {
55+ *--ptr = c;
56+ ptr++;
57+ ret = 1;
58+ } else {
59+ *ptr++ = 'x';
60+ *ptr++ = hex[(c >> 4) & 0x0f];
61+ *ptr++ = hex[ c & 0x0f];
62+ ret = 4;
63 }
64- OUT('\\'); OUT('x');
65- OUT(hex[(c >> 4) & 0x0f]);
66- OUT(hex[ c & 0x0f]);
67+ break;
68+
69+ case '\a': *ptr++ = 'a'; ret = 2; break;
70+ case '\b': *ptr++ = 'b'; ret = 2; break;
71+ case '\f': *ptr++ = 'f'; ret = 2; break;
72+ case '\n': *ptr++ = 'n'; ret = 2; break;
73+ case '\r': *ptr++ = 'r'; ret = 2; break;
74+ case '\t': *ptr++ = 't'; ret = 2; break;
75+ case '\v': *ptr++ = 'v'; ret = 2; break;
76+ case '\\': *ptr++ = '\\'; ret = 2; break;
77+ case '\'': *ptr++ = '\''; ret = 2; break;
78+ case '\"': *ptr++ = '"'; ret = 2; break;
79+ case '\0': *ptr++ = '0'; ret = 2; break;
80+ }
81+
82+ *ptr = 0;
83+ return ret;
84+}
85+
86+/**
87+ * Copy string, converting non-printable characters into their escape sequence
88+ * source string.
89+ *
90+ * epicsStrnEscapedFromRaw does the opposite of epicsStrnRawFromEscaped: It tries
91+ * to copy strlen characters from the string src into a buffer dst of size dstlen,
92+ * converting non-printable characters into C-style escape sequences. A zero byte
93+ * will not terminate the input string. The output string will be zero-terminated
94+ * as long as dstlen is non-zero. No more than dstlen characters will actually be
95+ * written into the output buffer, although all the characters in the input string
96+ * will be read. The return value is the number of characters that would have been
97+ * stored in the output buffer if it were large enough, or a negative value if dst
98+ * == src. In-place translations are not allowed since the escaped results will
99+ * usually be larger than the input string.
100+ *
101+ * The following escaped character constants will be used in the output:
102+ * \a \b \f \n \r \t \v \\ \' \"
103+ *
104+ * All other non-printable characters appear as hexadeimal escapes in form \xNN
105+ * where NN are two hex digits (0-9, a-f). Non-printable characters are
106+ * determined by the C runtime library’s isprint() function.
107+ */
108+int epicsStrnEscapedFromRaw(char *dst, size_t dstlen, const char *src, size_t srclen)
109+{
110+ char expanded[6];
111+ int remain = dstlen;
112+ int cnt = 0;
113+
114+ if( src == dst)
115+ return -1;
116+
117+ for( int i = 0; i < srclen; i++) {
118+ int num = translateEscapedChar( src[i], expanded);
119+ if( num < remain) {
120+ strcpy( dst, expanded);
121+ remain -= num;
122+ dst += num;
123 }
124- #undef OUT
125+ cnt += num;
126 }
127- if (dstlen)
128- *dst = '\0';
129- return ndst;
130+
131+ if( dstlen != 0)
132+ *dst = 0;
133+ return cnt;
134 }
135
136 size_t epicsStrnEscapedFromRawSize(const char *src, size_t srclen)
137diff --git a/modules/libcom/test/epicsStringTest.c b/modules/libcom/test/epicsStringTest.c
138index 7abffa3..185d0b5 100644
139--- a/modules/libcom/test/epicsStringTest.c
140+++ b/modules/libcom/test/epicsStringTest.c
141@@ -155,7 +155,7 @@ MAIN(epicsStringTest)
142 char *s;
143 int status;
144
145- testPlan(427);
146+ testPlan(431);
147
148 testChars();
149
150@@ -244,10 +244,17 @@ MAIN(epicsStringTest)
151
152 memset(result, 'x', sizeof(result));
153 status = epicsStrnEscapedFromRaw(result, 4, ABCD, 5);
154- testOk(status == 6, "esc(\"ABCD\", 5) -> %d (exp. 8)", status);
155+ testOk(status == 6, "esc(\"ABCD\", 5) -> %d (exp. 6)", status);
156 testOk(result[3] == 0, " 0-terminated");
157 testOk(result[4] == 'x', " No overrun");
158
159+ memset(result, 'x', sizeof(result));
160+ status = epicsStrnEscapedFromRaw(result, 5, "ABC\"DEF", 6);
161+ testOk(status == 7, "esc(\"ABC\\\"DEF\", 5) -> %d (exp. 7)", status);
162+ testOk(result[3] != '\\', " no partial escape sequence");
163+ testOk(result[4] == 0, " 0-terminated");
164+ testOk(result[5] == 'x', " No overrun");
165+
166 testDiag("Testing raw = epicsStrnRawFromEscaped(out, 4, ...)");
167
168 memset(result, 'x', sizeof(result));

Subscribers

People subscribed via source and target branches