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