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