xref: /freebsd/crypto/heimdal/lib/roken/vis.c (revision b9f654b163bce26de79705e77b872427c9f2afa1)
1 /*	$NetBSD: vis.c,v 1.37 2008/07/25 22:29:23 dsl Exp $	*/
2 
3 /*-
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*-
33  * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
46  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
47  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
49  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55  * POSSIBILITY OF SUCH DAMAGE.
56  */
57 
58 #if 1
59 #include <config.h>
60 #include "roken.h"
61 #ifndef _DIAGASSERT
62 #define _DIAGASSERT(X)
63 #endif
64 #else /* heimdal */
65 #include <sys/cdefs.h>
66 #if defined(LIBC_SCCS) && !defined(lint)
67 __RCSID("$NetBSD: vis.c,v 1.37 2008/07/25 22:29:23 dsl Exp $");
68 #endif /* LIBC_SCCS and not lint */
69 
70 #include "namespace.h"
71 #endif /* heimdal */
72 
73 #include <sys/types.h>
74 
75 #include <assert.h>
76 #include <ctype.h>
77 #include <limits.h>
78 #include <stdio.h>
79 #include <string.h>
80 #include <vis.h>
81 #include <stdlib.h>
82 
83 #if 0
84 #ifdef __weak_alias
85 __weak_alias(strsvis,_strsvis)
86 __weak_alias(strsvisx,_strsvisx)
87 __weak_alias(strvis,_strvis)
88 __weak_alias(strvisx,_strvisx)
89 __weak_alias(svis,_svis)
90 __weak_alias(vis,_vis)
91 #endif
92 #endif
93 
94 #if !HAVE_VIS || !HAVE_SVIS
95 #include <ctype.h>
96 #include <limits.h>
97 #include <stdio.h>
98 #include <string.h>
99 
100 static char *do_svis(char *, int, int, int, const char *);
101 
102 #undef BELL
103 #if defined(__STDC__)
104 #define BELL '\a'
105 #else
106 #define BELL '\007'
107 #endif
108 
109 ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
110 	rk_vis (char *, int, int, int);
111 ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
112 	rk_svis (char *, int, int, int, const char *);
113 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
114 	rk_strvis (char *, const char *, int);
115 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
116 	rk_strsvis (char *, const char *, int, const char *);
117 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
118 	rk_strvisx (char *, const char *, size_t, int);
119 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
120 	rk_strsvisx (char *, const char *, size_t, int, const char *);
121 
122 
123 #define isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
124 #define iswhite(c)	(c == ' ' || c == '\t' || c == '\n')
125 #define issafe(c)	(c == '\b' || c == BELL || c == '\r')
126 #define xtoa(c)		"0123456789abcdef"[c]
127 
128 #define MAXEXTRAS	5
129 
130 #define MAKEEXTRALIST(flag, extra, orig_str)				      \
131 do {									      \
132 	const char *orig = orig_str;					      \
133 	const char *o = orig;						      \
134 	char *e;							      \
135 	while (*o++)							      \
136 		continue;						      \
137 	extra = malloc((size_t)((o - orig) + MAXEXTRAS));		      \
138 	if (!extra) break;						      \
139 	for (o = orig, e = extra; (*e++ = *o++) != '\0';)		      \
140 		continue;						      \
141 	e--;								      \
142 	if (flag & VIS_SP) *e++ = ' ';					      \
143 	if (flag & VIS_TAB) *e++ = '\t';				      \
144 	if (flag & VIS_NL) *e++ = '\n';					      \
145 	if ((flag & VIS_NOSLASH) == 0) *e++ = '\\';			      \
146 	*e = '\0';							      \
147 } while (/*CONSTCOND*/0)
148 
149 /*
150  * This is do_hvis, for HTTP style (RFC 1808)
151  */
152 static char *
153 do_hvis(char *dst, int c, int flag, int nextc, const char *extra)
154 {
155 	if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) {
156 		*dst++ = '%';
157 		*dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
158 		*dst++ = xtoa((unsigned int)c & 0xf);
159 	} else {
160 		dst = do_svis(dst, c, flag, nextc, extra);
161 	}
162 	return dst;
163 }
164 
165 /*
166  * This is do_vis, the central code of vis.
167  * dst:	      Pointer to the destination buffer
168  * c:	      Character to encode
169  * flag:      Flag word
170  * nextc:     The character following 'c'
171  * extra:     Pointer to the list of extra characters to be
172  *	      backslash-protected.
173  */
174 static char *
175 do_svis(char *dst, int c, int flag, int nextc, const char *extra)
176 {
177 	int isextra;
178 	isextra = strchr(extra, c) != NULL;
179 	if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||
180 	    ((flag & VIS_SAFE) && issafe(c)))) {
181 		*dst++ = c;
182 		return dst;
183 	}
184 	if (flag & VIS_CSTYLE) {
185 		switch (c) {
186 		case '\n':
187 			*dst++ = '\\'; *dst++ = 'n';
188 			return dst;
189 		case '\r':
190 			*dst++ = '\\'; *dst++ = 'r';
191 			return dst;
192 		case '\b':
193 			*dst++ = '\\'; *dst++ = 'b';
194 			return dst;
195 		case BELL:
196 			*dst++ = '\\'; *dst++ = 'a';
197 			return dst;
198 		case '\v':
199 			*dst++ = '\\'; *dst++ = 'v';
200 			return dst;
201 		case '\t':
202 			*dst++ = '\\'; *dst++ = 't';
203 			return dst;
204 		case '\f':
205 			*dst++ = '\\'; *dst++ = 'f';
206 			return dst;
207 		case ' ':
208 			*dst++ = '\\'; *dst++ = 's';
209 			return dst;
210 		case '\0':
211 			*dst++ = '\\'; *dst++ = '0';
212 			if (isoctal(nextc)) {
213 				*dst++ = '0';
214 				*dst++ = '0';
215 			}
216 			return dst;
217 		default:
218 			if (isgraph(c)) {
219 				*dst++ = '\\'; *dst++ = c;
220 				return dst;
221 			}
222 		}
223 	}
224 	if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
225 		*dst++ = '\\';
226 		*dst++ = (u_char)(((unsigned int)(u_char)c >> 6) & 03) + '0';
227 		*dst++ = (u_char)(((unsigned int)(u_char)c >> 3) & 07) + '0';
228 		*dst++ = (u_char)(			 c       & 07) + '0';
229 	} else {
230 		if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';
231 		if (c & 0200) {
232 			c &= 0177; *dst++ = 'M';
233 		}
234 		if (iscntrl(c)) {
235 			*dst++ = '^';
236 			if (c == 0177)
237 				*dst++ = '?';
238 			else
239 				*dst++ = c + '@';
240 		} else {
241 			*dst++ = '-'; *dst++ = c;
242 		}
243 	}
244 	return dst;
245 }
246 
247 
248 /*
249  * svis - visually encode characters, also encoding the characters
250  *	  pointed to by `extra'
251  */
252 ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
253 rk_svis(char *dst, int c, int flag, int nextc, const char *extra)
254 {
255 	char *nextra = NULL;
256 
257 	_DIAGASSERT(dst != NULL);
258 	_DIAGASSERT(extra != NULL);
259 	MAKEEXTRALIST(flag, nextra, extra);
260 	if (!nextra) {
261 		*dst = '\0';		/* can't create nextra, return "" */
262 		return dst;
263 	}
264 	if (flag & VIS_HTTPSTYLE)
265 		dst = do_hvis(dst, c, flag, nextc, nextra);
266 	else
267 		dst = do_svis(dst, c, flag, nextc, nextra);
268 	free(nextra);
269 	*dst = '\0';
270 	return dst;
271 }
272 
273 
274 /*
275  * strsvis, strsvisx - visually encode characters from src into dst
276  *
277  *	Extra is a pointer to a \0-terminated list of characters to
278  *	be encoded, too. These functions are useful e. g. to
279  *	encode strings in such a way so that they are not interpreted
280  *	by a shell.
281  *
282  *	Dst must be 4 times the size of src to account for possible
283  *	expansion.  The length of dst, not including the trailing NULL,
284  *	is returned.
285  *
286  *	Strsvisx encodes exactly len bytes from src into dst.
287  *	This is useful for encoding a block of data.
288  */
289 
290 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
291 rk_strsvis(char *dst, const char *csrc, int flag, const char *extra)
292 {
293 	int c;
294 	char *start;
295 	char *nextra = NULL;
296 	const unsigned char *src = (const unsigned char *)csrc;
297 
298 	_DIAGASSERT(dst != NULL);
299 	_DIAGASSERT(src != NULL);
300 	_DIAGASSERT(extra != NULL);
301 	MAKEEXTRALIST(flag, nextra, extra);
302 	if (!nextra) {
303 		*dst = '\0';		/* can't create nextra, return "" */
304 		return 0;
305 	}
306 	if (flag & VIS_HTTPSTYLE) {
307 		for (start = dst; (c = *src++) != '\0'; /* empty */)
308 			dst = do_hvis(dst, c, flag, *src, nextra);
309 	} else {
310 		for (start = dst; (c = *src++) != '\0'; /* empty */)
311 			dst = do_svis(dst, c, flag, *src, nextra);
312 	}
313 	free(nextra);
314 	*dst = '\0';
315 	return (dst - start);
316 }
317 
318 
319 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
320 rk_strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra)
321 {
322 	unsigned char c;
323 	char *start;
324 	char *nextra = NULL;
325 	const unsigned char *src = (const unsigned char *)csrc;
326 
327 	_DIAGASSERT(dst != NULL);
328 	_DIAGASSERT(src != NULL);
329 	_DIAGASSERT(extra != NULL);
330 	MAKEEXTRALIST(flag, nextra, extra);
331 	if (! nextra) {
332 		*dst = '\0';		/* can't create nextra, return "" */
333 		return 0;
334 	}
335 
336 	if (flag & VIS_HTTPSTYLE) {
337 		for (start = dst; len > 0; len--) {
338 			c = *src++;
339 			dst = do_hvis(dst, c, flag, len ? *src : '\0', nextra);
340 		}
341 	} else {
342 		for (start = dst; len > 0; len--) {
343 			c = *src++;
344 			dst = do_svis(dst, c, flag, len ? *src : '\0', nextra);
345 		}
346 	}
347 	free(nextra);
348 	*dst = '\0';
349 	return (dst - start);
350 }
351 #endif
352 
353 #if !HAVE_VIS
354 /*
355  * vis - visually encode characters
356  */
357 ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
358 rk_vis(char *dst, int c, int flag, int nextc)
359 {
360 	char *extra = NULL;
361 	unsigned char uc = (unsigned char)c;
362 
363 	_DIAGASSERT(dst != NULL);
364 
365 	MAKEEXTRALIST(flag, extra, "");
366 	if (! extra) {
367 		*dst = '\0';		/* can't create extra, return "" */
368 		return dst;
369 	}
370 	if (flag & VIS_HTTPSTYLE)
371 		dst = do_hvis(dst, uc, flag, nextc, extra);
372 	else
373 		dst = do_svis(dst, uc, flag, nextc, extra);
374 	free(extra);
375 	*dst = '\0';
376 	return dst;
377 }
378 
379 
380 /*
381  * strvis, strvisx - visually encode characters from src into dst
382  *
383  *	Dst must be 4 times the size of src to account for possible
384  *	expansion.  The length of dst, not including the trailing NULL,
385  *	is returned.
386  *
387  *	Strvisx encodes exactly len bytes from src into dst.
388  *	This is useful for encoding a block of data.
389  */
390 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
391 rk_strvis(char *dst, const char *src, int flag)
392 {
393 	char *extra = NULL;
394 	int rv;
395 
396 	MAKEEXTRALIST(flag, extra, "");
397 	if (!extra) {
398 		*dst = '\0';		/* can't create extra, return "" */
399 		return 0;
400 	}
401 	rv = strsvis(dst, src, flag, extra);
402 	free(extra);
403 	return rv;
404 }
405 
406 
407 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
408 rk_strvisx(char *dst, const char *src, size_t len, int flag)
409 {
410 	char *extra = NULL;
411 	int rv;
412 
413 	MAKEEXTRALIST(flag, extra, "");
414 	if (!extra) {
415 		*dst = '\0';		/* can't create extra, return "" */
416 		return 0;
417 	}
418 	rv = strsvisx(dst, src, len, flag, extra);
419 	free(extra);
420 	return rv;
421 }
422 #endif
423