xref: /freebsd-src/contrib/libc-vis/vis.c (revision 8ccca1222d3d9e815f972a7acfc18a034ce4a4bb)
1*8ccca122SBrooks Davis /*	$NetBSD: vis.c,v 1.45 2012/12/14 21:38:18 christos Exp $	*/
2*8ccca122SBrooks Davis 
3*8ccca122SBrooks Davis /*-
4*8ccca122SBrooks Davis  * Copyright (c) 1989, 1993
5*8ccca122SBrooks Davis  *	The Regents of the University of California.  All rights reserved.
6*8ccca122SBrooks Davis  *
7*8ccca122SBrooks Davis  * Redistribution and use in source and binary forms, with or without
8*8ccca122SBrooks Davis  * modification, are permitted provided that the following conditions
9*8ccca122SBrooks Davis  * are met:
10*8ccca122SBrooks Davis  * 1. Redistributions of source code must retain the above copyright
11*8ccca122SBrooks Davis  *    notice, this list of conditions and the following disclaimer.
12*8ccca122SBrooks Davis  * 2. Redistributions in binary form must reproduce the above copyright
13*8ccca122SBrooks Davis  *    notice, this list of conditions and the following disclaimer in the
14*8ccca122SBrooks Davis  *    documentation and/or other materials provided with the distribution.
15*8ccca122SBrooks Davis  * 3. Neither the name of the University nor the names of its contributors
16*8ccca122SBrooks Davis  *    may be used to endorse or promote products derived from this software
17*8ccca122SBrooks Davis  *    without specific prior written permission.
18*8ccca122SBrooks Davis  *
19*8ccca122SBrooks Davis  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*8ccca122SBrooks Davis  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*8ccca122SBrooks Davis  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*8ccca122SBrooks Davis  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*8ccca122SBrooks Davis  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*8ccca122SBrooks Davis  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*8ccca122SBrooks Davis  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*8ccca122SBrooks Davis  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*8ccca122SBrooks Davis  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*8ccca122SBrooks Davis  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*8ccca122SBrooks Davis  * SUCH DAMAGE.
30*8ccca122SBrooks Davis  */
31*8ccca122SBrooks Davis 
32*8ccca122SBrooks Davis /*-
33*8ccca122SBrooks Davis  * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
34*8ccca122SBrooks Davis  * All rights reserved.
35*8ccca122SBrooks Davis  *
36*8ccca122SBrooks Davis  * Redistribution and use in source and binary forms, with or without
37*8ccca122SBrooks Davis  * modification, are permitted provided that the following conditions
38*8ccca122SBrooks Davis  * are met:
39*8ccca122SBrooks Davis  * 1. Redistributions of source code must retain the above copyright
40*8ccca122SBrooks Davis  *    notice, this list of conditions and the following disclaimer.
41*8ccca122SBrooks Davis  * 2. Redistributions in binary form must reproduce the above copyright
42*8ccca122SBrooks Davis  *    notice, this list of conditions and the following disclaimer in the
43*8ccca122SBrooks Davis  *    documentation and/or other materials provided with the distribution.
44*8ccca122SBrooks Davis  *
45*8ccca122SBrooks Davis  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
46*8ccca122SBrooks Davis  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
47*8ccca122SBrooks Davis  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48*8ccca122SBrooks Davis  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
49*8ccca122SBrooks Davis  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50*8ccca122SBrooks Davis  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51*8ccca122SBrooks Davis  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52*8ccca122SBrooks Davis  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53*8ccca122SBrooks Davis  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54*8ccca122SBrooks Davis  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55*8ccca122SBrooks Davis  * POSSIBILITY OF SUCH DAMAGE.
56*8ccca122SBrooks Davis  */
57*8ccca122SBrooks Davis 
58*8ccca122SBrooks Davis #include <sys/cdefs.h>
59*8ccca122SBrooks Davis #if defined(LIBC_SCCS) && !defined(lint)
60*8ccca122SBrooks Davis __RCSID("$NetBSD: vis.c,v 1.45 2012/12/14 21:38:18 christos Exp $");
61*8ccca122SBrooks Davis #endif /* LIBC_SCCS and not lint */
62*8ccca122SBrooks Davis __FBSDID("$FreeBSD$");
63*8ccca122SBrooks Davis 
64*8ccca122SBrooks Davis #include "namespace.h"
65*8ccca122SBrooks Davis #include <sys/types.h>
66*8ccca122SBrooks Davis 
67*8ccca122SBrooks Davis #include <assert.h>
68*8ccca122SBrooks Davis #include <vis.h>
69*8ccca122SBrooks Davis #include <errno.h>
70*8ccca122SBrooks Davis #include <stdlib.h>
71*8ccca122SBrooks Davis 
72*8ccca122SBrooks Davis #define	_DIAGASSERT(x)	assert(x)
73*8ccca122SBrooks Davis 
74*8ccca122SBrooks Davis #ifdef __weak_alias
75*8ccca122SBrooks Davis __weak_alias(strvisx,_strvisx)
76*8ccca122SBrooks Davis #endif
77*8ccca122SBrooks Davis 
78*8ccca122SBrooks Davis #if !HAVE_VIS || !HAVE_SVIS
79*8ccca122SBrooks Davis #include <ctype.h>
80*8ccca122SBrooks Davis #include <limits.h>
81*8ccca122SBrooks Davis #include <stdio.h>
82*8ccca122SBrooks Davis #include <string.h>
83*8ccca122SBrooks Davis 
84*8ccca122SBrooks Davis static char *do_svis(char *, size_t *, int, int, int, const char *);
85*8ccca122SBrooks Davis 
86*8ccca122SBrooks Davis #undef BELL
87*8ccca122SBrooks Davis #define BELL '\a'
88*8ccca122SBrooks Davis 
89*8ccca122SBrooks Davis #define isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
90*8ccca122SBrooks Davis #define iswhite(c)	(c == ' ' || c == '\t' || c == '\n')
91*8ccca122SBrooks Davis #define issafe(c)	(c == '\b' || c == BELL || c == '\r')
92*8ccca122SBrooks Davis #define xtoa(c)		"0123456789abcdef"[c]
93*8ccca122SBrooks Davis #define XTOA(c)		"0123456789ABCDEF"[c]
94*8ccca122SBrooks Davis 
95*8ccca122SBrooks Davis #define MAXEXTRAS	9
96*8ccca122SBrooks Davis 
97*8ccca122SBrooks Davis #define MAKEEXTRALIST(flag, extra, orig_str)				      \
98*8ccca122SBrooks Davis do {									      \
99*8ccca122SBrooks Davis 	const char *orig = orig_str;					      \
100*8ccca122SBrooks Davis 	const char *o = orig;						      \
101*8ccca122SBrooks Davis 	char *e;							      \
102*8ccca122SBrooks Davis 	while (*o++)							      \
103*8ccca122SBrooks Davis 		continue;						      \
104*8ccca122SBrooks Davis 	extra = malloc((size_t)((o - orig) + MAXEXTRAS));		      \
105*8ccca122SBrooks Davis 	if (!extra) break;						      \
106*8ccca122SBrooks Davis 	for (o = orig, e = extra; (*e++ = *o++) != '\0';)		      \
107*8ccca122SBrooks Davis 		continue;						      \
108*8ccca122SBrooks Davis 	e--;								      \
109*8ccca122SBrooks Davis 	if (flag & VIS_GLOB) {						      \
110*8ccca122SBrooks Davis 		*e++ = '*';						      \
111*8ccca122SBrooks Davis 		*e++ = '?';						      \
112*8ccca122SBrooks Davis 		*e++ = '[';						      \
113*8ccca122SBrooks Davis 		*e++ = '#';						      \
114*8ccca122SBrooks Davis 	}								      \
115*8ccca122SBrooks Davis 	if (flag & VIS_SP) *e++ = ' ';					      \
116*8ccca122SBrooks Davis 	if (flag & VIS_TAB) *e++ = '\t';				      \
117*8ccca122SBrooks Davis 	if (flag & VIS_NL) *e++ = '\n';					      \
118*8ccca122SBrooks Davis 	if ((flag & VIS_NOSLASH) == 0) *e++ = '\\';			      \
119*8ccca122SBrooks Davis 	*e = '\0';							      \
120*8ccca122SBrooks Davis } while (/*CONSTCOND*/0)
121*8ccca122SBrooks Davis 
122*8ccca122SBrooks Davis /*
123*8ccca122SBrooks Davis  * This is do_hvis, for HTTP style (RFC 1808)
124*8ccca122SBrooks Davis  */
125*8ccca122SBrooks Davis static char *
126*8ccca122SBrooks Davis do_hvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra)
127*8ccca122SBrooks Davis {
128*8ccca122SBrooks Davis 
129*8ccca122SBrooks Davis 	if ((isascii(c) && isalnum(c))
130*8ccca122SBrooks Davis 	    /* safe */
131*8ccca122SBrooks Davis 	    || c == '$' || c == '-' || c == '_' || c == '.' || c == '+'
132*8ccca122SBrooks Davis 	    /* extra */
133*8ccca122SBrooks Davis 	    || c == '!' || c == '*' || c == '\'' || c == '(' || c == ')'
134*8ccca122SBrooks Davis 	    || c == ',') {
135*8ccca122SBrooks Davis 		dst = do_svis(dst, dlen, c, flag, nextc, extra);
136*8ccca122SBrooks Davis 	} else {
137*8ccca122SBrooks Davis 		if (dlen) {
138*8ccca122SBrooks Davis 			if (*dlen < 3)
139*8ccca122SBrooks Davis 				return NULL;
140*8ccca122SBrooks Davis 			*dlen -= 3;
141*8ccca122SBrooks Davis 		}
142*8ccca122SBrooks Davis 		*dst++ = '%';
143*8ccca122SBrooks Davis 		*dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
144*8ccca122SBrooks Davis 		*dst++ = xtoa((unsigned int)c & 0xf);
145*8ccca122SBrooks Davis 	}
146*8ccca122SBrooks Davis 
147*8ccca122SBrooks Davis 	return dst;
148*8ccca122SBrooks Davis }
149*8ccca122SBrooks Davis 
150*8ccca122SBrooks Davis /*
151*8ccca122SBrooks Davis  * This is do_mvis, for Quoted-Printable MIME (RFC 2045)
152*8ccca122SBrooks Davis  * NB: No handling of long lines or CRLF.
153*8ccca122SBrooks Davis  */
154*8ccca122SBrooks Davis static char *
155*8ccca122SBrooks Davis do_mvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra)
156*8ccca122SBrooks Davis {
157*8ccca122SBrooks Davis 	if ((c != '\n') &&
158*8ccca122SBrooks Davis 	    /* Space at the end of the line */
159*8ccca122SBrooks Davis 	    ((isspace(c) && (nextc == '\r' || nextc == '\n')) ||
160*8ccca122SBrooks Davis 	    /* Out of range */
161*8ccca122SBrooks Davis 	    (!isspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) ||
162*8ccca122SBrooks Davis 	    /* Specific char to be escaped */
163*8ccca122SBrooks Davis 	    strchr("#$@[\\]^`{|}~", c) != NULL)) {
164*8ccca122SBrooks Davis 		if (dlen) {
165*8ccca122SBrooks Davis 			if (*dlen < 3)
166*8ccca122SBrooks Davis 				return NULL;
167*8ccca122SBrooks Davis 			*dlen -= 3;
168*8ccca122SBrooks Davis 		}
169*8ccca122SBrooks Davis 		*dst++ = '=';
170*8ccca122SBrooks Davis 		*dst++ = XTOA(((unsigned int)c >> 4) & 0xf);
171*8ccca122SBrooks Davis 		*dst++ = XTOA((unsigned int)c & 0xf);
172*8ccca122SBrooks Davis 	} else {
173*8ccca122SBrooks Davis 		dst = do_svis(dst, dlen, c, flag, nextc, extra);
174*8ccca122SBrooks Davis 	}
175*8ccca122SBrooks Davis 	return dst;
176*8ccca122SBrooks Davis }
177*8ccca122SBrooks Davis 
178*8ccca122SBrooks Davis /*
179*8ccca122SBrooks Davis  * This is do_vis, the central code of vis.
180*8ccca122SBrooks Davis  * dst:	      Pointer to the destination buffer
181*8ccca122SBrooks Davis  * c:	      Character to encode
182*8ccca122SBrooks Davis  * flag:      Flag word
183*8ccca122SBrooks Davis  * nextc:     The character following 'c'
184*8ccca122SBrooks Davis  * extra:     Pointer to the list of extra characters to be
185*8ccca122SBrooks Davis  *	      backslash-protected.
186*8ccca122SBrooks Davis  */
187*8ccca122SBrooks Davis static char *
188*8ccca122SBrooks Davis do_svis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra)
189*8ccca122SBrooks Davis {
190*8ccca122SBrooks Davis 	int isextra;
191*8ccca122SBrooks Davis 	size_t odlen = dlen ? *dlen : 0;
192*8ccca122SBrooks Davis 
193*8ccca122SBrooks Davis 	isextra = strchr(extra, c) != NULL;
194*8ccca122SBrooks Davis #define HAVE(x) \
195*8ccca122SBrooks Davis 	do { \
196*8ccca122SBrooks Davis 		if (dlen) { \
197*8ccca122SBrooks Davis 			if (*dlen < (x)) \
198*8ccca122SBrooks Davis 				goto out; \
199*8ccca122SBrooks Davis 			*dlen -= (x); \
200*8ccca122SBrooks Davis 		} \
201*8ccca122SBrooks Davis 	} while (/*CONSTCOND*/0)
202*8ccca122SBrooks Davis 	if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||
203*8ccca122SBrooks Davis 	    ((flag & VIS_SAFE) && issafe(c)))) {
204*8ccca122SBrooks Davis 		HAVE(1);
205*8ccca122SBrooks Davis 		*dst++ = c;
206*8ccca122SBrooks Davis 		return dst;
207*8ccca122SBrooks Davis 	}
208*8ccca122SBrooks Davis 	if (flag & VIS_CSTYLE) {
209*8ccca122SBrooks Davis 		HAVE(2);
210*8ccca122SBrooks Davis 		switch (c) {
211*8ccca122SBrooks Davis 		case '\n':
212*8ccca122SBrooks Davis 			*dst++ = '\\'; *dst++ = 'n';
213*8ccca122SBrooks Davis 			return dst;
214*8ccca122SBrooks Davis 		case '\r':
215*8ccca122SBrooks Davis 			*dst++ = '\\'; *dst++ = 'r';
216*8ccca122SBrooks Davis 			return dst;
217*8ccca122SBrooks Davis 		case '\b':
218*8ccca122SBrooks Davis 			*dst++ = '\\'; *dst++ = 'b';
219*8ccca122SBrooks Davis 			return dst;
220*8ccca122SBrooks Davis 		case BELL:
221*8ccca122SBrooks Davis 			*dst++ = '\\'; *dst++ = 'a';
222*8ccca122SBrooks Davis 			return dst;
223*8ccca122SBrooks Davis 		case '\v':
224*8ccca122SBrooks Davis 			*dst++ = '\\'; *dst++ = 'v';
225*8ccca122SBrooks Davis 			return dst;
226*8ccca122SBrooks Davis 		case '\t':
227*8ccca122SBrooks Davis 			*dst++ = '\\'; *dst++ = 't';
228*8ccca122SBrooks Davis 			return dst;
229*8ccca122SBrooks Davis 		case '\f':
230*8ccca122SBrooks Davis 			*dst++ = '\\'; *dst++ = 'f';
231*8ccca122SBrooks Davis 			return dst;
232*8ccca122SBrooks Davis 		case ' ':
233*8ccca122SBrooks Davis 			*dst++ = '\\'; *dst++ = 's';
234*8ccca122SBrooks Davis 			return dst;
235*8ccca122SBrooks Davis 		case '\0':
236*8ccca122SBrooks Davis 			*dst++ = '\\'; *dst++ = '0';
237*8ccca122SBrooks Davis 			if (isoctal(nextc)) {
238*8ccca122SBrooks Davis 				HAVE(2);
239*8ccca122SBrooks Davis 				*dst++ = '0';
240*8ccca122SBrooks Davis 				*dst++ = '0';
241*8ccca122SBrooks Davis 			}
242*8ccca122SBrooks Davis 			return dst;
243*8ccca122SBrooks Davis 		default:
244*8ccca122SBrooks Davis 			if (isgraph(c)) {
245*8ccca122SBrooks Davis 				*dst++ = '\\'; *dst++ = c;
246*8ccca122SBrooks Davis 				return dst;
247*8ccca122SBrooks Davis 			}
248*8ccca122SBrooks Davis 			if (dlen)
249*8ccca122SBrooks Davis 				*dlen = odlen;
250*8ccca122SBrooks Davis 		}
251*8ccca122SBrooks Davis 	}
252*8ccca122SBrooks Davis 	if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
253*8ccca122SBrooks Davis 		HAVE(4);
254*8ccca122SBrooks Davis 		*dst++ = '\\';
255*8ccca122SBrooks Davis 		*dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0';
256*8ccca122SBrooks Davis 		*dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0';
257*8ccca122SBrooks Davis 		*dst++ =			     (c	      & 07) + '0';
258*8ccca122SBrooks Davis 	} else {
259*8ccca122SBrooks Davis 		if ((flag & VIS_NOSLASH) == 0) {
260*8ccca122SBrooks Davis 			HAVE(1);
261*8ccca122SBrooks Davis 			*dst++ = '\\';
262*8ccca122SBrooks Davis 		}
263*8ccca122SBrooks Davis 
264*8ccca122SBrooks Davis 		if (c & 0200) {
265*8ccca122SBrooks Davis 			HAVE(1);
266*8ccca122SBrooks Davis 			c &= 0177; *dst++ = 'M';
267*8ccca122SBrooks Davis 		}
268*8ccca122SBrooks Davis 
269*8ccca122SBrooks Davis 		if (iscntrl(c)) {
270*8ccca122SBrooks Davis 			HAVE(2);
271*8ccca122SBrooks Davis 			*dst++ = '^';
272*8ccca122SBrooks Davis 			if (c == 0177)
273*8ccca122SBrooks Davis 				*dst++ = '?';
274*8ccca122SBrooks Davis 			else
275*8ccca122SBrooks Davis 				*dst++ = c + '@';
276*8ccca122SBrooks Davis 		} else {
277*8ccca122SBrooks Davis 			HAVE(2);
278*8ccca122SBrooks Davis 			*dst++ = '-'; *dst++ = c;
279*8ccca122SBrooks Davis 		}
280*8ccca122SBrooks Davis 	}
281*8ccca122SBrooks Davis 	return dst;
282*8ccca122SBrooks Davis out:
283*8ccca122SBrooks Davis 	*dlen = odlen;
284*8ccca122SBrooks Davis 	return NULL;
285*8ccca122SBrooks Davis }
286*8ccca122SBrooks Davis 
287*8ccca122SBrooks Davis typedef char *(*visfun_t)(char *, size_t *, int, int, int, const char *);
288*8ccca122SBrooks Davis 
289*8ccca122SBrooks Davis /*
290*8ccca122SBrooks Davis  * Return the appropriate encoding function depending on the flags given.
291*8ccca122SBrooks Davis  */
292*8ccca122SBrooks Davis static visfun_t
293*8ccca122SBrooks Davis getvisfun(int flag)
294*8ccca122SBrooks Davis {
295*8ccca122SBrooks Davis 	if (flag & VIS_HTTPSTYLE)
296*8ccca122SBrooks Davis 		return do_hvis;
297*8ccca122SBrooks Davis 	if (flag & VIS_MIMESTYLE)
298*8ccca122SBrooks Davis 		return do_mvis;
299*8ccca122SBrooks Davis 	return do_svis;
300*8ccca122SBrooks Davis }
301*8ccca122SBrooks Davis 
302*8ccca122SBrooks Davis /*
303*8ccca122SBrooks Davis  * isnvis - visually encode characters, also encoding the characters
304*8ccca122SBrooks Davis  *	  pointed to by `extra'
305*8ccca122SBrooks Davis  */
306*8ccca122SBrooks Davis static char *
307*8ccca122SBrooks Davis isnvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra)
308*8ccca122SBrooks Davis {
309*8ccca122SBrooks Davis 	char *nextra = NULL;
310*8ccca122SBrooks Davis 	visfun_t f;
311*8ccca122SBrooks Davis 
312*8ccca122SBrooks Davis 	_DIAGASSERT(dst != NULL);
313*8ccca122SBrooks Davis 	_DIAGASSERT(extra != NULL);
314*8ccca122SBrooks Davis 	MAKEEXTRALIST(flag, nextra, extra);
315*8ccca122SBrooks Davis 	if (!nextra) {
316*8ccca122SBrooks Davis 		if (dlen && *dlen == 0) {
317*8ccca122SBrooks Davis 			errno = ENOSPC;
318*8ccca122SBrooks Davis 			return NULL;
319*8ccca122SBrooks Davis 		}
320*8ccca122SBrooks Davis 		*dst = '\0';		/* can't create nextra, return "" */
321*8ccca122SBrooks Davis 		return dst;
322*8ccca122SBrooks Davis 	}
323*8ccca122SBrooks Davis 	f = getvisfun(flag);
324*8ccca122SBrooks Davis 	dst = (*f)(dst, dlen, c, flag, nextc, nextra);
325*8ccca122SBrooks Davis 	free(nextra);
326*8ccca122SBrooks Davis 	if (dst == NULL || (dlen && *dlen == 0)) {
327*8ccca122SBrooks Davis 		errno = ENOSPC;
328*8ccca122SBrooks Davis 		return NULL;
329*8ccca122SBrooks Davis 	}
330*8ccca122SBrooks Davis 	*dst = '\0';
331*8ccca122SBrooks Davis 	return dst;
332*8ccca122SBrooks Davis }
333*8ccca122SBrooks Davis 
334*8ccca122SBrooks Davis char *
335*8ccca122SBrooks Davis svis(char *dst, int c, int flag, int nextc, const char *extra)
336*8ccca122SBrooks Davis {
337*8ccca122SBrooks Davis 	return isnvis(dst, NULL, c, flag, nextc, extra);
338*8ccca122SBrooks Davis }
339*8ccca122SBrooks Davis 
340*8ccca122SBrooks Davis char *
341*8ccca122SBrooks Davis snvis(char *dst, size_t dlen, int c, int flag, int nextc, const char *extra)
342*8ccca122SBrooks Davis {
343*8ccca122SBrooks Davis 	return isnvis(dst, &dlen, c, flag, nextc, extra);
344*8ccca122SBrooks Davis }
345*8ccca122SBrooks Davis 
346*8ccca122SBrooks Davis 
347*8ccca122SBrooks Davis /*
348*8ccca122SBrooks Davis  * strsvis, strsvisx - visually encode characters from src into dst
349*8ccca122SBrooks Davis  *
350*8ccca122SBrooks Davis  *	Extra is a pointer to a \0-terminated list of characters to
351*8ccca122SBrooks Davis  *	be encoded, too. These functions are useful e. g. to
352*8ccca122SBrooks Davis  *	encode strings in such a way so that they are not interpreted
353*8ccca122SBrooks Davis  *	by a shell.
354*8ccca122SBrooks Davis  *
355*8ccca122SBrooks Davis  *	Dst must be 4 times the size of src to account for possible
356*8ccca122SBrooks Davis  *	expansion.  The length of dst, not including the trailing NULL,
357*8ccca122SBrooks Davis  *	is returned.
358*8ccca122SBrooks Davis  *
359*8ccca122SBrooks Davis  *	Strsvisx encodes exactly len bytes from src into dst.
360*8ccca122SBrooks Davis  *	This is useful for encoding a block of data.
361*8ccca122SBrooks Davis  */
362*8ccca122SBrooks Davis static int
363*8ccca122SBrooks Davis istrsnvis(char *dst, size_t *dlen, const char *csrc, int flag, const char *extra)
364*8ccca122SBrooks Davis {
365*8ccca122SBrooks Davis 	int c;
366*8ccca122SBrooks Davis 	char *start;
367*8ccca122SBrooks Davis 	char *nextra = NULL;
368*8ccca122SBrooks Davis 	const unsigned char *src = (const unsigned char *)csrc;
369*8ccca122SBrooks Davis 	visfun_t f;
370*8ccca122SBrooks Davis 
371*8ccca122SBrooks Davis 	_DIAGASSERT(dst != NULL);
372*8ccca122SBrooks Davis 	_DIAGASSERT(src != NULL);
373*8ccca122SBrooks Davis 	_DIAGASSERT(extra != NULL);
374*8ccca122SBrooks Davis 	MAKEEXTRALIST(flag, nextra, extra);
375*8ccca122SBrooks Davis 	if (!nextra) {
376*8ccca122SBrooks Davis 		*dst = '\0';		/* can't create nextra, return "" */
377*8ccca122SBrooks Davis 		return 0;
378*8ccca122SBrooks Davis 	}
379*8ccca122SBrooks Davis 	f = getvisfun(flag);
380*8ccca122SBrooks Davis 	for (start = dst; (c = *src++) != '\0'; /* empty */) {
381*8ccca122SBrooks Davis 		dst = (*f)(dst, dlen, c, flag, *src, nextra);
382*8ccca122SBrooks Davis 		if (dst == NULL) {
383*8ccca122SBrooks Davis 			errno = ENOSPC;
384*8ccca122SBrooks Davis 			return -1;
385*8ccca122SBrooks Davis 		}
386*8ccca122SBrooks Davis 	}
387*8ccca122SBrooks Davis 	free(nextra);
388*8ccca122SBrooks Davis 	if (dlen && *dlen == 0) {
389*8ccca122SBrooks Davis 		errno = ENOSPC;
390*8ccca122SBrooks Davis 		return -1;
391*8ccca122SBrooks Davis 	}
392*8ccca122SBrooks Davis 	*dst = '\0';
393*8ccca122SBrooks Davis 	return (int)(dst - start);
394*8ccca122SBrooks Davis }
395*8ccca122SBrooks Davis 
396*8ccca122SBrooks Davis int
397*8ccca122SBrooks Davis strsvis(char *dst, const char *csrc, int flag, const char *extra)
398*8ccca122SBrooks Davis {
399*8ccca122SBrooks Davis 	return istrsnvis(dst, NULL, csrc, flag, extra);
400*8ccca122SBrooks Davis }
401*8ccca122SBrooks Davis 
402*8ccca122SBrooks Davis int
403*8ccca122SBrooks Davis strsnvis(char *dst, size_t dlen, const char *csrc, int flag, const char *extra)
404*8ccca122SBrooks Davis {
405*8ccca122SBrooks Davis 	return istrsnvis(dst, &dlen, csrc, flag, extra);
406*8ccca122SBrooks Davis }
407*8ccca122SBrooks Davis 
408*8ccca122SBrooks Davis static int
409*8ccca122SBrooks Davis istrsnvisx(char *dst, size_t *dlen, const char *csrc, size_t len, int flag,
410*8ccca122SBrooks Davis     const char *extra)
411*8ccca122SBrooks Davis {
412*8ccca122SBrooks Davis 	unsigned char c;
413*8ccca122SBrooks Davis 	char *start;
414*8ccca122SBrooks Davis 	char *nextra = NULL;
415*8ccca122SBrooks Davis 	const unsigned char *src = (const unsigned char *)csrc;
416*8ccca122SBrooks Davis 	visfun_t f;
417*8ccca122SBrooks Davis 
418*8ccca122SBrooks Davis 	_DIAGASSERT(dst != NULL);
419*8ccca122SBrooks Davis 	_DIAGASSERT(src != NULL);
420*8ccca122SBrooks Davis 	_DIAGASSERT(extra != NULL);
421*8ccca122SBrooks Davis 	MAKEEXTRALIST(flag, nextra, extra);
422*8ccca122SBrooks Davis 	if (! nextra) {
423*8ccca122SBrooks Davis 		if (dlen && *dlen == 0) {
424*8ccca122SBrooks Davis 			errno = ENOSPC;
425*8ccca122SBrooks Davis 			return -1;
426*8ccca122SBrooks Davis 		}
427*8ccca122SBrooks Davis 		*dst = '\0';		/* can't create nextra, return "" */
428*8ccca122SBrooks Davis 		return 0;
429*8ccca122SBrooks Davis 	}
430*8ccca122SBrooks Davis 
431*8ccca122SBrooks Davis 	f = getvisfun(flag);
432*8ccca122SBrooks Davis 	for (start = dst; len > 0; len--) {
433*8ccca122SBrooks Davis 		c = *src++;
434*8ccca122SBrooks Davis 		dst = (*f)(dst, dlen, c, flag, len > 1 ? *src : '\0', nextra);
435*8ccca122SBrooks Davis 		if (dst == NULL) {
436*8ccca122SBrooks Davis 			errno = ENOSPC;
437*8ccca122SBrooks Davis 			return -1;
438*8ccca122SBrooks Davis 		}
439*8ccca122SBrooks Davis 	}
440*8ccca122SBrooks Davis 	free(nextra);
441*8ccca122SBrooks Davis 	if (dlen && *dlen == 0) {
442*8ccca122SBrooks Davis 		errno = ENOSPC;
443*8ccca122SBrooks Davis 		return -1;
444*8ccca122SBrooks Davis 	}
445*8ccca122SBrooks Davis 	*dst = '\0';
446*8ccca122SBrooks Davis 	return (int)(dst - start);
447*8ccca122SBrooks Davis }
448*8ccca122SBrooks Davis 
449*8ccca122SBrooks Davis int
450*8ccca122SBrooks Davis strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra)
451*8ccca122SBrooks Davis {
452*8ccca122SBrooks Davis 	return istrsnvisx(dst, NULL, csrc, len, flag, extra);
453*8ccca122SBrooks Davis }
454*8ccca122SBrooks Davis 
455*8ccca122SBrooks Davis int
456*8ccca122SBrooks Davis strsnvisx(char *dst, size_t dlen, const char *csrc, size_t len, int flag,
457*8ccca122SBrooks Davis     const char *extra)
458*8ccca122SBrooks Davis {
459*8ccca122SBrooks Davis 	return istrsnvisx(dst, &dlen, csrc, len, flag, extra);
460*8ccca122SBrooks Davis }
461*8ccca122SBrooks Davis #endif
462*8ccca122SBrooks Davis 
463*8ccca122SBrooks Davis #if !HAVE_VIS
464*8ccca122SBrooks Davis /*
465*8ccca122SBrooks Davis  * vis - visually encode characters
466*8ccca122SBrooks Davis  */
467*8ccca122SBrooks Davis static char *
468*8ccca122SBrooks Davis invis(char *dst, size_t *dlen, int c, int flag, int nextc)
469*8ccca122SBrooks Davis {
470*8ccca122SBrooks Davis 	char *extra = NULL;
471*8ccca122SBrooks Davis 	unsigned char uc = (unsigned char)c;
472*8ccca122SBrooks Davis 	visfun_t f;
473*8ccca122SBrooks Davis 
474*8ccca122SBrooks Davis 	_DIAGASSERT(dst != NULL);
475*8ccca122SBrooks Davis 
476*8ccca122SBrooks Davis 	MAKEEXTRALIST(flag, extra, "");
477*8ccca122SBrooks Davis 	if (! extra) {
478*8ccca122SBrooks Davis 		if (dlen && *dlen == 0) {
479*8ccca122SBrooks Davis 			errno = ENOSPC;
480*8ccca122SBrooks Davis 			return NULL;
481*8ccca122SBrooks Davis 		}
482*8ccca122SBrooks Davis 		*dst = '\0';		/* can't create extra, return "" */
483*8ccca122SBrooks Davis 		return dst;
484*8ccca122SBrooks Davis 	}
485*8ccca122SBrooks Davis 	f = getvisfun(flag);
486*8ccca122SBrooks Davis 	dst = (*f)(dst, dlen, uc, flag, nextc, extra);
487*8ccca122SBrooks Davis 	free(extra);
488*8ccca122SBrooks Davis 	if (dst == NULL || (dlen && *dlen == 0)) {
489*8ccca122SBrooks Davis 		errno = ENOSPC;
490*8ccca122SBrooks Davis 		return NULL;
491*8ccca122SBrooks Davis 	}
492*8ccca122SBrooks Davis 	*dst = '\0';
493*8ccca122SBrooks Davis 	return dst;
494*8ccca122SBrooks Davis }
495*8ccca122SBrooks Davis 
496*8ccca122SBrooks Davis char *
497*8ccca122SBrooks Davis vis(char *dst, int c, int flag, int nextc)
498*8ccca122SBrooks Davis {
499*8ccca122SBrooks Davis 	return invis(dst, NULL, c, flag, nextc);
500*8ccca122SBrooks Davis }
501*8ccca122SBrooks Davis 
502*8ccca122SBrooks Davis char *
503*8ccca122SBrooks Davis nvis(char *dst, size_t dlen, int c, int flag, int nextc)
504*8ccca122SBrooks Davis {
505*8ccca122SBrooks Davis 	return invis(dst, &dlen, c, flag, nextc);
506*8ccca122SBrooks Davis }
507*8ccca122SBrooks Davis 
508*8ccca122SBrooks Davis 
509*8ccca122SBrooks Davis /*
510*8ccca122SBrooks Davis  * strvis, strvisx - visually encode characters from src into dst
511*8ccca122SBrooks Davis  *
512*8ccca122SBrooks Davis  *	Dst must be 4 times the size of src to account for possible
513*8ccca122SBrooks Davis  *	expansion.  The length of dst, not including the trailing NULL,
514*8ccca122SBrooks Davis  *	is returned.
515*8ccca122SBrooks Davis  *
516*8ccca122SBrooks Davis  *	Strvisx encodes exactly len bytes from src into dst.
517*8ccca122SBrooks Davis  *	This is useful for encoding a block of data.
518*8ccca122SBrooks Davis  */
519*8ccca122SBrooks Davis static int
520*8ccca122SBrooks Davis istrnvis(char *dst, size_t *dlen, const char *src, int flag)
521*8ccca122SBrooks Davis {
522*8ccca122SBrooks Davis 	char *extra = NULL;
523*8ccca122SBrooks Davis 	int rv;
524*8ccca122SBrooks Davis 
525*8ccca122SBrooks Davis 	MAKEEXTRALIST(flag, extra, "");
526*8ccca122SBrooks Davis 	if (!extra) {
527*8ccca122SBrooks Davis 		if (dlen && *dlen == 0) {
528*8ccca122SBrooks Davis 			errno = ENOSPC;
529*8ccca122SBrooks Davis 			return -1;
530*8ccca122SBrooks Davis 		}
531*8ccca122SBrooks Davis 		*dst = '\0';		/* can't create extra, return "" */
532*8ccca122SBrooks Davis 		return 0;
533*8ccca122SBrooks Davis 	}
534*8ccca122SBrooks Davis 	rv = istrsnvis(dst, dlen, src, flag, extra);
535*8ccca122SBrooks Davis 	free(extra);
536*8ccca122SBrooks Davis 	return rv;
537*8ccca122SBrooks Davis }
538*8ccca122SBrooks Davis 
539*8ccca122SBrooks Davis int
540*8ccca122SBrooks Davis strvis(char *dst, const char *src, int flag)
541*8ccca122SBrooks Davis {
542*8ccca122SBrooks Davis 	return istrnvis(dst, NULL, src, flag);
543*8ccca122SBrooks Davis }
544*8ccca122SBrooks Davis 
545*8ccca122SBrooks Davis int
546*8ccca122SBrooks Davis strnvis(char *dst, size_t dlen, const char *src, int flag)
547*8ccca122SBrooks Davis {
548*8ccca122SBrooks Davis 	return istrnvis(dst, &dlen, src, flag);
549*8ccca122SBrooks Davis }
550*8ccca122SBrooks Davis 
551*8ccca122SBrooks Davis static int
552*8ccca122SBrooks Davis istrnvisx(char *dst, size_t *dlen, const char *src, size_t len, int flag)
553*8ccca122SBrooks Davis {
554*8ccca122SBrooks Davis 	char *extra = NULL;
555*8ccca122SBrooks Davis 	int rv;
556*8ccca122SBrooks Davis 
557*8ccca122SBrooks Davis 	MAKEEXTRALIST(flag, extra, "");
558*8ccca122SBrooks Davis 	if (!extra) {
559*8ccca122SBrooks Davis 		if (dlen && *dlen == 0) {
560*8ccca122SBrooks Davis 			errno = ENOSPC;
561*8ccca122SBrooks Davis 			return -1;
562*8ccca122SBrooks Davis 		}
563*8ccca122SBrooks Davis 		*dst = '\0';		/* can't create extra, return "" */
564*8ccca122SBrooks Davis 		return 0;
565*8ccca122SBrooks Davis 	}
566*8ccca122SBrooks Davis 	rv = istrsnvisx(dst, dlen, src, len, flag, extra);
567*8ccca122SBrooks Davis 	free(extra);
568*8ccca122SBrooks Davis 	return rv;
569*8ccca122SBrooks Davis }
570*8ccca122SBrooks Davis 
571*8ccca122SBrooks Davis int
572*8ccca122SBrooks Davis strvisx(char *dst, const char *src, size_t len, int flag)
573*8ccca122SBrooks Davis {
574*8ccca122SBrooks Davis 	return istrnvisx(dst, NULL, src, len, flag);
575*8ccca122SBrooks Davis }
576*8ccca122SBrooks Davis 
577*8ccca122SBrooks Davis int
578*8ccca122SBrooks Davis strnvisx(char *dst, size_t dlen, const char *src, size_t len, int flag)
579*8ccca122SBrooks Davis {
580*8ccca122SBrooks Davis 	return istrnvisx(dst, &dlen, src, len, flag);
581*8ccca122SBrooks Davis }
582*8ccca122SBrooks Davis 
583*8ccca122SBrooks Davis #endif
584