Home | History | Annotate | Line # | Download | only in gen
vis.c revision 1.39
      1 /*	$NetBSD: vis.c,v 1.39 2009/02/10 23:06:31 christos 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.39 2009/02/10 23:06:31 christos 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 #define XTOA(c)		"0123456789ABCDEF"[c]
     95 
     96 #define MAXEXTRAS	5
     97 
     98 #define MAKEEXTRALIST(flag, extra, orig_str)				      \
     99 do {									      \
    100 	const char *orig = orig_str;					      \
    101 	const char *o = orig;						      \
    102 	char *e;							      \
    103 	while (*o++)							      \
    104 		continue;						      \
    105 	extra = malloc((size_t)((o - orig) + MAXEXTRAS));		      \
    106 	if (!extra) break;						      \
    107 	for (o = orig, e = extra; (*e++ = *o++) != '\0';)		      \
    108 		continue;						      \
    109 	e--;								      \
    110 	if (flag & VIS_SP) *e++ = ' ';					      \
    111 	if (flag & VIS_TAB) *e++ = '\t';				      \
    112 	if (flag & VIS_NL) *e++ = '\n';					      \
    113 	if ((flag & VIS_NOSLASH) == 0) *e++ = '\\';			      \
    114 	*e = '\0';							      \
    115 } while (/*CONSTCOND*/0)
    116 
    117 /*
    118  * This is do_hvis, for HTTP style (RFC 1808)
    119  */
    120 static char *
    121 do_hvis(char *dst, int c, int flag, int nextc, const char *extra)
    122 {
    123 	if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) {
    124 		*dst++ = '%';
    125 		*dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
    126 		*dst++ = xtoa((unsigned int)c & 0xf);
    127 	} else {
    128 		dst = do_svis(dst, c, flag, nextc, extra);
    129 	}
    130 	return dst;
    131 }
    132 
    133 /*
    134  * This is do_mvis, for Quoted-Printable MIME (RFC 2045)
    135  * NB: No handling of long lines or CRLF.
    136  */
    137 static char *
    138 do_mvis(char *dst, int c, int flag, int nextc, const char *extra)
    139 {
    140 	if ((c != '\n') &&
    141 	    /* Space at the end of the line */
    142 	    ((isspace(c) && (nextc == '\r' || nextc == '\n')) ||
    143 	    /* Out of range */
    144 	    (!isspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) ||
    145 	    /* Specific char to be escaped */
    146 	    strchr("#$@[\\]^`{|}~", c) != NULL)) {
    147 		*dst++ = '=';
    148 		*dst++ = XTOA(((unsigned int)c >> 4) & 0xf);
    149 		*dst++ = XTOA((unsigned int)c & 0xf);
    150 	} else {
    151 		dst = do_svis(dst, c, flag, nextc, extra);
    152 	}
    153 	return dst;
    154 }
    155 
    156 /*
    157  * This is do_vis, the central code of vis.
    158  * dst:	      Pointer to the destination buffer
    159  * c:	      Character to encode
    160  * flag:      Flag word
    161  * nextc:     The character following 'c'
    162  * extra:     Pointer to the list of extra characters to be
    163  *	      backslash-protected.
    164  */
    165 static char *
    166 do_svis(char *dst, int c, int flag, int nextc, const char *extra)
    167 {
    168 	int isextra;
    169 	isextra = strchr(extra, c) != NULL;
    170 	if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||
    171 	    ((flag & VIS_SAFE) && issafe(c)))) {
    172 		*dst++ = c;
    173 		return dst;
    174 	}
    175 	if (flag & VIS_CSTYLE) {
    176 		switch (c) {
    177 		case '\n':
    178 			*dst++ = '\\'; *dst++ = 'n';
    179 			return dst;
    180 		case '\r':
    181 			*dst++ = '\\'; *dst++ = 'r';
    182 			return dst;
    183 		case '\b':
    184 			*dst++ = '\\'; *dst++ = 'b';
    185 			return dst;
    186 		case BELL:
    187 			*dst++ = '\\'; *dst++ = 'a';
    188 			return dst;
    189 		case '\v':
    190 			*dst++ = '\\'; *dst++ = 'v';
    191 			return dst;
    192 		case '\t':
    193 			*dst++ = '\\'; *dst++ = 't';
    194 			return dst;
    195 		case '\f':
    196 			*dst++ = '\\'; *dst++ = 'f';
    197 			return dst;
    198 		case ' ':
    199 			*dst++ = '\\'; *dst++ = 's';
    200 			return dst;
    201 		case '\0':
    202 			*dst++ = '\\'; *dst++ = '0';
    203 			if (isoctal(nextc)) {
    204 				*dst++ = '0';
    205 				*dst++ = '0';
    206 			}
    207 			return dst;
    208 		default:
    209 			if (isgraph(c)) {
    210 				*dst++ = '\\'; *dst++ = c;
    211 				return dst;
    212 			}
    213 		}
    214 	}
    215 	if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
    216 		*dst++ = '\\';
    217 		*dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0';
    218 		*dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0';
    219 		*dst++ =			     (c	      & 07) + '0';
    220 	} else {
    221 		if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';
    222 		if (c & 0200) {
    223 			c &= 0177; *dst++ = 'M';
    224 		}
    225 		if (iscntrl(c)) {
    226 			*dst++ = '^';
    227 			if (c == 0177)
    228 				*dst++ = '?';
    229 			else
    230 				*dst++ = c + '@';
    231 		} else {
    232 			*dst++ = '-'; *dst++ = c;
    233 		}
    234 	}
    235 	return dst;
    236 }
    237 
    238 typedef char *(*visfun_t)(char *, int, int, int, const char *);
    239 
    240 /*
    241  * Return the appropriate encoding function depending on the flags given.
    242  */
    243 static visfun_t
    244 getvisfun(int flag)
    245 {
    246 	if (flag & VIS_HTTPSTYLE)
    247 		return do_hvis;
    248 	if (flag * VIS_MIMESTYLE)
    249 		return do_mvis;
    250 	return do_svis;
    251 }
    252 
    253 /*
    254  * svis - visually encode characters, also encoding the characters
    255  *	  pointed to by `extra'
    256  */
    257 char *
    258 svis(char *dst, int c, int flag, int nextc, const char *extra)
    259 {
    260 	char *nextra = NULL;
    261 	visfun_t f;
    262 
    263 	_DIAGASSERT(dst != NULL);
    264 	_DIAGASSERT(extra != NULL);
    265 	MAKEEXTRALIST(flag, nextra, extra);
    266 	if (!nextra) {
    267 		*dst = '\0';		/* can't create nextra, return "" */
    268 		return dst;
    269 	}
    270 	f = getvisfun(flag);
    271 	dst = (*f)(dst, c, flag, nextc, nextra);
    272 	free(nextra);
    273 	*dst = '\0';
    274 	return dst;
    275 }
    276 
    277 
    278 /*
    279  * strsvis, strsvisx - visually encode characters from src into dst
    280  *
    281  *	Extra is a pointer to a \0-terminated list of characters to
    282  *	be encoded, too. These functions are useful e. g. to
    283  *	encode strings in such a way so that they are not interpreted
    284  *	by a shell.
    285  *
    286  *	Dst must be 4 times the size of src to account for possible
    287  *	expansion.  The length of dst, not including the trailing NULL,
    288  *	is returned.
    289  *
    290  *	Strsvisx encodes exactly len bytes from src into dst.
    291  *	This is useful for encoding a block of data.
    292  */
    293 int
    294 strsvis(char *dst, const char *csrc, int flag, const char *extra)
    295 {
    296 	int c;
    297 	char *start;
    298 	char *nextra = NULL;
    299 	const unsigned char *src = (const unsigned char *)csrc;
    300 	visfun_t f;
    301 
    302 	_DIAGASSERT(dst != NULL);
    303 	_DIAGASSERT(src != NULL);
    304 	_DIAGASSERT(extra != NULL);
    305 	MAKEEXTRALIST(flag, nextra, extra);
    306 	if (!nextra) {
    307 		*dst = '\0';		/* can't create nextra, return "" */
    308 		return 0;
    309 	}
    310 	f = getvisfun(flag);
    311 	for (start = dst; (c = *src++) != '\0'; /* empty */)
    312 		dst = (*f)(dst, c, flag, *src, nextra);
    313 	free(nextra);
    314 	*dst = '\0';
    315 	return (int)(dst - start);
    316 }
    317 
    318 
    319 int
    320 strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra)
    321 {
    322 	unsigned char c;
    323 	char *start;
    324 	char *nextra = NULL;
    325 	const unsigned char *src = (const unsigned char *)csrc;
    326 	visfun_t f;
    327 
    328 	_DIAGASSERT(dst != NULL);
    329 	_DIAGASSERT(src != NULL);
    330 	_DIAGASSERT(extra != NULL);
    331 	MAKEEXTRALIST(flag, nextra, extra);
    332 	if (! nextra) {
    333 		*dst = '\0';		/* can't create nextra, return "" */
    334 		return 0;
    335 	}
    336 
    337 	f = getvisfun(flag);
    338 	for (start = dst; len > 0; len--) {
    339 		c = *src++;
    340 		dst = (*f)(dst, c, flag, len > 1 ? *src : '\0', nextra);
    341 	}
    342 	free(nextra);
    343 	*dst = '\0';
    344 	return (int)(dst - start);
    345 }
    346 #endif
    347 
    348 #if !HAVE_VIS
    349 /*
    350  * vis - visually encode characters
    351  */
    352 char *
    353 vis(char *dst, int c, int flag, int nextc)
    354 {
    355 	char *extra = NULL;
    356 	unsigned char uc = (unsigned char)c;
    357 	visfun_t f;
    358 
    359 	_DIAGASSERT(dst != NULL);
    360 
    361 	MAKEEXTRALIST(flag, extra, "");
    362 	if (! extra) {
    363 		*dst = '\0';		/* can't create extra, return "" */
    364 		return dst;
    365 	}
    366 	f = getvisfun(flag);
    367 	dst = (*f)(dst, uc, flag, nextc, extra);
    368 	free(extra);
    369 	*dst = '\0';
    370 	return dst;
    371 }
    372 
    373 
    374 /*
    375  * strvis, strvisx - visually encode characters from src into dst
    376  *
    377  *	Dst must be 4 times the size of src to account for possible
    378  *	expansion.  The length of dst, not including the trailing NULL,
    379  *	is returned.
    380  *
    381  *	Strvisx encodes exactly len bytes from src into dst.
    382  *	This is useful for encoding a block of data.
    383  */
    384 int
    385 strvis(char *dst, const char *src, int flag)
    386 {
    387 	char *extra = NULL;
    388 	int rv;
    389 
    390 	MAKEEXTRALIST(flag, extra, "");
    391 	if (!extra) {
    392 		*dst = '\0';		/* can't create extra, return "" */
    393 		return 0;
    394 	}
    395 	rv = strsvis(dst, src, flag, extra);
    396 	free(extra);
    397 	return rv;
    398 }
    399 
    400 
    401 int
    402 strvisx(char *dst, const char *src, size_t len, int flag)
    403 {
    404 	char *extra = NULL;
    405 	int rv;
    406 
    407 	MAKEEXTRALIST(flag, extra, "");
    408 	if (!extra) {
    409 		*dst = '\0';		/* can't create extra, return "" */
    410 		return 0;
    411 	}
    412 	rv = strsvisx(dst, src, len, flag, extra);
    413 	free(extra);
    414 	return rv;
    415 }
    416 #endif
    417