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