diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2019-07-11 11:29:34 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2019-07-11 11:29:34 +0300 |
commit | 2ad00905cde7230317c27fcbb3c41969ca5b79ab (patch) | |
tree | 5a159e95e5d9a649b189fc634832320010ec4657 /libmailutils | |
parent | 4ba3d95fe9bd9bb3b93be60a8ea89e381c5f88c0 (diff) | |
download | mailutils-2ad00905cde7230317c27fcbb3c41969ca5b79ab.tar.gz mailutils-2ad00905cde7230317c27fcbb3c41969ca5b79ab.tar.bz2 |
Pull wordsplit from submodule.
* .gitmodules: Add wordsplit.
* configure.ac: Version 3.7.90
* NEWS: Raise version number.
* include/mailutils/sys/Makefile.am: Include wordsplit.h from the
submodule.
* include/mailutils/sys/wordsplit.h: New file.
* include/mailutils/wordsplit.h: Rewrite as a wrapper over
mailutils/sys/wordsplit.h
* libmailutils/Makefile.am: Distribute files from wordsplit.
* libmailutils/string/Makefile.am: Add libmailutils/wordsplit to
the include path.
* libmailutils/string/wordsplit.c: Replace with a wrapper over
wordsplit/wordsplit.c
* libmailutils/tests/.gitignore: Update.
* libmailutils/tests/Makefile.am: Pull wordsplit testsuite from
the submodule.
* libmailutils/tests/wordsplit.at: Remove.
* libmailutils/tests/wsp.c: Remove.
Diffstat (limited to 'libmailutils')
-rw-r--r-- | libmailutils/Makefile.am | 6 | ||||
-rw-r--r-- | libmailutils/string/Makefile.am | 6 | ||||
-rw-r--r-- | libmailutils/string/wordsplit.c | 2382 | ||||
-rw-r--r-- | libmailutils/tests/.gitignore | 1 | ||||
-rw-r--r-- | libmailutils/tests/Makefile.am | 35 | ||||
-rw-r--r-- | libmailutils/tests/wordsplit.at | 787 | ||||
-rw-r--r-- | libmailutils/tests/wsp.c | 654 | ||||
m--------- | libmailutils/wordsplit | 0 |
8 files changed, 44 insertions, 3827 deletions
diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am index 422d2c154..71bcda298 100644 --- a/libmailutils/Makefile.am +++ b/libmailutils/Makefile.am @@ -77,6 +77,12 @@ libmailutils_la_LIBADD = \ stdstream/libstdstream.la\ url/liburl.la\ wicket/libwicket.la libmailutils_la_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ +EXTRA_DIST =\ + wordsplit/wordsplit.c\ + wordsplit/wordsplit.h\ + wordsplit/wordsplit.at\ + wordsplit/wsp.c + diff --git a/libmailutils/string/Makefile.am b/libmailutils/string/Makefile.am index 5cdd73913..24557717a 100644 --- a/libmailutils/string/Makefile.am +++ b/libmailutils/string/Makefile.am @@ -47,7 +47,11 @@ libstring_la_SOURCES = \ mkfilename.c\ wordsplit.c\ xdecode.c EXTRA_DIST=to_sn.c to_un.c -AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils -I${srcdir} +AM_CPPFLAGS = \ + @MU_LIB_COMMON_INCLUDES@\ + -I${srcdir}\ + -I${top_srcdir}/libmailutils\ + -I${top_srcdir}/libmailutils/wordsplit diff --git a/libmailutils/string/wordsplit.c b/libmailutils/string/wordsplit.c index 1f9b32a66..dc3a04df8 100644 --- a/libmailutils/string/wordsplit.c +++ b/libmailutils/string/wordsplit.c @@ -1,2382 +1,2 @@ -/* wordsplit - a word splitter - Copyright (C) 2009-2015 Sergey Poznyakoff - - This program 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. - - This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ - -/* This module is shared with Grecs: http://puszcza.gnu.org.ua/projects/grecs. - The intent is to keep it as mu-independent as possible, so that the two - projects can be easily synchronized. Some time in the future I'll think - about providing a better way of synching, perhaps by integrating Grecs to - Mailutils as a submodule. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <errno.h> -#include <ctype.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <stdarg.h> -#include <pwd.h> -#include <glob.h> - -#include <mailutils/nls.h> #include <mailutils/wordsplit.h> - -#define ISWS(c) ((c)==' '||(c)=='\t'||(c)=='\n') -#define ISDELIM(ws,c) \ - (strchr ((ws)->ws_delim, (c)) != NULL) -#define ISPUNCT(c) (strchr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",(c))!=NULL) -#define ISUPPER(c) ('A' <= ((unsigned) (c)) && ((unsigned) (c)) <= 'Z') -#define ISLOWER(c) ('a' <= ((unsigned) (c)) && ((unsigned) (c)) <= 'z') -#define ISALPHA(c) (ISUPPER(c) || ISLOWER(c)) -#define ISDIGIT(c) ('0' <= ((unsigned) (c)) && ((unsigned) (c)) <= '9') -#define ISXDIGIT(c) (strchr("abcdefABCDEF", c)!=NULL) -#define ISALNUM(c) (ISALPHA(c) || ISDIGIT(c)) -#define ISPRINT(c) (' ' <= ((unsigned) (c)) && ((unsigned) (c)) <= 127) - -#define ISVARBEG(c) (ISALPHA(c) || c == '_') -#define ISVARCHR(c) (ISALNUM(c) || c == '_') - -#define ALLOC_INIT 128 -#define ALLOC_INCR 128 - -static void -_wsplt_alloc_die (struct mu_wordsplit *wsp) -{ - wsp->ws_error ("%s", _("memory exhausted")); - abort (); -} - -static void -_wsplt_error (const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - fputc ('\n', stderr); -} - -static void mu_wordsplit_free_nodes (struct mu_wordsplit *); - -static int -_wsplt_seterr (struct mu_wordsplit *wsp, int ec) -{ - wsp->ws_errno = ec; - if (wsp->ws_flags & MU_WRDSF_SHOWERR) - mu_wordsplit_perror (wsp); - return ec; -} - -static int -_wsplt_nomem (struct mu_wordsplit *wsp) -{ - errno = ENOMEM; - wsp->ws_errno = MU_WRDSE_NOSPACE; - if (wsp->ws_flags & MU_WRDSF_ENOMEMABRT) - wsp->ws_alloc_die (wsp); - if (wsp->ws_flags & MU_WRDSF_SHOWERR) - mu_wordsplit_perror (wsp); - if (!(wsp->ws_flags & MU_WRDSF_REUSE)) - mu_wordsplit_free (wsp); - mu_wordsplit_free_nodes (wsp); - return wsp->ws_errno; -} - -static int mu_wordsplit_run (const char *command, size_t length, - struct mu_wordsplit *wsp, - int flags, int lvl); - -static int -_wsplt_subsplit (struct mu_wordsplit *wsp, struct mu_wordsplit *wss, - char const *str, int len, - int flags) -{ - wss->ws_delim = wsp->ws_delim; - wss->ws_debug = wsp->ws_debug; - wss->ws_error = wsp->ws_error; - wss->ws_alloc_die = wsp->ws_alloc_die; - - if (!(flags & MU_WRDSF_NOVAR)) - { - wss->ws_env = wsp->ws_env; - wss->ws_getvar = wsp->ws_getvar; - flags |= wsp->ws_flags & (MU_WRDSF_ENV | MU_WRDSF_ENV_KV | MU_WRDSF_GETVAR); - } - if (!(flags & MU_WRDSF_NOCMD)) - { - wss->ws_command = wsp->ws_command; - } - - if ((flags & (MU_WRDSF_NOVAR|MU_WRDSF_NOCMD)) != (MU_WRDSF_NOVAR|MU_WRDSF_NOCMD)) - { - wss->ws_closure = wsp->ws_closure; - flags |= wsp->ws_flags & MU_WRDSF_CLOSURE; - } - - wss->ws_options = wsp->ws_options; - - flags |= MU_WRDSF_DELIM - | MU_WRDSF_ALLOC_DIE - | MU_WRDSF_ERROR - | MU_WRDSF_DEBUG - | (wsp->ws_flags & (MU_WRDSF_SHOWDBG | MU_WRDSF_SHOWERR | MU_WRDSF_OPTIONS)); - - return mu_wordsplit_run (str, len, wss, flags, wsp->ws_lvl + 1); -} - -static void -_wsplt_seterr_sub (struct mu_wordsplit *wsp, struct mu_wordsplit *wss) -{ - if (wsp->ws_errno == MU_WRDSE_USERERR) - free (wsp->ws_usererr); - wsp->ws_errno = wss->ws_errno; - if (wss->ws_errno == MU_WRDSE_USERERR) - { - wsp->ws_usererr = wss->ws_usererr; - wss->ws_errno = MU_WRDSE_EOF; - wss->ws_usererr = NULL; - } -} - -static void -mu_wordsplit_init0 (struct mu_wordsplit *wsp) -{ - if (wsp->ws_flags & MU_WRDSF_REUSE) - { - if (!(wsp->ws_flags & MU_WRDSF_APPEND)) - mu_wordsplit_free_words (wsp); - mu_wordsplit_clearerr (wsp); - } - else - { - wsp->ws_wordv = NULL; - wsp->ws_wordc = 0; - wsp->ws_wordn = 0; - } - - wsp->ws_errno = 0; - wsp->ws_head = wsp->ws_tail = NULL; -} - -char mu_wordsplit_c_escape_tab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v"; - -static int -mu_wordsplit_init (struct mu_wordsplit *wsp, const char *input, size_t len, - int flags) -{ - wsp->ws_flags = flags; - - if (!(wsp->ws_flags & MU_WRDSF_ALLOC_DIE)) - wsp->ws_alloc_die = _wsplt_alloc_die; - if (!(wsp->ws_flags & MU_WRDSF_ERROR)) - wsp->ws_error = _wsplt_error; - - if (!(wsp->ws_flags & MU_WRDSF_NOVAR)) - { - /* These will be initialized on first variable assignment */ - wsp->ws_envidx = wsp->ws_envsiz = 0; - wsp->ws_envbuf = NULL; - } - - if (!(wsp->ws_flags & MU_WRDSF_NOCMD)) - { - if (!wsp->ws_command) - { - _wsplt_seterr (wsp, MU_WRDSE_USAGE); - errno = EINVAL; - return wsp->ws_errno; - } - } - - if (wsp->ws_flags & MU_WRDSF_SHOWDBG) - { - if (!(wsp->ws_flags & MU_WRDSF_DEBUG)) - { - if (wsp->ws_flags & MU_WRDSF_ERROR) - wsp->ws_debug = wsp->ws_error; - else if (wsp->ws_flags & MU_WRDSF_SHOWERR) - wsp->ws_debug = _wsplt_error; - else - wsp->ws_flags &= ~MU_WRDSF_SHOWDBG; - } - } - - wsp->ws_input = input; - wsp->ws_len = len; - - if (!(wsp->ws_flags & MU_WRDSF_DOOFFS)) - wsp->ws_offs = 0; - - if (!(wsp->ws_flags & MU_WRDSF_DELIM)) - wsp->ws_delim = " \t\n"; - - if (!(wsp->ws_flags & MU_WRDSF_COMMENT)) - wsp->ws_comment = NULL; - - if (!(wsp->ws_flags & MU_WRDSF_CLOSURE)) - wsp->ws_closure = NULL; - - if (!(wsp->ws_flags & MU_WRDSF_OPTIONS)) - wsp->ws_options = 0; - - if (wsp->ws_flags & MU_WRDSF_ESCAPE) - { - if (!wsp->ws_escape[MU_WRDSX_WORD]) - wsp->ws_escape[MU_WRDSX_WORD] = ""; - if (!wsp->ws_escape[MU_WRDSX_QUOTE]) - wsp->ws_escape[MU_WRDSX_QUOTE] = ""; - } - else - { - if (wsp->ws_flags & MU_WRDSF_CESCAPES) - { - wsp->ws_escape[MU_WRDSX_WORD] = mu_wordsplit_c_escape_tab; - wsp->ws_escape[MU_WRDSX_QUOTE] = mu_wordsplit_c_escape_tab; - wsp->ws_options |= MU_WRDSO_OESC_QUOTE | MU_WRDSO_OESC_WORD - | MU_WRDSO_XESC_QUOTE | MU_WRDSO_XESC_WORD; - } - else - { - wsp->ws_escape[MU_WRDSX_WORD] = ""; - wsp->ws_escape[MU_WRDSX_QUOTE] = "\\\\\"\""; - wsp->ws_options |= MU_WRDSO_BSKEEP_QUOTE; - } - } - - wsp->ws_endp = 0; - - mu_wordsplit_init0 (wsp); - - return 0; -} - -static int -alloc_space (struct mu_wordsplit *wsp, size_t count) -{ - size_t offs = (wsp->ws_flags & MU_WRDSF_DOOFFS) ? wsp->ws_offs : 0; - char **ptr; - size_t newalloc; - - if (wsp->ws_wordv == NULL) - { - newalloc = offs + count > ALLOC_INIT ? count : ALLOC_INIT; - ptr = calloc (newalloc, sizeof (ptr[0])); - } - else if (wsp->ws_wordn < offs + wsp->ws_wordc + count) - { - newalloc = offs + wsp->ws_wordc + - (count > ALLOC_INCR ? count : ALLOC_INCR); - ptr = realloc (wsp->ws_wordv, newalloc * sizeof (ptr[0])); - } - else - return 0; - - if (ptr) - { - wsp->ws_wordn = newalloc; - wsp->ws_wordv = ptr; - } - else - return _wsplt_nomem (wsp); - return 0; -} - - -/* Node state flags */ -#define _WSNF_NULL 0x01 /* null node (a noop) */ -#define _WSNF_WORD 0x02 /* node contains word in v.word */ -#define _WSNF_QUOTE 0x04 /* text is quoted */ -#define _WSNF_NOEXPAND 0x08 /* text is not subject to expansion */ -#define _WSNF_JOIN 0x10 /* node must be joined with the next node */ -#define _WSNF_SEXP 0x20 /* is a sed expression */ -#define _WSNF_DELIM 0x40 /* node is a delimiter */ - -#define _WSNF_EMPTYOK 0x0100 /* special flag indicating that - mu_wordsplit_add_segm must add the - segment even if it is empty */ - -struct mu_wordsplit_node -{ - struct mu_wordsplit_node *prev; /* Previous element */ - struct mu_wordsplit_node *next; /* Next element */ - int flags; /* Node flags */ - union - { - struct - { - size_t beg; /* Start of word in ws_input */ - size_t end; /* End of word in ws_input */ - } segm; - char *word; - } v; -}; - -static const char * -wsnode_flagstr (int flags) -{ - static char retbuf[7]; - char *p = retbuf; - - if (flags & _WSNF_WORD) - *p++ = 'w'; - else if (flags & _WSNF_NULL) - *p++ = 'n'; - else - *p++ = '-'; - if (flags & _WSNF_QUOTE) - *p++ = 'q'; - else - *p++ = '-'; - if (flags & _WSNF_NOEXPAND) - *p++ = 'E'; - else - *p++ = '-'; - if (flags & _WSNF_JOIN) - *p++ = 'j'; - else - *p++ = '-'; - if (flags & _WSNF_SEXP) - *p++ = 's'; - else - *p++ = '-'; - if (flags & _WSNF_DELIM) - *p++ = 'd'; - else - *p++ = '-'; - *p = 0; - return retbuf; -} - -static const char * -wsnode_ptr (struct mu_wordsplit *wsp, struct mu_wordsplit_node *p) -{ - if (p->flags & _WSNF_NULL) - return ""; - else if (p->flags & _WSNF_WORD) - return p->v.word; - else - return wsp->ws_input + p->v.segm.beg; -} - -static size_t -wsnode_len (struct mu_wordsplit_node *p) -{ - if (p->flags & _WSNF_NULL) - return 0; - else if (p->flags & _WSNF_WORD) - return strlen (p->v.word); - else - return p->v.segm.end - p->v.segm.beg; -} - -static int -wsnode_new (struct mu_wordsplit *wsp, struct mu_wordsplit_node **pnode) -{ - struct mu_wordsplit_node *node = calloc (1, sizeof (*node)); - if (!node) - return _wsplt_nomem (wsp); - *pnode = node; - return 0; -} - -static void -wsnode_free (struct mu_wordsplit_node *p) -{ - if (p->flags & _WSNF_WORD) - free (p->v.word); - free (p); -} - -static void -wsnode_append (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node) -{ - node->next = NULL; - node->prev = wsp->ws_tail; - if (wsp->ws_tail) - wsp->ws_tail->next = node; - else - wsp->ws_head = node; - wsp->ws_tail = node; -} - -static void -wsnode_remove (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node) -{ - struct mu_wordsplit_node *p; - - p = node->prev; - if (p) - { - p->next = node->next; - if (!node->next) - p->flags &= ~_WSNF_JOIN; - } - else - wsp->ws_head = node->next; - - p = node->next; - if (p) - p->prev = node->prev; - else - wsp->ws_tail = node->prev; - - node->next = node->prev = NULL; -} - -static void -wsnode_insert (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node, - struct mu_wordsplit_node *anchor, int before) -{ - if (!wsp->ws_head) - { - node->next = node->prev = NULL; - wsp->ws_head = wsp->ws_tail = node; - } - else if (before) - { - if (anchor->prev) - wsnode_insert (wsp, node, anchor->prev, 0); - else - { - node->prev = NULL; - node->next = anchor; - anchor->prev = node; - wsp->ws_head = node; - } - } - else - { - struct mu_wordsplit_node *p; - - p = anchor->next; - if (p) - p->prev = node; - else - wsp->ws_tail = node; - node->next = p; - node->prev = anchor; - anchor->next = node; - } -} - -static int -mu_wordsplit_add_segm (struct mu_wordsplit *wsp, size_t beg, size_t end, int flg) -{ - struct mu_wordsplit_node *node; - int rc; - - if (end == beg && !(flg & _WSNF_EMPTYOK)) - return 0; - rc = wsnode_new (wsp, &node); - if (rc) - return rc; - node->flags = flg & ~(_WSNF_WORD | _WSNF_EMPTYOK); - node->v.segm.beg = beg; - node->v.segm.end = end; - wsnode_append (wsp, node); - return 0; -} - -static void -mu_wordsplit_free_nodes (struct mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p; - - for (p = wsp->ws_head; p;) - { - struct mu_wordsplit_node *next = p->next; - wsnode_free (p); - p = next; - } - wsp->ws_head = wsp->ws_tail = NULL; -} - -static void -mu_wordsplit_dump_nodes (struct mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p; - int n = 0; - - for (p = wsp->ws_head, n = 0; p; p = p->next, n++) - { - if (p->flags & _WSNF_WORD) - wsp->ws_debug ("(%02d) %4d: %p: %#04x (%s):%s;", - wsp->ws_lvl, - n, p, p->flags, wsnode_flagstr (p->flags), p->v.word); - else - wsp->ws_debug ("(%02d) %4d: %p: %#04x (%s):%.*s;", - wsp->ws_lvl, - n, p, p->flags, wsnode_flagstr (p->flags), - (int) (p->v.segm.end - p->v.segm.beg), - wsp->ws_input + p->v.segm.beg); - } -} - -static int -coalesce_segment (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node) -{ - struct mu_wordsplit_node *p, *end; - size_t len = 0; - char *buf, *cur; - int stop; - - for (p = node; p && (p->flags & _WSNF_JOIN); p = p->next) - { - len += wsnode_len (p); - } - if (p) - len += wsnode_len (p); - end = p; - - buf = malloc (len + 1); - if (!buf) - return _wsplt_nomem (wsp); - cur = buf; - - p = node; - for (stop = 0; !stop;) - { - struct mu_wordsplit_node *next = p->next; - const char *str = wsnode_ptr (wsp, p); - size_t slen = wsnode_len (p); - - memcpy (cur, str, slen); - cur += slen; - if (p != node) - { - node->flags |= p->flags & _WSNF_QUOTE; - wsnode_remove (wsp, p); - stop = p == end; - wsnode_free (p); - } - p = next; - } - - *cur = 0; - - node->flags &= ~_WSNF_JOIN; - - if (node->flags & _WSNF_WORD) - free (node->v.word); - else - node->flags |= _WSNF_WORD; - node->v.word = buf; - return 0; -} - -static void mu_wordsplit_string_unquote_copy (struct mu_wordsplit *ws, - int inquote, - char *dst, const char *src, - size_t n); - -static int -wsnode_quoteremoval (struct mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p; - - for (p = wsp->ws_head; p; p = p->next) - { - const char *str = wsnode_ptr (wsp, p); - size_t slen = wsnode_len (p); - int unquote; - - if (wsp->ws_flags & MU_WRDSF_QUOTE) - { - unquote = !(p->flags & _WSNF_NOEXPAND); - } - else - unquote = 0; - - if (unquote) - { - if (!(p->flags & _WSNF_WORD)) - { - char *newstr = malloc (slen + 1); - if (!newstr) - return _wsplt_nomem (wsp); - memcpy (newstr, str, slen); - newstr[slen] = 0; - p->v.word = newstr; - p->flags |= _WSNF_WORD; - } - - mu_wordsplit_string_unquote_copy (wsp, p->flags & _WSNF_QUOTE, - p->v.word, str, slen); - } - } - return 0; -} - -static int -wsnode_coalesce (struct mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p; - - for (p = wsp->ws_head; p; p = p->next) - { - if (p->flags & _WSNF_JOIN) - if (coalesce_segment (wsp, p)) - return 1; - } - return 0; -} - -static int -mu_wordsplit_finish (struct mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p; - size_t n; - - n = 0; - - for (p = wsp->ws_head; p; p = p->next) - n++; - - if (alloc_space (wsp, n + 1)) - return 1; - - for (p = wsp->ws_head; p; p = p->next) - { - const char *str = wsnode_ptr (wsp, p); - size_t slen = wsnode_len (p); - char *newstr = malloc (slen + 1); - - /* Assign newstr first, even if it is NULL. This way - mu_wordsplit_free will work even if we return - nomem later. */ - wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = newstr; - if (!newstr) - return _wsplt_nomem (wsp); - memcpy (newstr, str, slen); - newstr[slen] = 0; - - wsp->ws_wordc++; - - } - wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = NULL; - return 0; -} - -int -mu_wordsplit_append (struct mu_wordsplit *wsp, int argc, char **argv) -{ - int rc; - size_t i; - - rc = alloc_space (wsp, wsp->ws_wordc + argc + 1); - if (rc) - return rc; - for (i = 0; i < argc; i++) - { - char *newstr = strdup (argv[i]); - if (!newstr) - { - while (i > 0) - { - free (wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc + i - 1]); - wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc + i - 1] = NULL; - i--; - } - return _wsplt_nomem (wsp); - } - wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc + i] = newstr; - } - wsp->ws_wordc += i; - wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = NULL; - return 0; -} - -/* Variable expansion */ -static int -node_split_prefix (struct mu_wordsplit *wsp, - struct mu_wordsplit_node **ptail, - struct mu_wordsplit_node *node, - size_t beg, size_t len, int flg) -{ - struct mu_wordsplit_node *newnode; - - if (len == 0) - return 0; - if (wsnode_new (wsp, &newnode)) - return 1; - wsnode_insert (wsp, newnode, *ptail, 0); - if (node->flags & _WSNF_WORD) - { - const char *str = wsnode_ptr (wsp, node); - char *newstr = malloc (len + 1); - if (!newstr) - return _wsplt_nomem (wsp); - memcpy (newstr, str + beg, len); - newstr[len] = 0; - newnode->flags = _WSNF_WORD; - newnode->v.word = newstr; - } - else - { - newnode->v.segm.beg = node->v.segm.beg + beg; - newnode->v.segm.end = newnode->v.segm.beg + len; - } - newnode->flags |= flg; - *ptail = newnode; - return 0; -} - -static int -find_closing_paren (const char *str, size_t i, size_t len, size_t *poff, - char *paren) -{ - enum { st_init, st_squote, st_dquote } state = st_init; - size_t level = 1; - - for (; i < len; i++) - { - switch (state) - { - case st_init: - switch (str[i]) - { - default: - if (str[i] == paren[0]) - { - level++; - break; - } - else if (str[i] == paren[1]) - { - if (--level == 0) - { - *poff = i; - return 0; - } - break; - } - break; - - case '"': - state = st_dquote; - break; - - case '\'': - state = st_squote; - break; - } - break; - - case st_squote: - if (str[i] == '\'') - state = st_init; - break; - - case st_dquote: - if (str[i] == '\\') - i++; - else if (str[i] == '"') - state = st_init; - break; - } - } - return 1; -} - -static int -mu_wordsplit_find_env (struct mu_wordsplit *wsp, const char *name, size_t len, - char const **ret) -{ - size_t i; - - if (!(wsp->ws_flags & MU_WRDSF_ENV)) - return MU_WRDSE_UNDEF; - - if (wsp->ws_flags & MU_WRDSF_ENV_KV) - { - /* A key-value pair environment */ - for (i = 0; wsp->ws_env[i]; i++) - { - size_t elen = strlen (wsp->ws_env[i]); - if (elen == len && memcmp (wsp->ws_env[i], name, elen) == 0) - { - *ret = wsp->ws_env[i + 1]; - return MU_WRDSE_OK; - } - /* Skip the value. Break the loop if it is NULL. */ - i++; - if (wsp->ws_env[i] == NULL) - break; - } - } - else if (wsp->ws_env) - { - /* Usual (A=B) environment. */ - for (i = 0; wsp->ws_env[i]; i++) - { - size_t j; - const char *var = wsp->ws_env[i]; - - for (j = 0; j < len; j++) - if (name[j] != var[j]) - break; - if (j == len && var[j] == '=') - { - *ret = var + j + 1; - return MU_WRDSE_OK; - } - } - } - return MU_WRDSE_UNDEF; -} - -static int -wsplt_assign_var (struct mu_wordsplit *wsp, const char *name, size_t namelen, - char *value) -{ - int n = (wsp->ws_flags & MU_WRDSF_ENV_KV) ? 2 : 1; - char *v; - - if (wsp->ws_envidx + n >= wsp->ws_envsiz) - { - size_t sz; - char **newenv; - - if (!wsp->ws_envbuf) - { - if (wsp->ws_flags & MU_WRDSF_ENV) - { - size_t i = 0, j; - - if (wsp->ws_env) - { - for (; wsp->ws_env[i]; i++) - ; - } - - sz = i + n + 1; - - newenv = calloc (sz, sizeof(newenv[0])); - if (!newenv) - return _wsplt_nomem (wsp); - - for (j = 0; j < i; j++) - { - newenv[j] = strdup (wsp->ws_env[j]); - if (!newenv[j]) - { - for (; j > 1; j--) - free (newenv[j-1]); - free (newenv[j-1]); - return _wsplt_nomem (wsp); - } - } - newenv[j] = NULL; - - wsp->ws_envbuf = newenv; - wsp->ws_envidx = i; - wsp->ws_envsiz = sz; - wsp->ws_env = (const char**) wsp->ws_envbuf; - } - else - { - newenv = calloc (MU_WORDSPLIT_ENV_INIT, sizeof(newenv[0])); - if (!newenv) - return _wsplt_nomem (wsp); - wsp->ws_envbuf = newenv; - wsp->ws_envidx = 0; - wsp->ws_envsiz = MU_WORDSPLIT_ENV_INIT; - wsp->ws_env = (const char**) wsp->ws_envbuf; - wsp->ws_flags |= MU_WRDSF_ENV; - } - } - else - { - wsp->ws_envsiz *= 2; - newenv = realloc (wsp->ws_envbuf, - wsp->ws_envsiz * sizeof (wsp->ws_envbuf[0])); - if (!newenv) - return _wsplt_nomem (wsp); - wsp->ws_envbuf = newenv; - wsp->ws_env = (const char**) wsp->ws_envbuf; - } - } - - if (wsp->ws_flags & MU_WRDSF_ENV_KV) - { - /* A key-value pair environment */ - char *p = malloc (namelen + 1); - if (!p) - return _wsplt_nomem (wsp); - memcpy (p, name, namelen); - p[namelen] = 0; - - v = strdup (value); - if (!v) - { - free (p); - return _wsplt_nomem (wsp); - } - wsp->ws_env[wsp->ws_envidx++] = p; - wsp->ws_env[wsp->ws_envidx++] = v; - } - else - { - v = malloc (namelen + strlen(value) + 2); - if (!v) - return _wsplt_nomem (wsp); - memcpy (v, name, namelen); - v[namelen++] = '='; - strcpy(v + namelen, value); - wsp->ws_env[wsp->ws_envidx++] = v; - } - wsp->ws_env[wsp->ws_envidx++] = NULL; - return MU_WRDSE_OK; -} - -static int -expvar (struct mu_wordsplit *wsp, const char *str, size_t len, - struct mu_wordsplit_node **ptail, const char **pend, int flg) -{ - size_t i = 0; - const char *defstr = NULL; - char *value; - const char *vptr; - struct mu_wordsplit_node *newnode; - const char *start = str - 1; - int rc; - struct mu_wordsplit ws; - - if (ISVARBEG (str[0])) - { - for (i = 1; i < len; i++) - if (!ISVARCHR (str[i])) - break; - *pend = str + i - 1; - } - else if (str[0] == '{') - { - str++; - len--; - for (i = 1; i < len; i++) - { - if (str[i] == ':') - { - size_t j; - - defstr = str + i + 1; - if (find_closing_paren (str, i + 1, len, &j, "{}")) - return _wsplt_seterr (wsp, MU_WRDSE_CBRACE); - *pend = str + j; - break; - } - else if (str[i] == '}') - { - defstr = NULL; - *pend = str + i; - break; - } - else if (strchr ("-+?=", str[i])) - { - size_t j; - - defstr = str + i; - if (find_closing_paren (str, i, len, &j, "{}")) - return _wsplt_seterr (wsp, MU_WRDSE_CBRACE); - *pend = str + j; - break; - } - } - if (i == len) - return _wsplt_seterr (wsp, MU_WRDSE_CBRACE); - } - else - { - if (wsnode_new (wsp, &newnode)) - return 1; - wsnode_insert (wsp, newnode, *ptail, 0); - *ptail = newnode; - newnode->flags = _WSNF_WORD | flg; - newnode->v.word = malloc (3); - if (!newnode->v.word) - return _wsplt_nomem (wsp); - newnode->v.word[0] = '$'; - newnode->v.word[1] = str[0]; - newnode->v.word[2] = 0; - *pend = str; - return 0; - } - - /* Actually expand the variable */ - /* str - start of the variable name - i - its length - defstr - default replacement str */ - - if (defstr && strchr("-+?=", defstr[0]) == 0) - { - rc = MU_WRDSE_UNDEF; - defstr = NULL; - } - else - { - rc = mu_wordsplit_find_env (wsp, str, i, &vptr); - if (rc == MU_WRDSE_OK) - { - if (vptr) - { - value = strdup (vptr); - if (!value) - rc = MU_WRDSE_NOSPACE; - } - else - rc = MU_WRDSE_UNDEF; - } - else if (wsp->ws_flags & MU_WRDSF_GETVAR) - rc = wsp->ws_getvar (&value, str, i, wsp->ws_closure); - else - rc = MU_WRDSE_UNDEF; - - if (rc == MU_WRDSE_OK - && (!value || value[0] == 0) - && defstr && defstr[-1] == ':') - { - free (value); - rc = MU_WRDSE_UNDEF; - } - } - - switch (rc) - { - case MU_WRDSE_OK: - if (defstr && *defstr == '+') - { - size_t size = *pend - ++defstr; - - rc = _wsplt_subsplit (wsp, &ws, defstr, size, - MU_WRDSF_NOSPLIT | MU_WRDSF_WS | MU_WRDSF_QUOTE | - (wsp->ws_flags & - (MU_WRDSF_NOVAR | MU_WRDSF_NOCMD))); - if (rc) - return rc; - free (value); - value = ws.ws_wordv[0]; - ws.ws_wordv[0] = NULL; - mu_wordsplit_free (&ws); - } - break; - - case MU_WRDSE_UNDEF: - if (defstr) - { - size_t size; - if (*defstr == '-' || *defstr == '=') - { - size = *pend - ++defstr; - - rc = _wsplt_subsplit (wsp, &ws, defstr, size, - MU_WRDSF_NOSPLIT | MU_WRDSF_WS | MU_WRDSF_QUOTE | - (wsp->ws_flags & - (MU_WRDSF_NOVAR | MU_WRDSF_NOCMD))); - if (rc) - return rc; - - value = ws.ws_wordv[0]; - ws.ws_wordv[0] = NULL; - mu_wordsplit_free (&ws); - - if (defstr[-1] == '=') - wsplt_assign_var (wsp, str, i, value); - } - else - { - if (*defstr == '?') - { - size = *pend - ++defstr; - if (size == 0) - wsp->ws_error (_("%.*s: variable null or not set"), - (int) i, str); - else - { - rc = _wsplt_subsplit (wsp, &ws, defstr, size, - MU_WRDSF_NOSPLIT | MU_WRDSF_WS | - MU_WRDSF_QUOTE | - (wsp->ws_flags & - (MU_WRDS |