update from Dave Borman; make "u=g" work.
[unix-history] / usr / src / lib / libc / gen / unvis.c
CommitLineData
d6a13ceb 1/*-
1af61e06
MT
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
d6a13ceb 5 * %sccs.include.redist.c%
1af61e06
MT
6 */
7
8#if defined(LIBC_SCCS) && !defined(lint)
2e93102d 9static char sccsid[] = "@(#)unvis.c 1.3 (Berkeley) %G%";
1af61e06
MT
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
d6a13ceb
MT
27#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
28
1af61e06
MT
29/*
30 * unvis - decode characters previously encoded by vis
31 */
32unvis(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);
d6a13ceb
MT
116 case '$':
117 /*
118 * hidden marker
119 */
120 *astate = S_GROUND;
121 return (UNVIS_NOCHAR);
1af61e06
MT
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 */
2e93102d
MT
180 *astate = S_GROUND;
181 return (UNVIS_SYNBAD);
1af61e06
MT
182 }
183}
184
185/*
d6a13ceb 186 * strunvis - decode src into dst
1af61e06 187 *
d6a13ceb
MT
188 * Number of chars decoded into dst is returned, -1 on error.
189 * Dst is null terminated.
1af61e06 190 */
d6a13ceb
MT
191
192strunvis(dst, src)
1af61e06 193 register char *dst, *src;
1af61e06 194{
d6a13ceb 195 register char c;
1af61e06 196 char *start = dst;
2e93102d 197 int state = 0;
1af61e06 198
d6a13ceb
MT
199 while (c = *src++) {
200 again:
201 switch (unvis(dst, c, &state, 0)) {
202 case UNVIS_VALID:
203 dst++;
1af61e06 204 break;
d6a13ceb
MT
205 case UNVIS_VALIDPUSH:
206 dst++;
207 goto again;
208 case 0:
209 case UNVIS_NOCHAR:
210 break;
211 default:
212 return (-1);
213 }
1af61e06 214 }
2e93102d
MT
215 if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
216 dst++;
d6a13ceb 217 *dst = '\0';
1af61e06
MT
218 return (dst - start);
219}