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 30 #if defined(LIBC_SCCS) && !defined(lint) 31 static char rcsid[] = "$OpenBSD: unvis.c,v 1.8 2003/06/02 20:18:35 millert Exp $"; 32 #endif /* LIBC_SCCS and not lint */ 33 34 #include <sys/types.h> 35 #include <ctype.h> 36 #include <vis.h> 37 38 /* 39 * decode driven by state machine 40 */ 41 #define S_GROUND 0 /* haven't seen escape char */ 42 #define S_START 1 /* start decoding special sequence */ 43 #define S_META 2 /* metachar started (M) */ 44 #define S_META1 3 /* metachar more, regular char (-) */ 45 #define S_CTRL 4 /* control char started (^) */ 46 #define S_OCTAL2 5 /* octal digit 2 */ 47 #define S_OCTAL3 6 /* octal digit 3 */ 48 49 #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') 50 51 /* 52 * unvis - decode characters previously encoded by vis 53 */ 54 int 55 unvis(char *cp, char c, int *astate, int flag) 56 { 57 58 if (flag & UNVIS_END) { 59 if (*astate == S_OCTAL2 || *astate == S_OCTAL3) { 60 *astate = S_GROUND; 61 return (UNVIS_VALID); 62 } 63 return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD); 64 } 65 66 switch (*astate) { 67 68 case S_GROUND: 69 *cp = 0; 70 if (c == '\\') { 71 *astate = S_START; 72 return (0); 73 } 74 *cp = c; 75 return (UNVIS_VALID); 76 77 case S_START: 78 switch(c) { 79 case '\\': 80 *cp = c; 81 *astate = S_GROUND; 82 return (UNVIS_VALID); 83 case '0': case '1': case '2': case '3': 84 case '4': case '5': case '6': case '7': 85 *cp = (c - '0'); 86 *astate = S_OCTAL2; 87 return (0); 88 case 'M': 89 *cp = (char) 0200; 90 *astate = S_META; 91 return (0); 92 case '^': 93 *astate = S_CTRL; 94 return (0); 95 case 'n': 96 *cp = '\n'; 97 *astate = S_GROUND; 98 return (UNVIS_VALID); 99 case 'r': 100 *cp = '\r'; 101 *astate = S_GROUND; 102 return (UNVIS_VALID); 103 case 'b': 104 *cp = '\b'; 105 *astate = S_GROUND; 106 return (UNVIS_VALID); 107 case 'a': 108 *cp = '\007'; 109 *astate = S_GROUND; 110 return (UNVIS_VALID); 111 case 'v': 112 *cp = '\v'; 113 *astate = S_GROUND; 114 return (UNVIS_VALID); 115 case 't': 116 *cp = '\t'; 117 *astate = S_GROUND; 118 return (UNVIS_VALID); 119 case 'f': 120 *cp = '\f'; 121 *astate = S_GROUND; 122 return (UNVIS_VALID); 123 case 's': 124 *cp = ' '; 125 *astate = S_GROUND; 126 return (UNVIS_VALID); 127 case 'E': 128 *cp = '\033'; 129 *astate = S_GROUND; 130 return (UNVIS_VALID); 131 case '\n': 132 /* 133 * hidden newline 134 */ 135 *astate = S_GROUND; 136 return (UNVIS_NOCHAR); 137 case '$': 138 /* 139 * hidden marker 140 */ 141 *astate = S_GROUND; 142 return (UNVIS_NOCHAR); 143 } 144 *astate = S_GROUND; 145 return (UNVIS_SYNBAD); 146 147 case S_META: 148 if (c == '-') 149 *astate = S_META1; 150 else if (c == '^') 151 *astate = S_CTRL; 152 else { 153 *astate = S_GROUND; 154 return (UNVIS_SYNBAD); 155 } 156 return (0); 157 158 case S_META1: 159 *astate = S_GROUND; 160 *cp |= c; 161 return (UNVIS_VALID); 162 163 case S_CTRL: 164 if (c == '?') 165 *cp |= 0177; 166 else 167 *cp |= c & 037; 168 *astate = S_GROUND; 169 return (UNVIS_VALID); 170 171 case S_OCTAL2: /* second possible octal digit */ 172 if (isoctal(c)) { 173 /* 174 * yes - and maybe a third 175 */ 176 *cp = (*cp << 3) + (c - '0'); 177 *astate = S_OCTAL3; 178 return (0); 179 } 180 /* 181 * no - done with current sequence, push back passed char 182 */ 183 *astate = S_GROUND; 184 return (UNVIS_VALIDPUSH); 185 186 case S_OCTAL3: /* third possible octal digit */ 187 *astate = S_GROUND; 188 if (isoctal(c)) { 189 *cp = (*cp << 3) + (c - '0'); 190 return (UNVIS_VALID); 191 } 192 /* 193 * we were done, push back passed char 194 */ 195 return (UNVIS_VALIDPUSH); 196 197 default: 198 /* 199 * decoder in unknown state - (probably uninitialized) 200 */ 201 *astate = S_GROUND; 202 return (UNVIS_SYNBAD); 203 } 204 } 205 206 /* 207 * strunvis - decode src into dst 208 * 209 * Number of chars decoded into dst is returned, -1 on error. 210 * Dst is null terminated. 211 */ 212 213 int 214 strunvis(dst, src) 215 register char *dst; 216 register const char *src; 217 { 218 register char c; 219 char *start = dst; 220 int state = 0; 221 222 while ((c = *src++)) { 223 again: 224 switch (unvis(dst, c, &state, 0)) { 225 case UNVIS_VALID: 226 dst++; 227 break; 228 case UNVIS_VALIDPUSH: 229 dst++; 230 goto again; 231 case 0: 232 case UNVIS_NOCHAR: 233 break; 234 default: 235 return (-1); 236 } 237 } 238 if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID) 239 dst++; 240 *dst = '\0'; 241 return (dst - start); 242 } 243