97406cdf8c8521fc25f98260e8b02b3859737a25
[asterisk/asterisk.git] / editline / np / vis.c
1 /*      $NetBSD: vis.c,v 1.22 2002/03/23 17:38:27 christos Exp $        */
2
3 /*-
4  * Copyright (c) 1999 The NetBSD Foundation, Inc.
5  * Copyright (c) 1989, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #include <sys/cdefs.h>
38 #if defined(LIBC_SCCS) && !defined(lint)
39 __RCSID("$NetBSD: vis.c,v 1.22 2002/03/23 17:38:27 christos Exp $");
40 #endif /* LIBC_SCCS and not lint */
41
42 #include <sys/types.h>
43
44 #include <assert.h>
45 #include "np/vis.h"
46 #include <stdlib.h>
47
48 #ifdef __weak_alias
49 __weak_alias(strsvis,_strsvis)
50 __weak_alias(strsvisx,_strsvisx)
51 __weak_alias(strvis,_strvis)
52 __weak_alias(strvisx,_strvisx)
53 __weak_alias(svis,_svis)
54 __weak_alias(vis,_vis)
55 #endif
56
57 #if !HAVE_VIS_H
58 #include <ctype.h>
59 #include <limits.h>
60 #include <stdio.h>
61 #include <string.h>
62
63 #undef BELL
64 #if defined(__STDC__)
65 #define BELL '\a'
66 #else
67 #define BELL '\007'
68 #endif
69
70 #ifdef SOLARIS
71 typedef unsigned int    u_int32_t;
72 #endif
73
74 #define isoctal(c)      (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
75 #define iswhite(c)      (c == ' ' || c == '\t' || c == '\n')
76 #define issafe(c)       (c == '\b' || c == BELL || c == '\r')
77 #define xtoa(c)         "0123456789abcdef"[c]
78
79 #define MAXEXTRAS       5
80
81
82 #define MAKEEXTRALIST(flag, extra, orig)                                      \
83 do {                                                                          \
84         const char *o = orig;                                                 \
85         char *e;                                                              \
86         while (*o++)                                                          \
87                 continue;                                                     \
88         extra = alloca((size_t)((o - orig) + MAXEXTRAS));                     \
89         for (o = orig, e = extra; (*e++ = *o++) != '\0';)                     \
90                 continue;                                                     \
91         e--;                                                                  \
92         if (flag & VIS_SP) *e++ = ' ';                                        \
93         if (flag & VIS_TAB) *e++ = '\t';                                      \
94         if (flag & VIS_NL) *e++ = '\n';                                       \
95         if ((flag & VIS_NOSLASH) == 0) *e++ = '\\';                           \
96         *e = '\0';                                                            \
97 } while (/*CONSTCOND*/0)
98
99
100 /*
101  * This is HVIS, the macro of vis used to HTTP style (RFC 1808)
102  */
103 #define HVIS(dst, c, flag, nextc, extra)                                      \
104 do                                                                            \
105         if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) { \
106                 *dst++ = '%';                                                 \
107                 *dst++ = xtoa(((unsigned int)c >> 4) & 0xf);                  \
108                 *dst++ = xtoa((unsigned int)c & 0xf);                         \
109         } else {                                                              \
110                 SVIS(dst, c, flag, nextc, extra);                             \
111         }                                                                     \
112 while (/*CONSTCOND*/0)
113         
114 /*
115  * This is SVIS, the central macro of vis.
116  * dst:       Pointer to the destination buffer
117  * c:         Character to encode
118  * flag:      Flag word
119  * nextc:     The character following 'c'
120  * extra:     Pointer to the list of extra characters to be
121  *            backslash-protected.
122  */
123 #define SVIS(dst, c, flag, nextc, extra)                                      \
124 do {                                                                          \
125         int isextra, isc;                                                     \
126         isextra = strchr(extra, c) != NULL;                                   \
127         if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||            \
128             ((flag & VIS_SAFE) && issafe(c)))) {                              \
129                 *dst++ = c;                                                   \
130                 break;                                                        \
131         }                                                                     \
132         isc = 0;                                                              \
133         if (flag & VIS_CSTYLE) {                                              \
134                 switch (c) {                                                  \
135                 case '\n':                                                    \
136                         isc = 1; *dst++ = '\\'; *dst++ = 'n';                 \
137                         break;                                                \
138                 case '\r':                                                    \
139                         isc = 1; *dst++ = '\\'; *dst++ = 'r';                 \
140                         break;                                                \
141                 case '\b':                                                    \
142                         isc = 1; *dst++ = '\\'; *dst++ = 'b';                 \
143                         break;                                                \
144                 case BELL:                                                    \
145                         isc = 1; *dst++ = '\\'; *dst++ = 'a';                 \
146                         break;                                                \
147                 case '\v':                                                    \
148                         isc = 1; *dst++ = '\\'; *dst++ = 'v';                 \
149                         break;                                                \
150                 case '\t':                                                    \
151                         isc = 1; *dst++ = '\\'; *dst++ = 't';                 \
152                         break;                                                \
153                 case '\f':                                                    \
154                         isc = 1; *dst++ = '\\'; *dst++ = 'f';                 \
155                         break;                                                \
156                 case ' ':                                                     \
157                         isc = 1; *dst++ = '\\'; *dst++ = 's';                 \
158                         break;                                                \
159                 case '\0':                                                    \
160                         isc = 1; *dst++ = '\\'; *dst++ = '0';                 \
161                         if (isoctal(nextc)) {                                 \
162                                 *dst++ = '0';                                 \
163                                 *dst++ = '0';                                 \
164                         }                                                     \
165                 }                                                             \
166         }                                                                     \
167         if (isc) break;                                                       \
168         if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {           \
169                 *dst++ = '\\';                                                \
170                 *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0';    \
171                 *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0';    \
172                 *dst++ =                             (c       & 07) + '0';    \
173         } else {                                                              \
174                 if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';                 \
175                 if (c & 0200) {                                               \
176                         c &= 0177; *dst++ = 'M';                              \
177                 }                                                             \
178                 if (iscntrl(c)) {                                             \
179                         *dst++ = '^';                                         \
180                         if (c == 0177)                                        \
181                                 *dst++ = '?';                                 \
182                         else                                                  \
183                                 *dst++ = c + '@';                             \
184                 } else {                                                      \
185                         *dst++ = '-'; *dst++ = c;                             \
186                 }                                                             \
187         }                                                                     \
188 } while (/*CONSTCOND*/0)
189
190
191 /*
192  * svis - visually encode characters, also encoding the characters
193  *        pointed to by `extra'
194  */
195 char *
196 svis(dst, c, flag, nextc, extra)
197         char *dst;
198         int c, flag, nextc;
199         const char *extra;
200 {
201         char *nextra;
202         _DIAGASSERT(dst != NULL);
203         _DIAGASSERT(extra != NULL);
204         MAKEEXTRALIST(flag, nextra, extra);
205         if (flag & VIS_HTTPSTYLE)
206                 HVIS(dst, c, flag, nextc, nextra);
207         else
208                 SVIS(dst, c, flag, nextc, nextra);
209         *dst = '\0';
210         return(dst);
211 }
212
213
214 /*
215  * strsvis, strsvisx - visually encode characters from src into dst
216  *
217  *      Extra is a pointer to a \0-terminated list of characters to
218  *      be encoded, too. These functions are useful e. g. to
219  *      encode strings in such a way so that they are not interpreted
220  *      by a shell.
221  *      
222  *      Dst must be 4 times the size of src to account for possible
223  *      expansion.  The length of dst, not including the trailing NULL,
224  *      is returned. 
225  *
226  *      Strsvisx encodes exactly len bytes from src into dst.
227  *      This is useful for encoding a block of data.
228  */
229 int
230 strsvis(dst, src, flag, extra)
231         char *dst;
232         const char *src;
233         int flag;
234         const char *extra;
235 {
236         char c;
237         char *start;
238         char *nextra;
239
240         _DIAGASSERT(dst != NULL);
241         _DIAGASSERT(src != NULL);
242         _DIAGASSERT(extra != NULL);
243         MAKEEXTRALIST(flag, nextra, extra);
244         if (flag & VIS_HTTPSTYLE) {
245                 for (start = dst; (c = *src++) != '\0'; /* empty */)
246                         HVIS(dst, c, flag, *src, nextra);
247         } else {
248                 for (start = dst; (c = *src++) != '\0'; /* empty */)
249                         SVIS(dst, c, flag, *src, nextra);
250         }
251         *dst = '\0';
252         return (dst - start);
253 }
254
255
256 int
257 strsvisx(dst, src, len, flag, extra)
258         char *dst;
259         const char *src;
260         size_t len;
261         int flag;
262         const char *extra;
263 {
264         char c;
265         char *start;
266         char *nextra;
267
268         _DIAGASSERT(dst != NULL);
269         _DIAGASSERT(src != NULL);
270         _DIAGASSERT(extra != NULL);
271         MAKEEXTRALIST(flag, nextra, extra);
272
273         if (flag & VIS_HTTPSTYLE) {
274                 for (start = dst; len > 0; len--) {
275                         c = *src++;
276                         HVIS(dst, c, flag, len ? *src : '\0', nextra);
277                 }
278         } else {
279                 for (start = dst; len > 0; len--) {
280                         c = *src++;
281                         SVIS(dst, c, flag, len ? *src : '\0', nextra);
282                 }
283         }
284         *dst = '\0';
285         return (dst - start);
286 }
287
288
289 /*
290  * vis - visually encode characters
291  */
292 char *
293 vis(dst, c, flag, nextc)
294         char *dst;
295         int c, flag, nextc;
296         
297 {
298         char *extra;
299
300         _DIAGASSERT(dst != NULL);
301
302         MAKEEXTRALIST(flag, extra, "");
303         if (flag & VIS_HTTPSTYLE)
304             HVIS(dst, c, flag, nextc, extra);
305         else
306             SVIS(dst, c, flag, nextc, extra);
307         *dst = '\0';
308         return (dst);
309 }
310
311
312 /*
313  * strvis, strvisx - visually encode characters from src into dst
314  *      
315  *      Dst must be 4 times the size of src to account for possible
316  *      expansion.  The length of dst, not including the trailing NULL,
317  *      is returned. 
318  *
319  *      Strvisx encodes exactly len bytes from src into dst.
320  *      This is useful for encoding a block of data.
321  */
322 int
323 strvis(dst, src, flag)
324         char *dst;
325         const char *src;
326         int flag;
327 {
328         char *extra;
329
330         MAKEEXTRALIST(flag, extra, "");
331         return (strsvis(dst, src, flag, extra));
332 }
333
334
335 int
336 strvisx(dst, src, len, flag)
337         char *dst;
338         const char *src;
339         size_t len;
340         int flag;
341 {
342         char *extra;
343
344         MAKEEXTRALIST(flag, extra, "");
345         return (strsvisx(dst, src, len, flag, extra));
346 }
347 #endif