vis.c revision 241236
1241236Sbrooks/*	$NetBSD: vis.c,v 1.44 2011/03/12 19:52:48 christos Exp $	*/
2241236Sbrooks
3241236Sbrooks/*-
4241236Sbrooks * Copyright (c) 1989, 1993
5241236Sbrooks *	The Regents of the University of California.  All rights reserved.
6241236Sbrooks *
7241236Sbrooks * Redistribution and use in source and binary forms, with or without
8241236Sbrooks * modification, are permitted provided that the following conditions
9241236Sbrooks * are met:
10241236Sbrooks * 1. Redistributions of source code must retain the above copyright
11241236Sbrooks *    notice, this list of conditions and the following disclaimer.
12241236Sbrooks * 2. Redistributions in binary form must reproduce the above copyright
13241236Sbrooks *    notice, this list of conditions and the following disclaimer in the
14241236Sbrooks *    documentation and/or other materials provided with the distribution.
15241236Sbrooks * 3. Neither the name of the University nor the names of its contributors
16241236Sbrooks *    may be used to endorse or promote products derived from this software
17241236Sbrooks *    without specific prior written permission.
18241236Sbrooks *
19241236Sbrooks * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20241236Sbrooks * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21241236Sbrooks * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22241236Sbrooks * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23241236Sbrooks * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24241236Sbrooks * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25241236Sbrooks * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26241236Sbrooks * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27241236Sbrooks * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28241236Sbrooks * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29241236Sbrooks * SUCH DAMAGE.
30241236Sbrooks */
31241236Sbrooks
32241236Sbrooks/*-
33241236Sbrooks * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
34241236Sbrooks * All rights reserved.
35241236Sbrooks *
36241236Sbrooks * Redistribution and use in source and binary forms, with or without
37241236Sbrooks * modification, are permitted provided that the following conditions
38241236Sbrooks * are met:
39241236Sbrooks * 1. Redistributions of source code must retain the above copyright
40241236Sbrooks *    notice, this list of conditions and the following disclaimer.
41241236Sbrooks * 2. Redistributions in binary form must reproduce the above copyright
42241236Sbrooks *    notice, this list of conditions and the following disclaimer in the
43241236Sbrooks *    documentation and/or other materials provided with the distribution.
44241236Sbrooks *
45241236Sbrooks * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
46241236Sbrooks * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
47241236Sbrooks * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48241236Sbrooks * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
49241236Sbrooks * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50241236Sbrooks * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51241236Sbrooks * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52241236Sbrooks * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53241236Sbrooks * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54241236Sbrooks * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55241236Sbrooks * POSSIBILITY OF SUCH DAMAGE.
56241236Sbrooks */
57241236Sbrooks
58241236Sbrooks#include <sys/cdefs.h>
59241236Sbrooks#if defined(LIBC_SCCS) && !defined(lint)
60241236Sbrooks__RCSID("$NetBSD: vis.c,v 1.44 2011/03/12 19:52:48 christos Exp $");
61241236Sbrooks#endif /* LIBC_SCCS and not lint */
62241236Sbrooks
63241236Sbrooks#include "namespace.h"
64241236Sbrooks#include <sys/types.h>
65241236Sbrooks
66241236Sbrooks#include <assert.h>
67241236Sbrooks#include <vis.h>
68241236Sbrooks#include <errno.h>
69241236Sbrooks#include <stdlib.h>
70241236Sbrooks
71241236Sbrooks#ifdef __weak_alias
72241236Sbrooks__weak_alias(strvisx,_strvisx)
73241236Sbrooks#endif
74241236Sbrooks
75241236Sbrooks#if !HAVE_VIS || !HAVE_SVIS
76241236Sbrooks#include <ctype.h>
77241236Sbrooks#include <limits.h>
78241236Sbrooks#include <stdio.h>
79241236Sbrooks#include <string.h>
80241236Sbrooks
81241236Sbrooksstatic char *do_svis(char *, size_t *, int, int, int, const char *);
82241236Sbrooks
83241236Sbrooks#undef BELL
84241236Sbrooks#define BELL '\a'
85241236Sbrooks
86241236Sbrooks#define isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
87241236Sbrooks#define iswhite(c)	(c == ' ' || c == '\t' || c == '\n')
88241236Sbrooks#define issafe(c)	(c == '\b' || c == BELL || c == '\r')
89241236Sbrooks#define xtoa(c)		"0123456789abcdef"[c]
90241236Sbrooks#define XTOA(c)		"0123456789ABCDEF"[c]
91241236Sbrooks
92241236Sbrooks#define MAXEXTRAS	5
93241236Sbrooks
94241236Sbrooks#define MAKEEXTRALIST(flag, extra, orig_str)				      \
95241236Sbrooksdo {									      \
96241236Sbrooks	const char *orig = orig_str;					      \
97241236Sbrooks	const char *o = orig;						      \
98241236Sbrooks	char *e;							      \
99241236Sbrooks	while (*o++)							      \
100241236Sbrooks		continue;						      \
101241236Sbrooks	extra = malloc((size_t)((o - orig) + MAXEXTRAS));		      \
102241236Sbrooks	if (!extra) break;						      \
103241236Sbrooks	for (o = orig, e = extra; (*e++ = *o++) != '\0';)		      \
104241236Sbrooks		continue;						      \
105241236Sbrooks	e--;								      \
106241236Sbrooks	if (flag & VIS_SP) *e++ = ' ';					      \
107241236Sbrooks	if (flag & VIS_TAB) *e++ = '\t';				      \
108241236Sbrooks	if (flag & VIS_NL) *e++ = '\n';					      \
109241236Sbrooks	if ((flag & VIS_NOSLASH) == 0) *e++ = '\\';			      \
110241236Sbrooks	*e = '\0';							      \
111241236Sbrooks} while (/*CONSTCOND*/0)
112241236Sbrooks
113241236Sbrooks/*
114241236Sbrooks * This is do_hvis, for HTTP style (RFC 1808)
115241236Sbrooks */
116241236Sbrooksstatic char *
117241236Sbrooksdo_hvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra)
118241236Sbrooks{
119241236Sbrooks
120241236Sbrooks	if ((isascii(c) && isalnum(c))
121241236Sbrooks	    /* safe */
122241236Sbrooks	    || c == '$' || c == '-' || c == '_' || c == '.' || c == '+'
123241236Sbrooks	    /* extra */
124241236Sbrooks	    || c == '!' || c == '*' || c == '\'' || c == '(' || c == ')'
125241236Sbrooks	    || c == ',') {
126241236Sbrooks		dst = do_svis(dst, dlen, c, flag, nextc, extra);
127241236Sbrooks	} else {
128241236Sbrooks		if (dlen) {
129241236Sbrooks			if (*dlen < 3)
130241236Sbrooks				return NULL;
131241236Sbrooks			*dlen -= 3;
132241236Sbrooks		}
133241236Sbrooks		*dst++ = '%';
134241236Sbrooks		*dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
135241236Sbrooks		*dst++ = xtoa((unsigned int)c & 0xf);
136241236Sbrooks	}
137241236Sbrooks
138241236Sbrooks	return dst;
139241236Sbrooks}
140241236Sbrooks
141241236Sbrooks/*
142241236Sbrooks * This is do_mvis, for Quoted-Printable MIME (RFC 2045)
143241236Sbrooks * NB: No handling of long lines or CRLF.
144241236Sbrooks */
145241236Sbrooksstatic char *
146241236Sbrooksdo_mvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra)
147241236Sbrooks{
148241236Sbrooks	if ((c != '\n') &&
149241236Sbrooks	    /* Space at the end of the line */
150241236Sbrooks	    ((isspace(c) && (nextc == '\r' || nextc == '\n')) ||
151241236Sbrooks	    /* Out of range */
152241236Sbrooks	    (!isspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) ||
153241236Sbrooks	    /* Specific char to be escaped */
154241236Sbrooks	    strchr("#$@[\\]^`{|}~", c) != NULL)) {
155241236Sbrooks		if (dlen) {
156241236Sbrooks			if (*dlen < 3)
157241236Sbrooks				return NULL;
158241236Sbrooks			*dlen -= 3;
159241236Sbrooks		}
160241236Sbrooks		*dst++ = '=';
161241236Sbrooks		*dst++ = XTOA(((unsigned int)c >> 4) & 0xf);
162241236Sbrooks		*dst++ = XTOA((unsigned int)c & 0xf);
163241236Sbrooks	} else {
164241236Sbrooks		dst = do_svis(dst, dlen, c, flag, nextc, extra);
165241236Sbrooks	}
166241236Sbrooks	return dst;
167241236Sbrooks}
168241236Sbrooks
169241236Sbrooks/*
170241236Sbrooks * This is do_vis, the central code of vis.
171241236Sbrooks * dst:	      Pointer to the destination buffer
172241236Sbrooks * c:	      Character to encode
173241236Sbrooks * flag:      Flag word
174241236Sbrooks * nextc:     The character following 'c'
175241236Sbrooks * extra:     Pointer to the list of extra characters to be
176241236Sbrooks *	      backslash-protected.
177241236Sbrooks */
178241236Sbrooksstatic char *
179241236Sbrooksdo_svis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra)
180241236Sbrooks{
181241236Sbrooks	int isextra;
182241236Sbrooks	size_t odlen = dlen ? *dlen : 0;
183241236Sbrooks
184241236Sbrooks	isextra = strchr(extra, c) != NULL;
185241236Sbrooks#define HAVE(x) \
186241236Sbrooks	do { \
187241236Sbrooks		if (dlen) { \
188241236Sbrooks			if (*dlen < (x)) \
189241236Sbrooks				goto out; \
190241236Sbrooks			*dlen -= (x); \
191241236Sbrooks		} \
192241236Sbrooks	} while (/*CONSTCOND*/0)
193241236Sbrooks	if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||
194241236Sbrooks	    ((flag & VIS_SAFE) && issafe(c)))) {
195241236Sbrooks		HAVE(1);
196241236Sbrooks		*dst++ = c;
197241236Sbrooks		return dst;
198241236Sbrooks	}
199241236Sbrooks	if (flag & VIS_CSTYLE) {
200241236Sbrooks		HAVE(2);
201241236Sbrooks		switch (c) {
202241236Sbrooks		case '\n':
203241236Sbrooks			*dst++ = '\\'; *dst++ = 'n';
204241236Sbrooks			return dst;
205241236Sbrooks		case '\r':
206241236Sbrooks			*dst++ = '\\'; *dst++ = 'r';
207241236Sbrooks			return dst;
208241236Sbrooks		case '\b':
209241236Sbrooks			*dst++ = '\\'; *dst++ = 'b';
210241236Sbrooks			return dst;
211241236Sbrooks		case BELL:
212241236Sbrooks			*dst++ = '\\'; *dst++ = 'a';
213241236Sbrooks			return dst;
214241236Sbrooks		case '\v':
215241236Sbrooks			*dst++ = '\\'; *dst++ = 'v';
216241236Sbrooks			return dst;
217241236Sbrooks		case '\t':
218241236Sbrooks			*dst++ = '\\'; *dst++ = 't';
219241236Sbrooks			return dst;
220241236Sbrooks		case '\f':
221241236Sbrooks			*dst++ = '\\'; *dst++ = 'f';
222241236Sbrooks			return dst;
223241236Sbrooks		case ' ':
224241236Sbrooks			*dst++ = '\\'; *dst++ = 's';
225241236Sbrooks			return dst;
226241236Sbrooks		case '\0':
227241236Sbrooks			*dst++ = '\\'; *dst++ = '0';
228241236Sbrooks			if (isoctal(nextc)) {
229241236Sbrooks				HAVE(2);
230241236Sbrooks				*dst++ = '0';
231241236Sbrooks				*dst++ = '0';
232241236Sbrooks			}
233241236Sbrooks			return dst;
234241236Sbrooks		default:
235241236Sbrooks			if (isgraph(c)) {
236241236Sbrooks				*dst++ = '\\'; *dst++ = c;
237241236Sbrooks				return dst;
238241236Sbrooks			}
239241236Sbrooks			if (dlen)
240241236Sbrooks				*dlen = odlen;
241241236Sbrooks		}
242241236Sbrooks	}
243241236Sbrooks	if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
244241236Sbrooks		HAVE(4);
245241236Sbrooks		*dst++ = '\\';
246241236Sbrooks		*dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0';
247241236Sbrooks		*dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0';
248241236Sbrooks		*dst++ =			     (c	      & 07) + '0';
249241236Sbrooks	} else {
250241236Sbrooks		if ((flag & VIS_NOSLASH) == 0) {
251241236Sbrooks			HAVE(1);
252241236Sbrooks			*dst++ = '\\';
253241236Sbrooks		}
254241236Sbrooks
255241236Sbrooks		if (c & 0200) {
256241236Sbrooks			HAVE(1);
257241236Sbrooks			c &= 0177; *dst++ = 'M';
258241236Sbrooks		}
259241236Sbrooks
260241236Sbrooks		if (iscntrl(c)) {
261241236Sbrooks			HAVE(2);
262241236Sbrooks			*dst++ = '^';
263241236Sbrooks			if (c == 0177)
264241236Sbrooks				*dst++ = '?';
265241236Sbrooks			else
266241236Sbrooks				*dst++ = c + '@';
267241236Sbrooks		} else {
268241236Sbrooks			HAVE(2);
269241236Sbrooks			*dst++ = '-'; *dst++ = c;
270241236Sbrooks		}
271241236Sbrooks	}
272241236Sbrooks	return dst;
273241236Sbrooksout:
274241236Sbrooks	*dlen = odlen;
275241236Sbrooks	return NULL;
276241236Sbrooks}
277241236Sbrooks
278241236Sbrookstypedef char *(*visfun_t)(char *, size_t *, int, int, int, const char *);
279241236Sbrooks
280241236Sbrooks/*
281241236Sbrooks * Return the appropriate encoding function depending on the flags given.
282241236Sbrooks */
283241236Sbrooksstatic visfun_t
284241236Sbrooksgetvisfun(int flag)
285241236Sbrooks{
286241236Sbrooks	if (flag & VIS_HTTPSTYLE)
287241236Sbrooks		return do_hvis;
288241236Sbrooks	if (flag & VIS_MIMESTYLE)
289241236Sbrooks		return do_mvis;
290241236Sbrooks	return do_svis;
291241236Sbrooks}
292241236Sbrooks
293241236Sbrooks/*
294241236Sbrooks * isnvis - visually encode characters, also encoding the characters
295241236Sbrooks *	  pointed to by `extra'
296241236Sbrooks */
297241236Sbrooksstatic char *
298241236Sbrooksisnvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra)
299241236Sbrooks{
300241236Sbrooks	char *nextra = NULL;
301241236Sbrooks	visfun_t f;
302241236Sbrooks
303241236Sbrooks	_DIAGASSERT(dst != NULL);
304241236Sbrooks	_DIAGASSERT(extra != NULL);
305241236Sbrooks	MAKEEXTRALIST(flag, nextra, extra);
306241236Sbrooks	if (!nextra) {
307241236Sbrooks		if (dlen && *dlen == 0) {
308241236Sbrooks			errno = ENOSPC;
309241236Sbrooks			return NULL;
310241236Sbrooks		}
311241236Sbrooks		*dst = '\0';		/* can't create nextra, return "" */
312241236Sbrooks		return dst;
313241236Sbrooks	}
314241236Sbrooks	f = getvisfun(flag);
315241236Sbrooks	dst = (*f)(dst, dlen, c, flag, nextc, nextra);
316241236Sbrooks	free(nextra);
317241236Sbrooks	if (dst == NULL || (dlen && *dlen == 0)) {
318241236Sbrooks		errno = ENOSPC;
319241236Sbrooks		return NULL;
320241236Sbrooks	}
321241236Sbrooks	*dst = '\0';
322241236Sbrooks	return dst;
323241236Sbrooks}
324241236Sbrooks
325241236Sbrookschar *
326241236Sbrookssvis(char *dst, int c, int flag, int nextc, const char *extra)
327241236Sbrooks{
328241236Sbrooks	return isnvis(dst, NULL, c, flag, nextc, extra);
329241236Sbrooks}
330241236Sbrooks
331241236Sbrookschar *
332241236Sbrookssnvis(char *dst, size_t dlen, int c, int flag, int nextc, const char *extra)
333241236Sbrooks{
334241236Sbrooks	return isnvis(dst, &dlen, c, flag, nextc, extra);
335241236Sbrooks}
336241236Sbrooks
337241236Sbrooks
338241236Sbrooks/*
339241236Sbrooks * strsvis, strsvisx - visually encode characters from src into dst
340241236Sbrooks *
341241236Sbrooks *	Extra is a pointer to a \0-terminated list of characters to
342241236Sbrooks *	be encoded, too. These functions are useful e. g. to
343241236Sbrooks *	encode strings in such a way so that they are not interpreted
344241236Sbrooks *	by a shell.
345241236Sbrooks *
346241236Sbrooks *	Dst must be 4 times the size of src to account for possible
347241236Sbrooks *	expansion.  The length of dst, not including the trailing NULL,
348241236Sbrooks *	is returned.
349241236Sbrooks *
350241236Sbrooks *	Strsvisx encodes exactly len bytes from src into dst.
351241236Sbrooks *	This is useful for encoding a block of data.
352241236Sbrooks */
353241236Sbrooksstatic int
354241236Sbrooksistrsnvis(char *dst, size_t *dlen, const char *csrc, int flag, const char *extra)
355241236Sbrooks{
356241236Sbrooks	int c;
357241236Sbrooks	char *start;
358241236Sbrooks	char *nextra = NULL;
359241236Sbrooks	const unsigned char *src = (const unsigned char *)csrc;
360241236Sbrooks	visfun_t f;
361241236Sbrooks
362241236Sbrooks	_DIAGASSERT(dst != NULL);
363241236Sbrooks	_DIAGASSERT(src != NULL);
364241236Sbrooks	_DIAGASSERT(extra != NULL);
365241236Sbrooks	MAKEEXTRALIST(flag, nextra, extra);
366241236Sbrooks	if (!nextra) {
367241236Sbrooks		*dst = '\0';		/* can't create nextra, return "" */
368241236Sbrooks		return 0;
369241236Sbrooks	}
370241236Sbrooks	f = getvisfun(flag);
371241236Sbrooks	for (start = dst; (c = *src++) != '\0'; /* empty */) {
372241236Sbrooks		dst = (*f)(dst, dlen, c, flag, *src, nextra);
373241236Sbrooks		if (dst == NULL) {
374241236Sbrooks			errno = ENOSPC;
375241236Sbrooks			return -1;
376241236Sbrooks		}
377241236Sbrooks	}
378241236Sbrooks	free(nextra);
379241236Sbrooks	if (dlen && *dlen == 0) {
380241236Sbrooks		errno = ENOSPC;
381241236Sbrooks		return -1;
382241236Sbrooks	}
383241236Sbrooks	*dst = '\0';
384241236Sbrooks	return (int)(dst - start);
385241236Sbrooks}
386241236Sbrooks
387241236Sbrooksint
388241236Sbrooksstrsvis(char *dst, const char *csrc, int flag, const char *extra)
389241236Sbrooks{
390241236Sbrooks	return istrsnvis(dst, NULL, csrc, flag, extra);
391241236Sbrooks}
392241236Sbrooks
393241236Sbrooksint
394241236Sbrooksstrsnvis(char *dst, size_t dlen, const char *csrc, int flag, const char *extra)
395241236Sbrooks{
396241236Sbrooks	return istrsnvis(dst, &dlen, csrc, flag, extra);
397241236Sbrooks}
398241236Sbrooks
399241236Sbrooksstatic int
400241236Sbrooksistrsnvisx(char *dst, size_t *dlen, const char *csrc, size_t len, int flag,
401241236Sbrooks    const char *extra)
402241236Sbrooks{
403241236Sbrooks	unsigned char c;
404241236Sbrooks	char *start;
405241236Sbrooks	char *nextra = NULL;
406241236Sbrooks	const unsigned char *src = (const unsigned char *)csrc;
407241236Sbrooks	visfun_t f;
408241236Sbrooks
409241236Sbrooks	_DIAGASSERT(dst != NULL);
410241236Sbrooks	_DIAGASSERT(src != NULL);
411241236Sbrooks	_DIAGASSERT(extra != NULL);
412241236Sbrooks	MAKEEXTRALIST(flag, nextra, extra);
413241236Sbrooks	if (! nextra) {
414241236Sbrooks		if (dlen && *dlen == 0) {
415241236Sbrooks			errno = ENOSPC;
416241236Sbrooks			return -1;
417241236Sbrooks		}
418241236Sbrooks		*dst = '\0';		/* can't create nextra, return "" */
419241236Sbrooks		return 0;
420241236Sbrooks	}
421241236Sbrooks
422241236Sbrooks	f = getvisfun(flag);
423241236Sbrooks	for (start = dst; len > 0; len--) {
424241236Sbrooks		c = *src++;
425241236Sbrooks		dst = (*f)(dst, dlen, c, flag, len > 1 ? *src : '\0', nextra);
426241236Sbrooks		if (dst == NULL) {
427241236Sbrooks			errno = ENOSPC;
428241236Sbrooks			return -1;
429241236Sbrooks		}
430241236Sbrooks	}
431241236Sbrooks	free(nextra);
432241236Sbrooks	if (dlen && *dlen == 0) {
433241236Sbrooks		errno = ENOSPC;
434241236Sbrooks		return -1;
435241236Sbrooks	}
436241236Sbrooks	*dst = '\0';
437241236Sbrooks	return (int)(dst - start);
438241236Sbrooks}
439241236Sbrooks
440241236Sbrooksint
441241236Sbrooksstrsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra)
442241236Sbrooks{
443241236Sbrooks	return istrsnvisx(dst, NULL, csrc, len, flag, extra);
444241236Sbrooks}
445241236Sbrooks
446241236Sbrooksint
447241236Sbrooksstrsnvisx(char *dst, size_t dlen, const char *csrc, size_t len, int flag,
448241236Sbrooks    const char *extra)
449241236Sbrooks{
450241236Sbrooks	return istrsnvisx(dst, &dlen, csrc, len, flag, extra);
451241236Sbrooks}
452241236Sbrooks#endif
453241236Sbrooks
454241236Sbrooks#if !HAVE_VIS
455241236Sbrooks/*
456241236Sbrooks * vis - visually encode characters
457241236Sbrooks */
458241236Sbrooksstatic char *
459241236Sbrooksinvis(char *dst, size_t *dlen, int c, int flag, int nextc)
460241236Sbrooks{
461241236Sbrooks	char *extra = NULL;
462241236Sbrooks	unsigned char uc = (unsigned char)c;
463241236Sbrooks	visfun_t f;
464241236Sbrooks
465241236Sbrooks	_DIAGASSERT(dst != NULL);
466241236Sbrooks
467241236Sbrooks	MAKEEXTRALIST(flag, extra, "");
468241236Sbrooks	if (! extra) {
469241236Sbrooks		if (dlen && *dlen == 0) {
470241236Sbrooks			errno = ENOSPC;
471241236Sbrooks			return NULL;
472241236Sbrooks		}
473241236Sbrooks		*dst = '\0';		/* can't create extra, return "" */
474241236Sbrooks		return dst;
475241236Sbrooks	}
476241236Sbrooks	f = getvisfun(flag);
477241236Sbrooks	dst = (*f)(dst, dlen, uc, flag, nextc, extra);
478241236Sbrooks	free(extra);
479241236Sbrooks	if (dst == NULL || (dlen && *dlen == 0)) {
480241236Sbrooks		errno = ENOSPC;
481241236Sbrooks		return NULL;
482241236Sbrooks	}
483241236Sbrooks	*dst = '\0';
484241236Sbrooks	return dst;
485241236Sbrooks}
486241236Sbrooks
487241236Sbrookschar *
488241236Sbrooksvis(char *dst, int c, int flag, int nextc)
489241236Sbrooks{
490241236Sbrooks	return invis(dst, NULL, c, flag, nextc);
491241236Sbrooks}
492241236Sbrooks
493241236Sbrookschar *
494241236Sbrooksnvis(char *dst, size_t dlen, int c, int flag, int nextc)
495241236Sbrooks{
496241236Sbrooks	return invis(dst, &dlen, c, flag, nextc);
497241236Sbrooks}
498241236Sbrooks
499241236Sbrooks
500241236Sbrooks/*
501241236Sbrooks * strvis, strvisx - visually encode characters from src into dst
502241236Sbrooks *
503241236Sbrooks *	Dst must be 4 times the size of src to account for possible
504241236Sbrooks *	expansion.  The length of dst, not including the trailing NULL,
505241236Sbrooks *	is returned.
506241236Sbrooks *
507241236Sbrooks *	Strvisx encodes exactly len bytes from src into dst.
508241236Sbrooks *	This is useful for encoding a block of data.
509241236Sbrooks */
510241236Sbrooksstatic int
511241236Sbrooksistrnvis(char *dst, size_t *dlen, const char *src, int flag)
512241236Sbrooks{
513241236Sbrooks	char *extra = NULL;
514241236Sbrooks	int rv;
515241236Sbrooks
516241236Sbrooks	MAKEEXTRALIST(flag, extra, "");
517241236Sbrooks	if (!extra) {
518241236Sbrooks		if (dlen && *dlen == 0) {
519241236Sbrooks			errno = ENOSPC;
520241236Sbrooks			return -1;
521241236Sbrooks		}
522241236Sbrooks		*dst = '\0';		/* can't create extra, return "" */
523241236Sbrooks		return 0;
524241236Sbrooks	}
525241236Sbrooks	rv = istrsnvis(dst, dlen, src, flag, extra);
526241236Sbrooks	free(extra);
527241236Sbrooks	return rv;
528241236Sbrooks}
529241236Sbrooks
530241236Sbrooksint
531241236Sbrooksstrvis(char *dst, const char *src, int flag)
532241236Sbrooks{
533241236Sbrooks	return istrnvis(dst, NULL, src, flag);
534241236Sbrooks}
535241236Sbrooks
536241236Sbrooksint
537241236Sbrooksstrnvis(char *dst, size_t dlen, const char *src, int flag)
538241236Sbrooks{
539241236Sbrooks	return istrnvis(dst, &dlen, src, flag);
540241236Sbrooks}
541241236Sbrooks
542241236Sbrooksstatic int
543241236Sbrooksistrnvisx(char *dst, size_t *dlen, const char *src, size_t len, int flag)
544241236Sbrooks{
545241236Sbrooks	char *extra = NULL;
546241236Sbrooks	int rv;
547241236Sbrooks
548241236Sbrooks	MAKEEXTRALIST(flag, extra, "");
549241236Sbrooks	if (!extra) {
550241236Sbrooks		if (dlen && *dlen == 0) {
551241236Sbrooks			errno = ENOSPC;
552241236Sbrooks			return -1;
553241236Sbrooks		}
554241236Sbrooks		*dst = '\0';		/* can't create extra, return "" */
555241236Sbrooks		return 0;
556241236Sbrooks	}
557241236Sbrooks	rv = istrsnvisx(dst, dlen, src, len, flag, extra);
558241236Sbrooks	free(extra);
559241236Sbrooks	return rv;
560241236Sbrooks}
561241236Sbrooks
562241236Sbrooksint
563241236Sbrooksstrvisx(char *dst, const char *src, size_t len, int flag)
564241236Sbrooks{
565241236Sbrooks	return istrnvisx(dst, NULL, src, len, flag);
566241236Sbrooks}
567241236Sbrooks
568241236Sbrooksint
569241236Sbrooksstrnvisx(char *dst, size_t dlen, const char *src, size_t len, int flag)
570241236Sbrooks{
571241236Sbrooks	return istrnvisx(dst, &dlen, src, len, flag);
572241236Sbrooks}
573241236Sbrooks
574241236Sbrooks#endif
575