1 /* $NetBSD: vis.c,v 1.23 2002/05/26 14:03:20 wiz 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 #include <sys/cdefs.h> 38 #if defined(LIBC_SCCS) && !defined(lint) 39 __RCSID("$NetBSD: vis.c,v 1.23 2002/05/26 14:03:20 wiz Exp $"); 40 #endif /* LIBC_SCCS and not lint */ 41 42 #include "namespace.h" 43 #include <sys/types.h> 44 45 #include <assert.h> 46 #include <vis.h> 47 #include <stdlib.h> 48 49 #ifdef __weak_alias 50 __weak_alias(strsvis,_strsvis) 51 __weak_alias(strsvisx,_strsvisx) 52 __weak_alias(strvis,_strvis) 53 __weak_alias(strvisx,_strvisx) 54 __weak_alias(svis,_svis) 55 __weak_alias(vis,_vis) 56 #endif 57 58 #if !HAVE_VIS_H 59 #include <ctype.h> 60 #include <limits.h> 61 #include <stdio.h> 62 #include <string.h> 63 64 #undef BELL 65 #define BELL '\a' 66 67 #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') 68 #define iswhite(c) (c == ' ' || c == '\t' || c == '\n') 69 #define issafe(c) (c == '\b' || c == BELL || c == '\r') 70 #define xtoa(c) "0123456789abcdef"[c] 71 72 #define MAXEXTRAS 5 73 74 75 #define MAKEEXTRALIST(flag, extra, orig) \ 76 do { \ 77 const char *o = orig; \ 78 char *e; \ 79 while (*o++) \ 80 continue; \ 81 extra = alloca((size_t)((o - orig) + MAXEXTRAS)); \ 82 for (o = orig, e = extra; (*e++ = *o++) != '\0';) \ 83 continue; \ 84 e--; \ 85 if (flag & VIS_SP) *e++ = ' '; \ 86 if (flag & VIS_TAB) *e++ = '\t'; \ 87 if (flag & VIS_NL) *e++ = '\n'; \ 88 if ((flag & VIS_NOSLASH) == 0) *e++ = '\\'; \ 89 *e = '\0'; \ 90 } while (/*CONSTCOND*/0) 91 92 93 /* 94 * This is HVIS, the macro of vis used to HTTP style (RFC 1808) 95 */ 96 #define HVIS(dst, c, flag, nextc, extra) \ 97 do \ 98 if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) { \ 99 *dst++ = '%'; \ 100 *dst++ = xtoa(((unsigned int)c >> 4) & 0xf); \ 101 *dst++ = xtoa((unsigned int)c & 0xf); \ 102 } else { \ 103 SVIS(dst, c, flag, nextc, extra); \ 104 } \ 105 while (/*CONSTCOND*/0) 106 107 /* 108 * This is SVIS, the central macro of vis. 109 * dst: Pointer to the destination buffer 110 * c: Character to encode 111 * flag: Flag word 112 * nextc: The character following 'c' 113 * extra: Pointer to the list of extra characters to be 114 * backslash-protected. 115 */ 116 #define SVIS(dst, c, flag, nextc, extra) \ 117 do { \ 118 int isextra, isc; \ 119 isextra = strchr(extra, c) != NULL; \ 120 if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) || \ 121 ((flag & VIS_SAFE) && issafe(c)))) { \ 122 *dst++ = c; \ 123 break; \ 124 } \ 125 isc = 0; \ 126 if (flag & VIS_CSTYLE) { \ 127 switch (c) { \ 128 case '\n': \ 129 isc = 1; *dst++ = '\\'; *dst++ = 'n'; \ 130 break; \ 131 case '\r': \ 132 isc = 1; *dst++ = '\\'; *dst++ = 'r'; \ 133 break; \ 134 case '\b': \ 135 isc = 1; *dst++ = '\\'; *dst++ = 'b'; \ 136 break; \ 137 case BELL: \ 138 isc = 1; *dst++ = '\\'; *dst++ = 'a'; \ 139 break; \ 140 case '\v': \ 141 isc = 1; *dst++ = '\\'; *dst++ = 'v'; \ 142 break; \ 143 case '\t': \ 144 isc = 1; *dst++ = '\\'; *dst++ = 't'; \ 145 break; \ 146 case '\f': \ 147 isc = 1; *dst++ = '\\'; *dst++ = 'f'; \ 148 break; \ 149 case ' ': \ 150 isc = 1; *dst++ = '\\'; *dst++ = 's'; \ 151 break; \ 152 case '\0': \ 153 isc = 1; *dst++ = '\\'; *dst++ = '0'; \ 154 if (isoctal(nextc)) { \ 155 *dst++ = '0'; \ 156 *dst++ = '0'; \ 157 } \ 158 } \ 159 } \ 160 if (isc) break; \ 161 if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) { \ 162 *dst++ = '\\'; \ 163 *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0'; \ 164 *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0'; \ 165 *dst++ = (c & 07) + '0'; \ 166 } else { \ 167 if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\'; \ 168 if (c & 0200) { \ 169 c &= 0177; *dst++ = 'M'; \ 170 } \ 171 if (iscntrl(c)) { \ 172 *dst++ = '^'; \ 173 if (c == 0177) \ 174 *dst++ = '?'; \ 175 else \ 176 *dst++ = c + '@'; \ 177 } else { \ 178 *dst++ = '-'; *dst++ = c; \ 179 } \ 180 } \ 181 } while (/*CONSTCOND*/0) 182 183 184 /* 185 * svis - visually encode characters, also encoding the characters 186 * pointed to by `extra' 187 */ 188 char * 189 svis(dst, c, flag, nextc, extra) 190 char *dst; 191 int c, flag, nextc; 192 const char *extra; 193 { 194 char *nextra; 195 _DIAGASSERT(dst != NULL); 196 _DIAGASSERT(extra != NULL); 197 MAKEEXTRALIST(flag, nextra, extra); 198 if (flag & VIS_HTTPSTYLE) 199 HVIS(dst, c, flag, nextc, nextra); 200 else 201 SVIS(dst, c, flag, nextc, nextra); 202 *dst = '\0'; 203 return(dst); 204 } 205 206 207 /* 208 * strsvis, strsvisx - visually encode characters from src into dst 209 * 210 * Extra is a pointer to a \0-terminated list of characters to 211 * be encoded, too. These functions are useful e. g. to 212 * encode strings in such a way so that they are not interpreted 213 * by a shell. 214 * 215 * Dst must be 4 times the size of src to account for possible 216 * expansion. The length of dst, not including the trailing NULL, 217 * is returned. 218 * 219 * Strsvisx encodes exactly len bytes from src into dst. 220 * This is useful for encoding a block of data. 221 */ 222 int 223 strsvis(dst, src, flag, extra) 224 char *dst; 225 const char *src; 226 int flag; 227 const char *extra; 228 { 229 char c; 230 char *start; 231 char *nextra; 232 233 _DIAGASSERT(dst != NULL); 234 _DIAGASSERT(src != NULL); 235 _DIAGASSERT(extra != NULL); 236 MAKEEXTRALIST(flag, nextra, extra); 237 if (flag & VIS_HTTPSTYLE) { 238 for (start = dst; (c = *src++) != '\0'; /* empty */) 239 HVIS(dst, c, flag, *src, nextra); 240 } else { 241 for (start = dst; (c = *src++) != '\0'; /* empty */) 242 SVIS(dst, c, flag, *src, nextra); 243 } 244 *dst = '\0'; 245 return (dst - start); 246 } 247 248 249 int 250 strsvisx(dst, src, len, flag, extra) 251 char *dst; 252 const char *src; 253 size_t len; 254 int flag; 255 const char *extra; 256 { 257 char c; 258 char *start; 259 char *nextra; 260 261 _DIAGASSERT(dst != NULL); 262 _DIAGASSERT(src != NULL); 263 _DIAGASSERT(extra != NULL); 264 MAKEEXTRALIST(flag, nextra, extra); 265 266 if (flag & VIS_HTTPSTYLE) { 267 for (start = dst; len > 0; len--) { 268 c = *src++; 269 HVIS(dst, c, flag, len ? *src : '\0', nextra); 270 } 271 } else { 272 for (start = dst; len > 0; len--) { 273 c = *src++; 274 SVIS(dst, c, flag, len ? *src : '\0', nextra); 275 } 276 } 277 *dst = '\0'; 278 return (dst - start); 279 } 280 281 282 /* 283 * vis - visually encode characters 284 */ 285 char * 286 vis(dst, c, flag, nextc) 287 char *dst; 288 int c, flag, nextc; 289 290 { 291 char *extra; 292 293 _DIAGASSERT(dst != NULL); 294 295 MAKEEXTRALIST(flag, extra, ""); 296 if (flag & VIS_HTTPSTYLE) 297 HVIS(dst, c, flag, nextc, extra); 298 else 299 SVIS(dst, c, flag, nextc, extra); 300 *dst = '\0'; 301 return (dst); 302 } 303 304 305 /* 306 * strvis, strvisx - visually encode characters from src into dst 307 * 308 * Dst must be 4 times the size of src to account for possible 309 * expansion. The length of dst, not including the trailing NULL, 310 * is returned. 311 * 312 * Strvisx encodes exactly len bytes from src into dst. 313 * This is useful for encoding a block of data. 314 */ 315 int 316 strvis(dst, src, flag) 317 char *dst; 318 const char *src; 319 int flag; 320 { 321 char *extra; 322 323 MAKEEXTRALIST(flag, extra, ""); 324 return (strsvis(dst, src, flag, extra)); 325 } 326 327 328 int 329 strvisx(dst, src, len, flag) 330 char *dst; 331 const char *src; 332 size_t len; 333 int flag; 334 { 335 char *extra; 336 337 MAKEEXTRALIST(flag, extra, ""); 338 return (strsvisx(dst, src, len, flag, extra)); 339 } 340 #endif 341