Merged revisions 12161 via svnmerge from
[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 #include <alloca.h>
72 typedef unsigned int    u_int32_t;
73 #endif
74
75 #define isoctal(c)      (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
76 #define iswhite(c)      (c == ' ' || c == '\t' || c == '\n')
77 #define issafe(c)       (c == '\b' || c == BELL || c == '\r')
78 #define xtoa(c)         "0123456789abcdef"[c]
79
80 #define MAXEXTRAS       5
81
82
83 #define MAKEEXTRALIST(flag, extra, orig)                                      \
84 do {                                                                          \
85         const char *o = orig;                                                 \
86         char *e;                                                              \
87         while (*o++)                                                          \
88                 continue;                                                     \
89         extra = alloca((size_t)((o - orig) + MAXEXTRAS));                     \
90         for (o = orig, e = extra; (*e++ = *o++) != '\0';)                     \
91                 continue;                                                     \
92         e--;                                                                  \
93         if (flag & VIS_SP) *e++ = ' ';                                        \
94         if (flag & VIS_TAB) *e++ = '\t';                                      \
95         if (flag & VIS_NL) *e++ = '\n';                                       \
96         if ((flag & VIS_NOSLASH) == 0) *e++ = '\\';                           \
97         *e = '\0';                                                            \
98 } while (/*CONSTCOND*/0)
99
100
101 /*
102  * This is HVIS, the macro of vis used to HTTP style (RFC 1808)
103  */
104 #define HVIS(dst, c, flag, nextc, extra)                                      \
105 do                                                                            \
106         if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) { \
107                 *dst++ = '%';                                                 \
108                 *dst++ = xtoa(((unsigned int)c >> 4) & 0xf);                  \
109                 *dst++ = xtoa((unsigned int)c & 0xf);                         \
110         } else {                                                              \
111                 SVIS(dst, c, flag, nextc, extra);                             \
112         }                                                                     \
113 while (/*CONSTCOND*/0)
114         
115 /*
116  * This is SVIS, the central macro of vis.
117  * dst:       Pointer to the destination buffer
118  * c:         Character to encode
119  * flag:      Flag word
120  * nextc:     The character following 'c'
121  * extra:     Pointer to the list of extra characters to be
122  *            backslash-protected.
123  */
124 #define SVIS(dst, c, flag, nextc, extra)                                      \
125 do {                                                                          \
126         int isextra, isc;                                                     \
127         isextra = strchr(extra, c) != NULL;                                   \
128         if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||            \
129             ((flag & VIS_SAFE) && issafe(c)))) {                              \
130                 *dst++ = c;                                                   \
131                 break;                                                        \
132         }                                                                     \
133         isc = 0;                                                              \
134         if (flag & VIS_CSTYLE) {                                              \
135                 switch (c) {                                                  \
136                 case '\n':                                                    \
137                         isc = 1; *dst++ = '\\'; *dst++ = 'n';                 \
138                         break;                                                \
139                 case '\r':                                                    \
140                         isc = 1; *dst++ = '\\'; *dst++ = 'r';                 \
141                         break;                                                \
142                 case '\b':                                                    \
143                         isc = 1; *dst++ = '\\'; *dst++ = 'b';                 \
144                         break;                                                \
145                 case BELL:                                                    \
146                         isc = 1; *dst++ = '\\'; *dst++ = 'a';                 \
147                         break;                                                \
148                 case '\v':                                                    \
149                         isc = 1; *dst++ = '\\'; *dst++ = 'v';                 \
150                         break;                                                \
151                 case '\t':                                                    \
152                         isc = 1; *dst++ = '\\'; *dst++ = 't';                 \
153                         break;                                                \
154                 case '\f':                                                    \
155                         isc = 1; *dst++ = '\\'; *dst++ = 'f';                 \
156                         break;                                                \
157                 case ' ':                                                     \
158                         isc = 1; *dst++ = '\\'; *dst++ = 's';                 \
159                         break;                                                \
160                 case '\0':                                                    \
161                         isc = 1; *dst++ = '\\'; *dst++ = '0';                 \
162                         if (isoctal(nextc)) {                                 \
163                                 *dst++ = '0';                                 \
164                                 *dst++ = '0';                                 \
165                         }                                                     \
166                 }                                                             \
167         }                                                                     \
168         if (isc) break;                                                       \
169         if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {           \
170                 *dst++ = '\\';                                                \
171                 *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0';    \
172                 *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0';    \
173                 *dst++ =                             (c       & 07) + '0';    \
174         } else {                                                              \
175                 if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';                 \
176                 if (c & 0200) {                                               \
177                         c &= 0177; *dst++ = 'M';                              \
178                 }                                                             \
179                 if (iscntrl(c)) {                                             \
180                         *dst++ = '^';                                         \
181                         if (c == 0177)                                        \
182                                 *dst++ = '?';                                 \
183                         else                                                  \
184                                 *dst++ = c + '@';                             \
185                 } else {                                                      \
186                         *dst++ = '-'; *dst++ = c;                             \
187                 }                                                             \
188         }                                                                     \
189 } while (/*CONSTCOND*/0)
190
191
192 /*
193  * svis - visually encode characters, also encoding the characters
194  *        pointed to by `extra'
195  */
196 char *
197 svis(dst, c, flag, nextc, extra)
198         char *dst;
199         int c, flag, nextc;
200         const char *extra;
201 {
202         char *nextra;
203         _DIAGASSERT(dst != NULL);
204         _DIAGASSERT(extra != NULL);
205         MAKEEXTRALIST(flag, nextra, extra);
206         if (flag & VIS_HTTPSTYLE)
207                 HVIS(dst, c, flag, nextc, nextra);
208         else
209                 SVIS(dst, c, flag, nextc, nextra);
210         *dst = '\0';
211         return(dst);
212 }
213
214
215 /*
216  * strsvis, strsvisx - visually encode characters from src into dst
217  *
218  *      Extra is a pointer to a \0-terminated list of characters to
219  *      be encoded, too. These functions are useful e. g. to
220  *      encode strings in such a way so that they are not interpreted
221  *      by a shell.
222  *      
223  *      Dst must be 4 times the size of src to account for possible
224  *      expansion.  The length of dst, not including the trailing NULL,
225  *      is returned. 
226  *
227  *      Strsvisx encodes exactly len bytes from src into dst.
228  *      This is useful for encoding a block of data.
229  */
230 int
231 strsvis(dst, src, flag, extra)
232         char *dst;
233         const char *src;
234         int flag;
235         const char *extra;
236 {
237         char c;
238         char *start;
239         char *nextra;
240
241         _DIAGASSERT(dst != NULL);
242         _DIAGASSERT(src != NULL);
243         _DIAGASSERT(extra != NULL);
244         MAKEEXTRALIST(flag, nextra, extra);
245         if (flag & VIS_HTTPSTYLE) {
246                 for (start = dst; (c = *src++) != '\0'; /* empty */)
247                         HVIS(dst, c, flag, *src, nextra);
248         } else {
249                 for (start = dst; (c = *src++) != '\0'; /* empty */)
250                         SVIS(dst, c, flag, *src, nextra);
251         }
252         *dst = '\0';
253         return (dst - start);
254 }
255
256
257 int
258 strsvisx(dst, src, len, flag, extra)
259         char *dst;
260         const char *src;
261         size_t len;
262         int flag;
263         const char *extra;
264 {
265         char c;
266         char *start;
267         char *nextra;
268
269         _DIAGASSERT(dst != NULL);
270         _DIAGASSERT(src != NULL);
271         _DIAGASSERT(extra != NULL);
272         MAKEEXTRALIST(flag, nextra, extra);
273
274         if (flag & VIS_HTTPSTYLE) {
275                 for (start = dst; len > 0; len--) {
276                         c = *src++;
277                         HVIS(dst, c, flag, len ? *src : '\0', nextra);
278                 }
279         } else {
280                 for (start = dst; len > 0; len--) {
281                         c = *src++;
282                         SVIS(dst, c, flag, len ? *src : '\0', nextra);
283                 }
284         }
285         *dst = '\0';
286         return (dst - start);
287 }
288
289
290 /*
291  * vis - visually encode characters
292  */
293 char *
294 vis(dst, c, flag, nextc)
295         char *dst;
296         int c, flag, nextc;
297         
298 {
299         char *extra;
300
301         _DIAGASSERT(dst != NULL);
302
303         MAKEEXTRALIST(flag, extra, "");
304         if (flag & VIS_HTTPSTYLE)
305             HVIS(dst, c, flag, nextc, extra);
306         else
307             SVIS(dst, c, flag, nextc, extra);
308         *dst = '\0';
309         return (dst);
310 }
311
312
313 /*
314  * strvis, strvisx - visually encode characters from src into dst
315  *      
316  *      Dst must be 4 times the size of src to account for possible
317  *      expansion.  The length of dst, not including the trailing NULL,
318  *      is returned. 
319  *
320  *      Strvisx encodes exactly len bytes from src into dst.
321  *      This is useful for encoding a block of data.
322  */
323 int
324 strvis(dst, src, flag)
325         char *dst;
326         const char *src;
327         int flag;
328 {
329         char *extra;
330
331         MAKEEXTRALIST(flag, extra, "");
332         return (strsvis(dst, src, flag, extra));
333 }
334
335
336 int
337 strvisx(dst, src, len, flag)
338         char *dst;
339         const char *src;
340         size_t len;
341         int flag;
342 {
343         char *extra;
344
345         MAKEEXTRALIST(flag, extra, "");
346         return (strsvisx(dst, src, len, flag, extra));
347 }
348 #endif