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