1233294Sstas/* $NetBSD: vis.c,v 1.37 2008/07/25 22:29:23 dsl Exp $ */ 272445Sassar 372445Sassar/*- 472445Sassar * Copyright (c) 1989, 1993 572445Sassar * The Regents of the University of California. All rights reserved. 672445Sassar * 772445Sassar * Redistribution and use in source and binary forms, with or without 872445Sassar * modification, are permitted provided that the following conditions 972445Sassar * are met: 1072445Sassar * 1. Redistributions of source code must retain the above copyright 1172445Sassar * notice, this list of conditions and the following disclaimer. 1272445Sassar * 2. Redistributions in binary form must reproduce the above copyright 1372445Sassar * notice, this list of conditions and the following disclaimer in the 1472445Sassar * documentation and/or other materials provided with the distribution. 15178825Sdfr * 3. Neither the name of the University nor the names of its contributors 16178825Sdfr * may be used to endorse or promote products derived from this software 17178825Sdfr * without specific prior written permission. 18178825Sdfr * 19178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29178825Sdfr * SUCH DAMAGE. 30178825Sdfr */ 31178825Sdfr 32178825Sdfr/*- 33233294Sstas * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc. 34233294Sstas * All rights reserved. 35178825Sdfr * 36178825Sdfr * Redistribution and use in source and binary forms, with or without 37178825Sdfr * modification, are permitted provided that the following conditions 38178825Sdfr * are met: 39178825Sdfr * 1. Redistributions of source code must retain the above copyright 40178825Sdfr * notice, this list of conditions and the following disclaimer. 41178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 42178825Sdfr * notice, this list of conditions and the following disclaimer in the 43178825Sdfr * documentation and/or other materials provided with the distribution. 4472445Sassar * 45233294Sstas * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 46233294Sstas * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 47233294Sstas * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 48233294Sstas * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 49233294Sstas * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 50233294Sstas * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 51233294Sstas * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 52233294Sstas * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 53233294Sstas * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54233294Sstas * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 55233294Sstas * POSSIBILITY OF SUCH DAMAGE. 5672445Sassar */ 5772445Sassar 5872445Sassar#if 1 5972445Sassar#include <config.h> 60178825Sdfr#include "roken.h" 6172445Sassar#ifndef _DIAGASSERT 6272445Sassar#define _DIAGASSERT(X) 6372445Sassar#endif 64233294Sstas#else /* heimdal */ 6572445Sassar#include <sys/cdefs.h> 66233294Sstas#if defined(LIBC_SCCS) && !defined(lint) 67233294Sstas__RCSID("$NetBSD: vis.c,v 1.37 2008/07/25 22:29:23 dsl Exp $"); 68233294Sstas#endif /* LIBC_SCCS and not lint */ 6972445Sassar 7072445Sassar#include "namespace.h" 71233294Sstas#endif /* heimdal */ 72233294Sstas 7372445Sassar#include <sys/types.h> 7472445Sassar 7572445Sassar#include <assert.h> 7672445Sassar#include <ctype.h> 7772445Sassar#include <limits.h> 7872445Sassar#include <stdio.h> 7972445Sassar#include <string.h> 8072445Sassar#include <vis.h> 81233294Sstas#include <stdlib.h> 8272445Sassar 8372445Sassar#if 0 8472445Sassar#ifdef __weak_alias 8572445Sassar__weak_alias(strsvis,_strsvis) 8672445Sassar__weak_alias(strsvisx,_strsvisx) 8772445Sassar__weak_alias(strvis,_strvis) 8872445Sassar__weak_alias(strvisx,_strvisx) 8972445Sassar__weak_alias(svis,_svis) 9072445Sassar__weak_alias(vis,_vis) 9172445Sassar#endif 9272445Sassar#endif 9372445Sassar 94233294Sstas#if !HAVE_VIS || !HAVE_SVIS 95233294Sstas#include <ctype.h> 96233294Sstas#include <limits.h> 97233294Sstas#include <stdio.h> 98233294Sstas#include <string.h> 99233294Sstas 100233294Sstasstatic char *do_svis(char *, int, int, int, const char *); 101233294Sstas 10272445Sassar#undef BELL 10372445Sassar#if defined(__STDC__) 10472445Sassar#define BELL '\a' 10572445Sassar#else 10672445Sassar#define BELL '\007' 10772445Sassar#endif 10872445Sassar 109233294SstasROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL 110233294Sstas rk_vis (char *, int, int, int); 111233294SstasROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL 112233294Sstas rk_svis (char *, int, int, int, const char *); 113233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 114178825Sdfr rk_strvis (char *, const char *, int); 115233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 116178825Sdfr rk_strsvis (char *, const char *, int, const char *); 117233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 118178825Sdfr rk_strvisx (char *, const char *, size_t, int); 119233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 120178825Sdfr rk_strsvisx (char *, const char *, size_t, int, const char *); 121178825Sdfr 122178825Sdfr 12372445Sassar#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') 12472445Sassar#define iswhite(c) (c == ' ' || c == '\t' || c == '\n') 12572445Sassar#define issafe(c) (c == '\b' || c == BELL || c == '\r') 126233294Sstas#define xtoa(c) "0123456789abcdef"[c] 12772445Sassar 128233294Sstas#define MAXEXTRAS 5 12972445Sassar 130233294Sstas#define MAKEEXTRALIST(flag, extra, orig_str) \ 13172445Sassardo { \ 132233294Sstas const char *orig = orig_str; \ 133233294Sstas const char *o = orig; \ 134233294Sstas char *e; \ 135233294Sstas while (*o++) \ 136233294Sstas continue; \ 137233294Sstas extra = malloc((size_t)((o - orig) + MAXEXTRAS)); \ 138233294Sstas if (!extra) break; \ 139233294Sstas for (o = orig, e = extra; (*e++ = *o++) != '\0';) \ 140233294Sstas continue; \ 141233294Sstas e--; \ 142233294Sstas if (flag & VIS_SP) *e++ = ' '; \ 143233294Sstas if (flag & VIS_TAB) *e++ = '\t'; \ 144233294Sstas if (flag & VIS_NL) *e++ = '\n'; \ 145233294Sstas if ((flag & VIS_NOSLASH) == 0) *e++ = '\\'; \ 146233294Sstas *e = '\0'; \ 14772445Sassar} while (/*CONSTCOND*/0) 14872445Sassar 14972445Sassar/* 150233294Sstas * This is do_hvis, for HTTP style (RFC 1808) 151233294Sstas */ 152233294Sstasstatic char * 153233294Sstasdo_hvis(char *dst, int c, int flag, int nextc, const char *extra) 154233294Sstas{ 155233294Sstas if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) { 156233294Sstas *dst++ = '%'; 157233294Sstas *dst++ = xtoa(((unsigned int)c >> 4) & 0xf); 158233294Sstas *dst++ = xtoa((unsigned int)c & 0xf); 159233294Sstas } else { 160233294Sstas dst = do_svis(dst, c, flag, nextc, extra); 161233294Sstas } 162233294Sstas return dst; 163233294Sstas} 164233294Sstas 165233294Sstas/* 166233294Sstas * This is do_vis, the central code of vis. 16772445Sassar * dst: Pointer to the destination buffer 16872445Sassar * c: Character to encode 16972445Sassar * flag: Flag word 17072445Sassar * nextc: The character following 'c' 17172445Sassar * extra: Pointer to the list of extra characters to be 17272445Sassar * backslash-protected. 17372445Sassar */ 174233294Sstasstatic char * 175233294Sstasdo_svis(char *dst, int c, int flag, int nextc, const char *extra) 176233294Sstas{ 177233294Sstas int isextra; 178233294Sstas isextra = strchr(extra, c) != NULL; 179233294Sstas if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) || 180233294Sstas ((flag & VIS_SAFE) && issafe(c)))) { 181233294Sstas *dst++ = c; 182233294Sstas return dst; 183233294Sstas } 184233294Sstas if (flag & VIS_CSTYLE) { 185233294Sstas switch (c) { 186233294Sstas case '\n': 187233294Sstas *dst++ = '\\'; *dst++ = 'n'; 188233294Sstas return dst; 189233294Sstas case '\r': 190233294Sstas *dst++ = '\\'; *dst++ = 'r'; 191233294Sstas return dst; 192233294Sstas case '\b': 193233294Sstas *dst++ = '\\'; *dst++ = 'b'; 194233294Sstas return dst; 195233294Sstas case BELL: 196233294Sstas *dst++ = '\\'; *dst++ = 'a'; 197233294Sstas return dst; 198233294Sstas case '\v': 199233294Sstas *dst++ = '\\'; *dst++ = 'v'; 200233294Sstas return dst; 201233294Sstas case '\t': 202233294Sstas *dst++ = '\\'; *dst++ = 't'; 203233294Sstas return dst; 204233294Sstas case '\f': 205233294Sstas *dst++ = '\\'; *dst++ = 'f'; 206233294Sstas return dst; 207233294Sstas case ' ': 208233294Sstas *dst++ = '\\'; *dst++ = 's'; 209233294Sstas return dst; 210233294Sstas case '\0': 211233294Sstas *dst++ = '\\'; *dst++ = '0'; 212233294Sstas if (isoctal(nextc)) { 213233294Sstas *dst++ = '0'; 214233294Sstas *dst++ = '0'; 215233294Sstas } 216233294Sstas return dst; 217233294Sstas default: 218233294Sstas if (isgraph(c)) { 219233294Sstas *dst++ = '\\'; *dst++ = c; 220233294Sstas return dst; 221233294Sstas } 222233294Sstas } 223233294Sstas } 224233294Sstas if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) { 225233294Sstas *dst++ = '\\'; 226233294Sstas *dst++ = (u_char)(((unsigned int)(u_char)c >> 6) & 03) + '0'; 227233294Sstas *dst++ = (u_char)(((unsigned int)(u_char)c >> 3) & 07) + '0'; 228233294Sstas *dst++ = (u_char)( c & 07) + '0'; 229233294Sstas } else { 230233294Sstas if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\'; 231233294Sstas if (c & 0200) { 232233294Sstas c &= 0177; *dst++ = 'M'; 233233294Sstas } 234233294Sstas if (iscntrl(c)) { 235233294Sstas *dst++ = '^'; 236233294Sstas if (c == 0177) 237233294Sstas *dst++ = '?'; 238233294Sstas else 239233294Sstas *dst++ = c + '@'; 240233294Sstas } else { 241233294Sstas *dst++ = '-'; *dst++ = c; 242233294Sstas } 243233294Sstas } 244233294Sstas return dst; 245233294Sstas} 24672445Sassar 24772445Sassar 24872445Sassar/* 24972445Sassar * svis - visually encode characters, also encoding the characters 250233294Sstas * pointed to by `extra' 25172445Sassar */ 252233294SstasROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL 253178825Sdfrrk_svis(char *dst, int c, int flag, int nextc, const char *extra) 25472445Sassar{ 255233294Sstas char *nextra = NULL; 256233294Sstas 25772445Sassar _DIAGASSERT(dst != NULL); 25872445Sassar _DIAGASSERT(extra != NULL); 259233294Sstas MAKEEXTRALIST(flag, nextra, extra); 260233294Sstas if (!nextra) { 261233294Sstas *dst = '\0'; /* can't create nextra, return "" */ 262233294Sstas return dst; 263233294Sstas } 264233294Sstas if (flag & VIS_HTTPSTYLE) 265233294Sstas dst = do_hvis(dst, c, flag, nextc, nextra); 266233294Sstas else 267233294Sstas dst = do_svis(dst, c, flag, nextc, nextra); 268233294Sstas free(nextra); 26972445Sassar *dst = '\0'; 270233294Sstas return dst; 27172445Sassar} 27272445Sassar 27372445Sassar 27472445Sassar/* 27572445Sassar * strsvis, strsvisx - visually encode characters from src into dst 27672445Sassar * 27772445Sassar * Extra is a pointer to a \0-terminated list of characters to 27872445Sassar * be encoded, too. These functions are useful e. g. to 27972445Sassar * encode strings in such a way so that they are not interpreted 28072445Sassar * by a shell. 281233294Sstas * 28272445Sassar * Dst must be 4 times the size of src to account for possible 28372445Sassar * expansion. The length of dst, not including the trailing NULL, 284233294Sstas * is returned. 28572445Sassar * 28672445Sassar * Strsvisx encodes exactly len bytes from src into dst. 28772445Sassar * This is useful for encoding a block of data. 28872445Sassar */ 289178825Sdfr 290233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 291233294Sstasrk_strsvis(char *dst, const char *csrc, int flag, const char *extra) 29272445Sassar{ 293233294Sstas int c; 29472445Sassar char *start; 295233294Sstas char *nextra = NULL; 296233294Sstas const unsigned char *src = (const unsigned char *)csrc; 29772445Sassar 29872445Sassar _DIAGASSERT(dst != NULL); 29972445Sassar _DIAGASSERT(src != NULL); 30072445Sassar _DIAGASSERT(extra != NULL); 301233294Sstas MAKEEXTRALIST(flag, nextra, extra); 302233294Sstas if (!nextra) { 303233294Sstas *dst = '\0'; /* can't create nextra, return "" */ 304233294Sstas return 0; 305233294Sstas } 306233294Sstas if (flag & VIS_HTTPSTYLE) { 307233294Sstas for (start = dst; (c = *src++) != '\0'; /* empty */) 308233294Sstas dst = do_hvis(dst, c, flag, *src, nextra); 309233294Sstas } else { 310233294Sstas for (start = dst; (c = *src++) != '\0'; /* empty */) 311233294Sstas dst = do_svis(dst, c, flag, *src, nextra); 312233294Sstas } 313233294Sstas free(nextra); 31472445Sassar *dst = '\0'; 31572445Sassar return (dst - start); 31672445Sassar} 31772445Sassar 31872445Sassar 319233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 320233294Sstasrk_strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra) 32172445Sassar{ 322233294Sstas unsigned char c; 32372445Sassar char *start; 324233294Sstas char *nextra = NULL; 325233294Sstas const unsigned char *src = (const unsigned char *)csrc; 32672445Sassar 32772445Sassar _DIAGASSERT(dst != NULL); 32872445Sassar _DIAGASSERT(src != NULL); 32972445Sassar _DIAGASSERT(extra != NULL); 330233294Sstas MAKEEXTRALIST(flag, nextra, extra); 331233294Sstas if (! nextra) { 332233294Sstas *dst = '\0'; /* can't create nextra, return "" */ 333233294Sstas return 0; 334233294Sstas } 33572445Sassar 336233294Sstas if (flag & VIS_HTTPSTYLE) { 337233294Sstas for (start = dst; len > 0; len--) { 338233294Sstas c = *src++; 339233294Sstas dst = do_hvis(dst, c, flag, len ? *src : '\0', nextra); 340233294Sstas } 341233294Sstas } else { 342233294Sstas for (start = dst; len > 0; len--) { 343233294Sstas c = *src++; 344233294Sstas dst = do_svis(dst, c, flag, len ? *src : '\0', nextra); 345233294Sstas } 34672445Sassar } 347233294Sstas free(nextra); 34872445Sassar *dst = '\0'; 34972445Sassar return (dst - start); 35072445Sassar} 351233294Sstas#endif 35272445Sassar 353233294Sstas#if !HAVE_VIS 35472445Sassar/* 35572445Sassar * vis - visually encode characters 35672445Sassar */ 357233294SstasROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL 358178825Sdfrrk_vis(char *dst, int c, int flag, int nextc) 35972445Sassar{ 360233294Sstas char *extra = NULL; 361233294Sstas unsigned char uc = (unsigned char)c; 36272445Sassar 36372445Sassar _DIAGASSERT(dst != NULL); 36472445Sassar 365233294Sstas MAKEEXTRALIST(flag, extra, ""); 366233294Sstas if (! extra) { 367233294Sstas *dst = '\0'; /* can't create extra, return "" */ 368233294Sstas return dst; 369233294Sstas } 370233294Sstas if (flag & VIS_HTTPSTYLE) 371233294Sstas dst = do_hvis(dst, uc, flag, nextc, extra); 372233294Sstas else 373233294Sstas dst = do_svis(dst, uc, flag, nextc, extra); 374233294Sstas free(extra); 37572445Sassar *dst = '\0'; 376233294Sstas return dst; 37772445Sassar} 37872445Sassar 37972445Sassar 38072445Sassar/* 38172445Sassar * strvis, strvisx - visually encode characters from src into dst 382233294Sstas * 38372445Sassar * Dst must be 4 times the size of src to account for possible 38472445Sassar * expansion. The length of dst, not including the trailing NULL, 385233294Sstas * is returned. 38672445Sassar * 38772445Sassar * Strvisx encodes exactly len bytes from src into dst. 38872445Sassar * This is useful for encoding a block of data. 38972445Sassar */ 390233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 391178825Sdfrrk_strvis(char *dst, const char *src, int flag) 39272445Sassar{ 393233294Sstas char *extra = NULL; 394233294Sstas int rv; 39572445Sassar 396233294Sstas MAKEEXTRALIST(flag, extra, ""); 397233294Sstas if (!extra) { 398233294Sstas *dst = '\0'; /* can't create extra, return "" */ 399233294Sstas return 0; 400233294Sstas } 401233294Sstas rv = strsvis(dst, src, flag, extra); 402233294Sstas free(extra); 403233294Sstas return rv; 40472445Sassar} 40572445Sassar 40672445Sassar 407233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 408178825Sdfrrk_strvisx(char *dst, const char *src, size_t len, int flag) 40972445Sassar{ 410233294Sstas char *extra = NULL; 411233294Sstas int rv; 41272445Sassar 413233294Sstas MAKEEXTRALIST(flag, extra, ""); 414233294Sstas if (!extra) { 415233294Sstas *dst = '\0'; /* can't create extra, return "" */ 416233294Sstas return 0; 417233294Sstas } 418233294Sstas rv = strsvisx(dst, src, len, flag, extra); 419233294Sstas free(extra); 420233294Sstas return rv; 42172445Sassar} 422233294Sstas#endif 423