1323129Sdes/* $OpenBSD: vis.c,v 1.25 2015/09/13 11:32:51 guenther Exp $ */ 2113908Sdes/*- 3113908Sdes * Copyright (c) 1989, 1993 4113908Sdes * The Regents of the University of California. All rights reserved. 5113908Sdes * 6113908Sdes * Redistribution and use in source and binary forms, with or without 7113908Sdes * modification, are permitted provided that the following conditions 8113908Sdes * are met: 9113908Sdes * 1. Redistributions of source code must retain the above copyright 10113908Sdes * notice, this list of conditions and the following disclaimer. 11113908Sdes * 2. Redistributions in binary form must reproduce the above copyright 12113908Sdes * notice, this list of conditions and the following disclaimer in the 13113908Sdes * documentation and/or other materials provided with the distribution. 14124208Sdes * 3. Neither the name of the University nor the names of its contributors 15113908Sdes * may be used to endorse or promote products derived from this software 16113908Sdes * without specific prior written permission. 17113908Sdes * 18113908Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19113908Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20113908Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21113908Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22113908Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23113908Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24113908Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25113908Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26113908Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27113908Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28113908Sdes * SUCH DAMAGE. 29113908Sdes */ 30157016Sdes 31157016Sdes/* OPENBSD ORIGINAL: lib/libc/gen/vis.c */ 32157016Sdes 33124208Sdes#include "includes.h" 34248619Sdes#if !defined(HAVE_STRNVIS) || defined(BROKEN_STRNVIS) 35113908Sdes 36323129Sdes#include <sys/types.h> 37323129Sdes#include <errno.h> 38113908Sdes#include <ctype.h> 39323129Sdes#include <limits.h> 40124208Sdes#include <string.h> 41323129Sdes#include <stdlib.h> 42113908Sdes 43113908Sdes#include "vis.h" 44113908Sdes 45113908Sdes#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') 46323129Sdes#define isvisible(c,flag) \ 47323129Sdes (((c) == '\\' || (flag & VIS_ALL) == 0) && \ 48157016Sdes (((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) && \ 49157016Sdes (((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') || \ 50157016Sdes (flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) || \ 51157016Sdes ((flag & VIS_SP) == 0 && (c) == ' ') || \ 52157016Sdes ((flag & VIS_TAB) == 0 && (c) == '\t') || \ 53157016Sdes ((flag & VIS_NL) == 0 && (c) == '\n') || \ 54157016Sdes ((flag & VIS_SAFE) && ((c) == '\b' || \ 55157016Sdes (c) == '\007' || (c) == '\r' || \ 56323129Sdes isgraph((u_char)(c)))))) 57113908Sdes 58113908Sdes/* 59113908Sdes * vis - visually encode characters 60113908Sdes */ 61113908Sdeschar * 62157016Sdesvis(char *dst, int c, int flag, int nextc) 63113908Sdes{ 64323129Sdes if (isvisible(c, flag)) { 65323129Sdes if ((c == '"' && (flag & VIS_DQ) != 0) || 66323129Sdes (c == '\\' && (flag & VIS_NOSLASH) == 0)) 67323129Sdes *dst++ = '\\'; 68113908Sdes *dst++ = c; 69113908Sdes *dst = '\0'; 70113908Sdes return (dst); 71113908Sdes } 72113908Sdes 73113908Sdes if (flag & VIS_CSTYLE) { 74113908Sdes switch(c) { 75113908Sdes case '\n': 76113908Sdes *dst++ = '\\'; 77113908Sdes *dst++ = 'n'; 78113908Sdes goto done; 79113908Sdes case '\r': 80113908Sdes *dst++ = '\\'; 81113908Sdes *dst++ = 'r'; 82113908Sdes goto done; 83113908Sdes case '\b': 84113908Sdes *dst++ = '\\'; 85113908Sdes *dst++ = 'b'; 86113908Sdes goto done; 87113908Sdes case '\a': 88113908Sdes *dst++ = '\\'; 89113908Sdes *dst++ = 'a'; 90113908Sdes goto done; 91113908Sdes case '\v': 92113908Sdes *dst++ = '\\'; 93113908Sdes *dst++ = 'v'; 94113908Sdes goto done; 95113908Sdes case '\t': 96113908Sdes *dst++ = '\\'; 97113908Sdes *dst++ = 't'; 98113908Sdes goto done; 99113908Sdes case '\f': 100113908Sdes *dst++ = '\\'; 101113908Sdes *dst++ = 'f'; 102113908Sdes goto done; 103113908Sdes case ' ': 104113908Sdes *dst++ = '\\'; 105113908Sdes *dst++ = 's'; 106113908Sdes goto done; 107113908Sdes case '\0': 108113908Sdes *dst++ = '\\'; 109113908Sdes *dst++ = '0'; 110113908Sdes if (isoctal(nextc)) { 111113908Sdes *dst++ = '0'; 112113908Sdes *dst++ = '0'; 113113908Sdes } 114113908Sdes goto done; 115113908Sdes } 116113908Sdes } 117157016Sdes if (((c & 0177) == ' ') || (flag & VIS_OCTAL) || 118157016Sdes ((flag & VIS_GLOB) && (c == '*' || c == '?' || c == '[' || c == '#'))) { 119113908Sdes *dst++ = '\\'; 120113908Sdes *dst++ = ((u_char)c >> 6 & 07) + '0'; 121113908Sdes *dst++ = ((u_char)c >> 3 & 07) + '0'; 122113908Sdes *dst++ = ((u_char)c & 07) + '0'; 123113908Sdes goto done; 124113908Sdes } 125113908Sdes if ((flag & VIS_NOSLASH) == 0) 126113908Sdes *dst++ = '\\'; 127113908Sdes if (c & 0200) { 128113908Sdes c &= 0177; 129113908Sdes *dst++ = 'M'; 130113908Sdes } 131157016Sdes if (iscntrl((u_char)c)) { 132113908Sdes *dst++ = '^'; 133113908Sdes if (c == 0177) 134113908Sdes *dst++ = '?'; 135113908Sdes else 136113908Sdes *dst++ = c + '@'; 137113908Sdes } else { 138113908Sdes *dst++ = '-'; 139113908Sdes *dst++ = c; 140113908Sdes } 141113908Sdesdone: 142113908Sdes *dst = '\0'; 143113908Sdes return (dst); 144113908Sdes} 145323129SdesDEF_WEAK(vis); 146113908Sdes 147113908Sdes/* 148113908Sdes * strvis, strnvis, strvisx - visually encode characters from src into dst 149113908Sdes * 150113908Sdes * Dst must be 4 times the size of src to account for possible 151113908Sdes * expansion. The length of dst, not including the trailing NULL, 152113908Sdes * is returned. 153113908Sdes * 154113908Sdes * Strnvis will write no more than siz-1 bytes (and will NULL terminate). 155113908Sdes * The number of bytes needed to fully encode the string is returned. 156113908Sdes * 157113908Sdes * Strvisx encodes exactly len bytes from src into dst. 158113908Sdes * This is useful for encoding a block of data. 159113908Sdes */ 160113908Sdesint 161157016Sdesstrvis(char *dst, const char *src, int flag) 162113908Sdes{ 163157016Sdes char c; 164113908Sdes char *start; 165113908Sdes 166113908Sdes for (start = dst; (c = *src);) 167113908Sdes dst = vis(dst, c, flag, *++src); 168113908Sdes *dst = '\0'; 169113908Sdes return (dst - start); 170113908Sdes} 171323129SdesDEF_WEAK(strvis); 172113908Sdes 173113908Sdesint 174157016Sdesstrnvis(char *dst, const char *src, size_t siz, int flag) 175113908Sdes{ 176113908Sdes char *start, *end; 177124208Sdes char tbuf[5]; 178157016Sdes int c, i; 179113908Sdes 180124208Sdes i = 0; 181113908Sdes for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) { 182323129Sdes if (isvisible(c, flag)) { 183323129Sdes if ((c == '"' && (flag & VIS_DQ) != 0) || 184323129Sdes (c == '\\' && (flag & VIS_NOSLASH) == 0)) { 185113908Sdes /* need space for the extra '\\' */ 186323129Sdes if (dst + 1 >= end) { 187124208Sdes i = 2; 188113908Sdes break; 189113908Sdes } 190323129Sdes *dst++ = '\\'; 191113908Sdes } 192323129Sdes i = 1; 193323129Sdes *dst++ = c; 194113908Sdes src++; 195113908Sdes } else { 196124208Sdes i = vis(tbuf, c, flag, *++src) - tbuf; 197124208Sdes if (dst + i <= end) { 198124208Sdes memcpy(dst, tbuf, i); 199124208Sdes dst += i; 200124208Sdes } else { 201124208Sdes src--; 202113908Sdes break; 203124208Sdes } 204113908Sdes } 205113908Sdes } 206124208Sdes if (siz > 0) 207124208Sdes *dst = '\0'; 208124208Sdes if (dst + i > end) { 209113908Sdes /* adjust return value for truncation */ 210113908Sdes while ((c = *src)) 211113908Sdes dst += vis(tbuf, c, flag, *++src) - tbuf; 212113908Sdes } 213113908Sdes return (dst - start); 214113908Sdes} 215113908Sdes 216113908Sdesint 217323129Sdesstravis(char **outp, const char *src, int flag) 218323129Sdes{ 219323129Sdes char *buf; 220323129Sdes int len, serrno; 221323129Sdes 222323129Sdes buf = reallocarray(NULL, 4, strlen(src) + 1); 223323129Sdes if (buf == NULL) 224323129Sdes return -1; 225323129Sdes len = strvis(buf, src, flag); 226323129Sdes serrno = errno; 227323129Sdes *outp = realloc(buf, len + 1); 228323129Sdes if (*outp == NULL) { 229323129Sdes *outp = buf; 230323129Sdes errno = serrno; 231323129Sdes } 232323129Sdes return (len); 233323129Sdes} 234323129Sdes 235323129Sdesint 236157016Sdesstrvisx(char *dst, const char *src, size_t len, int flag) 237113908Sdes{ 238157016Sdes char c; 239113908Sdes char *start; 240113908Sdes 241113908Sdes for (start = dst; len > 1; len--) { 242113908Sdes c = *src; 243113908Sdes dst = vis(dst, c, flag, *++src); 244113908Sdes } 245113908Sdes if (len) 246113908Sdes dst = vis(dst, *src, flag, '\0'); 247113908Sdes *dst = '\0'; 248113908Sdes return (dst - start); 249113908Sdes} 250113908Sdes 251113908Sdes#endif 252