xref: /csrg-svn/lib/libc/gen/unvis.c (revision 44333)
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