unvis.c revision 1.2 1 /*-
2 * Copyright (c) 1989 The Regents of the University of California.
3 * 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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #if defined(LIBC_SCCS) && !defined(lint)
35 /*static char sccsid[] = "from: @(#)unvis.c 1.4 (Berkeley) 2/23/91";*/
36 static char rcsid[] = "$Id: unvis.c,v 1.2 1993/07/30 08:23:55 mycroft Exp $";
37 #endif /* LIBC_SCCS and not lint */
38
39 #include <sys/types.h>
40 #include <ctype.h>
41 #include <vis.h>
42
43 /*
44 * decode driven by state machine
45 */
46 #define S_GROUND 0 /* haven't seen escape char */
47 #define S_START 1 /* start decoding special sequence */
48 #define S_META 2 /* metachar started (M) */
49 #define S_META1 3 /* metachar more, regular char (-) */
50 #define S_CTRL 4 /* control char started (^) */
51 #define S_OCTAL2 5 /* octal digit 2 */
52 #define S_OCTAL3 6 /* octal digit 3 */
53
54 #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
55
56 /*
57 * unvis - decode characters previously encoded by vis
58 */
59 int
60 #if __STDC__
61 unvis(char *cp, char c, int *astate, int flag)
62 #else
63 unvis(cp, c, astate, flag)
64 char *cp, c;
65 int *astate, flag;
66 #endif
67 {
68
69 if (flag & UNVIS_END) {
70 if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
71 *astate = S_GROUND;
72 return (UNVIS_VALID);
73 }
74 return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
75 }
76
77 switch (*astate) {
78
79 case S_GROUND:
80 *cp = 0;
81 if (c == '\\') {
82 *astate = S_START;
83 return (0);
84 }
85 *cp = c;
86 return (UNVIS_VALID);
87
88 case S_START:
89 switch(c) {
90 case '\\':
91 *cp = c;
92 *astate = S_GROUND;
93 return (UNVIS_VALID);
94 case '0': case '1': case '2': case '3':
95 case '4': case '5': case '6': case '7':
96 *cp = (c - '0');
97 *astate = S_OCTAL2;
98 return (0);
99 case 'M':
100 *cp = 0200;
101 *astate = S_META;
102 return (0);
103 case '^':
104 *astate = S_CTRL;
105 return (0);
106 case 'n':
107 *cp = '\n';
108 *astate = S_GROUND;
109 return (UNVIS_VALID);
110 case 'r':
111 *cp = '\r';
112 *astate = S_GROUND;
113 return (UNVIS_VALID);
114 case 'b':
115 *cp = '\b';
116 *astate = S_GROUND;
117 return (UNVIS_VALID);
118 case 'a':
119 *cp = '\007';
120 *astate = S_GROUND;
121 return (UNVIS_VALID);
122 case 'v':
123 *cp = '\v';
124 *astate = S_GROUND;
125 return (UNVIS_VALID);
126 case 't':
127 *cp = '\t';
128 *astate = S_GROUND;
129 return (UNVIS_VALID);
130 case 'f':
131 *cp = '\f';
132 *astate = S_GROUND;
133 return (UNVIS_VALID);
134 case 's':
135 *cp = ' ';
136 *astate = S_GROUND;
137 return (UNVIS_VALID);
138 case 'E':
139 *cp = '\033';
140 *astate = S_GROUND;
141 return (UNVIS_VALID);
142 case '\n':
143 /*
144 * hidden newline
145 */
146 *astate = S_GROUND;
147 return (UNVIS_NOCHAR);
148 case '$':
149 /*
150 * hidden marker
151 */
152 *astate = S_GROUND;
153 return (UNVIS_NOCHAR);
154 }
155 *astate = S_GROUND;
156 return (UNVIS_SYNBAD);
157
158 case S_META:
159 if (c == '-')
160 *astate = S_META1;
161 else if (c == '^')
162 *astate = S_CTRL;
163 else {
164 *astate = S_GROUND;
165 return (UNVIS_SYNBAD);
166 }
167 return (0);
168
169 case S_META1:
170 *astate = S_GROUND;
171 *cp |= c;
172 return (UNVIS_VALID);
173
174 case S_CTRL:
175 if (c == '?')
176 *cp |= 0177;
177 else
178 *cp |= c & 037;
179 *astate = S_GROUND;
180 return (UNVIS_VALID);
181
182 case S_OCTAL2: /* second possible octal digit */
183 if (isoctal(c)) {
184 /*
185 * yes - and maybe a third
186 */
187 *cp = (*cp << 3) + (c - '0');
188 *astate = S_OCTAL3;
189 return (0);
190 }
191 /*
192 * no - done with current sequence, push back passed char
193 */
194 *astate = S_GROUND;
195 return (UNVIS_VALIDPUSH);
196
197 case S_OCTAL3: /* third possible octal digit */
198 *astate = S_GROUND;
199 if (isoctal(c)) {
200 *cp = (*cp << 3) + (c - '0');
201 return (UNVIS_VALID);
202 }
203 /*
204 * we were done, push back passed char
205 */
206 return (UNVIS_VALIDPUSH);
207
208 default:
209 /*
210 * decoder in unknown state - (probably uninitialized)
211 */
212 *astate = S_GROUND;
213 return (UNVIS_SYNBAD);
214 }
215 }
216
217 /*
218 * strunvis - decode src into dst
219 *
220 * Number of chars decoded into dst is returned, -1 on error.
221 * Dst is null terminated.
222 */
223
224 int
225 strunvis(dst, src)
226 register char *dst;
227 register const char *src;
228 {
229 register char c;
230 char *start = dst;
231 int state = 0;
232
233 while (c = *src++) {
234 again:
235 switch (unvis(dst, c, &state, 0)) {
236 case UNVIS_VALID:
237 dst++;
238 break;
239 case UNVIS_VALIDPUSH:
240 dst++;
241 goto again;
242 case 0:
243 case UNVIS_NOCHAR:
244 break;
245 default:
246 return (-1);
247 }
248 }
249 if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
250 dst++;
251 *dst = '\0';
252 return (dst - start);
253 }
254