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