vis.c revision 72445
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.3 2000/12/10 23:10:48 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 && isascii(c) && (isgraph(c) || iswhite(c) ||	      \
115	    ((flag & VIS_SAFE) && issafe(c)))) {			      \
116		*dst++ = c;						      \
117		break;							      \
118	}								      \
119	isc = 0;							      \
120	if (flag & VIS_CSTYLE) {					      \
121		switch (c) {						      \
122		case '\n':						      \
123			isc = 1; *dst++ = '\\'; *dst++ = 'n';		      \
124			break;						      \
125		case '\r':						      \
126			isc = 1; *dst++ = '\\'; *dst++ = 'r';		      \
127			break;						      \
128		case '\b':						      \
129			isc = 1; *dst++ = '\\'; *dst++ = 'b';		      \
130			break;						      \
131		case BELL:						      \
132			isc = 1; *dst++ = '\\'; *dst++ = 'a';		      \
133			break;						      \
134		case '\v':						      \
135			isc = 1; *dst++ = '\\'; *dst++ = 'v';		      \
136			break;						      \
137		case '\t':						      \
138			isc = 1; *dst++ = '\\'; *dst++ = 't';		      \
139			break;						      \
140		case '\f':						      \
141			isc = 1; *dst++ = '\\'; *dst++ = 'f';		      \
142			break;						      \
143		case ' ':						      \
144			isc = 1; *dst++ = '\\'; *dst++ = 's';		      \
145			break;						      \
146		case '\0':						      \
147			isc = 1; *dst++ = '\\'; *dst++ = '0';		      \
148			if (isoctal(nextc)) {				      \
149				*dst++ = '0';				      \
150				*dst++ = '0';				      \
151			}						      \
152		}							      \
153	}								      \
154	if (isc) break;							      \
155	if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {	      \
156		*dst++ = '\\';						      \
157		*dst++ = (u_char)(((unsigned)(u_char)c >> 6) & 03) + '0';     \
158		*dst++ = (u_char)(((unsigned)(u_char)c >> 3) & 07) + '0';     \
159		*dst++ =			     (c	      & 07) + '0';    \
160	} else {							      \
161		if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';		      \
162		if (c & 0200) {						      \
163			c &= 0177; *dst++ = 'M';			      \
164		}							      \
165		if (iscntrl(c)) {					      \
166			*dst++ = '^';					      \
167			if (c == 0177)					      \
168				*dst++ = '?';				      \
169			else						      \
170				*dst++ = c + '@';			      \
171		} else {						      \
172			*dst++ = '-'; *dst++ = c;			      \
173		}							      \
174	}								      \
175} while (/*CONSTCOND*/0)
176
177
178/*
179 * svis - visually encode characters, also encoding the characters
180 * 	  pointed to by `extra'
181 */
182#ifndef HAVE_SVIS
183char *
184svis(char *dst, int c, int flag, int nextc, const char *extra)
185{
186	_DIAGASSERT(dst != NULL);
187	_DIAGASSERT(extra != NULL);
188
189	SVIS(dst, c, flag, nextc, extra);
190	*dst = '\0';
191	return(dst);
192}
193#endif
194
195
196/*
197 * strsvis, strsvisx - visually encode characters from src into dst
198 *
199 *	Extra is a pointer to a \0-terminated list of characters to
200 *	be encoded, too. These functions are useful e. g. to
201 *	encode strings in such a way so that they are not interpreted
202 *	by a shell.
203 *
204 *	Dst must be 4 times the size of src to account for possible
205 *	expansion.  The length of dst, not including the trailing NULL,
206 *	is returned.
207 *
208 *	Strsvisx encodes exactly len bytes from src into dst.
209 *	This is useful for encoding a block of data.
210 */
211#ifndef HAVE_STRSVIS
212int
213strsvis(char *dst, const char *src, int flag, const char *extra)
214{
215	char c;
216	char *start;
217
218	_DIAGASSERT(dst != NULL);
219	_DIAGASSERT(src != NULL);
220	_DIAGASSERT(extra != NULL);
221
222	for (start = dst; (c = *src++) != '\0'; /* empty */)
223	    SVIS(dst, c, flag, *src, extra);
224	*dst = '\0';
225	return (dst - start);
226}
227#endif
228
229
230#ifndef HAVE_STRVISX
231int
232strsvisx(char *dst, const char *src, size_t len, int flag, const char *extra)
233{
234	char c;
235	char *start;
236
237	_DIAGASSERT(dst != NULL);
238	_DIAGASSERT(src != NULL);
239	_DIAGASSERT(extra != NULL);
240
241	for (start = dst; len > 0; len--) {
242		c = *src++;
243		SVIS(dst, c, flag, len ? *src : '\0', extra);
244	}
245	*dst = '\0';
246	return (dst - start);
247}
248#endif
249
250
251/*
252 * vis - visually encode characters
253 */
254#ifndef HAVE_VIS
255char *
256vis(char *dst, int c, int flag, int nextc)
257{
258	char extra[MAXEXTRAS];
259
260	_DIAGASSERT(dst != NULL);
261
262	MAKEEXTRALIST(flag, extra);
263	SVIS(dst, c, flag, nextc, extra);
264	*dst = '\0';
265	return (dst);
266}
267#endif
268
269
270/*
271 * strvis, strvisx - visually encode characters from src into dst
272 *
273 *	Dst must be 4 times the size of src to account for possible
274 *	expansion.  The length of dst, not including the trailing NULL,
275 *	is returned.
276 *
277 *	Strvisx encodes exactly len bytes from src into dst.
278 *	This is useful for encoding a block of data.
279 */
280#ifndef HAVE_STRVIS
281int
282strvis(char *dst, const char *src, int flag)
283{
284	char extra[MAXEXTRAS];
285
286	MAKEEXTRALIST(flag, extra);
287	return (strsvis(dst, src, flag, extra));
288}
289#endif
290
291
292#ifndef HAVE_STRVISX
293int
294strvisx(char *dst, const char *src, size_t len, int flag)
295{
296	char extra[MAXEXTRAS];
297
298	MAKEEXTRALIST(flag, extra);
299	return (strsvisx(dst, src, len, flag, extra));
300}
301#endif
302