Merge from vendor branch BZIP:
[dragonfly.git] / lib / libc / gen / vis.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  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: src/lib/libc/gen/vis.c,v 1.13 2003/10/30 12:41:50 phk Exp $
34  * $DragonFly: src/lib/libc/gen/vis.c,v 1.6 2005/11/13 00:07:42 swildner Exp $
35  */
36
37 #include <sys/types.h>
38 #include <ctype.h>
39 #include <limits.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <vis.h>
43
44 #define isoctal(c)      (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
45
46 /*
47  * vis - visually encode characters
48  */
49 char *
50 vis(char *dst, int c, int flag, int nextc)
51 {
52         c = (unsigned char)c;
53
54         if (flag & VIS_HTTPSTYLE) {
55                 /* Described in RFC 1808 */
56                 if (!(isalnum(c) /* alpha-numeric */
57                     /* safe */
58                     || c == '$' || c == '-' || c == '_' || c == '.' || c == '+'
59                     /* extra */
60                     || c == '!' || c == '*' || c == '\'' || c == '('
61                     || c == ')' || c == ',')) {
62                         *dst++ = '%';
63                         snprintf(dst, 4, (c < 16 ? "0%X" : "%X"), c);
64                         dst += 2;
65                         goto done;
66                 }
67         }
68
69         if ((flag & VIS_GLOB) &&
70             (c == '*' || c == '?' || c == '[' || c == '#'))
71                 ;
72         else if (isgraph(c) ||
73            ((flag & VIS_SP) == 0 && c == ' ') ||
74            ((flag & VIS_TAB) == 0 && c == '\t') ||
75            ((flag & VIS_NL) == 0 && c == '\n') ||
76            ((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) {
77                 *dst++ = c;
78                 if (c == '\\' && (flag & VIS_NOSLASH) == 0)
79                         *dst++ = '\\';
80                 *dst = '\0';
81                 return (dst);
82         }
83
84         if (flag & VIS_CSTYLE) {
85                 switch(c) {
86                 case '\n':
87                         *dst++ = '\\';
88                         *dst++ = 'n';
89                         goto done;
90                 case '\r':
91                         *dst++ = '\\';
92                         *dst++ = 'r';
93                         goto done;
94                 case '\b':
95                         *dst++ = '\\';
96                         *dst++ = 'b';
97                         goto done;
98                 case '\a':
99                         *dst++ = '\\';
100                         *dst++ = 'a';
101                         goto done;
102                 case '\v':
103                         *dst++ = '\\';
104                         *dst++ = 'v';
105                         goto done;
106                 case '\t':
107                         *dst++ = '\\';
108                         *dst++ = 't';
109                         goto done;
110                 case '\f':
111                         *dst++ = '\\';
112                         *dst++ = 'f';
113                         goto done;
114                 case ' ':
115                         *dst++ = '\\';
116                         *dst++ = 's';
117                         goto done;
118                 case '\0':
119                         *dst++ = '\\';
120                         *dst++ = '0';
121                         if (isoctal(nextc)) {
122                                 *dst++ = '0';
123                                 *dst++ = '0';
124                         }
125                         goto done;
126                 }
127         }
128         if (((c & 0177) == ' ') || isgraph(c) || (flag & VIS_OCTAL)) {
129                 *dst++ = '\\';
130                 *dst++ = ((u_char)c >> 6 & 07) + '0';
131                 *dst++ = ((u_char)c >> 3 & 07) + '0';
132                 *dst++ = ((u_char)c & 07) + '0';
133                 goto done;
134         }
135         if ((flag & VIS_NOSLASH) == 0)
136                 *dst++ = '\\';
137         if (c & 0200) {
138                 c &= 0177;
139                 *dst++ = 'M';
140         }
141         if (iscntrl(c)) {
142                 *dst++ = '^';
143                 if (c == 0177)
144                         *dst++ = '?';
145                 else
146                         *dst++ = c + '@';
147         } else {
148                 *dst++ = '-';
149                 *dst++ = c;
150         }
151 done:
152         *dst = '\0';
153         return (dst);
154 }
155
156 /*
157  * strvis, strvisx - visually encode characters from src into dst
158  *
159  *      Dst must be 4 times the size of src to account for possible
160  *      expansion.  The length of dst, not including the trailing NUL,
161  *      is returned.
162  *
163  *      Strvisx encodes exactly len bytes from src into dst.
164  *      This is useful for encoding a block of data.
165  */
166 int
167 strvis(char *dst, const char *src, int flag)
168 {
169         char c;
170         char *start;
171
172         for (start = dst; (c = *src); )
173                 dst = vis(dst, c, flag, *++src);
174         *dst = '\0';
175         return (dst - start);
176 }
177
178 int
179 strnvis(char *dst, const char *src, size_t len, int flag)
180 {
181         char *start, *end;
182         char buf[5];
183         int c, i;
184
185         i = 0;
186         start = dst;
187         end = start + len -1;
188         for (; (c = *src) != '\0';) {
189                 i = vis(buf, c, flag, *++src) - buf;
190                 if (start + i > end) {
191                         --src;
192                         break;
193                 }
194                 memcpy(dst, buf, i);
195                 dst += i;
196         }
197         if (len > 0)
198                 *dst = '\0';
199         if (dst + i > end) {
200                 /* adjust return value for truncation */
201                 while ((c = *src) != '\0')
202                         dst += vis(buf, c, flag, *++src) - buf;
203         }
204         return (dst - start);
205 }
206
207 int
208 strvisx(char *dst, const char *src, size_t len, int flag)
209 {
210         int c;
211         char *start;
212
213         for (start = dst; len > 1; len--) {
214                 c = *src;
215                 dst = vis(dst, c, flag, *++src);
216         }
217         if (len)
218                 dst = vis(dst, *src, flag, '\0');
219         *dst = '\0';
220
221         return (dst - start);
222 }