1 /* $OpenBSD: vis.c,v 1.26 2022/05/04 18:57:50 deraadt Exp $ */ 2 /*- 3 * Copyright (c) 1989, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/types.h> 32 #include <errno.h> 33 #include <ctype.h> 34 #include <limits.h> 35 #include <string.h> 36 #include <stdlib.h> 37 #include <vis.h> 38 39 static int 40 isoctal(int c) 41 { 42 u_char uc = c; 43 44 return uc >= '0' && uc <= '7'; 45 } 46 47 static int 48 isvisible(int c, int flag) 49 { 50 int vis_sp = flag & VIS_SP; 51 int vis_tab = flag & VIS_TAB; 52 int vis_nl = flag & VIS_NL; 53 int vis_safe = flag & VIS_SAFE; 54 int vis_glob = flag & VIS_GLOB; 55 int vis_all = flag & VIS_ALL; 56 u_char uc = c; 57 58 if (c == '\\' || !vis_all) { 59 if ((u_int)c <= UCHAR_MAX && isascii(uc) && 60 ((c != '*' && c != '?' && c != '[' && c != '#') || !vis_glob) && 61 isgraph(uc)) 62 return 1; 63 if (!vis_sp && c == ' ') 64 return 1; 65 if (!vis_tab && c == '\t') 66 return 1; 67 if (!vis_nl && c == '\n') 68 return 1; 69 if (vis_safe && (c == '\b' || c == '\007' || c == '\r' || isgraph(uc))) 70 return 1; 71 } 72 return 0; 73 } 74 75 /* 76 * vis - visually encode characters 77 */ 78 char * 79 vis(char *dst, int c, int flag, int nextc) 80 { 81 int vis_dq = flag & VIS_DQ; 82 int vis_noslash = flag & VIS_NOSLASH; 83 int vis_cstyle = flag & VIS_CSTYLE; 84 int vis_octal = flag & VIS_OCTAL; 85 int vis_glob = flag & VIS_GLOB; 86 87 if (isvisible(c, flag)) { 88 if ((c == '"' && vis_dq) || 89 (c == '\\' && !vis_noslash)) 90 *dst++ = '\\'; 91 *dst++ = c; 92 *dst = '\0'; 93 return (dst); 94 } 95 96 if (vis_cstyle) { 97 switch (c) { 98 case '\n': 99 *dst++ = '\\'; 100 *dst++ = 'n'; 101 goto done; 102 case '\r': 103 *dst++ = '\\'; 104 *dst++ = 'r'; 105 goto done; 106 case '\b': 107 *dst++ = '\\'; 108 *dst++ = 'b'; 109 goto done; 110 case '\a': 111 *dst++ = '\\'; 112 *dst++ = 'a'; 113 goto done; 114 case '\v': 115 *dst++ = '\\'; 116 *dst++ = 'v'; 117 goto done; 118 case '\t': 119 *dst++ = '\\'; 120 *dst++ = 't'; 121 goto done; 122 case '\f': 123 *dst++ = '\\'; 124 *dst++ = 'f'; 125 goto done; 126 case ' ': 127 *dst++ = '\\'; 128 *dst++ = 's'; 129 goto done; 130 case '\0': 131 *dst++ = '\\'; 132 *dst++ = '0'; 133 if (isoctal(nextc)) { 134 *dst++ = '0'; 135 *dst++ = '0'; 136 } 137 goto done; 138 } 139 } 140 if (((c & 0177) == ' ') || vis_octal || 141 (vis_glob && (c == '*' || c == '?' || c == '[' || c == '#'))) { 142 *dst++ = '\\'; 143 *dst++ = ((u_char)c >> 6 & 07) + '0'; 144 *dst++ = ((u_char)c >> 3 & 07) + '0'; 145 *dst++ = ((u_char)c & 07) + '0'; 146 goto done; 147 } 148 if (!vis_noslash) 149 *dst++ = '\\'; 150 if (c & 0200) { 151 c &= 0177; 152 *dst++ = 'M'; 153 } 154 if (iscntrl((u_char)c)) { 155 *dst++ = '^'; 156 if (c == 0177) 157 *dst++ = '?'; 158 else 159 *dst++ = c + '@'; 160 } else { 161 *dst++ = '-'; 162 *dst++ = c; 163 } 164 done: 165 *dst = '\0'; 166 return (dst); 167 } 168 DEF_WEAK(vis); 169 170 /* 171 * strvis, strnvis, strvisx - visually encode characters from src into dst 172 * 173 * Dst must be 4 times the size of src to account for possible 174 * expansion. The length of dst, not including the trailing NULL, 175 * is returned. 176 * 177 * Strnvis will write no more than siz-1 bytes (and will NULL terminate). 178 * The number of bytes needed to fully encode the string is returned. 179 * 180 * Strvisx encodes exactly len bytes from src into dst. 181 * This is useful for encoding a block of data. 182 */ 183 int 184 strvis(char *dst, const char *src, int flag) 185 { 186 char c; 187 char *start; 188 189 for (start = dst; (c = *src);) 190 dst = vis(dst, c, flag, *++src); 191 *dst = '\0'; 192 return (dst - start); 193 } 194 DEF_WEAK(strvis); 195 196 int 197 strnvis(char *dst, const char *src, size_t siz, int flag) 198 { 199 int vis_dq = flag & VIS_DQ; 200 int vis_noslash = flag & VIS_NOSLASH; 201 char *start, *end; 202 char tbuf[5]; 203 int c, i; 204 205 i = 0; 206 for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) { 207 if (isvisible(c, flag)) { 208 if ((c == '"' && vis_dq) || 209 (c == '\\' && !vis_noslash)) { 210 /* need space for the extra '\\' */ 211 if (dst + 1 >= end) { 212 i = 2; 213 break; 214 } 215 *dst++ = '\\'; 216 } 217 i = 1; 218 *dst++ = c; 219 src++; 220 } else { 221 i = vis(tbuf, c, flag, *++src) - tbuf; 222 if (dst + i <= end) { 223 memcpy(dst, tbuf, i); 224 dst += i; 225 } else { 226 src--; 227 break; 228 } 229 } 230 } 231 if (siz > 0) 232 *dst = '\0'; 233 if (dst + i > end) { 234 /* adjust return value for truncation */ 235 while ((c = *src)) 236 dst += vis(tbuf, c, flag, *++src) - tbuf; 237 } 238 return (dst - start); 239 } 240 241 int 242 stravis(char **outp, const char *src, int flag) 243 { 244 char *buf; 245 int len, serrno; 246 247 buf = reallocarray(NULL, 4, strlen(src) + 1); 248 if (buf == NULL) 249 return -1; 250 len = strvis(buf, src, flag); 251 serrno = errno; 252 *outp = realloc(buf, len + 1); 253 if (*outp == NULL) { 254 *outp = buf; 255 errno = serrno; 256 } 257 return (len); 258 } 259 260 int 261 strvisx(char *dst, const char *src, size_t len, int flag) 262 { 263 char c; 264 char *start; 265 266 for (start = dst; len > 1; len--) { 267 c = *src; 268 dst = vis(dst, c, flag, *++src); 269 } 270 if (len) 271 dst = vis(dst, *src, flag, '\0'); 272 *dst = '\0'; 273 return (dst - start); 274 } 275