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