/* wordsplit - a word splitter
Copyright (C) 2009-2019 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/>. */
#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>
#if ENABLE_NLS
# include <gettext.h>
#else
# define gettext(msgid) msgid
#endif
#define _(msgid) gettext (msgid)
#define N_(msgid) msgid
#include <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 ALLOC_INIT 128
#define ALLOC_INCR 128
static void
_wsplt_alloc_die (struct wordsplit *wsp)
{
wsp->ws_error (_("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 wordsplit_free_nodes (struct wordsplit *);
static int
_wsplt_nomem (struct wordsplit *wsp)
{
errno = ENOMEM;
wsp->ws_errno = WRDSE_NOSPACE;
if (wsp->ws_flags & WRDSF_ENOMEMABRT)
wsp->ws_alloc_die (wsp);
if (wsp->ws_flags & WRDSF_SHOWERR)
wordsplit_perror (wsp);
if (!(wsp->ws_flags & WRDSF_REUSE))
wordsplit_free (wsp);
wordsplit_free_nodes (wsp);
return wsp->ws_errno;
}
static void
wordsplit_init0 (struct wordsplit *wsp)
{
if (wsp->ws_flags & WRDSF_REUSE)
{
if (!(wsp->ws_flags & WRDSF_APPEND))
wordsplit_free_words (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;
}
static int
wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
int flags)
{
wsp->ws_flags = flags;
if (!(wsp->ws_flags & WRDSF_ALLOC_DIE))
wsp->ws_alloc_die = _wsplt_alloc_die;
if (!(wsp->ws_flags & WRDSF_ERROR))
wsp->ws_error = _wsplt_error;
if (!(wsp->ws_flags & WRDSF_NOVAR)
&& !(wsp->ws_flags & (WRDSF_ENV | WRDSF_GETVAR)))
{
errno = EINVAL;
wsp->ws_errno = WRDSE_USAGE;
if (wsp->ws_flags & WRDSF_SHOWERR)
wordsplit_perror (wsp);
return wsp->ws_errno;
}
if (!(wsp->ws_flags & WRDSF_NOCMD))
{
errno = EINVAL;
wsp->ws_errno = WRDSE_NOSUPP;
if (wsp->ws_flags & WRDSF_SHOWERR)
wordsplit_perror (wsp);
return wsp->ws_errno;
}
if (wsp->ws_flags & WRDSF_SHOWDBG)
{
if (!(wsp->ws_flags & WRDSF_DEBUG))
{
if (wsp->ws_flags & WRDSF_ERROR)
wsp->ws_debug = wsp->ws_error;
else if (wsp->ws_flags & WRDSF_SHOWERR)
wsp->ws_debug = _wsplt_error;
else
wsp->ws_flags &= ~WRDSF_SHOWDBG;
}
}
wsp->ws_input = input;
wsp->ws_len = len;
if (!(wsp->ws_flags & WRDSF_DOOFFS))
wsp->ws_offs = 0;
if (!(wsp->ws_flags & WRDSF_DELIM))
wsp->ws_delim = " \t\n";
if (!(wsp->ws_flags & WRDSF_COMMENT))
wsp->ws_comment = NULL;
if (!(wsp->ws_flags & WRDSF_CLOSURE))
wsp->ws_closure = NULL;
wsp->ws_endp = 0;
wordsplit_init0 (wsp);
return 0;
}
static int
alloc_space (struct wordsplit *wsp, size_t count)
{
size_t offs = (wsp->ws_flags & 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 /*
|