1233294Sstas/*	$NetBSD: vis.c,v 1.37 2008/07/25 22:29:23 dsl Exp $	*/
272445Sassar
372445Sassar/*-
472445Sassar * Copyright (c) 1989, 1993
572445Sassar *	The Regents of the University of California.  All rights reserved.
672445Sassar *
772445Sassar * Redistribution and use in source and binary forms, with or without
872445Sassar * modification, are permitted provided that the following conditions
972445Sassar * are met:
1072445Sassar * 1. Redistributions of source code must retain the above copyright
1172445Sassar *    notice, this list of conditions and the following disclaimer.
1272445Sassar * 2. Redistributions in binary form must reproduce the above copyright
1372445Sassar *    notice, this list of conditions and the following disclaimer in the
1472445Sassar *    documentation and/or other materials provided with the distribution.
15178825Sdfr * 3. Neither the name of the University nor the names of its contributors
16178825Sdfr *    may be used to endorse or promote products derived from this software
17178825Sdfr *    without specific prior written permission.
18178825Sdfr *
19178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29178825Sdfr * SUCH DAMAGE.
30178825Sdfr */
31178825Sdfr
32178825Sdfr/*-
33233294Sstas * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
34233294Sstas * All rights reserved.
35178825Sdfr *
36178825Sdfr * Redistribution and use in source and binary forms, with or without
37178825Sdfr * modification, are permitted provided that the following conditions
38178825Sdfr * are met:
39178825Sdfr * 1. Redistributions of source code must retain the above copyright
40178825Sdfr *    notice, this list of conditions and the following disclaimer.
41178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
42178825Sdfr *    notice, this list of conditions and the following disclaimer in the
43178825Sdfr *    documentation and/or other materials provided with the distribution.
4472445Sassar *
45233294Sstas * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
46233294Sstas * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
47233294Sstas * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48233294Sstas * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
49233294Sstas * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50233294Sstas * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51233294Sstas * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52233294Sstas * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53233294Sstas * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54233294Sstas * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55233294Sstas * POSSIBILITY OF SUCH DAMAGE.
5672445Sassar */
5772445Sassar
5872445Sassar#if 1
5972445Sassar#include <config.h>
60178825Sdfr#include "roken.h"
6172445Sassar#ifndef _DIAGASSERT
6272445Sassar#define _DIAGASSERT(X)
6372445Sassar#endif
64233294Sstas#else /* heimdal */
6572445Sassar#include <sys/cdefs.h>
66233294Sstas#if defined(LIBC_SCCS) && !defined(lint)
67233294Sstas__RCSID("$NetBSD: vis.c,v 1.37 2008/07/25 22:29:23 dsl Exp $");
68233294Sstas#endif /* LIBC_SCCS and not lint */
6972445Sassar
7072445Sassar#include "namespace.h"
71233294Sstas#endif /* heimdal */
72233294Sstas
7372445Sassar#include <sys/types.h>
7472445Sassar
7572445Sassar#include <assert.h>
7672445Sassar#include <ctype.h>
7772445Sassar#include <limits.h>
7872445Sassar#include <stdio.h>
7972445Sassar#include <string.h>
8072445Sassar#include <vis.h>
81233294Sstas#include <stdlib.h>
8272445Sassar
8372445Sassar#if 0
8472445Sassar#ifdef __weak_alias
8572445Sassar__weak_alias(strsvis,_strsvis)
8672445Sassar__weak_alias(strsvisx,_strsvisx)
8772445Sassar__weak_alias(strvis,_strvis)
8872445Sassar__weak_alias(strvisx,_strvisx)
8972445Sassar__weak_alias(svis,_svis)
9072445Sassar__weak_alias(vis,_vis)
9172445Sassar#endif
9272445Sassar#endif
9372445Sassar
94233294Sstas#if !HAVE_VIS || !HAVE_SVIS
95233294Sstas#include <ctype.h>
96233294Sstas#include <limits.h>
97233294Sstas#include <stdio.h>
98233294Sstas#include <string.h>
99233294Sstas
100233294Sstasstatic char *do_svis(char *, int, int, int, const char *);
101233294Sstas
10272445Sassar#undef BELL
10372445Sassar#if defined(__STDC__)
10472445Sassar#define BELL '\a'
10572445Sassar#else
10672445Sassar#define BELL '\007'
10772445Sassar#endif
10872445Sassar
109233294SstasROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
110233294Sstas	rk_vis (char *, int, int, int);
111233294SstasROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
112233294Sstas	rk_svis (char *, int, int, int, const char *);
113233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
114178825Sdfr	rk_strvis (char *, const char *, int);
115233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
116178825Sdfr	rk_strsvis (char *, const char *, int, const char *);
117233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
118178825Sdfr	rk_strvisx (char *, const char *, size_t, int);
119233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
120178825Sdfr	rk_strsvisx (char *, const char *, size_t, int, const char *);
121178825Sdfr
122178825Sdfr
12372445Sassar#define isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
12472445Sassar#define iswhite(c)	(c == ' ' || c == '\t' || c == '\n')
12572445Sassar#define issafe(c)	(c == '\b' || c == BELL || c == '\r')
126233294Sstas#define xtoa(c)		"0123456789abcdef"[c]
12772445Sassar
128233294Sstas#define MAXEXTRAS	5
12972445Sassar
130233294Sstas#define MAKEEXTRALIST(flag, extra, orig_str)				      \
13172445Sassardo {									      \
132233294Sstas	const char *orig = orig_str;					      \
133233294Sstas	const char *o = orig;						      \
134233294Sstas	char *e;							      \
135233294Sstas	while (*o++)							      \
136233294Sstas		continue;						      \
137233294Sstas	extra = malloc((size_t)((o - orig) + MAXEXTRAS));		      \
138233294Sstas	if (!extra) break;						      \
139233294Sstas	for (o = orig, e = extra; (*e++ = *o++) != '\0';)		      \
140233294Sstas		continue;						      \
141233294Sstas	e--;								      \
142233294Sstas	if (flag & VIS_SP) *e++ = ' ';					      \
143233294Sstas	if (flag & VIS_TAB) *e++ = '\t';				      \
144233294Sstas	if (flag & VIS_NL) *e++ = '\n';					      \
145233294Sstas	if ((flag & VIS_NOSLASH) == 0) *e++ = '\\';			      \
146233294Sstas	*e = '\0';							      \
14772445Sassar} while (/*CONSTCOND*/0)
14872445Sassar
14972445Sassar/*
150233294Sstas * This is do_hvis, for HTTP style (RFC 1808)
151233294Sstas */
152233294Sstasstatic char *
153233294Sstasdo_hvis(char *dst, int c, int flag, int nextc, const char *extra)
154233294Sstas{
155233294Sstas	if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) {
156233294Sstas		*dst++ = '%';
157233294Sstas		*dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
158233294Sstas		*dst++ = xtoa((unsigned int)c & 0xf);
159233294Sstas	} else {
160233294Sstas		dst = do_svis(dst, c, flag, nextc, extra);
161233294Sstas	}
162233294Sstas	return dst;
163233294Sstas}
164233294Sstas
165233294Sstas/*
166233294Sstas * This is do_vis, the central code of vis.
16772445Sassar * dst:	      Pointer to the destination buffer
16872445Sassar * c:	      Character to encode
16972445Sassar * flag:      Flag word
17072445Sassar * nextc:     The character following 'c'
17172445Sassar * extra:     Pointer to the list of extra characters to be
17272445Sassar *	      backslash-protected.
17372445Sassar */
174233294Sstasstatic char *
175233294Sstasdo_svis(char *dst, int c, int flag, int nextc, const char *extra)
176233294Sstas{
177233294Sstas	int isextra;
178233294Sstas	isextra = strchr(extra, c) != NULL;
179233294Sstas	if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||
180233294Sstas	    ((flag & VIS_SAFE) && issafe(c)))) {
181233294Sstas		*dst++ = c;
182233294Sstas		return dst;
183233294Sstas	}
184233294Sstas	if (flag & VIS_CSTYLE) {
185233294Sstas		switch (c) {
186233294Sstas		case '\n':
187233294Sstas			*dst++ = '\\'; *dst++ = 'n';
188233294Sstas			return dst;
189233294Sstas		case '\r':
190233294Sstas			*dst++ = '\\'; *dst++ = 'r';
191233294Sstas			return dst;
192233294Sstas		case '\b':
193233294Sstas			*dst++ = '\\'; *dst++ = 'b';
194233294Sstas			return dst;
195233294Sstas		case BELL:
196233294Sstas			*dst++ = '\\'; *dst++ = 'a';
197233294Sstas			return dst;
198233294Sstas		case '\v':
199233294Sstas			*dst++ = '\\'; *dst++ = 'v';
200233294Sstas			return dst;
201233294Sstas		case '\t':
202233294Sstas			*dst++ = '\\'; *dst++ = 't';
203233294Sstas			return dst;
204233294Sstas		case '\f':
205233294Sstas			*dst++ = '\\'; *dst++ = 'f';
206233294Sstas			return dst;
207233294Sstas		case ' ':
208233294Sstas			*dst++ = '\\'; *dst++ = 's';
209233294Sstas			return dst;
210233294Sstas		case '\0':
211233294Sstas			*dst++ = '\\'; *dst++ = '0';
212233294Sstas			if (isoctal(nextc)) {
213233294Sstas				*dst++ = '0';
214233294Sstas				*dst++ = '0';
215233294Sstas			}
216233294Sstas			return dst;
217233294Sstas		default:
218233294Sstas			if (isgraph(c)) {
219233294Sstas				*dst++ = '\\'; *dst++ = c;
220233294Sstas				return dst;
221233294Sstas			}
222233294Sstas		}
223233294Sstas	}
224233294Sstas	if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
225233294Sstas		*dst++ = '\\';
226233294Sstas		*dst++ = (u_char)(((unsigned int)(u_char)c >> 6) & 03) + '0';
227233294Sstas		*dst++ = (u_char)(((unsigned int)(u_char)c >> 3) & 07) + '0';
228233294Sstas		*dst++ = (u_char)(			 c       & 07) + '0';
229233294Sstas	} else {
230233294Sstas		if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';
231233294Sstas		if (c & 0200) {
232233294Sstas			c &= 0177; *dst++ = 'M';
233233294Sstas		}
234233294Sstas		if (iscntrl(c)) {
235233294Sstas			*dst++ = '^';
236233294Sstas			if (c == 0177)
237233294Sstas				*dst++ = '?';
238233294Sstas			else
239233294Sstas				*dst++ = c + '@';
240233294Sstas		} else {
241233294Sstas			*dst++ = '-'; *dst++ = c;
242233294Sstas		}
243233294Sstas	}
244233294Sstas	return dst;
245233294Sstas}
24672445Sassar
24772445Sassar
24872445Sassar/*
24972445Sassar * svis - visually encode characters, also encoding the characters
250233294Sstas *	  pointed to by `extra'
25172445Sassar */
252233294SstasROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
253178825Sdfrrk_svis(char *dst, int c, int flag, int nextc, const char *extra)
25472445Sassar{
255233294Sstas	char *nextra = NULL;
256233294Sstas
25772445Sassar	_DIAGASSERT(dst != NULL);
25872445Sassar	_DIAGASSERT(extra != NULL);
259233294Sstas	MAKEEXTRALIST(flag, nextra, extra);
260233294Sstas	if (!nextra) {
261233294Sstas		*dst = '\0';		/* can't create nextra, return "" */
262233294Sstas		return dst;
263233294Sstas	}
264233294Sstas	if (flag & VIS_HTTPSTYLE)
265233294Sstas		dst = do_hvis(dst, c, flag, nextc, nextra);
266233294Sstas	else
267233294Sstas		dst = do_svis(dst, c, flag, nextc, nextra);
268233294Sstas	free(nextra);
26972445Sassar	*dst = '\0';
270233294Sstas	return dst;
27172445Sassar}
27272445Sassar
27372445Sassar
27472445Sassar/*
27572445Sassar * strsvis, strsvisx - visually encode characters from src into dst
27672445Sassar *
27772445Sassar *	Extra is a pointer to a \0-terminated list of characters to
27872445Sassar *	be encoded, too. These functions are useful e. g. to
27972445Sassar *	encode strings in such a way so that they are not interpreted
28072445Sassar *	by a shell.
281233294Sstas *
28272445Sassar *	Dst must be 4 times the size of src to account for possible
28372445Sassar *	expansion.  The length of dst, not including the trailing NULL,
284233294Sstas *	is returned.
28572445Sassar *
28672445Sassar *	Strsvisx encodes exactly len bytes from src into dst.
28772445Sassar *	This is useful for encoding a block of data.
28872445Sassar */
289178825Sdfr
290233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
291233294Sstasrk_strsvis(char *dst, const char *csrc, int flag, const char *extra)
29272445Sassar{
293233294Sstas	int c;
29472445Sassar	char *start;
295233294Sstas	char *nextra = NULL;
296233294Sstas	const unsigned char *src = (const unsigned char *)csrc;
29772445Sassar
29872445Sassar	_DIAGASSERT(dst != NULL);
29972445Sassar	_DIAGASSERT(src != NULL);
30072445Sassar	_DIAGASSERT(extra != NULL);
301233294Sstas	MAKEEXTRALIST(flag, nextra, extra);
302233294Sstas	if (!nextra) {
303233294Sstas		*dst = '\0';		/* can't create nextra, return "" */
304233294Sstas		return 0;
305233294Sstas	}
306233294Sstas	if (flag & VIS_HTTPSTYLE) {
307233294Sstas		for (start = dst; (c = *src++) != '\0'; /* empty */)
308233294Sstas			dst = do_hvis(dst, c, flag, *src, nextra);
309233294Sstas	} else {
310233294Sstas		for (start = dst; (c = *src++) != '\0'; /* empty */)
311233294Sstas			dst = do_svis(dst, c, flag, *src, nextra);
312233294Sstas	}
313233294Sstas	free(nextra);
31472445Sassar	*dst = '\0';
31572445Sassar	return (dst - start);
31672445Sassar}
31772445Sassar
31872445Sassar
319233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
320233294Sstasrk_strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra)
32172445Sassar{
322233294Sstas	unsigned char c;
32372445Sassar	char *start;
324233294Sstas	char *nextra = NULL;
325233294Sstas	const unsigned char *src = (const unsigned char *)csrc;
32672445Sassar
32772445Sassar	_DIAGASSERT(dst != NULL);
32872445Sassar	_DIAGASSERT(src != NULL);
32972445Sassar	_DIAGASSERT(extra != NULL);
330233294Sstas	MAKEEXTRALIST(flag, nextra, extra);
331233294Sstas	if (! nextra) {
332233294Sstas		*dst = '\0';		/* can't create nextra, return "" */
333233294Sstas		return 0;
334233294Sstas	}
33572445Sassar
336233294Sstas	if (flag & VIS_HTTPSTYLE) {
337233294Sstas		for (start = dst; len > 0; len--) {
338233294Sstas			c = *src++;
339233294Sstas			dst = do_hvis(dst, c, flag, len ? *src : '\0', nextra);
340233294Sstas		}
341233294Sstas	} else {
342233294Sstas		for (start = dst; len > 0; len--) {
343233294Sstas			c = *src++;
344233294Sstas			dst = do_svis(dst, c, flag, len ? *src : '\0', nextra);
345233294Sstas		}
34672445Sassar	}
347233294Sstas	free(nextra);
34872445Sassar	*dst = '\0';
34972445Sassar	return (dst - start);
35072445Sassar}
351233294Sstas#endif
35272445Sassar
353233294Sstas#if !HAVE_VIS
35472445Sassar/*
35572445Sassar * vis - visually encode characters
35672445Sassar */
357233294SstasROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
358178825Sdfrrk_vis(char *dst, int c, int flag, int nextc)
35972445Sassar{
360233294Sstas	char *extra = NULL;
361233294Sstas	unsigned char uc = (unsigned char)c;
36272445Sassar
36372445Sassar	_DIAGASSERT(dst != NULL);
36472445Sassar
365233294Sstas	MAKEEXTRALIST(flag, extra, "");
366233294Sstas	if (! extra) {
367233294Sstas		*dst = '\0';		/* can't create extra, return "" */
368233294Sstas		return dst;
369233294Sstas	}
370233294Sstas	if (flag & VIS_HTTPSTYLE)
371233294Sstas		dst = do_hvis(dst, uc, flag, nextc, extra);
372233294Sstas	else
373233294Sstas		dst = do_svis(dst, uc, flag, nextc, extra);
374233294Sstas	free(extra);
37572445Sassar	*dst = '\0';
376233294Sstas	return dst;
37772445Sassar}
37872445Sassar
37972445Sassar
38072445Sassar/*
38172445Sassar * strvis, strvisx - visually encode characters from src into dst
382233294Sstas *
38372445Sassar *	Dst must be 4 times the size of src to account for possible
38472445Sassar *	expansion.  The length of dst, not including the trailing NULL,
385233294Sstas *	is returned.
38672445Sassar *
38772445Sassar *	Strvisx encodes exactly len bytes from src into dst.
38872445Sassar *	This is useful for encoding a block of data.
38972445Sassar */
390233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
391178825Sdfrrk_strvis(char *dst, const char *src, int flag)
39272445Sassar{
393233294Sstas	char *extra = NULL;
394233294Sstas	int rv;
39572445Sassar
396233294Sstas	MAKEEXTRALIST(flag, extra, "");
397233294Sstas	if (!extra) {
398233294Sstas		*dst = '\0';		/* can't create extra, return "" */
399233294Sstas		return 0;
400233294Sstas	}
401233294Sstas	rv = strsvis(dst, src, flag, extra);
402233294Sstas	free(extra);
403233294Sstas	return rv;
40472445Sassar}
40572445Sassar
40672445Sassar
407233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
408178825Sdfrrk_strvisx(char *dst, const char *src, size_t len, int flag)
40972445Sassar{
410233294Sstas	char *extra = NULL;
411233294Sstas	int rv;
41272445Sassar
413233294Sstas	MAKEEXTRALIST(flag, extra, "");
414233294Sstas	if (!extra) {
415233294Sstas		*dst = '\0';		/* can't create extra, return "" */
416233294Sstas		return 0;
417233294Sstas	}
418233294Sstas	rv = strsvisx(dst, src, len, flag, extra);
419233294Sstas	free(extra);
420233294Sstas	return rv;
42172445Sassar}
422233294Sstas#endif
423