summaryrefslogtreecommitdiff
path: root/libmailutils
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-07-11 11:29:34 +0300
committerSergey Poznyakoff <gray@gnu.org>2019-07-11 11:29:34 +0300
commit2ad00905cde7230317c27fcbb3c41969ca5b79ab (patch)
tree5a159e95e5d9a649b189fc634832320010ec4657 /libmailutils
parent4ba3d95fe9bd9bb3b93be60a8ea89e381c5f88c0 (diff)
downloadmailutils-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.am6
-rw-r--r--libmailutils/string/Makefile.am6
-rw-r--r--libmailutils/string/wordsplit.c2382
-rw-r--r--libmailutils/tests/.gitignore1
-rw-r--r--libmailutils/tests/Makefile.am35
-rw-r--r--libmailutils/tests/wordsplit.at787
-rw-r--r--libmailutils/tests/wsp.c654
m---------libmailutils/wordsplit0
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