diff options
Diffstat (limited to 'lib/roken/vis.c')
| -rw-r--r-- | lib/roken/vis.c | 333 |
1 files changed, 280 insertions, 53 deletions
diff --git a/lib/roken/vis.c b/lib/roken/vis.c index 19ff29d95ca8..0fe44ae35023 100644 --- a/lib/roken/vis.c +++ b/lib/roken/vis.c @@ -55,48 +55,110 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#if 1 +#define _DEFAULT_SOURCE #include <config.h> #include "roken.h" +#ifdef TEST +#include "getarg.h" +#endif #ifndef _DIAGASSERT #define _DIAGASSERT(X) #endif -#else /* heimdal */ -#include <sys/cdefs.h> -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: vis.c,v 1.37 2008/07/25 22:29:23 dsl Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#include "namespace.h" -#endif /* heimdal */ #include <sys/types.h> - #include <assert.h> #include <ctype.h> +#ifdef TEST +#include <err.h> +#endif +#include <errno.h> #include <limits.h> #include <stdio.h> #include <string.h> -#include <vis.h> #include <stdlib.h> - -#if 0 -#ifdef __weak_alias -__weak_alias(strsvis,_strsvis) -__weak_alias(strsvisx,_strsvisx) -__weak_alias(strvis,_strvis) -__weak_alias(strvisx,_strvisx) -__weak_alias(svis,_svis) -__weak_alias(vis,_vis) -#endif -#endif +#include <vis.h> #if !HAVE_VIS || !HAVE_SVIS #include <ctype.h> #include <limits.h> #include <stdio.h> #include <string.h> +#endif + +#if !HAVE_VIS || !HAVE_SVIS || TEST +/* + * We use makextralist() in main(), so we need it even if we have all the VIS + * routines in the host's C libraries. + */ + +/* 5 is for VIS_SP, VIS_TAB, VIS_NL, VIS_DQ, and VIS_NOSLASH */ +#define MAXEXTRAS (sizeof(char_glob) - 1 + sizeof(char_shell) - 1 + 5) + +#ifndef VIS_SHELL +#define VIS_SHELL 0x2000 +#endif +#ifndef VIS_GLOB +#define VIS_GLOB 0x0100 +#endif + +#ifndef VIS_SP +#define VIS_SP 0x0004 /* also encode space */ +#endif +#ifndef VIS_TAB +#define VIS_TAB 0x0008 /* also encode tab */ +#endif +#ifndef VIS_NL +#define VIS_NL 0x0010 /* also encode newline */ +#endif +#ifndef VIS_WHITE +#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) +#endif +#ifndef VIS_SAFE +#define VIS_SAFE 0x0020 /* only encode "unsafe" characters */ +#endif +#ifndef VIS_DQ +#define VIS_DQ 0x8000 /* also encode double quotes */ +#endif + + +/* + * Expand list of extra characters to not visually encode. + */ +static char * +makeextralist(int flags, const char *src) +{ + static const char char_glob[] = "*?[#"; + static const char char_shell[] = "'`\";&<>()|{}]\\$!^~"; + char *dst, *d; + size_t len; + + len = strlen(src); + if ((dst = d = calloc(1, len + MAXEXTRAS + 1)) == NULL) + return NULL; + + memcpy(dst, src, len); + d += len; + + if (flags & VIS_GLOB) { + memcpy(d, char_glob, sizeof(char_glob) - 1); + d += sizeof(char_glob) - 1; + } + if (flags & VIS_SHELL) { + memcpy(d, char_shell, sizeof(char_shell) - 1); + d += sizeof(char_shell) - 1; + } + + if (flags & VIS_SP) *d++ = ' '; + if (flags & VIS_TAB) *d++ = '\t'; + if (flags & VIS_NL) *d++ = '\n'; + if (flags & VIS_DQ) *d++ = '"'; + if ((flags & VIS_NOSLASH) == 0) *d++ = '\\'; + + return dst; +} +#endif +#if !HAVE_VIS || !HAVE_SVIS static char *do_svis(char *, int, int, int, const char *); #undef BELL @@ -119,40 +181,19 @@ ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL rk_strsvisx (char *, const char *, size_t, int, const char *); - #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') #define iswhite(c) (c == ' ' || c == '\t' || c == '\n') #define issafe(c) (c == '\b' || c == BELL || c == '\r') #define xtoa(c) "0123456789abcdef"[c] -#define MAXEXTRAS 5 - -#define MAKEEXTRALIST(flag, extra, orig_str) \ -do { \ - const char *orig = orig_str; \ - const char *o = orig; \ - char *e; \ - while (*o++) \ - continue; \ - extra = malloc((size_t)((o - orig) + MAXEXTRAS)); \ - if (!extra) break; \ - for (o = orig, e = extra; (*e++ = *o++) != '\0';) \ - continue; \ - e--; \ - if (flag & VIS_SP) *e++ = ' '; \ - if (flag & VIS_TAB) *e++ = '\t'; \ - if (flag & VIS_NL) *e++ = '\n'; \ - if ((flag & VIS_NOSLASH) == 0) *e++ = '\\'; \ - *e = '\0'; \ -} while (/*CONSTCOND*/0) - /* * This is do_hvis, for HTTP style (RFC 1808) */ static char * do_hvis(char *dst, int c, int flag, int nextc, const char *extra) { - if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) { + if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL || + strchr(extra, c)) { *dst++ = '%'; *dst++ = xtoa(((unsigned int)c >> 4) & 0xf); *dst++ = xtoa((unsigned int)c & 0xf); @@ -256,7 +297,7 @@ rk_svis(char *dst, int c, int flag, int nextc, const char *extra) _DIAGASSERT(dst != NULL); _DIAGASSERT(extra != NULL); - MAKEEXTRALIST(flag, nextra, extra); + nextra = makeextralist(flag, extra); if (!nextra) { *dst = '\0'; /* can't create nextra, return "" */ return dst; @@ -298,7 +339,7 @@ rk_strsvis(char *dst, const char *csrc, int flag, const char *extra) _DIAGASSERT(dst != NULL); _DIAGASSERT(src != NULL); _DIAGASSERT(extra != NULL); - MAKEEXTRALIST(flag, nextra, extra); + nextra = makeextralist(flag, extra); if (!nextra) { *dst = '\0'; /* can't create nextra, return "" */ return 0; @@ -327,7 +368,7 @@ rk_strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra _DIAGASSERT(dst != NULL); _DIAGASSERT(src != NULL); _DIAGASSERT(extra != NULL); - MAKEEXTRALIST(flag, nextra, extra); + nextra = makeextralist(flag, extra); if (! nextra) { *dst = '\0'; /* can't create nextra, return "" */ return 0; @@ -336,12 +377,12 @@ rk_strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra if (flag & VIS_HTTPSTYLE) { for (start = dst; len > 0; len--) { c = *src++; - dst = do_hvis(dst, c, flag, len ? *src : '\0', nextra); + dst = do_hvis(dst, c, flag, *src, nextra); } } else { for (start = dst; len > 0; len--) { c = *src++; - dst = do_svis(dst, c, flag, len ? *src : '\0', nextra); + dst = do_svis(dst, c, flag, *src, nextra); } } free(nextra); @@ -350,6 +391,69 @@ rk_strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra } #endif +/* + * Heimdal innovations: functions that allocate or reallocate a destination + * buffer as needed. Based on OpenBSD's stravis(). + */ + +#include <vis-extras.h> + +ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +rk_strasvis(char **out, const char *csrc, int flag, const char *extra) +{ + return rk_strasvisx(out, csrc, strlen(csrc), flag, extra); +} + +ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +rk_strrasvis(char **out, size_t *outsz, const char *csrc, int flag, const char *extra) +{ + return rk_strrasvisx(out, outsz, csrc, strlen(csrc), flag, extra); +} + +ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +rk_strasvisx(char **out, const char *csrc, size_t len, int flag, const char *extra) +{ + size_t sz = 0; + + *out = NULL; + return rk_strrasvisx(out, &sz, csrc, strlen(csrc), flag, extra); +} + +ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +rk_strrasvisx(char **out, + size_t *outsz, + const char *csrc, + size_t len, + int flag, + const char *extra) +{ + size_t want = 4 * len + 4; + size_t have = *outsz; + char *s = *out; + int r; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(src != NULL); + _DIAGASSERT(extra != NULL); + if (want < len || want > INT_MAX) { + errno = EOVERFLOW; + return -1; + } + if (have < want) { + if ((s = realloc(s, want)) == NULL) + return -1; + *outsz = want; + *out = s; + } + if (*out == NULL) { + errno = EINVAL; + return -1; + } + **out = '\0'; /* Makes source debugging nicer, that's all */ + r = strsvisx(*out, csrc, len, flag, extra); + return r; +} + #if !HAVE_VIS /* * vis - visually encode characters @@ -362,7 +466,7 @@ rk_vis(char *dst, int c, int flag, int nextc) _DIAGASSERT(dst != NULL); - MAKEEXTRALIST(flag, extra, ""); + extra = makeextralist(flag, ""); if (! extra) { *dst = '\0'; /* can't create extra, return "" */ return dst; @@ -393,7 +497,7 @@ rk_strvis(char *dst, const char *src, int flag) char *extra = NULL; int rv; - MAKEEXTRALIST(flag, extra, ""); + extra = makeextralist(flag, ""); if (!extra) { *dst = '\0'; /* can't create extra, return "" */ return 0; @@ -410,7 +514,7 @@ rk_strvisx(char *dst, const char *src, size_t len, int flag) char *extra = NULL; int rv; - MAKEEXTRALIST(flag, extra, ""); + extra = makeextralist(flag, ""); if (!extra) { *dst = '\0'; /* can't create extra, return "" */ return 0; @@ -420,3 +524,126 @@ rk_strvisx(char *dst, const char *src, size_t len, int flag) return rv; } #endif + +#ifdef TEST +static const char *extra_arg = ""; +static int cstyle_flag; +static int glob_flag; +static int help_flag; +static int http_flag; +static int httponly_flag; +static int line_flag; +static int octal_flag; +static int safe_flag; +static int shell_flag; +static int stdin_flag; +static int tab_flag; +static int whitespace_flag; + +/* + * The short options are compatible with a subset of the FreeBSD contrib + * vis(1). Heimdal additions have long option names only. + */ +static struct getargs args[] = { + { "c", 'C', arg_flag, &cstyle_flag, "C style", "C style" }, + { "extra", 'e', arg_string, &extra_arg, "also encode extra", "also encode extra"}, + { "glob", 'g', arg_flag, &glob_flag, "escape glob specials", "escape glob specials" }, + { "help", 0, arg_flag, &help_flag, "help", "help"}, + { "line", 0, arg_flag, &line_flag, "read and escape stdin without escaping newlines", NULL }, + { "octal", 'o', arg_flag, &octal_flag, "octal escape", "octal escape" }, + { "safe", 's', arg_flag, &safe_flag, "only encode \"unsafe\" characters", "only encode \"unsafe\" characters" }, + { "shell", 'S', arg_flag, &shell_flag, "encode shell meta-characters", "encode shell meta-characters" }, + { "stdin", 0, arg_flag, &stdin_flag, "read and escape stdin", NULL }, + { "tab", 't', arg_flag, &tab_flag, "encode tabs", "encode tabs" }, + { "url", 'h', arg_flag, &http_flag, "url escape", "url escape" }, + { "url-only", 0, arg_flag, &httponly_flag, "url escape", "url escape" }, + { "whitespace", 'w', arg_flag, &whitespace_flag, "encode whitespace", "encode whitespace" }, + { 0, 0, 0, 0, 0, 0} +}; +static size_t num_args = sizeof(args)/sizeof(args[0]); + +int +main(int argc, char **argv) +{ + size_t sz = 0; + char *nextra = NULL; + char *s = NULL; + int goptind = 0; + int flags = 0; + + setprogname("vis"); + if (getarg(args, num_args, argc, argv, &goptind) || help_flag) { + arg_printusage(args, num_args, NULL, "strings..."); + return help_flag ? 0 : 1; + } + + argc -= goptind; + argv += goptind; + + if (argc == 0 && !stdin_flag && !line_flag) { + arg_printusage(args, num_args, NULL, "strings..."); + return 1; + } + + if (http_flag && cstyle_flag) + errx(1, "--http and --cstyle are mutually exclusive"); + + flags |= cstyle_flag ? VIS_CSTYLE : 0; + flags |= http_flag ? VIS_HTTPSTYLE : 0; + flags |= httponly_flag ? VIS_HTTPSTYLE | VIS_NOESCAPE : 0; + flags |= octal_flag ? VIS_OCTAL : 0; + flags |= safe_flag ? VIS_SAFE : 0; + flags |= tab_flag ? VIS_TAB : 0; + flags |= whitespace_flag ? VIS_WHITE : 0; + + if ((nextra = makeextralist(flags, extra_arg)) == NULL) + err(1, "Out of memory"); + + while (argc) { + if (rk_strrasvis(&s, &sz, argv[0], flags, nextra) < 0) + err(2, "Out of memory"); + printf("%s\n", s); + argc--; + } + if (line_flag) { + ssize_t nbytes; + size_t linesz = 0; + char *line = NULL; + + while (!feof(stdin) && + (nbytes = getline(&line, &linesz, stdin)) > 0) { + const char *nl = ""; + + if (line[nbytes - 1] == '\n') { + line[--nbytes] = '\0'; + nl = "\n"; + } + + if (rk_strrasvisx(&s, &sz, line, nbytes, flags, nextra) < 0) + err(2, "Out of memory"); + printf("%s%s", s, nl); + } + fflush(stdout); + if (ferror(stdin)) + errx(2, "I/O error"); + } else if (stdin_flag) { + size_t nbytes; + char buf[2048 + 1]; + char vbuf[4 * (sizeof(buf) - 1) + 1]; + + while (!feof(stdin) && + (nbytes = fread(buf, 1, sizeof(buf) - 1, stdin))) { + buf[nbytes] = '\0'; + strsvis(vbuf, buf, flags, nextra); + printf("%s", vbuf); + } + fflush(stdout); + if (ferror(stdin)) + errx(2, "I/O error"); + } + + free(nextra); + free(s); + return 0; +} +#endif |
