]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/libc-vis/vis.c
MFC r244401,245305,245308:
[FreeBSD/stable/9.git] / contrib / libc-vis / vis.c
1 /*      $NetBSD: vis.c,v 1.45 2012/12/14 21:38:18 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. 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 #include <sys/cdefs.h>
59 #if defined(LIBC_SCCS) && !defined(lint)
60 __RCSID("$NetBSD: vis.c,v 1.45 2012/12/14 21:38:18 christos Exp $");
61 #endif /* LIBC_SCCS and not lint */
62 __FBSDID("$FreeBSD$");
63
64 #include "namespace.h"
65 #include <sys/types.h>
66
67 #include <assert.h>
68 #include <vis.h>
69 #include <errno.h>
70 #include <stdlib.h>
71
72 #define _DIAGASSERT(x)  assert(x)
73
74 #ifdef __weak_alias
75 __weak_alias(strvisx,_strvisx)
76 #endif
77
78 #if !HAVE_VIS || !HAVE_SVIS
79 #include <ctype.h>
80 #include <limits.h>
81 #include <stdio.h>
82 #include <string.h>
83
84 static char *do_svis(char *, size_t *, int, int, int, const char *);
85
86 #undef BELL
87 #define BELL '\a'
88
89 #define isoctal(c)      (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
90 #define iswhite(c)      (c == ' ' || c == '\t' || c == '\n')
91 #define issafe(c)       (c == '\b' || c == BELL || c == '\r')
92 #define xtoa(c)         "0123456789abcdef"[c]
93 #define XTOA(c)         "0123456789ABCDEF"[c]
94
95 #define MAXEXTRAS       9
96
97 #define MAKEEXTRALIST(flag, extra, orig_str)                                  \
98 do {                                                                          \
99         const char *orig = orig_str;                                          \
100         const char *o = orig;                                                 \
101         char *e;                                                              \
102         while (*o++)                                                          \
103                 continue;                                                     \
104         extra = malloc((size_t)((o - orig) + MAXEXTRAS));                     \
105         if (!extra) break;                                                    \
106         for (o = orig, e = extra; (*e++ = *o++) != '\0';)                     \
107                 continue;                                                     \
108         e--;                                                                  \
109         if (flag & VIS_GLOB) {                                                \
110                 *e++ = '*';                                                   \
111                 *e++ = '?';                                                   \
112                 *e++ = '[';                                                   \
113                 *e++ = '#';                                                   \
114         }                                                                     \
115         if (flag & VIS_SP) *e++ = ' ';                                        \
116         if (flag & VIS_TAB) *e++ = '\t';                                      \
117         if (flag & VIS_NL) *e++ = '\n';                                       \
118         if ((flag & VIS_NOSLASH) == 0) *e++ = '\\';                           \
119         *e = '\0';                                                            \
120 } while (/*CONSTCOND*/0)
121
122 /*
123  * This is do_hvis, for HTTP style (RFC 1808)
124  */
125 static char *
126 do_hvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra)
127 {
128
129         if ((isascii(c) && isalnum(c))
130             /* safe */
131             || c == '$' || c == '-' || c == '_' || c == '.' || c == '+'
132             /* extra */
133             || c == '!' || c == '*' || c == '\'' || c == '(' || c == ')'
134             || c == ',') {
135                 dst = do_svis(dst, dlen, c, flag, nextc, extra);
136         } else {
137                 if (dlen) {
138                         if (*dlen < 3)
139                                 return NULL;
140                         *dlen -= 3;
141                 }
142                 *dst++ = '%';
143                 *dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
144                 *dst++ = xtoa((unsigned int)c & 0xf);
145         }
146
147         return dst;
148 }
149
150 /*
151  * This is do_mvis, for Quoted-Printable MIME (RFC 2045)
152  * NB: No handling of long lines or CRLF.
153  */
154 static char *
155 do_mvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra)
156 {
157         if ((c != '\n') &&
158             /* Space at the end of the line */
159             ((isspace(c) && (nextc == '\r' || nextc == '\n')) ||
160             /* Out of range */
161             (!isspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) ||
162             /* Specific char to be escaped */ 
163             strchr("#$@[\\]^`{|}~", c) != NULL)) {
164                 if (dlen) {
165                         if (*dlen < 3)
166                                 return NULL;
167                         *dlen -= 3;
168                 }
169                 *dst++ = '=';
170                 *dst++ = XTOA(((unsigned int)c >> 4) & 0xf);
171                 *dst++ = XTOA((unsigned int)c & 0xf);
172         } else {
173                 dst = do_svis(dst, dlen, c, flag, nextc, extra);
174         }
175         return dst;
176 }
177
178 /*
179  * This is do_vis, the central code of vis.
180  * dst:       Pointer to the destination buffer
181  * c:         Character to encode
182  * flag:      Flag word
183  * nextc:     The character following 'c'
184  * extra:     Pointer to the list of extra characters to be
185  *            backslash-protected.
186  */
187 static char *
188 do_svis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra)
189 {
190         int isextra;
191         size_t odlen = dlen ? *dlen : 0;
192
193         isextra = strchr(extra, c) != NULL;
194 #define HAVE(x) \
195         do { \
196                 if (dlen) { \
197                         if (*dlen < (x)) \
198                                 goto out; \
199                         *dlen -= (x); \
200                 } \
201         } while (/*CONSTCOND*/0)
202         if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||
203             ((flag & VIS_SAFE) && issafe(c)))) {
204                 HAVE(1);
205                 *dst++ = c;
206                 return dst;
207         }
208         if (flag & VIS_CSTYLE) {
209                 HAVE(2);
210                 switch (c) {
211                 case '\n':
212                         *dst++ = '\\'; *dst++ = 'n';
213                         return dst;
214                 case '\r':
215                         *dst++ = '\\'; *dst++ = 'r';
216                         return dst;
217                 case '\b':
218                         *dst++ = '\\'; *dst++ = 'b';
219                         return dst;
220                 case BELL:
221                         *dst++ = '\\'; *dst++ = 'a';
222                         return dst;
223                 case '\v':
224                         *dst++ = '\\'; *dst++ = 'v';
225                         return dst;
226                 case '\t':
227                         *dst++ = '\\'; *dst++ = 't';
228                         return dst;
229                 case '\f':
230                         *dst++ = '\\'; *dst++ = 'f';
231                         return dst;
232                 case ' ':
233                         *dst++ = '\\'; *dst++ = 's';
234                         return dst;
235                 case '\0':
236                         *dst++ = '\\'; *dst++ = '0';
237                         if (isoctal(nextc)) {
238                                 HAVE(2);
239                                 *dst++ = '0';
240                                 *dst++ = '0';
241                         }
242                         return dst;
243                 default:
244                         if (isgraph(c)) {
245                                 *dst++ = '\\'; *dst++ = c;
246                                 return dst;
247                         }
248                         if (dlen)
249                                 *dlen = odlen;
250                 }
251         }
252         if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
253                 HAVE(4);
254                 *dst++ = '\\';
255                 *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0';
256                 *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0';
257                 *dst++ =                             (c       & 07) + '0';
258         } else {
259                 if ((flag & VIS_NOSLASH) == 0) {
260                         HAVE(1);
261                         *dst++ = '\\';
262                 }
263
264                 if (c & 0200) {
265                         HAVE(1);
266                         c &= 0177; *dst++ = 'M';
267                 }
268
269                 if (iscntrl(c)) {
270                         HAVE(2);
271                         *dst++ = '^';
272                         if (c == 0177)
273                                 *dst++ = '?';
274                         else
275                                 *dst++ = c + '@';
276                 } else {
277                         HAVE(2);
278                         *dst++ = '-'; *dst++ = c;
279                 }
280         }
281         return dst;
282 out:
283         *dlen = odlen;
284         return NULL;
285 }
286
287 typedef char *(*visfun_t)(char *, size_t *, int, int, int, const char *);
288
289 /*
290  * Return the appropriate encoding function depending on the flags given.
291  */
292 static visfun_t
293 getvisfun(int flag)
294 {
295         if (flag & VIS_HTTPSTYLE)
296                 return do_hvis;
297         if (flag & VIS_MIMESTYLE)
298                 return do_mvis;
299         return do_svis;
300 }
301
302 /*
303  * isnvis - visually encode characters, also encoding the characters
304  *        pointed to by `extra'
305  */
306 static char *
307 isnvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra)
308 {
309         char *nextra = NULL;
310         visfun_t f;
311
312         _DIAGASSERT(dst != NULL);
313         _DIAGASSERT(extra != NULL);
314         MAKEEXTRALIST(flag, nextra, extra);
315         if (!nextra) {
316                 if (dlen && *dlen == 0) {
317                         errno = ENOSPC;
318                         return NULL;
319                 }
320                 *dst = '\0';            /* can't create nextra, return "" */
321                 return dst;
322         }
323         f = getvisfun(flag);
324         dst = (*f)(dst, dlen, c, flag, nextc, nextra);
325         free(nextra);
326         if (dst == NULL || (dlen && *dlen == 0)) {
327                 errno = ENOSPC;
328                 return NULL;
329         }
330         *dst = '\0';
331         return dst;
332 }
333
334 char *
335 svis(char *dst, int c, int flag, int nextc, const char *extra)
336 {
337         return isnvis(dst, NULL, c, flag, nextc, extra);
338 }
339
340 char *
341 snvis(char *dst, size_t dlen, int c, int flag, int nextc, const char *extra)
342 {
343         return isnvis(dst, &dlen, c, flag, nextc, extra);
344 }
345
346
347 /*
348  * strsvis, strsvisx - visually encode characters from src into dst
349  *
350  *      Extra is a pointer to a \0-terminated list of characters to
351  *      be encoded, too. These functions are useful e. g. to
352  *      encode strings in such a way so that they are not interpreted
353  *      by a shell.
354  *
355  *      Dst must be 4 times the size of src to account for possible
356  *      expansion.  The length of dst, not including the trailing NULL,
357  *      is returned.
358  *
359  *      Strsvisx encodes exactly len bytes from src into dst.
360  *      This is useful for encoding a block of data.
361  */
362 static int
363 istrsnvis(char *dst, size_t *dlen, const char *csrc, int flag, const char *extra)
364 {
365         int c;
366         char *start;
367         char *nextra = NULL;
368         const unsigned char *src = (const unsigned char *)csrc;
369         visfun_t f;
370
371         _DIAGASSERT(dst != NULL);
372         _DIAGASSERT(src != NULL);
373         _DIAGASSERT(extra != NULL);
374         MAKEEXTRALIST(flag, nextra, extra);
375         if (!nextra) {
376                 *dst = '\0';            /* can't create nextra, return "" */
377                 return 0;
378         }
379         f = getvisfun(flag);
380         for (start = dst; (c = *src++) != '\0'; /* empty */) {
381                 dst = (*f)(dst, dlen, c, flag, *src, nextra);
382                 if (dst == NULL) {
383                         errno = ENOSPC;
384                         return -1;
385                 }
386         }
387         free(nextra);
388         if (dlen && *dlen == 0) {
389                 errno = ENOSPC;
390                 return -1;
391         }
392         *dst = '\0';
393         return (int)(dst - start);
394 }
395
396 int
397 strsvis(char *dst, const char *csrc, int flag, const char *extra)
398 {
399         return istrsnvis(dst, NULL, csrc, flag, extra);
400 }
401
402 int
403 strsnvis(char *dst, size_t dlen, const char *csrc, int flag, const char *extra)
404 {
405         return istrsnvis(dst, &dlen, csrc, flag, extra);
406 }
407
408 static int
409 istrsnvisx(char *dst, size_t *dlen, const char *csrc, size_t len, int flag,
410     const char *extra)
411 {
412         unsigned char c;
413         char *start;
414         char *nextra = NULL;
415         const unsigned char *src = (const unsigned char *)csrc;
416         visfun_t f;
417
418         _DIAGASSERT(dst != NULL);
419         _DIAGASSERT(src != NULL);
420         _DIAGASSERT(extra != NULL);
421         MAKEEXTRALIST(flag, nextra, extra);
422         if (! nextra) {
423                 if (dlen && *dlen == 0) {
424                         errno = ENOSPC;
425                         return -1;
426                 }
427                 *dst = '\0';            /* can't create nextra, return "" */
428                 return 0;
429         }
430
431         f = getvisfun(flag);
432         for (start = dst; len > 0; len--) {
433                 c = *src++;
434                 dst = (*f)(dst, dlen, c, flag, len > 1 ? *src : '\0', nextra);
435                 if (dst == NULL) {
436                         errno = ENOSPC;
437                         return -1;
438                 }
439         }
440         free(nextra);
441         if (dlen && *dlen == 0) {
442                 errno = ENOSPC;
443                 return -1;
444         }
445         *dst = '\0';
446         return (int)(dst - start);
447 }
448
449 int
450 strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra)
451 {
452         return istrsnvisx(dst, NULL, csrc, len, flag, extra);
453 }
454
455 int
456 strsnvisx(char *dst, size_t dlen, const char *csrc, size_t len, int flag,
457     const char *extra)
458 {
459         return istrsnvisx(dst, &dlen, csrc, len, flag, extra);
460 }
461 #endif
462
463 #if !HAVE_VIS
464 /*
465  * vis - visually encode characters
466  */
467 static char *
468 invis(char *dst, size_t *dlen, int c, int flag, int nextc)
469 {
470         char *extra = NULL;
471         unsigned char uc = (unsigned char)c;
472         visfun_t f;
473
474         _DIAGASSERT(dst != NULL);
475
476         MAKEEXTRALIST(flag, extra, "");
477         if (! extra) {
478                 if (dlen && *dlen == 0) {
479                         errno = ENOSPC;
480                         return NULL;
481                 }
482                 *dst = '\0';            /* can't create extra, return "" */
483                 return dst;
484         }
485         f = getvisfun(flag);
486         dst = (*f)(dst, dlen, uc, flag, nextc, extra);
487         free(extra);
488         if (dst == NULL || (dlen && *dlen == 0)) {
489                 errno = ENOSPC;
490                 return NULL;
491         }
492         *dst = '\0';
493         return dst;
494 }
495
496 char *
497 vis(char *dst, int c, int flag, int nextc)
498 {
499         return invis(dst, NULL, c, flag, nextc);
500 }
501
502 char *
503 nvis(char *dst, size_t dlen, int c, int flag, int nextc)
504 {
505         return invis(dst, &dlen, c, flag, nextc);
506 }
507
508
509 /*
510  * strvis, strvisx - visually encode characters from src into dst
511  *
512  *      Dst must be 4 times the size of src to account for possible
513  *      expansion.  The length of dst, not including the trailing NULL,
514  *      is returned.
515  *
516  *      Strvisx encodes exactly len bytes from src into dst.
517  *      This is useful for encoding a block of data.
518  */
519 static int
520 istrnvis(char *dst, size_t *dlen, const char *src, int flag)
521 {
522         char *extra = NULL;
523         int rv;
524
525         MAKEEXTRALIST(flag, extra, "");
526         if (!extra) {
527                 if (dlen && *dlen == 0) {
528                         errno = ENOSPC;
529                         return -1;
530                 }
531                 *dst = '\0';            /* can't create extra, return "" */
532                 return 0;
533         }
534         rv = istrsnvis(dst, dlen, src, flag, extra);
535         free(extra);
536         return rv;
537 }
538
539 int
540 strvis(char *dst, const char *src, int flag)
541 {
542         return istrnvis(dst, NULL, src, flag);
543 }
544
545 int
546 strnvis(char *dst, size_t dlen, const char *src, int flag)
547 {
548         return istrnvis(dst, &dlen, src, flag);
549 }
550
551 static int
552 istrnvisx(char *dst, size_t *dlen, const char *src, size_t len, int flag)
553 {
554         char *extra = NULL;
555         int rv;
556
557         MAKEEXTRALIST(flag, extra, "");
558         if (!extra) {
559                 if (dlen && *dlen == 0) {
560                         errno = ENOSPC;
561                         return -1;
562                 }
563                 *dst = '\0';            /* can't create extra, return "" */
564                 return 0;
565         }
566         rv = istrsnvisx(dst, dlen, src, len, flag, extra);
567         free(extra);
568         return rv;
569 }
570
571 int
572 strvisx(char *dst, const char *src, size_t len, int flag)
573 {
574         return istrnvisx(dst, NULL, src, len, flag);
575 }
576
577 int
578 strnvisx(char *dst, size_t dlen, const char *src, size_t len, int flag)
579 {
580         return istrnvisx(dst, &dlen, src, len, flag);
581 }
582
583 #endif