From 01b5101b2ae8b52d1531a66fbaa4d03c954c5e48 Mon Sep 17 00:00:00 2001 From: phk Date: Tue, 14 Mar 2006 09:15:36 +0000 Subject: [PATCH] Add a function to break a command line like string into an argv[]. This will be useful for the various text based protocols etc. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@47 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- varnish-cache/include/Makefile.am | 2 +- varnish-cache/include/libvarnish.h | 7 + varnish-cache/lib/libvarnish/Makefile.am | 3 +- varnish-cache/lib/libvarnish/argv.c | 213 +++++++++++++++++++++++ 4 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 varnish-cache/include/libvarnish.h create mode 100644 varnish-cache/lib/libvarnish/argv.c diff --git a/varnish-cache/include/Makefile.am b/varnish-cache/include/Makefile.am index 2f0e8db4..57aaabb9 100644 --- a/varnish-cache/include/Makefile.am +++ b/varnish-cache/include/Makefile.am @@ -2,9 +2,9 @@ include_HEADERS = \ hash.h \ + libvarnish.h \ queue.h \ sbuf.h \ tree.h \ varnish/assert.h \ varnishapi.h - diff --git a/varnish-cache/include/libvarnish.h b/varnish-cache/include/libvarnish.h new file mode 100644 index 00000000..b50fcd25 --- /dev/null +++ b/varnish-cache/include/libvarnish.h @@ -0,0 +1,7 @@ +/* + * $Id$ + */ + +/* from libvarnish/argv.c */ +void FreeArgv(char **argv); +char **ParseArgv(const char *s, int comment); diff --git a/varnish-cache/lib/libvarnish/Makefile.am b/varnish-cache/lib/libvarnish/Makefile.am index 098bb4f9..6b1ed7c6 100644 --- a/varnish-cache/lib/libvarnish/Makefile.am +++ b/varnish-cache/lib/libvarnish/Makefile.am @@ -4,4 +4,5 @@ INCLUDES = -I$(top_srcdir)/include lib_LTLIBRARIES = libvarnish.la -libvarnish_la_SOURCES = +libvarnish_la_SOURCES = \ + argv.c diff --git a/varnish-cache/lib/libvarnish/argv.c b/varnish-cache/lib/libvarnish/argv.c new file mode 100644 index 00000000..52452309 --- /dev/null +++ b/varnish-cache/lib/libvarnish/argv.c @@ -0,0 +1,213 @@ +/* + * $Id$ + * + * char **ParseArgv(const char *s, int comment) + * Parse a command like line into an argv[] + * Index zero contains NULL or an error message + * "double quotes" and backslash substitution is handled. + * + * void FreeArgv(char **argv) + * Free the result of ParseArgv() + * + */ + +#include +#include +#include +#include +#include + +#include "libvarnish.h" + +static int +BackSlash(const char *s, int *res) +{ + int i, r; + + assert(*s == '\\'); + r = i = 0; + switch(s[1]) { + case 'n': + i = '\n'; + r = 2; + break; + case 'r': + i = '\r'; + r = 2; + break; + case 't': + i = '\t'; + r = 2; + break; + case '"': + i = '"'; + r = 2; + break; + case '\\': + i = '\\'; + r = 2; + break; + case '0': case '1': case '2': case 3: + case '4': case '5': case '6': case 7: + for (r = 1; r < 4; r++) { + if (!isdigit(s[r])) + break; + if (digittoint(s[r]) > 7) + break; + i <<= 3; + i |= digittoint(s[r]); + } + break; + case 'x': + if (1 == sscanf(s + 1, "x%02x", &i)) + r = 4; + break; + default: + break; + } + if (res != NULL) + *res = i; + return (r); +} + +static char * +BackSlashDecode(const char *s, const char *e) +{ + const char *q; + char *p, *r; + int i, j; + + p = calloc((e - s) + 1, 1); + if (p == NULL) + return (p); + for (r = p, q = s; q < e; ) { + if (*q != '\\') { + *r++ = *q++; + continue; + } + i = BackSlash(q, &j); + q += i; + *r++ = j; + } + *r = '\0'; + return (p); +} + +char ** +ParseArgv(const char *s, int comment) +{ + char **argv; + const char *p; + int nargv, largv; + int i, quote; + + assert(s != NULL); + nargv = 1; + largv = 16; + argv = calloc(sizeof *argv, largv); + if (argv == NULL) + return (NULL); + + for (;;) { + if (*s == '\0') + break; + if (isspace(*s)) { + s++; + continue; + } + if (comment && *s == '#') + break; + if (*s == '"') { + p = ++s; + quote = 1; + } else { + p = s; + quote = 0; + } + while (1) { + if (*s == '\\') { + i = BackSlash(s, NULL); + if (i == 0) { + argv[0] = __DECONST(void *, + "Illegal backslash sequence"); + return (argv); + } + s += i; + continue; + } + if (!quote) { + if (*s == '\0' || isspace(*s)) + break; + s++; + continue; + } + if (*s == '"') + break; + if (*s == '\0') { + argv[0] = __DECONST(void *, + "Missing '\"'"); + return (argv); + } + s++; + } + if (nargv + 1 >= largv) { + argv = realloc(argv, sizeof (*argv) * (largv += largv)); + assert(argv != NULL); + } + argv[nargv++] = BackSlashDecode(p, s); + if (*s != '\0') + s++; + } + argv[nargv++] = NULL; + return (argv); +} + +void +FreeArgv(char **argv) +{ + int i; + + for (i = 1; argv[i] != NULL; i++) + free(argv[i]); + free(argv); +} + +#ifdef TESTPROG + +#include + +static void +PrintArgv(char **argv) +{ + int i; + + printf("---- %p\n", argv); + if (argv[0] != NULL) + printf("err %V\n", argv[0]); + for (i = 1; argv[i] != NULL; i++) + printf("%3d %V\n", i, argv[i]); +} + +static void +Test(const char *str) +{ + char **av; + + printf("Test: <%V>\n", str); + av = ParseArgv(str, 0); + PrintArgv(av); +} + +int +main(int argc __unused, char **argv __unused) +{ + char buf[BUFSIZ]; + + register_printf_render_std("V"); + + while (fgets(buf, sizeof buf, stdin)) + Test(buf); + + return (0); +} +#endif -- 2.39.5