vis.c revision 90926
1/*	$NetBSD: vis.c,v 1.19 2000/01/22 22:42:45 mycroft Exp $	*/
2
3/*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * Copyright (c) 1989, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37
38#if 1
39#ifdef HAVE_CONFIG_H
40#include <config.h>
41RCSID("$Id: vis.c,v 1.5 2001/09/03 05:37:23 assar Exp $");
42#endif
43#include <roken.h>
44#ifndef _DIAGASSERT
45#define _DIAGASSERT(X)
46#endif
47#else
48#include <sys/cdefs.h>
49#if !defined(lint)
50__RCSID("$NetBSD: vis.c,v 1.19 2000/01/22 22:42:45 mycroft Exp $");
51#endif /* not lint */
52#endif
53
54#if 0
55#include "namespace.h"
56#endif
57#include <sys/types.h>
58
59#include <assert.h>
60#include <ctype.h>
61#include <limits.h>
62#include <stdio.h>
63#include <string.h>
64#include <vis.h>
65
66#if 0
67#ifdef __weak_alias
68__weak_alias(strsvis,_strsvis)
69__weak_alias(strsvisx,_strsvisx)
70__weak_alias(strvis,_strvis)
71__weak_alias(strvisx,_strvisx)
72__weak_alias(svis,_svis)
73__weak_alias(vis,_vis)
74#endif
75#endif
76
77#undef BELL
78#if defined(__STDC__)
79#define BELL '\a'
80#else
81#define BELL '\007'
82#endif
83
84#define isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
85#define iswhite(c)	(c == ' ' || c == '\t' || c == '\n')
86#define issafe(c)	(c == '\b' || c == BELL || c == '\r')
87
88#define MAXEXTRAS       5
89
90
91#define MAKEEXTRALIST(flag, extra)					      \
92do {									      \
93	char *pextra = extra;						      \
94	if (flag & VIS_SP) *pextra++ = ' ';				      \
95	if (flag & VIS_TAB) *pextra++ = '\t';				      \
96	if (flag & VIS_NL) *pextra++ = '\n';				      \
97	if ((flag & VIS_NOSLASH) == 0) *pextra++ = '\\';		      \
98	*pextra = '\0';							      \
99} while (/*CONSTCOND*/0)
100
101/*
102 * This is SVIS, the central macro of vis.
103 * dst:	      Pointer to the destination buffer
104 * c:	      Character to encode
105 * flag:      Flag word
106 * nextc:     The character following 'c'
107 * extra:     Pointer to the list of extra characters to be
108 *	      backslash-protected.
109 */
110#define SVIS(dst, c, flag, nextc, extra)				   \
111do {									   \
112	int isextra, isc;						   \
113	isextra = strchr(extra, c) != NULL;				   \
114	if (!isextra &&							   \
115	    isascii((unsigned char)c) &&				   \
116	    (isgraph((unsigned char)c) || iswhite(c) ||			   \
117	    ((flag & VIS_SAFE) && issafe(c)))) {			   \
118		*dst++ = c;						   \
119		break;							   \
120	}								   \
121	isc = 0;							   \
122	if (flag & VIS_CSTYLE) {					   \
123		switch (c) {						   \
124		case '\n':						   \
125			isc = 1; *dst++ = '\\'; *dst++ = 'n';		   \
126			break;						   \
127		case '\r':						   \
128			isc = 1; *dst++ = '\\'; *dst++ = 'r';		   \
129			break;						   \
130		case '\b':						   \
131			isc = 1; *dst++ = '\\'; *dst++ = 'b';		   \
132			break;						   \
133		case BELL:						   \
134			isc = 1; *dst++ = '\\'; *dst++ = 'a';		   \
135			break;						   \
136		case '\v':						   \
137			isc = 1; *dst++ = '\\'; *dst++ = 'v';		   \
138			break;						   \
139		case '\t':						   \
140			isc = 1; *dst++ = '\\'; *dst++ = 't';		   \
141			break;						   \
142		case '\f':						   \
143			isc = 1; *dst++ = '\\'; *dst++ = 'f';		   \
144			break;						   \
145		case ' ':						   \
146			isc = 1; *dst++ = '\\'; *dst++ = 's';		   \
147			break;						   \
148		case '\0':						   \
149			isc = 1; *dst++ = '\\'; *dst++ = '0';		   \
150			if (isoctal(nextc)) {				   \
151				*dst++ = '0';				   \
152				*dst++ = '0';				   \
153			}						   \
154		}							   \
155	}								   \
156	if (isc) break;							   \
157	if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {	   \
158		*dst++ = '\\';						   \
159		*dst++ = (u_char)(((unsigned)(u_char)c >> 6) & 03) + '0';  \
160		*dst++ = (u_char)(((unsigned)(u_char)c >> 3) & 07) + '0';  \
161		*dst++ =			     (c	      & 07) + '0'; \
162	} else {							   \
163		if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';		   \
164		if (c & 0200) {						   \
165			c &= 0177; *dst++ = 'M';			   \
166		}							   \
167		if (iscntrl((unsigned char)c)) {			   \
168			*dst++ = '^';					   \
169			if (c == 0177)					   \
170				*dst++ = '?';				   \
171			else						   \
172				*dst++ = c + '@';			   \
173		} else {						   \
174			*dst++ = '-'; *dst++ = c;			   \
175		}							   \
176	}								   \
177} while (/*CONSTCOND*/0)
178
179
180/*
181 * svis - visually encode characters, also encoding the characters
182 * 	  pointed to by `extra'
183 */
184#ifndef HAVE_SVIS
185char *
186svis(char *dst, int c, int flag, int nextc, const char *extra)
187{
188	_DIAGASSERT(dst != NULL);
189	_DIAGASSERT(extra != NULL);
190
191	SVIS(dst, c, flag, nextc, extra);
192	*dst = '\0';
193	return(dst);
194}
195#endif
196
197
198/*
199 * strsvis, strsvisx - visually encode characters from src into dst
200 *
201 *	Extra is a pointer to a \0-terminated list of characters to
202 *	be encoded, too. These functions are useful e. g. to
203 *	encode strings in such a way so that they are not interpreted
204 *	by a shell.
205 *
206 *	Dst must be 4 times the size of src to account for possible
207 *	expansion.  The length of dst, not including the trailing NULL,
208 *	is returned.
209 *
210 *	Strsvisx encodes exactly len bytes from src into dst.
211 *	This is useful for encoding a block of data.
212 */
213#ifndef HAVE_STRSVIS
214int
215strsvis(char *dst, const char *src, int flag, const char *extra)
216{
217	char c;
218	char *start;
219
220	_DIAGASSERT(dst != NULL);
221	_DIAGASSERT(src != NULL);
222	_DIAGASSERT(extra != NULL);
223
224	for (start = dst; (c = *src++) != '\0'; /* empty */)
225	    SVIS(dst, c, flag, *src, extra);
226	*dst = '\0';
227	return (dst - start);
228}
229#endif
230
231
232#ifndef HAVE_STRVISX
233int
234strsvisx(char *dst, const char *src, size_t len, int flag, const char *extra)
235{
236	char c;
237	char *start;
238
239	_DIAGASSERT(dst != NULL);
240	_DIAGASSERT(src != NULL);
241	_DIAGASSERT(extra != NULL);
242
243	for (start = dst; len > 0; len--) {
244		c = *src++;
245		SVIS(dst, c, flag, len ? *src : '\0', extra);
246	}
247	*dst = '\0';
248	return (dst - start);
249}
250#endif
251
252
253/*
254 * vis - visually encode characters
255 */
256#ifndef HAVE_VIS
257char *
258vis(char *dst, int c, int flag, int nextc)
259{
260	char extra[MAXEXTRAS];
261
262	_DIAGASSERT(dst != NULL);
263
264	MAKEEXTRALIST(flag, extra);
265	SVIS(dst, c, flag, nextc, extra);
266	*dst = '\0';
267	return (dst);
268}
269#endif
270
271
272/*
273 * strvis, strvisx - visually encode characters from src into dst
274 *
275 *	Dst must be 4 times the size of src to account for possible
276 *	expansion.  The length of dst, not including the trailing NULL,
277 *	is returned.
278 *
279 *	Strvisx encodes exactly len bytes from src into dst.
280 *	This is useful for encoding a block of data.
281 */
282#ifndef HAVE_STRVIS
283int
284strvis(char *dst, const char *src, int flag)
285{
286	char extra[MAXEXTRAS];
287
288	MAKEEXTRALIST(flag, extra);
289	return (strsvis(dst, src, flag, extra));
290}
291#endif
292
293
294#ifndef HAVE_STRVISX
295int
296strvisx(char *dst, const char *src, size_t len, int flag)
297{
298	char extra[MAXEXTRAS];
299
300	MAKEEXTRALIST(flag, extra);
301	return (strsvisx(dst, src, len, flag, extra));
302}
303#endif
304