aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--Makefile.am3
-rw-r--r--NEWS28
-rw-r--r--README4
m---------acvmod0
-rwxr-xr-xbootstrap2
-rw-r--r--configure.ac6
-rw-r--r--doc/vmod-dbrw.38
-rw-r--r--doc/vmod-dbrw.texi2
-rw-r--r--src/Makefile.am12
-rw-r--r--src/dbrw.h19
-rw-r--r--src/vmod_dbrw.c26
-rw-r--r--src/vmod_dbrw.vcc4
-rw-r--r--src/wordsplit.c2546
-rw-r--r--src/wordsplit.h271
-rw-r--r--tests/Makefile.am6
m---------wordsplit0
17 files changed, 81 insertions, 2859 deletions
diff --git a/.gitmodules b/.gitmodules
index 00ae21c..6f6db00 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "acvmod"]
path = acvmod
url = git://git.gnu.org.ua/acvmod.git
+[submodule "wordsplit"]
+ path = wordsplit
+ url = git://git.gnu.org.ua/wordsplit.git
diff --git a/Makefile.am b/Makefile.am
index a5248b8..df797dd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,5 @@
# This file is part of vmod-dbrw
-# Copyright (C) 2013-2017 Sergey Poznyakoff
+# Copyright (C) 2013-2019 Sergey Poznyakoff
#
# Vmod-dbrw is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -19,3 +19,4 @@ SUBDIRS = src doc tests
include acvmod/top.am
+EXTRA_DIST += wordsplit/wordsplit.c wordsplit/wordsplit.h
diff --git a/NEWS b/NEWS
index 516ca69..b54fe82 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,23 @@
-vmod-dbrw -- history of user-visible changes. 2019-02-13
+vmod-dbrw -- history of user-visible changes. 2022-08-21
See the end of file for copying conditions.
Please send vmod-dbrw bug reports to <gray@gnu.org>
-Version 2.4.90 (git)
+Version 2.8, 2022-08-21
+
+* Support for Varnish 7.1
+
+Version 2.7, 2020-04-09
+
+* Drop support for Varnish versions prior to 6.0
+
+
+Version 2.6, 2020-03-03
+
+* Builds with Varnish 6.3.1
+
+
+Version 2.5, 2019-02-15
* req.http.X-VMOD-DBRW-Error
@@ -17,6 +31,14 @@ set. The 'eq' flag instructs dbrw.rewrite to use exact string match,
instead of regular expressions. The 'regex' flag instructs it to use
regular expression matching. It is the default.
+* Improve error handling in mysql submodule
+
+Previously, error codes ER_PARSE_ERROR and ER_EMPTY_QUERY were treated
+as permanent conditions, causing mysql connection to be closed and
+disabled. This is no longer the case, as they both can well mean a
+transient condition (e.g. ER_PARSE_ERROR returned for the 'Illegal mix
+of collations' error).
+
Version 2.4, 2018-12-10
@@ -93,7 +115,7 @@ Initial release
=========================================================================
Copyright information:
-Copyright (C) 2013-2019 Sergey Poznyakoff
+Copyright (C) 2013-2020 Sergey Poznyakoff
Permission is granted to anyone to make or distribute verbatim copies
of this document as received, in any medium, provided that the
diff --git a/README b/README
index bcbce5a..a1d815b 100644
--- a/README
+++ b/README
@@ -30,7 +30,7 @@ of this approach is that rewrite rules stored in a database are easier
to maintain.
This version supports MySQL and PostgreSQL databases and is known to
-work for Varnish versions 4.1 through 6.0.2.
+work for Varnish versions 6.0.6 through 6.4.0.
* Example
@@ -222,7 +222,7 @@ Send bug reports and suggestions to <gray@gnu.org>
* Copyright information:
-Copyright (C) 2013-2018 Sergey Poznyakoff
+Copyright (C) 2013-2020 Sergey Poznyakoff
Permission is granted to anyone to make or distribute verbatim copies
of this document as received, in any medium, provided that the
diff --git a/acvmod b/acvmod
-Subproject 5b214e3d72f9e261a37cf31deb41e7f8a61a181
+Subproject 0516e2461e8f2e3b33a7fffa13705cdb1de77c5
diff --git a/bootstrap b/bootstrap
index 42bce68..2621e7a 100755
--- a/bootstrap
+++ b/bootstrap
@@ -4,6 +4,6 @@ do
test -d $dir || mkdir $dir
done
git submodule init
-git submodule update
+git submodule update --init --recursive
test -f ChangeLog || touch ChangeLog
autoreconf -f -i -s
diff --git a/configure.ac b/configure.ac
index fd618d3..470d09b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
# This file is part of vmod-dbrw -*- autoconf -*-
-# Copyright (C) 2013-2019 Sergey Poznyakoff
+# Copyright (C) 2013-2022 Sergey Poznyakoff
#
# Vmod-dbrw is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with vmod-dbrw. If not, see <http://www.gnu.org/licenses/>.
AC_PREREQ(2.69)
-AC_INIT([vmod-dbrw], 2.4.90, [gray@gnu.org])
+AC_INIT([vmod-dbrw], 2.8, [gray@gnu.org])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR(src/vmod_dbrw.vcc)
@@ -43,7 +43,7 @@ AC_PROG_MAKE_SET
AC_HEADER_STDC
AC_CHECK_HEADERS([sys/stdlib.h])
-AM_VARNISHAPI([4.1],[6.0.2])
+AM_VARNISHAPI([6.0],[7.1.0])
AC_DEFINE_UNQUOTED([VARNISHAPI_MAJOR],[$VARNISHAPI_MAJOR],
[Varnish API major version number])
diff --git a/doc/vmod-dbrw.3 b/doc/vmod-dbrw.3
index 9bec008..023e215 100644
--- a/doc/vmod-dbrw.3
+++ b/doc/vmod-dbrw.3
@@ -1,5 +1,5 @@
.\" This file is part of Vmod-dbrw -*- nroff -*-
-.\" Copyright (C) 2013-2018 Sergey Poznyakoff
+.\" Copyright (C) 2013-2022 Sergey Poznyakoff
.\"
.\" Vmod-dbrw is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
@@ -13,7 +13,7 @@
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with vmod-dbrw. If not, see <http://www.gnu.org/licenses/>.
-.TH VMOD-DBRW 3 "February 13, 2019" "VMOD-DBRW" "User Reference"
+.TH VMOD-DBRW 3 "August 21, 2022" "VMOD-DBRW" "User Reference"
.SH NAME
vmod-dbrw \- Database-driven rewrite rules for Varnish Cache
.SH SYNOPSIS
@@ -318,7 +318,7 @@ sub vcl_synth {
.\" for man-based doc pages.
.if "\V[MANCGI]"WEBDOC" \{\
. ds package vmod-dbrw
-. ds version 2.4
+. ds version 2.8
. so download.inc
\}
.SH "SEE ALSO"
@@ -354,7 +354,7 @@ Sergey Poznyakoff
.SH "BUG REPORTS"
Report bugs to <gray@gnu.org>.
.SH COPYRIGHT
-Copyright \(co 2013-2018 Sergey Poznyakoff
+Copyright \(co 2013-2022 Sergey Poznyakoff
.br
.na
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
diff --git a/doc/vmod-dbrw.texi b/doc/vmod-dbrw.texi
index 6a987ed..200ca0d 100644
--- a/doc/vmod-dbrw.texi
+++ b/doc/vmod-dbrw.texi
@@ -30,7 +30,7 @@ Published by the Free Software Foundation,
51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301 USA
-Copyright @copyright{} 2013-2018 Sergey Poznyakoff
+Copyright @copyright{} 2013-2020 Sergey Poznyakoff
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
diff --git a/src/Makefile.am b/src/Makefile.am
index 6cda3aa..2f23477 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
# This file is part of vmod-dbrw
-# Copyright (C) 2013-2017 Sergey Poznyakoff
+# Copyright (C) 2013-2019 Sergey Poznyakoff
#
# Vmod-dbrw is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,14 +14,20 @@
# You should have received a copy of the GNU General Public License
# along with vmod-dbrw. If not, see <http://www.gnu.org/licenses/>.
-AM_CPPFLAGS=$(VARNISHAPI_CFLAGS) -I$(srcdir) -I$(builddir)
+AM_CPPFLAGS=\
+ $(VARNISHAPI_CFLAGS)\
+ -I$(srcdir)\
+ -I$(builddir)\
+ -I$(top_srcdir)/wordsplit
noinst_LTLIBRARIES = libsql.la
libsql_la_SOURCES = \
be.c\
dbrw.h\
- sql.c\
+ sql.c
+nodist_libsql_la_SOURCES = \
wordsplit.h\
wordsplit.c
+VPATH += $(top_srcdir)/wordsplit
if USE_MYSQL
libsql_la_SOURCES += mysql.c
diff --git a/src/dbrw.h b/src/dbrw.h
index 9a8adf6..bbe1364 100644
--- a/src/dbrw.h
+++ b/src/dbrw.h
@@ -1,5 +1,5 @@
/* This file is part of vmod-dbrw
- Copyright (C) 2013-2018 Sergey Poznyakoff
+ Copyright (C) 2013-2020 Sergey Poznyakoff
Vmod-dbrw is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,17 +21,16 @@
#include <syslog.h>
#include <regex.h>
-#if VARNISHAPI_MAJOR > 5
-# include "cache/cache.h"
-# include "vcl.h"
-# include "vcc_if.h"
+#include "cache/cache.h"
+#include "vcl.h"
+#include "vcc_if.h"
+
+#ifdef VPFX
+# define VEVENT(a) VPFX(a)
#else
-# include "vcl.h"
-# include "vrt.h"
-# include "vcc_if.h"
-# include "cache/cache.h"
+/* For compatibility with varnish prior to 6.2 */
+# define VEVENT(a) a
#endif
-#define WSPTR(s) ((s)->ws)
struct dbrw_connection;
diff --git a/src/vmod_dbrw.c b/src/vmod_dbrw.c
index beeb9af..f6b6446 100644
--- a/src/vmod_dbrw.c
+++ b/src/vmod_dbrw.c
@@ -1,5 +1,5 @@
/* This file is part of vmod-dbrw
- Copyright (C) 2013-2019 Sergey Poznyakoff
+ Copyright (C) 2013-2022 Sergey Poznyakoff
Vmod-dbrw is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -121,7 +121,7 @@ disconnect(void)
}
int
-dbrw_event(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
+VEVENT(dbrw_event)(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
{
switch (e) {
case VCL_EVENT_LOAD:
@@ -311,12 +311,12 @@ expand_backref(VRT_CTX, const char *str, const char *val,
unsigned u;
char *b, *p;
- u = WS_Reserve(WSPTR(ctx), 0);
- p = b = WSPTR(ctx)->f;
+ u = WS_ReserveAll(ctx->ws);
+ p = b = ctx->ws->f;
while (*val) {
if (u == 0) {
- WS_Release(WSPTR(ctx), 0);
+ WS_Release(ctx->ws, 0);
return NULL;
}
if (*val == '\\' || *val == '$') {
@@ -329,7 +329,7 @@ expand_backref(VRT_CTX, const char *str, const char *val,
matches[n].rm_so;
if (len > u) {
- WS_Release(WSPTR(ctx), 0);
+ WS_Release(ctx->ws, 0);
return NULL;
}
@@ -355,7 +355,7 @@ expand_backref(VRT_CTX, const char *str, const char *val,
if (qry) {
size_t len = strlen(qry);
if (len + 1 >= u) {
- WS_Release(WSPTR(ctx), 0);
+ WS_Release(ctx->ws, 0);
return NULL;
}
if (strchr(b, '?'))
@@ -368,18 +368,22 @@ expand_backref(VRT_CTX, const char *str, const char *val,
}
if (u == 0) {
- WS_Release(WSPTR(ctx), 0);
+ WS_Release(ctx->ws, 0);
return NULL;
}
*p++ = 0;
- WS_ReleaseP(WSPTR(ctx), p);
+ WS_ReleaseP(ctx->ws, p);
return b;
}
#define ISEMPTY(s) ((s) == NULL || (s)[0] == 0)
+#if VARNISHAPI_MAJOR > 6
+# define vrt_magic_string_end 0
+#endif
+
static void
dbrw_sethdr(VRT_CTX, int where, const char *what, const char *value)
{
@@ -405,7 +409,7 @@ findmatch(VRT_CTX, struct dbrw_connection *conn, char **param)
debug(conn->conf, 2, ("query returned %u tuples, %u columns", nt, nf));
if (nf < 3)
- return WS_Copy(WSPTR(ctx), sql_get_column(conn, 0, 0), -1);
+ return WS_Copy(ctx->ws, sql_get_column(conn, 0, 0), -1);
/* Three or four fields:
result
@@ -428,7 +432,7 @@ findmatch(VRT_CTX, struct dbrw_connection *conn, char **param)
char *qry = NULL;
if (ISEMPTY(pat)) {
- res = WS_Copy(WSPTR(ctx), sql_get_column(conn, i, 0), -1);
+ res = WS_Copy(ctx->ws, sql_get_column(conn, i, 0), -1);
break;
}
diff --git a/src/vmod_dbrw.vcc b/src/vmod_dbrw.vcc
index 9a15af1..479ca66 100644
--- a/src/vmod_dbrw.vcc
+++ b/src/vmod_dbrw.vcc
@@ -1,5 +1,5 @@
# This file is part of vmod-dbrw
-# Copyright (C) 2013-2016 Sergey Poznyakoff
+# Copyright (C) 2013-2020 Sergey Poznyakoff
#
# Vmod-dbrw is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with vmod-dbrw. If not, see <http://www.gnu.org/licenses/>.
-$Module dbrw 3 Database-driven rewrite rules for Varnish Cache
+$Module dbrw 3 "Database-driven rewrite rules for Varnish Cache"
COLOPHON
========
diff --git a/src/wordsplit.c b/src/wordsplit.c
deleted file mode 100644
index bad59b1..0000000
--- a/src/wordsplit.c
+++ /dev/null
@@ -1,2546 +0,0 @@
-/* wordsplit - a word splitter
- Copyright (C) 2009-2018 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>
-#include <pwd.h>
-#include <glob.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 ISVARBEG(c) (ISALPHA(c) || c == '_')
-#define ISVARCHR(c) (ISALNUM(c) || c == '_')
-
-#define WSP_RETURN_DELIMS(wsp) \
- ((wsp)->ws_flags & WRDSF_RETURN_DELIMS || ((wsp)->ws_options & WRDSO_MAXWORDS))
-
-#define ALLOC_INIT 128
-#define ALLOC_INCR 128
-
-static void
-_wsplt_alloc_die (struct 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 wordsplit_free_nodes (struct wordsplit *);
-
-static int
-_wsplt_seterr (struct wordsplit *wsp, int ec)
-{
- wsp->ws_errno = ec;
- if (wsp->ws_flags & WRDSF_SHOWERR)
- wordsplit_perror (wsp);
- return ec;
-}
-
-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 int wordsplit_run (const char *command, size_t length,
- struct wordsplit *wsp,
- int flags, int lvl);
-
-static int wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
- int flags);
-static int wordsplit_process_list (struct wordsplit *wsp, size_t start);
-static int wordsplit_finish (struct wordsplit *wsp);
-
-static int
-_wsplt_subsplit (struct wordsplit *wsp, struct wordsplit *wss,
- char const *str, int len,
- int flags, int finalize)
-{
- int rc;
-
- 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 & WRDSF_NOVAR))
- {
- wss->ws_env = wsp->ws_env;
- wss->ws_getvar = wsp->ws_getvar;
- flags |= wsp->ws_flags & (WRDSF_ENV | WRDSF_ENV_KV | WRDSF_GETVAR);
- }
- if (!(flags & WRDSF_NOCMD))
- {
- wss->ws_command = wsp->ws_command;
- }
-
- if ((flags & (WRDSF_NOVAR|WRDSF_NOCMD)) != (WRDSF_NOVAR|WRDSF_NOCMD))
- {
- wss->ws_closure = wsp->ws_closure;
- flags |= wsp->ws_flags & WRDSF_CLOSURE;
- }
-
- wss->ws_options = wsp->ws_options;
-
- flags |= WRDSF_DELIM
- | WRDSF_ALLOC_DIE
- | WRDSF_ERROR
- | WRDSF_DEBUG
- | (wsp->ws_flags & (WRDSF_SHOWDBG | WRDSF_SHOWERR | WRDSF_OPTIONS));
-
- rc = wordsplit_init (wss, str, len, flags);
- if (rc)
- return rc;
- wss->ws_lvl = wsp->ws_lvl + 1;
- rc = wordsplit_process_list (wss, 0);
- if (rc)
- {
- wordsplit_free_nodes (wss);
- return rc;
- }
- if (finalize)
- {
- rc = wordsplit_finish (wss);
- wordsplit_free_nodes (wss);
- }
- return rc;
-}
-
-static void
-_wsplt_seterr_sub (struct wordsplit *wsp, struct wordsplit *wss)
-{
- if (wsp->ws_errno == WRDSE_USERERR)
- free (wsp->ws_usererr);
- wsp->ws_errno = wss->ws_errno;
- if (wss->ws_errno == WRDSE_USERERR)
- {
- wsp->ws_usererr = wss->ws_usererr;
- wss->ws_errno = WRDSE_EOF;
- wss->ws_usererr = NULL;
- }
-}
-
-static void
-wordsplit_init0 (struct wordsplit *wsp)
-{
- if (wsp->ws_flags & WRDSF_REUSE)
- {
- if (!(wsp->ws_flags & WRDSF_APPEND))
- wordsplit_free_words (wsp);
- wordsplit_clearerr (wsp);
- }
- else
- {
- wsp->ws_wordv = NULL;
- wsp->ws_wordc = 0;
- wsp->ws_wordn = 0;
- }
-
- wsp->ws_errno = 0;
-}
-
-char wordsplit_c_escape_tab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v";
-
-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))
- {
- /* These will be initialized on first variable assignment */
- wsp->ws_envidx = wsp->ws_envsiz = 0;
- wsp->ws_envbuf = NULL;
- }
-
- if (!(wsp->ws_flags & WRDSF_NOCMD))
- {
- if (!wsp->ws_command)
- {
- _wsplt_seterr (wsp, WRDSE_USAGE);
- errno = EINVAL;
- 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;
-
- if (!(wsp->ws_flags & WRDSF_OPTIONS))
- wsp->ws_options = 0;
-
- if (wsp->ws_flags & WRDSF_ESCAPE)
- {
- if (!wsp->ws_escape[WRDSX_WORD])
- wsp->ws_escape[WRDSX_WORD] = "";
- if (!wsp->ws_escape[WRDSX_QUOTE])
- wsp->ws_escape[WRDSX_QUOTE] = "";
- }
- else
- {
- if (wsp->ws_flags & WRDSF_CESCAPES)
- {
- wsp->ws_escape[WRDSX_WORD] = wordsplit_c_escape_tab;
- wsp->ws_escape[WRDSX_QUOTE] = wordsplit_c_escape_tab;
- wsp->ws_options |= WRDSO_OESC_QUOTE | WRDSO_OESC_WORD
- | WRDSO_XESC_QUOTE | WRDSO_XESC_WORD;
- }
- else
- {
- wsp->ws_escape[WRDSX_WORD] = "";
- wsp->ws_escape[WRDSX_QUOTE] = "\\\\\"\"";
- wsp->ws_options |= WRDSO_BSKEEP_QUOTE;
- }
- }
-
- wsp->ws_endp = 0;
- wsp->ws_wordi = 0;
-
- if (wsp->ws_flags & WRDSF_REUSE)
- wordsplit_free_nodes (wsp);
- wsp->ws_head = wsp->ws_tail = NULL;
-
- 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 /* is a sed expression */
-#define _WSNF_DELIM 0x40 /* node is a delimiter */
-
-#define _WSNF_EMPTYOK 0x0100 /* special flag indicating that
- wordsplit_add_segm must add the
- segment even if it is empty */
-
-struct wordsplit_node
-{
- struct wordsplit_node *prev; /* Previous element */
- struct 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 wordsplit *wsp, struct 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 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 wordsplit *wsp, struct wordsplit_node **pnode)
-{
- struct wordsplit_node *node = calloc (1, sizeof (*node));
- if (!node)
- return _wsplt_nomem (wsp);
- *pnode = node;
- return 0;
-}
-
-static void
-wsnode_free (struct wordsplit_node *p)
-{
- if (p->flags & _WSNF_WORD)
- free (p->v.word);
- free (p);
-}
-
-static void
-wsnode_append (struct wordsplit *wsp, struct 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 wordsplit *wsp, struct wordsplit_node *node)
-{
- struct 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 struct wordsplit_node *
-wsnode_tail (struct wordsplit_node *p)
-{
- while (p && p->next)
- p = p->next;
- return p;
-}
-
-static void
-wsnode_insert (struct wordsplit *wsp, struct wordsplit_node *node,
- struct 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
- {
- struct wordsplit_node *tail = wsnode_tail (node);
- node->prev = NULL;
- tail->next = anchor;
- anchor->prev = tail;
- wsp->ws_head = node;
- }
- }
- else
- {
- struct wordsplit_node *p;
- struct wordsplit_node *tail = wsnode_tail (node);
-
- p = anchor->next;
- if (p)
- p->prev = tail;
- else
- wsp->ws_tail = tail;
- tail->next = p;
- node->prev = anchor;
- anchor->next = node;
- }
-}
-
-static int
-wordsplit_add_segm (struct wordsplit *wsp, size_t beg, size_t end, int flg)
-{
- struct 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
-wordsplit_free_nodes (struct wordsplit *wsp)
-{
- struct wordsplit_node *p;
-
- for (p = wsp->ws_head; p;)
- {
- struct wordsplit_node *next = p->next;
- wsnode_free (p);
- p = next;
- }
- wsp->ws_head = wsp->ws_tail = NULL;
-}
-
-static void
-wordsplit_dump_nodes (struct wordsplit *wsp)
-{
- struct 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 wordsplit *wsp, struct wordsplit_node *node)
-{
- struct wordsplit_node *p, *end;
- size_t len = 0;
- char *buf, *cur;
- int stop;
-
- if (!(node->flags & _WSNF_JOIN))
- return 0;
-
- 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 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 wordsplit_string_unquote_copy (struct wordsplit *ws, int inquote,
- char *dst, const char *src,
- size_t n);
-
-static int
-wsnode_quoteremoval (struct wordsplit *wsp)
-{
- struct 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 & 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;
- }
-
- wordsplit_string_unquote_copy (wsp, p->flags & _WSNF_QUOTE,
- p->v.word, str, slen);
- }
- }
- return 0;
-}
-
-static int
-wsnode_coalesce (struct wordsplit *wsp)
-{
- struct 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
-wsnode_tail_coalesce (struct wordsplit *wsp, struct wordsplit_node *p)
-{
- if (p->next)
- {
- struct wordsplit_node *np = p;
- while (np && np->next)
- {
- np->flags |= _WSNF_JOIN;
- np = np->next;
- }
- if (coalesce_segment (wsp, p))
- return 1;
- }
- return 0;
-}
-
-static size_t skip_delim (struct wordsplit *wsp);
-
-static int
-wordsplit_finish (struct wordsplit *wsp)
-{
- struct wordsplit_node