1 /* $Id: strvis.c,v 1.18 2012/10/22 15:15:59 karls Exp $ */
2
3 #ifdef HAVE_CONFIG_H
4 #include "autoconf.h"
5 #endif /* HAVE_CONFIG_H */
6
7 #include "osdep.h"
8
9 /* $OpenBSD: vis.c,v 1.19 2005/09/01 17:15:49 millert Exp $ */
10 /*-
11 * Copyright (c) 1989, 1993
12 * The Regents of the University of California. All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #include "vis_compat.h"
40
41 #define isoctal(c) \
42 (((unsigned char)(c)) >= '0' && ((unsigned char)(c)) <= '7')
43 #define isvisible(c) \
44 (((unsigned int)(c) <= UCHAR_MAX && isascii((unsigned char)(c)) && \
45 (((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') || \
46 (flag & VIS_GLOB) == 0) && isgraph((unsigned char)(c))) || \
47 ((flag & VIS_SP) == 0 && (c) == ' ') || \
48 ((flag & VIS_TAB) == 0 && (c) == '\t') || \
49 ((flag & VIS_NL) == 0 && (c) == '\n') || \
50 ((flag & VIS_SAFE) && ((c) == '\b' || \
51 (c) == '\007' || (c) == '\r' || \
52 isgraph((unsigned char)(c)))))
53
54 /*
55 * vis - visually encode characters
56 */
57 char *
vis(char * dst,int c,int flag,int nextc)58 vis(char *dst, int c, int flag, int nextc)
59 {
60
61 /*
62 * For this:
63 CID 10114: Untrusted pointer read (TAINTED_SCALAR)
64 At (17): Using tainted variable "(int)(unsigned char)bufp[offset]" as an index to pointer "*__ctype_b_loc()".
65 *
66 */
67 const char truncate = (char)c;
68 c = truncate;
69
70 if (isvisible(c)) {
71 *dst++ = c;
72 if (c == '\\' && (flag & VIS_NOSLASH) == 0)
73 *dst++ = '\\';
74 *dst = '\0';
75 return (dst);
76 }
77
78 if (flag & VIS_CSTYLE) {
79 switch(c) {
80 case '\n':
81 *dst++ = '\\';
82 *dst++ = 'n';
83 goto done;
84 case '\r':
85 *dst++ = '\\';
86 *dst++ = 'r';
87 goto done;
88 case '\b':
89 *dst++ = '\\';
90 *dst++ = 'b';
91 goto done;
92 case '\a':
93 *dst++ = '\\';
94 *dst++ = 'a';
95 goto done;
96 case '\v':
97 *dst++ = '\\';
98 *dst++ = 'v';
99 goto done;
100 case '\t':
101 *dst++ = '\\';
102 *dst++ = 't';
103 goto done;
104 case '\f':
105 *dst++ = '\\';
106 *dst++ = 'f';
107 goto done;
108 case ' ':
109 *dst++ = '\\';
110 *dst++ = 's';
111 goto done;
112 case '\0':
113 *dst++ = '\\';
114 *dst++ = '0';
115 if (isoctal(nextc)) {
116 *dst++ = '0';
117 *dst++ = '0';
118 }
119 goto done;
120 }
121 }
122 if (((c & 0177) == ' ') || (flag & VIS_OCTAL) ||
123 ((flag & VIS_GLOB) && (c == '*' || c == '?' || c == '[' || c == '#'))) {
124 *dst++ = '\\';
125 *dst++ = ((unsigned char)c >> 6 & 07) + '0';
126 *dst++ = ((unsigned char)c >> 3 & 07) + '0';
127 *dst++ = ((unsigned char)c & 07) + '0';
128 goto done;
129 }
130 if ((flag & VIS_NOSLASH) == 0)
131 *dst++ = '\\';
132 if (c & 0200) {
133 c &= 0177;
134 *dst++ = 'M';
135 }
136 if (iscntrl((unsigned char)c)) {
137 *dst++ = '^';
138 if (c == 0177)
139 *dst++ = '?';
140 else
141 *dst++ = c + '@';
142 } else {
143 *dst++ = '-';
144 *dst++ = c;
145 }
146 done:
147 *dst = '\0';
148 return (dst);
149 }
150
151 /*
152 * strvis, strnvis, strvisx - visually encode characters from src into dst
153 *
154 * Dst must be 4 times the size of src to account for possible
155 * expansion. The length of dst, not including the trailing NULL,
156 * is returned.
157 *
158 * Strnvis will write no more than siz-1 bytes (and will NULL terminate).
159 * The number of bytes needed to fully encode the string is returned.
160 *
161 * Strvisx encodes exactly len bytes from src into dst.
162 * This is useful for encoding a block of data.
163 */
164 int
strvis(char * dst,const char * src,int flag)165 strvis(char *dst, const char *src, int flag)
166 {
167 char c;
168 char *start;
169
170 for (start = dst; (c = *src);)
171 dst = vis(dst, c, flag, *++src);
172 *dst = '\0';
173 return (dst - start);
174 }
175
176 int
strnvis(char * dst,const char * src,size_t siz,int flag)177 strnvis(char *dst, const char *src, size_t siz, int flag)
178 {
179 char *start, *end;
180 char tbuf[5];
181 int c, i;
182
183 i = 0;
184 for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) {
185 if (isvisible(c)) {
186 i = 1;
187 *dst++ = c;
188 if (c == '\\' && (flag & VIS_NOSLASH) == 0) {
189 /* need space for the extra '\\' */
190 if (dst < end)
191 *dst++ = '\\';
192 else {
193 dst--;
194 i = 2;
195 break;
196 }
197 }
198 src++;
199 } else {
200 i = vis(tbuf, c, flag, *++src) - tbuf;
201 if (dst + i <= end) {
202 memcpy(dst, tbuf, i);
203 dst += i;
204 } else {
205 src--;
206 break;
207 }
208 }
209 }
210 if (siz > 0)
211 *dst = '\0';
212 if (dst + i > end) {
213 /* adjust return value for truncation */
214 while ((c = *src))
215 dst += vis(tbuf, c, flag, *++src) - tbuf;
216 }
217 return (dst - start);
218 }
219
220 int
strvisx(char * dst,const char * src,size_t len,int flag)221 strvisx(char *dst, const char *src, size_t len, int flag)
222 {
223 char c;
224 char *start;
225
226 for (start = dst; len > 1; len--) {
227 c = *src;
228 dst = vis(dst, c, flag, *++src);
229 }
230 if (len)
231 dst = vis(dst, *src, flag, '\0');
232 *dst = '\0';
233 return (dst - start);
234 }
235