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