1 /*- 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * Defived from FreeBSD head/lib/libc/gen/vis.c 165903, head/include/vis.h 30 * 203964. 31 */ 32 33 #include <sys/types.h> 34 #include <limits.h> 35 #include <ctype.h> 36 #include <stdio.h> 37 38 /* 39 * to select alternate encoding format 40 */ 41 #define VIS_OCTAL 0x01 /* use octal \ddd format */ 42 #define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */ 43 44 /* 45 * to alter set of characters encoded (default is to encode all 46 * non-graphic except space, tab, and newline). 47 */ 48 #define VIS_SP 0x04 /* also encode space */ 49 #define VIS_TAB 0x08 /* also encode tab */ 50 #define VIS_NL 0x10 /* also encode newline */ 51 #define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) 52 #define VIS_SAFE 0x20 /* only encode "unsafe" characters */ 53 54 /* 55 * other 56 */ 57 #define VIS_NOSLASH 0x40 /* inhibit printing '\' */ 58 #define VIS_HTTPSTYLE 0x80 /* http-style escape % HEX HEX */ 59 #define VIS_GLOB 0x100 /* encode glob(3) magics */ 60 61 /* 62 * unvis return codes 63 */ 64 #define UNVIS_VALID 1 /* character valid */ 65 #define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ 66 #define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ 67 #define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ 68 #define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ 69 70 /* 71 * unvis flags 72 */ 73 #define UNVIS_END 1 /* no more characters */ 74 75 #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') 76 77 /* 78 * vis - visually encode characters 79 */ 80 char * 81 vis(dst, c, flag, nextc) 82 char *dst; 83 int c, nextc; 84 int flag; 85 { 86 c = (unsigned char)c; 87 88 if (flag & VIS_HTTPSTYLE) { 89 /* Described in RFC 1808 */ 90 if (!(isalnum(c) /* alpha-numeric */ 91 /* safe */ 92 || c == '$' || c == '-' || c == '_' || c == '.' || c == '+' 93 /* extra */ 94 || c == '!' || c == '*' || c == '\'' || c == '(' 95 || c == ')' || c == ',')) { 96 *dst++ = '%'; 97 snprintf(dst, 4, (c < 16 ? "0%X" : "%X"), c); 98 dst += 2; 99 goto done; 100 } 101 } 102 103 if ((flag & VIS_GLOB) && 104 (c == '*' || c == '?' || c == '[' || c == '#')) 105 ; 106 else if (isgraph(c) || 107 ((flag & VIS_SP) == 0 && c == ' ') || 108 ((flag & VIS_TAB) == 0 && c == '\t') || 109 ((flag & VIS_NL) == 0 && c == '\n') || 110 ((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) { 111 *dst++ = c; 112 if (c == '\\' && (flag & VIS_NOSLASH) == 0) 113 *dst++ = '\\'; 114 *dst = '\0'; 115 return (dst); 116 } 117 118 if (flag & VIS_CSTYLE) { 119 switch(c) { 120 case '\n': 121 *dst++ = '\\'; 122 *dst++ = 'n'; 123 goto done; 124 case '\r': 125 *dst++ = '\\'; 126 *dst++ = 'r'; 127 goto done; 128 case '\b': 129 *dst++ = '\\'; 130 *dst++ = 'b'; 131 goto done; 132 case '\a': 133 *dst++ = '\\'; 134 *dst++ = 'a'; 135 goto done; 136 case '\v': 137 *dst++ = '\\'; 138 *dst++ = 'v'; 139 goto done; 140 case '\t': 141 *dst++ = '\\'; 142 *dst++ = 't'; 143 goto done; 144 case '\f': 145 *dst++ = '\\'; 146 *dst++ = 'f'; 147 goto done; 148 case ' ': 149 *dst++ = '\\'; 150 *dst++ = 's'; 151 goto done; 152 case '\0': 153 *dst++ = '\\'; 154 *dst++ = '0'; 155 if (isoctal(nextc)) { 156 *dst++ = '0'; 157 *dst++ = '0'; 158 } 159 goto done; 160 } 161 } 162 if (((c & 0177) == ' ') || isgraph(c) || (flag & VIS_OCTAL)) { 163 *dst++ = '\\'; 164 *dst++ = ((u_char)c >> 6 & 07) + '0'; 165 *dst++ = ((u_char)c >> 3 & 07) + '0'; 166 *dst++ = ((u_char)c & 07) + '0'; 167 goto done; 168 } 169 if ((flag & VIS_NOSLASH) == 0) 170 *dst++ = '\\'; 171 if (c & 0200) { 172 c &= 0177; 173 *dst++ = 'M'; 174 } 175 if (iscntrl(c)) { 176 *dst++ = '^'; 177 if (c == 0177) 178 *dst++ = '?'; 179 else 180 *dst++ = c + '@'; 181 } else { 182 *dst++ = '-'; 183 *dst++ = c; 184 } 185 done: 186 *dst = '\0'; 187 return (dst); 188 } 189