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