Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:19

0001 /*  $NetBSD: vis.c,v 1.33 2005/05/28 13:11:14 lukem Exp $   */
0002 
0003 /*-
0004  * Copyright (c) 1989, 1993
0005  *  The Regents of the University of California.  All rights reserved.
0006  *
0007  * Redistribution and use in source and binary forms, with or without
0008  * modification, are permitted provided that the following conditions
0009  * are met:
0010  * 1. Redistributions of source code must retain the above copyright
0011  *    notice, this list of conditions and the following disclaimer.
0012  * 2. Redistributions in binary form must reproduce the above copyright
0013  *    notice, this list of conditions and the following disclaimer in the
0014  *    documentation and/or other materials provided with the distribution.
0015  * 3. Neither the name of the University nor the names of its contributors
0016  *    may be used to endorse or promote products derived from this software
0017  *    without specific prior written permission.
0018  *
0019  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
0020  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0021  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0022  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
0023  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0024  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0025  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0026  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0027  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0028  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0029  * SUCH DAMAGE.
0030  */
0031 
0032 /*-
0033  * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
0034  * All rights reserved.
0035  *
0036  * Redistribution and use in source and binary forms, with or without
0037  * modification, are permitted provided that the following conditions
0038  * are met:
0039  * 1. Redistributions of source code must retain the above copyright
0040  *    notice, this list of conditions and the following disclaimer.
0041  * 2. Redistributions in binary form must reproduce the above copyright
0042  *    notice, this list of conditions and the following disclaimer in the
0043  *    documentation and/or other materials provided with the distribution.
0044  * 3. All advertising materials mentioning features or use of this software
0045  *    must display the following acknowledgement:
0046  *        This product includes software developed by the NetBSD
0047  *        Foundation, Inc. and its contributors.
0048  * 4. Neither the name of The NetBSD Foundation nor the names of its
0049  *    contributors may be used to endorse or promote products derived
0050  *    from this software without specific prior written permission.
0051  *
0052  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
0053  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
0054  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0055  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
0056  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0057  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0058  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0059  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0060  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0061  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0062  * POSSIBILITY OF SUCH DAMAGE.
0063  */
0064 
0065 #ifdef HAVE_CONFIG_H
0066 #include "config.h"
0067 #endif
0068 
0069 #define _DIAGASSERT(a)
0070 
0071 #if 0
0072 #include <sys/cdefs.h>
0073 #if defined(LIBC_SCCS) && !defined(lint)
0074 __RCSID("$NetBSD: vis.c,v 1.33 2005/05/28 13:11:14 lukem Exp $");
0075 #endif /* LIBC_SCCS and not lint */
0076 #endif
0077 
0078 #include <sys/types.h>
0079 
0080 #include "vis.h"
0081 #include <stdlib.h>
0082 
0083 #if !HAVE_VIS || !HAVE_SVIS
0084 #include <ctype.h>
0085 #include <limits.h>
0086 #include <stdio.h>
0087 #include <string.h>
0088 
0089 #undef BELL
0090 #define BELL '\a'
0091 
0092 #define isoctal(c)  (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
0093 #define iswhite(c)  (c == ' ' || c == '\t' || c == '\n')
0094 #define issafe(c)   (c == '\b' || c == BELL || c == '\r')
0095 #define xtoa(c)     "0123456789abcdef"[c]
0096 
0097 #define MAXEXTRAS   5
0098 
0099 
0100 #define MAKEEXTRALIST(flag, extra, orig)                      \
0101 do {                                          \
0102     const char *o = orig;                             \
0103     char *e;                                  \
0104     while (*o++)                                  \
0105         continue;                             \
0106     extra = malloc((size_t)((o - orig) + MAXEXTRAS));             \
0107     if (!extra) break;                            \
0108     for (o = orig, e = extra; (*e++ = *o++) != '\0';)             \
0109         continue;                             \
0110     e--;                                      \
0111     if (flag & VIS_SP) *e++ = ' ';                        \
0112     if (flag & VIS_TAB) *e++ = '\t';                      \
0113     if (flag & VIS_NL) *e++ = '\n';                       \
0114     if ((flag & VIS_NOSLASH) == 0) *e++ = '\\';               \
0115     *e = '\0';                                \
0116 } while (/*CONSTCOND*/0)
0117 
0118 
0119 /*
0120  * This is HVIS, the macro of vis used to HTTP style (RFC 1808)
0121  */
0122 #define HVIS(dst, c, flag, nextc, extra)                      \
0123 do                                        \
0124     if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) { \
0125         *dst++ = '%';                             \
0126         *dst++ = xtoa(((unsigned int)c >> 4) & 0xf);              \
0127         *dst++ = xtoa((unsigned int)c & 0xf);                 \
0128     } else {                                  \
0129         SVIS(dst, c, flag, nextc, extra);                 \
0130     }                                     \
0131 while (/*CONSTCOND*/0)
0132 
0133 /*
0134  * This is SVIS, the central macro of vis.
0135  * dst:       Pointer to the destination buffer
0136  * c:         Character to encode
0137  * flag:      Flag word
0138  * nextc:     The character following 'c'
0139  * extra:     Pointer to the list of extra characters to be
0140  *        backslash-protected.
0141  */
0142 #define SVIS(dst, c, flag, nextc, extra)                      \
0143 do {                                          \
0144     int isextra;                                  \
0145     isextra = strchr(extra, c) != NULL;                   \
0146     if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||        \
0147         ((flag & VIS_SAFE) && issafe(c)))) {                  \
0148         *dst++ = c;                           \
0149         break;                                \
0150     }                                     \
0151     if (flag & VIS_CSTYLE) {                          \
0152         switch (c) {                              \
0153         case '\n':                            \
0154             *dst++ = '\\'; *dst++ = 'n';                  \
0155             continue;                         \
0156         case '\r':                            \
0157             *dst++ = '\\'; *dst++ = 'r';                  \
0158             continue;                         \
0159         case '\b':                            \
0160             *dst++ = '\\'; *dst++ = 'b';                  \
0161             continue;                         \
0162         case BELL:                            \
0163             *dst++ = '\\'; *dst++ = 'a';                  \
0164             continue;                         \
0165         case '\v':                            \
0166             *dst++ = '\\'; *dst++ = 'v';                  \
0167             continue;                         \
0168         case '\t':                            \
0169             *dst++ = '\\'; *dst++ = 't';                  \
0170             continue;                         \
0171         case '\f':                            \
0172             *dst++ = '\\'; *dst++ = 'f';                  \
0173             continue;                         \
0174         case ' ':                             \
0175             *dst++ = '\\'; *dst++ = 's';                  \
0176             continue;                         \
0177         case '\0':                            \
0178             *dst++ = '\\'; *dst++ = '0';                  \
0179             if (isoctal(nextc)) {                     \
0180                 *dst++ = '0';                     \
0181                 *dst++ = '0';                     \
0182             }                             \
0183             continue;                         \
0184         default:                              \
0185             if (isgraph(c)) {                     \
0186                 *dst++ = '\\'; *dst++ = c;            \
0187                 continue;                     \
0188             }                             \
0189         }                                 \
0190     }                                     \
0191     if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {       \
0192         *dst++ = '\\';                            \
0193         *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0';    \
0194         *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0';    \
0195         *dst++ =                 (c       & 07) + '0';    \
0196     } else {                                  \
0197         if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';             \
0198         if (c & 0200) {                           \
0199             c &= 0177; *dst++ = 'M';                  \
0200         }                                 \
0201         if (iscntrl(c)) {                         \
0202             *dst++ = '^';                         \
0203             if (c == 0177)                        \
0204                 *dst++ = '?';                     \
0205             else                              \
0206                 *dst++ = c + '@';                 \
0207         } else {                              \
0208             *dst++ = '-'; *dst++ = c;                 \
0209         }                                 \
0210     }                                     \
0211 } while (/*CONSTCOND*/0)
0212 
0213 
0214 /*
0215  * svis - visually encode characters, also encoding the characters
0216  *    pointed to by `extra'
0217  */
0218 char *
0219 svis(char *dst, int c, int flag, int nextc, const char *extra)
0220 {
0221     char *nextra = NULL;
0222 
0223     _DIAGASSERT(dst != NULL);
0224     _DIAGASSERT(extra != NULL);
0225     MAKEEXTRALIST(flag, nextra, extra);
0226     if (!nextra) {
0227         *dst = '\0';        /* can't create nextra, return "" */
0228         return dst;
0229     }
0230     if (flag & VIS_HTTPSTYLE)
0231         HVIS(dst, c, flag, nextc, nextra);
0232     else
0233         SVIS(dst, c, flag, nextc, nextra);
0234     free(nextra);
0235     *dst = '\0';
0236     return dst;
0237 }
0238 
0239 
0240 /*
0241  * strsvis, strsvisx - visually encode characters from src into dst
0242  *
0243  *  Extra is a pointer to a \0-terminated list of characters to
0244  *  be encoded, too. These functions are useful e. g. to
0245  *  encode strings in such a way so that they are not interpreted
0246  *  by a shell.
0247  *
0248  *  Dst must be 4 times the size of src to account for possible
0249  *  expansion.  The length of dst, not including the trailing NULL,
0250  *  is returned.
0251  *
0252  *  Strsvisx encodes exactly len bytes from src into dst.
0253  *  This is useful for encoding a block of data.
0254  */
0255 int
0256 strsvis(char *dst, const char *csrc, int flag, const char *extra)
0257 {
0258     int c;
0259     char *start;
0260     char *nextra = NULL;
0261     const unsigned char *src = (const unsigned char *)csrc;
0262 
0263     _DIAGASSERT(dst != NULL);
0264     _DIAGASSERT(src != NULL);
0265     _DIAGASSERT(extra != NULL);
0266     MAKEEXTRALIST(flag, nextra, extra);
0267     if (!nextra) {
0268         *dst = '\0';        /* can't create nextra, return "" */
0269         return 0;
0270     }
0271     if (flag & VIS_HTTPSTYLE) {
0272         for (start = dst; (c = *src++) != '\0'; /* empty */)
0273             HVIS(dst, c, flag, *src, nextra);
0274     } else {
0275         for (start = dst; (c = *src++) != '\0'; /* empty */)
0276             SVIS(dst, c, flag, *src, nextra);
0277     }
0278     free(nextra);
0279     *dst = '\0';
0280     return (dst - start);
0281 }
0282 
0283 
0284 int
0285 strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra)
0286 {
0287     unsigned char c;
0288     char *start;
0289     char *nextra = NULL;
0290     const unsigned char *src = (const unsigned char *)csrc;
0291 
0292     _DIAGASSERT(dst != NULL);
0293     _DIAGASSERT(src != NULL);
0294     _DIAGASSERT(extra != NULL);
0295     MAKEEXTRALIST(flag, nextra, extra);
0296     if (! nextra) {
0297         *dst = '\0';        /* can't create nextra, return "" */
0298         return 0;
0299     }
0300 
0301     if (flag & VIS_HTTPSTYLE) {
0302         for (start = dst; len > 0; len--) {
0303             c = *src++;
0304             HVIS(dst, c, flag, len ? *src : '\0', nextra);
0305         }
0306     } else {
0307         for (start = dst; len > 0; len--) {
0308             c = *src++;
0309             SVIS(dst, c, flag, len ? *src : '\0', nextra);
0310         }
0311     }
0312     free(nextra);
0313     *dst = '\0';
0314     return (dst - start);
0315 }
0316 #endif
0317 
0318 #if !HAVE_VIS
0319 /*
0320  * vis - visually encode characters
0321  */
0322 char *
0323 vis(char *dst, int c, int flag, int nextc)
0324 {
0325     char *extra = NULL;
0326     unsigned char uc = (unsigned char)c;
0327 
0328     _DIAGASSERT(dst != NULL);
0329 
0330     MAKEEXTRALIST(flag, extra, "");
0331     if (! extra) {
0332         *dst = '\0';        /* can't create extra, return "" */
0333         return dst;
0334     }
0335     if (flag & VIS_HTTPSTYLE)
0336         HVIS(dst, uc, flag, nextc, extra);
0337     else
0338         SVIS(dst, uc, flag, nextc, extra);
0339     free(extra);
0340     *dst = '\0';
0341     return dst;
0342 }
0343 
0344 
0345 /*
0346  * strvis, strvisx - visually encode characters from src into dst
0347  *
0348  *  Dst must be 4 times the size of src to account for possible
0349  *  expansion.  The length of dst, not including the trailing NULL,
0350  *  is returned.
0351  *
0352  *  Strvisx encodes exactly len bytes from src into dst.
0353  *  This is useful for encoding a block of data.
0354  */
0355 int
0356 strvis(char *dst, const char *src, int flag)
0357 {
0358     char *extra = NULL;
0359     int rv;
0360 
0361     MAKEEXTRALIST(flag, extra, "");
0362     if (!extra) {
0363         *dst = '\0';        /* can't create extra, return "" */
0364         return 0;
0365     }
0366     rv = strsvis(dst, src, flag, extra);
0367     free(extra);
0368     return rv;
0369 }
0370 
0371 
0372 int
0373 strvisx(char *dst, const char *src, size_t len, int flag)
0374 {
0375     char *extra = NULL;
0376     int rv;
0377 
0378     MAKEEXTRALIST(flag, extra, "");
0379     if (!extra) {
0380         *dst = '\0';        /* can't create extra, return "" */
0381         return 0;
0382     }
0383     rv = strsvisx(dst, src, len, flag, extra);
0384     free(extra);
0385     return rv;
0386 }
0387 #endif