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