1 /* $NetBSD: vis.c,v 1.25 2003/07/16 22:34:34 dsl 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.25 2003/07/16 22:34:34 dsl 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 || !HAVE_SVIS 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; \ 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 if (flag & VIS_CSTYLE) { \ 126 switch (c) { \ 127 case '\n': \ 128 *dst++ = '\\'; *dst++ = 'n'; \ 129 continue; \ 130 case '\r': \ 131 *dst++ = '\\'; *dst++ = 'r'; \ 132 continue; \ 133 case '\b': \ 134 *dst++ = '\\'; *dst++ = 'b'; \ 135 continue; \ 136 case BELL: \ 137 *dst++ = '\\'; *dst++ = 'a'; \ 138 continue; \ 139 case '\v': \ 140 *dst++ = '\\'; *dst++ = 'v'; \ 141 continue; \ 142 case '\t': \ 143 *dst++ = '\\'; *dst++ = 't'; \ 144 continue; \ 145 case '\f': \ 146 *dst++ = '\\'; *dst++ = 'f'; \ 147 continue; \ 148 case ' ': \ 149 *dst++ = '\\'; *dst++ = 's'; \ 150 continue; \ 151 case '\0': \ 152 *dst++ = '\\'; *dst++ = '0'; \ 153 if (isoctal(nextc)) { \ 154 *dst++ = '0'; \ 155 *dst++ = '0'; \ 156 } \ 157 continue; \ 158 default: \ 159 if (isgraph(c)) { \ 160 *dst++ = '\\'; *dst++ = c; \ 161 continue; \ 162 } \ 163 } \ 164 } \ 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, csrc, flag, extra) 228 char *dst; 229 const char *csrc; 230 int flag; 231 const char *extra; 232 { 233 int c; 234 char *start; 235 char *nextra; 236 const unsigned char *src = (const unsigned char *)csrc; 237 238 _DIAGASSERT(dst != NULL); 239 _DIAGASSERT(src != NULL); 240 _DIAGASSERT(extra != NULL); 241 MAKEEXTRALIST(flag, nextra, extra); 242 if (flag & VIS_HTTPSTYLE) { 243 for (start = dst; (c = *src++) != '\0'; /* empty */) 244 HVIS(dst, c, flag, *src, nextra); 245 } else { 246 for (start = dst; (c = *src++) != '\0'; /* empty */) 247 SVIS(dst, c, flag, *src, nextra); 248 } 249 *dst = '\0'; 250 return (dst - start); 251 } 252 253 254 int 255 strsvisx(dst, csrc, len, flag, extra) 256 char *dst; 257 const char *csrc; 258 size_t len; 259 int flag; 260 const char *extra; 261 { 262 int c; 263 char *start; 264 char *nextra; 265 const unsigned char *src = (const unsigned char *)csrc; 266 267 _DIAGASSERT(dst != NULL); 268 _DIAGASSERT(src != NULL); 269 _DIAGASSERT(extra != NULL); 270 MAKEEXTRALIST(flag, nextra, extra); 271 272 if (flag & VIS_HTTPSTYLE) { 273 for (start = dst; len > 0; len--) { 274 c = *src++; 275 HVIS(dst, c, flag, len ? *src : '\0', nextra); 276 } 277 } else { 278 for (start = dst; len > 0; len--) { 279 c = *src++; 280 SVIS(dst, c, flag, len ? *src : '\0', nextra); 281 } 282 } 283 *dst = '\0'; 284 return (dst - start); 285 } 286 #endif 287 288 #if !HAVE_VIS 289 /* 290 * vis - visually encode characters 291 */ 292 char * 293 vis(dst, c, flag, nextc) 294 char *dst; 295 int c, flag, nextc; 296 297 { 298 char *extra; 299 300 _DIAGASSERT(dst != NULL); 301 302 MAKEEXTRALIST(flag, extra, ""); 303 if (flag & VIS_HTTPSTYLE) 304 HVIS(dst, c, flag, nextc, extra); 305 else 306 SVIS(dst, c, flag, nextc, extra); 307 *dst = '\0'; 308 return (dst); 309 } 310 311 312 /* 313 * strvis, strvisx - visually encode characters from src into dst 314 * 315 * Dst must be 4 times the size of src to account for possible 316 * expansion. The length of dst, not including the trailing NULL, 317 * is returned. 318 * 319 * Strvisx encodes exactly len bytes from src into dst. 320 * This is useful for encoding a block of data. 321 */ 322 int 323 strvis(dst, src, flag) 324 char *dst; 325 const char *src; 326 int flag; 327 { 328 char *extra; 329 330 MAKEEXTRALIST(flag, extra, ""); 331 return (strsvis(dst, src, flag, extra)); 332 } 333 334 335 int 336 strvisx(dst, src, len, flag) 337 char *dst; 338 const char *src; 339 size_t len; 340 int flag; 341 { 342 char *extra; 343 344 MAKEEXTRALIST(flag, extra, ""); 345 return (strsvisx(dst, src, len, flag, extra)); 346 } 347 #endif 348