diff options
Diffstat (limited to 'tests/wsp.c')
-rw-r--r-- | tests/wsp.c | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/tests/wsp.c b/tests/wsp.c new file mode 100644 index 0000000..e06008f --- /dev/null +++ b/tests/wsp.c @@ -0,0 +1,377 @@ +/* grecs - Gray's Extensible Configuration System + Copyright (C) 2014 Sergey Poznyakoff + + Grecs is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + Grecs is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Grecs. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include "wordsplit.h" + +extern char **environ; + +char *progname; + +struct kwd +{ + const char *name; + int tok; +}; + +struct kwd bool_keytab[] = { + { "append", WRDSF_APPEND }, + /*{ "reuse", WRDSF_REUSE },*/ + { "undef", WRDSF_UNDEF }, + { "novar", WRDSF_NOVAR }, + { "nocmd", WRDSF_NOCMD }, + { "ws", WRDSF_WS }, + { "quote", WRDSF_QUOTE }, + { "squote", WRDSF_SQUOTE }, + { "dquote", WRDSF_DQUOTE }, + { "squeeze_delims", WRDSF_SQUEEZE_DELIMS }, + { "return_delims", WRDSF_RETURN_DELIMS }, + { "sed", WRDSF_SED_EXPR }, + { "debug", WRDSF_SHOWDBG }, + { "nosplit", WRDSF_NOSPLIT }, + { "keepundef", WRDSF_KEEPUNDEF }, + { "warnundef", WRDSF_WARNUNDEF }, + { "cescapes", WRDSF_CESCAPES }, + { "default", WRDSF_DEFFLAGS }, + { "env_kv", WRDSF_ENV_KV }, + { "incremental", WRDSF_INCREMENTAL }, + { NULL, 0 } +}; + +struct kwd string_keytab[] = { + { "delim", WRDSF_DELIM }, + { "comment", WRDSF_COMMENT }, + { "escape", WRDSF_ESCAPE }, + { NULL, 0 } +}; + +static int +kwxlat (struct kwd *kwp, const char *str, int *res) +{ + for (; kwp->name; kwp++) + if (strcmp (kwp->name, str) == 0) + { + *res = kwp->tok; + return 0; + } + return -1; +} + +static void +help () +{ + size_t i; + + printf ("usage: %s [options]\n", progname); + printf ("options are:\n"); + printf (" [-]trimnl\n"); + printf (" [-]plaintext\n"); + putchar ('\n'); + for (i = 0; bool_keytab[i].name; i++) + printf (" [-]%s\n", bool_keytab[i].name); + putchar ('\n'); + for (i = 0; string_keytab[i].name; i++) + { + printf (" -%s\n", bool_keytab[i].name); + printf (" %s ARG\n", bool_keytab[i].name); + } + putchar ('\n'); + printf (" -dooffs\n"); + printf (" dooffs COUNT ARGS...\n"); + exit (0); +} + +void +print_qword (const char *word, int plaintext) +{ + static char *qbuf = NULL; + static size_t qlen = 0; + int quote; + size_t size = wordsplit_c_quoted_length (word, 0, "e); + + if (plaintext) + { + printf ("%s", word); + return; + } + + if (*word == 0) + quote = 1; + + if (size >= qlen) + { + qlen = size + 1; + qbuf = realloc (qbuf, qlen); + assert (qbuf != NULL); + } + wordsplit_c_quote_copy (qbuf, word, 0); + qbuf[size] = 0; + if (quote) + printf ("\"%s\"", qbuf); + else + printf ("%s", qbuf); +} + +/* Convert environment to K/V form */ +static char ** +make_env_kv () +{ + size_t i, j, size; + char **newenv; + + /* Count the number of entries */ + for (i = 0; environ[i]; i++) + ; + + size = (i - 1) * 2 + 1; + newenv = calloc (size, sizeof (newenv[0])); + assert (newenv != NULL); + + for (i = j = 0; environ[i]; i++) + { + size_t len = strcspn (environ[i], "="); + char *p = malloc (len+1); + assert (p != NULL); + memcpy (p, environ[i], len); + p[len] = 0; + newenv[j++] = p; + p = strdup (environ[i] + len + 1); + assert (p != NULL); + newenv[j++] = p; + } + newenv[j] = NULL; + return newenv; +} + +int +main (int argc, char **argv) +{ + char buf[1024], *ptr; + int i, offarg = 0; + int trimnl_option = 0; + int plaintext_option = 0; + int wsflags = (WRDSF_DEFFLAGS & ~WRDSF_NOVAR) | + WRDSF_ENOMEMABRT | + WRDSF_ENV | WRDSF_SHOWERR; + struct wordsplit ws; + int next_call = 0; + + progname = argv[0]; + + for (i = 1; i < argc; i++) + { + char *opt = argv[i]; + int negate; + int flag; + + if (opt[0] == '-') + { + negate = 1; + opt++; + } + else if (opt[0] == '+') + { + negate = 0; + opt++; + } + else + negate = 0; + + if (strcmp (opt, "h") == 0 || + strcmp (opt, "help") == 0 || + strcmp (opt, "-help") == 0) + { + help (); + } + + if (strcmp (opt, "trimnl") == 0) + { + trimnl_option = !negate; + continue; + } + + if (strcmp (opt, "plaintext") == 0) + { + plaintext_option = !negate; + continue; + } + + if (kwxlat (bool_keytab, opt, &flag) == 0) + { + if (negate) + wsflags &= ~flag; + else + wsflags |= flag; + continue; + } + + if (kwxlat (string_keytab, opt, &flag) == 0) + { + if (negate) + wsflags &= ~flag; + else + { + i++; + if (i == argc) + { + fprintf (stderr, "%s: missing argument for %s\n", + progname, opt); + exit (1); + } + + switch (flag) + { + case WRDSF_DELIM: + ws.ws_delim = argv[i]; + break; + + case WRDSF_COMMENT: + ws.ws_comment = argv[i]; + break; + + case WRDSF_ESCAPE: + ws.ws_escape = argv[i]; + break; + } + + wsflags |= flag; + } + continue; + } + + if (strcmp (opt, "dooffs") == 0) + { + if (negate) + wsflags &= ~WRDSF_DOOFFS; + else + { + char *p; + + i++; + + if (i == argc) + { + fprintf (stderr, "%s: missing arguments for %s\n", + progname, opt); + exit (1); + } + ws.ws_offs = strtoul (argv[i], &p, 10); + if (*p) + { + fprintf (stderr, "%s: invalid number: %s\n", + progname, argv[i]); + exit (1); + } + + i++; + if (i + ws.ws_offs > argc) + { + fprintf (stderr, "%s: not enough arguments for %s\n", + progname, opt); + exit (1); + } + offarg = i; + i += ws.ws_offs - 1; + wsflags |= WRDSF_DOOFFS; + } + continue; + } + + fprintf (stderr, "%s: unrecognized argument for %s\n", + progname, opt); + exit (1); + } + + if (wsflags & WRDSF_ENV_KV) + ws.ws_env = (const char **) make_env_kv (); + else + ws.ws_env = (const char **) environ; + + if (wsflags & WRDSF_INCREMENTAL) + trimnl_option = 1; + + next_call = 0; + while ((ptr = fgets (buf, sizeof (buf), stdin))) + { + int rc; + size_t i; + + if (trimnl_option) + { + size_t len = strlen (ptr); + if (len && ptr[len-1] == '\n') + ptr[len-1] = 0; + } + + if (wsflags & WRDSF_INCREMENTAL) + { + if (next_call) + { + if (*ptr == 0) + ptr = NULL; + else + free ((void*)ws.ws_input); + } + else + next_call = 1; + if (ptr) + { + ptr = strdup (ptr); + assert (ptr != NULL); + } + } + + rc = wordsplit (ptr, &ws, wsflags); + if (rc) + { + if (!(wsflags & WRDSF_SHOWERR)) + wordsplit_perror (&ws); + continue; + } + + if (offarg) + { + for (i = 0; i < ws.ws_offs; i++) + ws.ws_wordv[i] = argv[offarg + i]; + offarg = 0; + } + + wsflags |= WRDSF_REUSE; + printf ("NF: %lu", (unsigned long) ws.ws_wordc); + if (wsflags & WRDSF_DOOFFS) + printf (" (%lu)", (unsigned long) ws.ws_offs); + putchar ('\n'); + for (i = 0; i < ws.ws_offs; i++) + { + printf ("(%lu): ", (unsigned long) i); + print_qword (ws.ws_wordv[i], plaintext_option); + putchar ('\n'); + } + for (; i < ws.ws_offs + ws.ws_wordc; i++) + { + printf ("%lu: ", (unsigned long) i); + print_qword (ws.ws_wordv[i], plaintext_option); + putchar ('\n'); + } + } + return 0; +} |