Blob


1 /* $OpenBSD: vis.c,v 1.26 2022/05/04 18:57:50 deraadt Exp $ */
2 /*-
3 * Copyright (c) 1989, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
31 #include "../config.h"
33 #include <sys/types.h>
34 #include <errno.h>
35 #include <ctype.h>
36 #include <limits.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <vis.h>
41 static int
42 isoctal(int c)
43 {
44 u_char uc = c;
46 return uc >= '0' && uc <= '7';
47 }
49 static int
50 isvisible(int c, int flag)
51 {
52 int vis_sp = flag & VIS_SP;
53 int vis_tab = flag & VIS_TAB;
54 int vis_nl = flag & VIS_NL;
55 int vis_safe = flag & VIS_SAFE;
56 int vis_glob = flag & VIS_GLOB;
57 int vis_all = flag & VIS_ALL;
58 u_char uc = c;
60 if (c == '\\' || !vis_all) {
61 if ((u_int)c <= UCHAR_MAX && isascii(uc) &&
62 ((c != '*' && c != '?' && c != '[' && c != '#') || !vis_glob) &&
63 isgraph(uc))
64 return 1;
65 if (!vis_sp && c == ' ')
66 return 1;
67 if (!vis_tab && c == '\t')
68 return 1;
69 if (!vis_nl && c == '\n')
70 return 1;
71 if (vis_safe && (c == '\b' || c == '\007' || c == '\r' || isgraph(uc)))
72 return 1;
73 }
74 return 0;
75 }
77 /*
78 * vis - visually encode characters
79 */
80 char *
81 vis(char *dst, int c, int flag, int nextc)
82 {
83 int vis_dq = flag & VIS_DQ;
84 int vis_noslash = flag & VIS_NOSLASH;
85 int vis_cstyle = flag & VIS_CSTYLE;
86 int vis_octal = flag & VIS_OCTAL;
87 int vis_glob = flag & VIS_GLOB;
89 if (isvisible(c, flag)) {
90 if ((c == '"' && vis_dq) ||
91 (c == '\\' && !vis_noslash))
92 *dst++ = '\\';
93 *dst++ = c;
94 *dst = '\0';
95 return (dst);
96 }
98 if (vis_cstyle) {
99 switch (c) {
100 case '\n':
101 *dst++ = '\\';
102 *dst++ = 'n';
103 goto done;
104 case '\r':
105 *dst++ = '\\';
106 *dst++ = 'r';
107 goto done;
108 case '\b':
109 *dst++ = '\\';
110 *dst++ = 'b';
111 goto done;
112 case '\a':
113 *dst++ = '\\';
114 *dst++ = 'a';
115 goto done;
116 case '\v':
117 *dst++ = '\\';
118 *dst++ = 'v';
119 goto done;
120 case '\t':
121 *dst++ = '\\';
122 *dst++ = 't';
123 goto done;
124 case '\f':
125 *dst++ = '\\';
126 *dst++ = 'f';
127 goto done;
128 case ' ':
129 *dst++ = '\\';
130 *dst++ = 's';
131 goto done;
132 case '\0':
133 *dst++ = '\\';
134 *dst++ = '0';
135 if (isoctal(nextc)) {
136 *dst++ = '0';
137 *dst++ = '0';
139 goto done;
142 if (((c & 0177) == ' ') || vis_octal ||
143 (vis_glob && (c == '*' || c == '?' || c == '[' || c == '#'))) {
144 *dst++ = '\\';
145 *dst++ = ((u_char)c >> 6 & 07) + '0';
146 *dst++ = ((u_char)c >> 3 & 07) + '0';
147 *dst++ = ((u_char)c & 07) + '0';
148 goto done;
150 if (!vis_noslash)
151 *dst++ = '\\';
152 if (c & 0200) {
153 c &= 0177;
154 *dst++ = 'M';
156 if (iscntrl((u_char)c)) {
157 *dst++ = '^';
158 if (c == 0177)
159 *dst++ = '?';
160 else
161 *dst++ = c + '@';
162 } else {
163 *dst++ = '-';
164 *dst++ = c;
166 done:
167 *dst = '\0';
168 return (dst);
171 /*
172 * strvis, strnvis, strvisx - visually encode characters from src into dst
174 * Dst must be 4 times the size of src to account for possible
175 * expansion. The length of dst, not including the trailing NULL,
176 * is returned.
178 * Strnvis will write no more than siz-1 bytes (and will NULL terminate).
179 * The number of bytes needed to fully encode the string is returned.
181 * Strvisx encodes exactly len bytes from src into dst.
182 * This is useful for encoding a block of data.
183 */
184 int
185 strvis(char *dst, const char *src, int flag)
187 char c;
188 char *start;
190 for (start = dst; (c = *src);)
191 dst = vis(dst, c, flag, *++src);
192 *dst = '\0';
193 return (dst - start);
196 int
197 strnvis(char *dst, const char *src, size_t siz, int flag)
199 int vis_dq = flag & VIS_DQ;
200 int vis_noslash = flag & VIS_NOSLASH;
201 char *start, *end;
202 char tbuf[5];
203 int c, i;
205 i = 0;
206 for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) {
207 if (isvisible(c, flag)) {
208 if ((c == '"' && vis_dq) ||
209 (c == '\\' && !vis_noslash)) {
210 /* need space for the extra '\\' */
211 if (dst + 1 >= end) {
212 i = 2;
213 break;
215 *dst++ = '\\';
217 i = 1;
218 *dst++ = c;
219 src++;
220 } else {
221 i = vis(tbuf, c, flag, *++src) - tbuf;
222 if (dst + i <= end) {
223 memcpy(dst, tbuf, i);
224 dst += i;
225 } else {
226 src--;
227 break;
231 if (siz > 0)
232 *dst = '\0';
233 if (dst + i > end) {
234 /* adjust return value for truncation */
235 while ((c = *src))
236 dst += vis(tbuf, c, flag, *++src) - tbuf;
238 return (dst - start);
241 int
242 stravis(char **outp, const char *src, int flag)
244 char *buf;
245 int len, serrno;
247 buf = reallocarray(NULL, 4, strlen(src) + 1);
248 if (buf == NULL)
249 return -1;
250 len = strvis(buf, src, flag);
251 serrno = errno;
252 *outp = realloc(buf, len + 1);
253 if (*outp == NULL) {
254 *outp = buf;
255 errno = serrno;
257 return (len);
260 int
261 strvisx(char *dst, const char *src, size_t len, int flag)
263 char c;
264 char *start;
266 for (start = dst; len > 1; len--) {
267 c = *src;
268 dst = vis(dst, c, flag, *++src);
270 if (len)
271 dst = vis(dst, *src, flag, '\0');
272 *dst = '\0';
273 return (dst - start);