Home | History | Annotate | Line # | Download | only in gen
vis.c revision 1.37
      1 /*	$NetBSD: vis.c,v 1.37 2008/07/25 22:29:23 dsl Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1989, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 /*-
     33  * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
     34  * All rights reserved.
     35  *
     36  * Redistribution and use in source and binary forms, with or without
     37  * modification, are permitted provided that the following conditions
     38  * are met:
     39  * 1. Redistributions of source code must retain the above copyright
     40  *    notice, this list of conditions and the following disclaimer.
     41  * 2. Redistributions in binary form must reproduce the above copyright
     42  *    notice, this list of conditions and the following disclaimer in the
     43  *    documentation and/or other materials provided with the distribution.
     44  *
     45  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     46  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     47  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     48  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     49  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     50  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     51  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     52  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     53  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     54  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     55  * POSSIBILITY OF SUCH DAMAGE.
     56  */
     57 
     58 #include <sys/cdefs.h>
     59 #if defined(LIBC_SCCS) && !defined(lint)
     60 __RCSID("$NetBSD: vis.c,v 1.37 2008/07/25 22:29:23 dsl Exp $");
     61 #endif /* LIBC_SCCS and not lint */
     62 
     63 #include "namespace.h"
     64 #include <sys/types.h>
     65 
     66 #include <assert.h>
     67 #include <vis.h>
     68 #include <stdlib.h>
     69 
     70 #ifdef __weak_alias
     71 __weak_alias(strsvis,_strsvis)
     72 __weak_alias(strsvisx,_strsvisx)
     73 __weak_alias(strvis,_strvis)
     74 __weak_alias(strvisx,_strvisx)
     75 __weak_alias(svis,_svis)
     76 __weak_alias(vis,_vis)
     77 #endif
     78 
     79 #if !HAVE_VIS || !HAVE_SVIS
     80 #include <ctype.h>
     81 #include <limits.h>
     82 #include <stdio.h>
     83 #include <string.h>
     84 
     85 static char *do_svis(char *, int, int, int, const char *);
     86 
     87 #undef BELL
     88 #define BELL '\a'
     89 
     90 #define isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
     91 #define iswhite(c)	(c == ' ' || c == '\t' || c == '\n')
     92 #define issafe(c)	(c == '\b' || c == BELL || c == '\r')
     93 #define xtoa(c)		"0123456789abcdef"[c]
     94 
     95 #define MAXEXTRAS	5
     96 
     97 #define MAKEEXTRALIST(flag, extra, orig_str)				      \
     98 do {									      \
     99 	const char *orig = orig_str;					      \
    100 	const char *o = orig;						      \
    101 	char *e;							      \
    102 	while (*o++)							      \
    103 		continue;						      \
    104 	extra = malloc((size_t)((o - orig) + MAXEXTRAS));		      \
    105 	if (!extra) break;						      \
    106 	for (o = orig, e = extra; (*e++ = *o++) != '\0';)		      \
    107 		continue;						      \
    108 	e--;								      \
    109 	if (flag & VIS_SP) *e++ = ' ';					      \
    110 	if (flag & VIS_TAB) *e++ = '\t';				      \
    111 	if (flag & VIS_NL) *e++ = '\n';					      \
    112 	if ((flag & VIS_NOSLASH) == 0) *e++ = '\\';			      \
    113 	*e = '\0';							      \
    114 } while (/*CONSTCOND*/0)
    115 
    116 /*
    117  * This is do_hvis, for HTTP style (RFC 1808)
    118  */
    119 static char *
    120 do_hvis(char *dst, int c, int flag, int nextc, const char *extra)
    121 {
    122 	if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) {
    123 		*dst++ = '%';
    124 		*dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
    125 		*dst++ = xtoa((unsigned int)c & 0xf);
    126 	} else {
    127 		dst = do_svis(dst, c, flag, nextc, extra);
    128 	}
    129 	return dst;
    130 }
    131 
    132 /*
    133  * This is do_vis, the central code of vis.
    134  * dst:	      Pointer to the destination buffer
    135  * c:	      Character to encode
    136  * flag:      Flag word
    137  * nextc:     The character following 'c'
    138  * extra:     Pointer to the list of extra characters to be
    139  *	      backslash-protected.
    140  */
    141 static char *
    142 do_svis(char *dst, int c, int flag, int nextc, const char *extra)
    143 {
    144 	int isextra;
    145 	isextra = strchr(extra, c) != NULL;
    146 	if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||
    147 	    ((flag & VIS_SAFE) && issafe(c)))) {
    148 		*dst++ = c;
    149 		return dst;
    150 	}
    151 	if (flag & VIS_CSTYLE) {
    152 		switch (c) {
    153 		case '\n':
    154 			*dst++ = '\\'; *dst++ = 'n';
    155 			return dst;
    156 		case '\r':
    157 			*dst++ = '\\'; *dst++ = 'r';
    158 			return dst;
    159 		case '\b':
    160 			*dst++ = '\\'; *dst++ = 'b';
    161 			return dst;
    162 		case BELL:
    163 			*dst++ = '\\'; *dst++ = 'a';
    164 			return dst;
    165 		case '\v':
    166 			*dst++ = '\\'; *dst++ = 'v';
    167 			return dst;
    168 		case '\t':
    169 			*dst++ = '\\'; *dst++ = 't';
    170 			return dst;
    171 		case '\f':
    172 			*dst++ = '\\'; *dst++ = 'f';
    173 			return dst;
    174 		case ' ':
    175 			*dst++ = '\\'; *dst++ = 's';
    176 			return dst;
    177 		case '\0':
    178 			*dst++ = '\\'; *dst++ = '0';
    179 			if (isoctal(nextc)) {
    180 				*dst++ = '0';
    181 				*dst++ = '0';
    182 			}
    183 			return dst;
    184 		default:
    185 			if (isgraph(c)) {
    186 				*dst++ = '\\'; *dst++ = c;
    187 				return dst;
    188 			}
    189 		}
    190 	}
    191 	if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
    192 		*dst++ = '\\';
    193 		*dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0';
    194 		*dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0';
    195 		*dst++ =			     (c	      & 07) + '0';
    196 	} else {
    197 		if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';
    198 		if (c & 0200) {
    199 			c &= 0177; *dst++ = 'M';
    200 		}
    201 		if (iscntrl(c)) {
    202 			*dst++ = '^';
    203 			if (c == 0177)
    204 				*dst++ = '?';
    205 			else
    206 				*dst++ = c + '@';
    207 		} else {
    208 			*dst++ = '-'; *dst++ = c;
    209 		}
    210 	}
    211 	return dst;
    212 }
    213 
    214 
    215 /*
    216  * svis - visually encode characters, also encoding the characters
    217  *	  pointed to by `extra'
    218  */
    219 char *
    220 svis(char *dst, int c, int flag, int nextc, const char *extra)
    221 {
    222 	char *nextra = NULL;
    223 
    224 	_DIAGASSERT(dst != NULL);
    225 	_DIAGASSERT(extra != NULL);
    226 	MAKEEXTRALIST(flag, nextra, extra);
    227 	if (!nextra) {
    228 		*dst = '\0';		/* can't create nextra, return "" */
    229 		return dst;
    230 	}
    231 	if (flag & VIS_HTTPSTYLE)
    232 		dst = do_hvis(dst, c, flag, nextc, nextra);
    233 	else
    234 		dst = do_svis(dst, c, flag, nextc, nextra);
    235 	free(nextra);
    236 	*dst = '\0';
    237 	return dst;
    238 }
    239 
    240 
    241 /*
    242  * strsvis, strsvisx - visually encode characters from src into dst
    243  *
    244  *	Extra is a pointer to a \0-terminated list of characters to
    245  *	be encoded, too. These functions are useful e. g. to
    246  *	encode strings in such a way so that they are not interpreted
    247  *	by a shell.
    248  *
    249  *	Dst must be 4 times the size of src to account for possible
    250  *	expansion.  The length of dst, not including the trailing NULL,
    251  *	is returned.
    252  *
    253  *	Strsvisx encodes exactly len bytes from src into dst.
    254  *	This is useful for encoding a block of data.
    255  */
    256 int
    257 strsvis(char *dst, const char *csrc, int flag, const char *extra)
    258 {
    259 	int c;
    260 	char *start;
    261 	char *nextra = NULL;
    262 	const unsigned char *src = (const unsigned char *)csrc;
    263 
    264 	_DIAGASSERT(dst != NULL);
    265 	_DIAGASSERT(src != NULL);
    266 	_DIAGASSERT(extra != NULL);
    267 	MAKEEXTRALIST(flag, nextra, extra);
    268 	if (!nextra) {
    269 		*dst = '\0';		/* can't create nextra, return "" */
    270 		return 0;
    271 	}
    272 	if (flag & VIS_HTTPSTYLE) {
    273 		for (start = dst; (c = *src++) != '\0'; /* empty */)
    274 			dst = do_hvis(dst, c, flag, *src, nextra);
    275 	} else {
    276 		for (start = dst; (c = *src++) != '\0'; /* empty */)
    277 			dst = do_svis(dst, c, flag, *src, nextra);
    278 	}
    279 	free(nextra);
    280 	*dst = '\0';
    281 	return (dst - start);
    282 }
    283 
    284 
    285 int
    286 strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra)
    287 {
    288 	unsigned char c;
    289 	char *start;
    290 	char *nextra = NULL;
    291 	const unsigned char *src = (const unsigned char *)csrc;
    292 
    293 	_DIAGASSERT(dst != NULL);
    294 	_DIAGASSERT(src != NULL);
    295 	_DIAGASSERT(extra != NULL);
    296 	MAKEEXTRALIST(flag, nextra, extra);
    297 	if (! nextra) {
    298 		*dst = '\0';		/* can't create nextra, return "" */
    299 		return 0;
    300 	}
    301 
    302 	if (flag & VIS_HTTPSTYLE) {
    303 		for (start = dst; len > 0; len--) {
    304 			c = *src++;
    305 			dst = do_hvis(dst, c, flag, len ? *src : '\0', nextra);
    306 		}
    307 	} else {
    308 		for (start = dst; len > 0; len--) {
    309 			c = *src++;
    310 			dst = do_svis(dst, c, flag, len ? *src : '\0', nextra);
    311 		}
    312 	}
    313 	free(nextra);
    314 	*dst = '\0';
    315 	return (dst - start);
    316 }
    317 #endif
    318 
    319 #if !HAVE_VIS
    320 /*
    321  * vis - visually encode characters
    322  */
    323 char *
    324 vis(char *dst, int c, int flag, int nextc)
    325 {
    326 	char *extra = NULL;
    327 	unsigned char uc = (unsigned char)c;
    328 
    329 	_DIAGASSERT(dst != NULL);
    330 
    331 	MAKEEXTRALIST(flag, extra, "");
    332 	if (! extra) {
    333 		*dst = '\0';		/* can't create extra, return "" */
    334 		return dst;
    335 	}
    336 	if (flag & VIS_HTTPSTYLE)
    337 		dst = do_hvis(dst, uc, flag, nextc, extra);
    338 	else
    339 		dst = do_svis(dst, uc, flag, nextc, extra);
    340 	free(extra);
    341 	*dst = '\0';
    342 	return dst;
    343 }
    344 
    345 
    346 /*
    347  * strvis, strvisx - visually encode characters from src into dst
    348  *
    349  *	Dst must be 4 times the size of src to account for possible
    350  *	expansion.  The length of dst, not including the trailing NULL,
    351  *	is returned.
    352  *
    353  *	Strvisx encodes exactly len bytes from src into dst.
    354  *	This is useful for encoding a block of data.
    355  */
    356 int
    357 strvis(char *dst, const char *src, int flag)
    358 {
    359 	char *extra = NULL;
    360 	int rv;
    361 
    362 	MAKEEXTRALIST(flag, extra, "");
    363 	if (!extra) {
    364 		*dst = '\0';		/* can't create extra, return "" */
    365 		return 0;
    366 	}
    367 	rv = strsvis(dst, src, flag, extra);
    368 	free(extra);
    369 	return rv;
    370 }
    371 
    372 
    373 int
    374 strvisx(char *dst, const char *src, size_t len, int flag)
    375 {
    376 	char *extra = NULL;
    377 	int rv;
    378 
    379 	MAKEEXTRALIST(flag, extra, "");
    380 	if (!extra) {
    381 		*dst = '\0';		/* can't create extra, return "" */
    382 		return 0;
    383 	}
    384 	rv = strsvisx(dst, src, len, flag, extra);
    385 	free(extra);
    386 	return rv;
    387 }
    388 #endif
    389