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