uncommitted - direvent

Ready changes

Summary

Import uploads missing from VCS:

Diff

diff --git a/ChangeLog b/ChangeLog
index 5fe9764..0128e4d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,316 @@
+2019-07-13  Sergey Poznyakoff  <gray@gnu.org>
+
+	Version 5.2
+
+2019-07-10  Sergey Poznyakoff  <gray@gnu.org>
+
+	Switch to grecs b06fb7d3
+
+2016-08-25  Sergey Poznyakoff  <gray@gnu.org>
+
+	Update the documentation
+
+2016-08-25  Sergey Poznyakoff  <gray@gnu.org.ua>
+
+	Get rid of hashtab.c, use symtab from grecs instead.
+
+	* grecs: Pull new version.
+	* src/hashtab.c: Remove.
+	* po/POTFILES.in: Remove src/hashtab.c
+	* src/Makefile.am (direvent_SOURCES): Remove hashtab.c
+	* src/config.c (grecs_parser_options): Set GRECS_OPTION_QUOTED_STRING_CONCAT.
+	* src/direvent.h: Remove hashtab prototypes.
+	* src/event.c: Use grecs_symtab.
+	* src/watcher.c: Likewise.
+
+	Rename a test case
+
+	* tests/Makefile.am: Update.
+	* tests/testsuite.at: Update.
+	* tests/conv.at: Rename to tests/file.at
+
+	Fix new functionality on BSD hosts.  Some minor fixes.
+
+	* src/direvent.c (main): Call watchpoint_gc in the main loop.
+	* src/direvent.h (watchpoint) <isdir>: New member.
+	(deliver_ev_create,subwatcher_create): Change signature.
+	* src/ev_kqueue.c (sysev_add_watch): Always monitor NOTE_DELETE.
+	(process_event): Special handling for file deletion.
+	* src/handler.c (handler_list_remove): Return the number of elements
+	remaining in the list.
+	* src/hashtab.c (hashtab_remove): Ignore unexisting entries
+	* src/progman.c (close_fds): Determine the highest used fd by
+	dup'ing standard input.
+	* src/watcher.c (watchpoint_install): Always increase refcnt.
+	(watchpoint_gc_list): New variable.
+	(watchpoint_gc): Iterate over watchpoint_gc_list deleting
+	elements from it.
+	(watchpoint_suspend): Install sentinels only for top-level
+	watchpoints that were removed.
+	(sentinel_handler_run): Deliver the create event.
+	(watchpoint_install_sentinel): Monitor generic create event.
+	(convert_watcher): Remove.
+	(subwatcher_create): Remove the isdir parameter.
+	(watch_subdirs): Exit early if the watchpoint is not a
+	directory.
+	(deliver_ev_create): Change signature.  Take both directory
+	and file name as arguments. All uses changes.
+	* tests/conv.at: Clear expected stderr.
+	* tests/sent.at: Fix race condition.
+
+	Add new tests + minor fixes.
+
+	* src/direvent.h (filpatlist_is_empty): New proto.
+	* src/fnpat.c (filpatlist_is_empty): New function.
+	* src/watcher.c (convert_watcher): Fix error handling.
+	(watchpoint_init): Remove spurious notice.
+
+	* tests/conv.at: New test.
+	* tests/sent.at: New test.
+	* tests/Makefile.am: Add new tests.
+	* tests/testsuite.at: Likewise.
+
+	Further modify struct handler.
+
+	Instead of accomodating two types of functionality, the new struct handler
+	has a pointer to the function that is responsible for handling the event,
+	and a pointer to data for that function (closure).  Additionally, a
+	pointer to deallocator function is also provided.
+
+	Existing functionality is reimplemented using this new struct.  New
+	types of handlers can easily be added.
+
+	* src/config.c (eventconf)<ev_mask,fpat,prog_handler>: New members
+	<handler>: Remove.
+	All uses changed.
+	* src/direvent.h (filpatlist_t)
+	(event_handler_fn, handler_free_fn): New data types.
+	(handler): Remove union and type.  Add two pointer to functions
+	that are to implement the functionality (run and free) and a pointer
+	to data for them.
+	(prog_handler): New struct.
+	(prog_handler_alloc,prog_handler_free)
+	(prog_handler_envrealloc)
+	(watchpoint_run_handlers): New protos.
+	(run_handler,filename_pattern_free)
+	(filename_pattern_match): Remove
+	(filpatlist_add, filpatlist_add_exact)
+	(filpatlist_destroy, filpatlist_match): New protos.
+	* src/ev_inotify.c (process_event): Use watchpoint_run_handlers
+	* src/ev_kqueue.c: Likewise.
+	* src/fnpat.c: Major rewrite.
+	* src/handler.c (handler_copy)
+	(handler_envrealloc,handler_add_pattern)
+	(handler_add_exact_filename): Remove
+	(handler_alloc): Change arguments.
+	(watchpoint_run_handlers): New function.
+	* src/progman.c (prog_handler_alloc)
+	(prog_handler_envrealloc): New functions.
+	* src/watcher.c: Reimplement sentinel watchers.
+
+	Rename: struct dirwatcher -> struct watchpoint
+
+	Implement sentinel handlers.
+
+	Sentinel handlers wait for a creation of a directory.  When
+	the target directory is created, the sentinel handler installs
+	the actual handler for that directory and destroys itself.  Thus,
+	basically sentinel handlers provide a way to defer setting a
+	watchpoint on a directory until it is created.
+
+	* src/handler.c: New source.
+	* src/Makefile.am (direvent_SOURCES): Add handler.c
+	* src/config.c: Move handler-specific stuff to handler.c
+	* src/direvent.h: Rename direvent_handler_ to handler_
+	(handler_free, handler_copy)
+	(handler_envrealloc)
+	(dirwatcher_init,dirwatcher_gc): New protos.
+	(dirwatcher_install_ptr)
+	(dirwatcher_install_sentinel): New protos.
+	* src/ev_inotify.c (process_event): Special handling for
+	IN_IGNORED.
+	(sysev_select): Ignore signo==0.
+	* src/hashtab.c (hashtab_remove): Add missing return statement.
+	(hashtab_foreach): Break out of look instead of returning from
+	it.
+	* src/progman.c (run_sentinel): Implement.
+	* src/watcher.c (+dirwatcher_install_ptr): New function.
+	(dirwatcher_gc): New function.
+
+	Bugfix
+
+	* src/hashtab.c (hashent_list_append): Fix allocated memory size.
+
+	Initial preparation for having distinct handler types.
+
+	* src/direvent.h (pattern_type): New enum, instead of
+	PAT_* defines.
+	(filename_pattern): use enum pattern_type.
+	(handler_type): New enum.
+	(handler): Can be of two types: HANDLER_EXTERN, which handles
+	external programs and is equivalent to the prior content of
+	the structure, and HANDLER_SENTINEL, which is planned to be
+	a built-in handler for configuring watchpoints for newly created
+	directories. All uses changed.
+	(dirwatcher) <refcnt>: Change type to size_t.
+	(handler_alloc,handler_add_pattern)
+	(handler_add_exact_filename): New protos.
+	* src/hashtab.c: Provisions for safe adding and removing
+	from the hashtable when iterating over it.
+	(hashtab) <flags>: Removed.
+	<itr_level, list_new, list_del>: New members.
+	(hashtab_remove): When iterating, place pointer to the removed
+	entry in list_del instead of actually removing it.
+	(hashtab_lookup_or_install): When iterating, add a pointer to
+	the newly created entry to the list_new list, instead of adding
+	it immediately.
+	(hashtab_foreach): Flush list_del and list_new at the end of
+	the topmost iteration.
+
+	* src/config.c (handler_alloc): Rename to handler_copy
+	(handler_alloc): New function.
+	(handler_free): Two types of handlers.
+	(handler_add_pattern)
+	(handler_add_exact_filename): New functions.
+	(file_name_pattern): Takes struct handler * as its
+	first argument.
+	(cb_file_pattern): Change accordingly.
+	* src/fnpat.c (filename_pattern_free): Handle PAT_EXACT.
+	(filename_pattern_match): Likewise.
+	* src/progman.c (run_handler): Two types of handlers.
+	* src/watcher.c (dirwatcher_install): Restore missing gettext
+	marker.
+	Allocate handler_list.
+	(dirwatcher_init): Convert non-directory watchpoints to directory
+	ones.
+
+2016-08-20  Sergey Poznyakoff  <gray@gnu.org>
+
+	Fix environment modification code
+
+	Port fixes from rush
+
+2016-08-13  Sergey Poznyakoff  <gray@gnu.org>
+
+	Clean-up handler initialization routines.
+
+	In particular, this change allows for placing several environ statements
+	in a single watcher statement.  Such environ statements accumulate.
+
+	* src/config.c (eventconf): Simplify the structure.
+	(handler_alloc): Take a pointer to struct handler as
+	argument.
+	(handler_envrealloc): New function.
+	(handler_free): Rename to handler_listent_free. All uses updated.
+	(handler_free): New function.
+	(eventconf_flush,cb_option,cb_user): Reflect changes to struct
+	eventconf
+	(cb_environ): Likewise. Reallocate env as necessary.
+
+	* doc/direvent.texi: Document the change.
+
+	* NEWS: Document the changes.
+
+	Limit memory usage.
+
+	Don't create duplicates of handler structs for each pathname
+	watched.  Instead keep a count of references to each handler
+	and handler list and deallocate them when the count falls to
+	zero.
+
+	* src/config.c (direvent_handler_list): New struct.
+	(direvent_handler_first,direvent_handler_next)
+	(direvent_handler_current)
+	(direvent_handler_list_create)
+	(direvent_handler_list_copy)
+	(direvent_handler_list_unref)
+	(direvent_handler_list_append): New functions.
+	(eventconf_flush): Create a single copy of watcher.
+	* src/direvent.c (main): Call shutdown_watchers before terminating.
+	* src/direvent.h (handler) <next>: Remove.
+	<refcnt>: New member.
+	<prog>: Remove const qualifier.
+	(direvent_handler_list_t)
+	(direvent_handler_iterator_t): New data types.
+	(dirwatcher): Remove handler_tail. Change type of
+	handler_list to direvent_handler_list_t.
+	(shutdown_watchers)
+	(direvent_handler_first,direvent_handler_next)
+	(direvent_handler_current)
+	(direvent_handler_list_create)
+	(direvent_handler_list_copy)
+	(direvent_handler_list_unref)
+	(direvent_handler_list_append): New protos.
+	(for_each_handler): New define.
+	* src/watcher.c (dirwatcher_unref): Call direvent_handler_list_unref.
+	(all functions): Use handler iterators where necessary
+	(shutdown_watchers): New function.
+	* src/ev_inotify.c: Use handler iterators.
+	* src/ev_kqueue.c: Likewise.
+
+	Fix comments
+
+2016-08-12  Sergey Poznyakoff  <gray@gnu.org.ua>
+
+	Version 5.1.90
+
+	* NEWS: Update.
+	* configure.ac: Update.
+	* src/watcher.c (setwatcher): Fix conditional.
+	* src/direvent.h (dirwatcher_pattern_match): Add missing prototype.
+
+	Don't keep watchpoint descriptor table
+
+	During the lifetime of a watcher, its descriptor can change, so
+	it cannot be reliably used to identify the watcher outside of
+	the ev_*.c module.  E.g. for kqueue interface, descriptors change
+	after compacting the event table, which happens when a watcher is
+	closed and removed.
+
+	Finding the watcher for the given event is now the responsibility
+	of the event module.
+
+	* src/direvent.h (dirwatcher_ref)
+	(dirwatcher_unref): New protos.
+	(dirwatcher_lookup_wd): Remove.
+	* src/watcher.c (dirwatcher_ref): New function.
+	(dirwatcher_register, dirwatcher_lookup_wd)
+	(dirwatcher_remove_wd): Remove.  All uses updated.
+	(setwatcher): Indicate successful initialization for
+	the caller.
+	(setup_watchers): Check success flag.
+	* src/ev_inotify.c (dwreg, dwunreg)
+	(dwget): New functions to keep track of the registered
+	watchers and their descriptors.
+	(sysev_add_watch): Register watcher.
+	(sysev_rm_watch): Deregister it.
+	* src/ev_kqueue.c (check_created): Skip directory entries
+	that don't match pattern.
+
+2016-08-11  Sergey Poznyakoff  <gray@gnu.org.ua>
+
+	Bugfixes
+
+	* src/Makefile.am (AM_CPPFLAGS): Define SYSCONFDIR.
+	* src/direvent.c (mkfilename): Don't append trailing /
+	if filename is empty.
+	* src/direvent.h (hashtab_count_entries): Remove.
+	* src/ev_inotify.c (process_event): Translate IN_IGNORED to IN_DELETE.
+	Remove the watcher only after all handlers have been invoked.
+	* src/hashtab.c (hashtab) <elcount>: New member. Keep the number
+	of actually used elements.
+	(hashtab_remove, hashtab_lookup_or_install)
+	(hashtab_create,hashtab_clear): Keep track of the number of
+	actually used elements.
+	(hashtab_count_entries): Remove duplicate function.
+	(hashtab_count): Return elcount without recomputing.
+	* src/watcher.c (texttab): Rename to nametab for clarity.
+	(dirwatcher_pattern_match): New function.
+	(watch_subdirs): Ignore subdirs that don't match file name
+	pattern.
+	(dirwatcher_destroy): Exit immediately if no more watchers
+	are left.
+
 2016-07-06  Sergey Poznyakoff  <gray@gnu.org.ua>
 
 	Version 5.1
diff --git a/INSTALL b/INSTALL
index 007e939..2099840 100644
--- a/INSTALL
+++ b/INSTALL
@@ -12,8 +12,8 @@ without warranty of any kind.
 Basic Installation
 ==================
 
-   Briefly, the shell commands `./configure; make; make install' should
-configure, build, and install this package.  The following
+   Briefly, the shell command `./configure && make && make install'
+should configure, build, and install this package.  The following
 more-detailed instructions are generic; see the `README' file for
 instructions specific to this package.  Some packages provide this
 `INSTALL' file but do not implement all of the features documented
diff --git a/Makefile.in b/Makefile.in
index 72e13b3..2cbba35 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -30,7 +30,17 @@
 # You should have received a copy of the GNU General Public License
 # along with Direvent.  If not, see <http://www.gnu.org/licenses/>.
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -94,19 +104,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = .
-DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog THANKS \
-	$(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/configure $(am__configure_deps) \
-	$(srcdir)/config.h.in ABOUT-NLS COPYING build-aux/compile \
-	build-aux/config.guess build-aux/config.rpath \
-	build-aux/config.sub build-aux/depcomp build-aux/install-sh \
-	build-aux/mdate-sh build-aux/missing build-aux/texinfo.tex \
-	build-aux/ylwrap $(top_srcdir)/build-aux/compile \
-	$(top_srcdir)/build-aux/config.guess \
-	$(top_srcdir)/build-aux/config.rpath \
-	$(top_srcdir)/build-aux/config.sub \
-	$(top_srcdir)/build-aux/install-sh \
-	$(top_srcdir)/build-aux/missing
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/am/gettext.m4 $(top_srcdir)/am/iconv.m4 \
@@ -117,6 +114,8 @@ am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+	$(am__configure_deps) $(am__DIST_COMMON)
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
  configure.lineno config.status.lineno
 mkinstalldirs = $(install_sh) -d
@@ -180,6 +179,18 @@ ETAGS = etags
 CTAGS = ctags
 CSCOPE = cscope
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+	$(top_srcdir)/build-aux/compile \
+	$(top_srcdir)/build-aux/config.guess \
+	$(top_srcdir)/build-aux/config.rpath \
+	$(top_srcdir)/build-aux/config.sub \
+	$(top_srcdir)/build-aux/install-sh \
+	$(top_srcdir)/build-aux/missing ABOUT-NLS AUTHORS COPYING \
+	ChangeLog INSTALL NEWS README THANKS build-aux/compile \
+	build-aux/config.guess build-aux/config.rpath \
+	build-aux/config.sub build-aux/depcomp build-aux/install-sh \
+	build-aux/mdate-sh build-aux/missing build-aux/texinfo.tex \
+	build-aux/ylwrap
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 distdir = $(PACKAGE)-$(VERSION)
 top_distdir = $(distdir)
@@ -252,7 +263,9 @@ GRECS_CHANGELOG = @GRECS_CHANGELOG@
 GRECS_DISTCK_AT = @GRECS_DISTCK_AT@
 GRECS_DISTDOC = @GRECS_DISTDOC@
 GRECS_DOCDIR = @GRECS_DOCDIR@
+GRECS_EXTRA_DIST = @GRECS_EXTRA_DIST@
 GRECS_HOST_PROJECT_INCLUDES = @GRECS_HOST_PROJECT_INCLUDES@
+GRECS_HOST_PROJECT_LDADD = @GRECS_HOST_PROJECT_LDADD@
 GRECS_INCLUDES = @GRECS_INCLUDES@
 GRECS_INCLUDE_DIR = @GRECS_INCLUDE_DIR@
 GRECS_LDADD = @GRECS_LDADD@
@@ -383,7 +396,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnits Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -611,15 +623,15 @@ dist-xz: distdir
 	$(am__post_remove_distdir)
 
 dist-tarZ: distdir
-	@echo WARNING: "Support for shar distribution archives is" \
-	               "deprecated." >&2
+	@echo WARNING: "Support for distribution archives compressed with" \
+		       "legacy program 'compress' is deprecated." >&2
 	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
 	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
 	$(am__post_remove_distdir)
 
 dist-shar: distdir
-	@echo WARNING: "Support for distribution archives compressed with" \
-		       "legacy program 'compress' is deprecated." >&2
+	@echo WARNING: "Support for shar distribution archives is" \
+	               "deprecated." >&2
 	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
 	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
 	$(am__post_remove_distdir)
@@ -655,16 +667,17 @@ distcheck: dist
 	esac
 	chmod -R a-w $(distdir)
 	chmod u+w $(distdir)
-	mkdir $(distdir)/_build $(distdir)/_inst
+	mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
 	chmod a-w $(distdir)
 	test -d $(distdir)/_build || exit 0; \
 	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
 	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
 	  && am__cwd=`pwd` \
-	  && $(am__cd) $(distdir)/_build \
-	  && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+	  && $(am__cd) $(distdir)/_build/sub \
+	  && ../../configure \
 	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
 	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	    --srcdir=../.. --prefix="$$dc_install_base" \
 	  && $(MAKE) $(AM_MAKEFLAGS) \
 	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
 	  && $(MAKE) $(AM_MAKEFLAGS) check \
@@ -839,6 +852,8 @@ uninstall-am:
 	mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am
 
+.PRECIOUS: Makefile
+
 
 .PHONY: ChangeLog
 ChangeLog:
diff --git a/NEWS b/NEWS
index cf85299..5e3e162 100644
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,38 @@
-direvent -- history of user-visible changes. 2016-07-06
-Copyright (C) 2012-2016 Sergey Poznyakoff
+direvent -- history of user-visible changes. 2019-07-13
+Copyright (C) 2012-2019 Sergey Poznyakoff
 See the end of file for copying conditions.
 
 Please send direvent bug reports to <bug-direvent@gnu.org.ua>
+
+Version 5.2, 2019-07-13
+
+* The path statement can refer to a regular file.
+
+Prior versions of direvent required the argument to the "path"
+statement to refer to an existing directory.  This requirement is now
+lifted.  The pathname can refer to any type of file (not only a
+directory).  Moreover, the file is not required to exist.  If it does
+not exist, direvent will set up an auxiliary watcher (called a
+"sentinel"), that will wake up upon creation of the file with that
+pathname and will set up the configured watcher once it is created.
+
+The process is reversed when the file referred to by the "path"
+statement is deleted.  In that case, the configured watcher is
+deactivated and a sentinel is set up which will bring it back when the
+destination file or directory is created.
+
+This mode of operation ensures that the configured watcher will always
+be operational.
+
+* Fix watcher removal on BSD-like systems.
+
+* Configuration changes
+
+** multiple environ statements
+
+Multiple environ statements can be used within a single watcher block.
+Such statements accumulate.
+
 
 Version 5.1, 2016-07-06
 
@@ -121,7 +151,7 @@ Initial release
 =========================================================================
 Copyright information:
 
-Copyright (C) 2012-2016 Sergey Poznyakoff
+Copyright (C) 2012-2019 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 3526276..5b53b7b 100644
--- a/README
+++ b/README
@@ -60,7 +60,7 @@ at http://direvent.man.gnu.org.ua.
 
 * Copyright information:
 
-Copyright (C) 2012-2014 Sergey Poznyakoff
+Copyright (C) 2012-2016 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/aclocal.m4 b/aclocal.m4
index c1b10e7..a7928f8 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.14 -*- Autoconf -*-
+# generated automatically by aclocal 1.15 -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -20,7 +20,7 @@ You have another version of autoconf.  It may work, but is not guaranteed to.
 If you have problems, you may need to regenerate the build system entirely.
 To do so, use the procedure documented by the package, typically 'autoreconf'.])])
 
-# Copyright (C) 2002-2013 Free Software Foundation, Inc.
+# Copyright (C) 2002-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -32,10 +32,10 @@ To do so, use the procedure documented by the package, typically 'autoreconf'.])
 # generated from the m4 files accompanying Automake X.Y.
 # (This private macro should not be called outside this file.)
 AC_DEFUN([AM_AUTOMAKE_VERSION],
-[am__api_version='1.14'
+[am__api_version='1.15'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.14], [],
+m4_if([$1], [1.15], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -51,14 +51,14 @@ m4_define([_AM_AUTOCONF_VERSION], [])
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.14])dnl
+[AM_AUTOMAKE_VERSION([1.15])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
 
 # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -103,15 +103,14 @@ _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
 # configured tree to be moved without reconfiguration.
 
 AC_DEFUN([AM_AUX_DIR_EXPAND],
-[dnl Rely on autoconf to set up CDPATH properly.
-AC_PREREQ([2.50])dnl
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
 ])
 
 # AM_CONDITIONAL                                            -*- Autoconf -*-
 
-# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+# Copyright (C) 1997-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -142,7 +141,7 @@ AC_CONFIG_COMMANDS_PRE(
 Usually this means the macro was only invoked conditionally.]])
 fi])])
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -333,7 +332,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
 
 # Generate code to set up dependency tracking.              -*- Autoconf -*-
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -409,7 +408,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
 
 # Do all the work for Automake.                             -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -499,8 +498,8 @@ AC_REQUIRE([AC_PROG_MKDIR_P])dnl
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
 AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
-# We need awk for the "check" target.  The system "awk" is bad on
-# some platforms.
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
 AC_REQUIRE([AC_PROG_AWK])dnl
 AC_REQUIRE([AC_PROG_MAKE_SET])dnl
 AC_REQUIRE([AM_SET_LEADING_DOT])dnl
@@ -573,7 +572,11 @@ to "yes", and re-run configure.
 END
     AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
   fi
-fi])
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
 
 dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
 dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
@@ -602,7 +605,7 @@ for _am_header in $config_headers :; do
 done
 echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -613,7 +616,7 @@ echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_co
 # Define $install_sh.
 AC_DEFUN([AM_PROG_INSTALL_SH],
 [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-if test x"${install_sh}" != xset; then
+if test x"${install_sh+set}" != xset; then
   case $am_aux_dir in
   *\ * | *\	*)
     install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -623,7 +626,7 @@ if test x"${install_sh}" != xset; then
 fi
 AC_SUBST([install_sh])])
 
-# Copyright (C) 2003-2013 Free Software Foundation, Inc.
+# Copyright (C) 2003-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -642,7 +645,7 @@ fi
 rmdir .tst 2>/dev/null
 AC_SUBST([am__leading_dot])])
 
-# Copyright (C) 1998-2013 Free Software Foundation, Inc.
+# Copyright (C) 1998-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -662,7 +665,7 @@ fi])
 
 # Check to see how 'make' treats includes.	            -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -712,7 +715,7 @@ rm -f confinc confmf
 
 # Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
 
-# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+# Copyright (C) 1997-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -749,7 +752,7 @@ else
 fi
 ])
 
-# Copyright (C) 2003-2013 Free Software Foundation, Inc.
+# Copyright (C) 2003-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -783,7 +786,7 @@ esac
 
 # Helper functions for option handling.                     -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -812,7 +815,7 @@ AC_DEFUN([_AM_SET_OPTIONS],
 AC_DEFUN([_AM_IF_OPTION],
 [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -859,7 +862,7 @@ AC_LANG_POP([C])])
 # For backward compatibility.
 AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -878,7 +881,7 @@ AC_DEFUN([AM_RUN_LOG],
 
 # Check to make sure that the build environment is sane.    -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -959,7 +962,7 @@ AC_CONFIG_COMMANDS_PRE(
 rm -f conftest.file
 ])
 
-# Copyright (C) 2009-2013 Free Software Foundation, Inc.
+# Copyright (C) 2009-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1019,7 +1022,7 @@ AC_SUBST([AM_BACKSLASH])dnl
 _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
 ])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1047,7 +1050,7 @@ fi
 INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
 AC_SUBST([INSTALL_STRIP_PROGRAM])])
 
-# Copyright (C) 2006-2013 Free Software Foundation, Inc.
+# Copyright (C) 2006-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1066,7 +1069,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
 
 # Check how to create a tarball.                            -*- Autoconf -*-
 
-# Copyright (C) 2004-2013 Free Software Foundation, Inc.
+# Copyright (C) 2004-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff --git a/build-aux/compile b/build-aux/compile
index 531136b..a85b723 100755
--- a/build-aux/compile
+++ b/build-aux/compile
@@ -3,7 +3,7 @@
 
 scriptversion=2012-10-14.11; # UTC
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 # Written by Tom Tromey <tromey@cygnus.com>.
 #
 # This program is free software; you can redistribute it and/or modify
diff --git a/build-aux/config.guess b/build-aux/config.guess
index b79252d..6c32c86 100755
--- a/build-aux/config.guess
+++ b/build-aux/config.guess
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2013 Free Software Foundation, Inc.
+#   Copyright 1992-2014 Free Software Foundation, Inc.
 
-timestamp='2013-06-10'
+timestamp='2014-11-04'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -24,12 +24,12 @@ timestamp='2013-06-10'
 # program.  This Exception is an additional permission under section 7
 # of the GNU General Public License, version 3 ("GPLv3").
 #
-# Originally written by Per Bothner.
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
 #
 # You can get the latest version of this script from:
 # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
 #
-# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+# Please send patches to <config-patches@gnu.org>.
 
 
 me=`echo "$0" | sed -e 's,.*/,,'`
@@ -50,7 +50,7 @@ version="\
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2013 Free Software Foundation, Inc.
+Copyright 1992-2014 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -149,7 +149,7 @@ Linux|GNU|GNU/*)
 	LIBC=gnu
 	#endif
 	EOF
-	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
 	;;
 esac
 
@@ -579,8 +579,9 @@ EOF
 	else
 		IBM_ARCH=powerpc
 	fi
-	if [ -x /usr/bin/oslevel ] ; then
-		IBM_REV=`/usr/bin/oslevel`
+	if [ -x /usr/bin/lslpp ] ; then
+		IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+			   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
 	else
 		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
 	fi
@@ -826,7 +827,7 @@ EOF
     *:MINGW*:*)
 	echo ${UNAME_MACHINE}-pc-mingw32
 	exit ;;
-    i*:MSYS*:*)
+    *:MSYS*:*)
 	echo ${UNAME_MACHINE}-pc-msys
 	exit ;;
     i*:windows32*:*)
@@ -969,10 +970,10 @@ EOF
 	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
 	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
 	;;
-    or1k:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+    openrisc*:Linux:*:*)
+	echo or1k-unknown-linux-${LIBC}
 	exit ;;
-    or32:Linux:*:*)
+    or32:Linux:*:* | or1k*:Linux:*:*)
 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
     padre:Linux:*:*)
@@ -1260,16 +1261,26 @@ EOF
 	if test "$UNAME_PROCESSOR" = unknown ; then
 	    UNAME_PROCESSOR=powerpc
 	fi
-	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
-	    if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
-		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
-		grep IS_64BIT_ARCH >/dev/null
-	    then
-		case $UNAME_PROCESSOR in
-		    i386) UNAME_PROCESSOR=x86_64 ;;
-		    powerpc) UNAME_PROCESSOR=powerpc64 ;;
-		esac
+	if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+	    if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		    (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		    grep IS_64BIT_ARCH >/dev/null
+		then
+		    case $UNAME_PROCESSOR in
+			i386) UNAME_PROCESSOR=x86_64 ;;
+			powerpc) UNAME_PROCESSOR=powerpc64 ;;
+		    esac
+		fi
 	    fi
+	elif test "$UNAME_PROCESSOR" = i386 ; then
+	    # Avoid executing cc on OS X 10.9, as it ships with a stub
+	    # that puts up a graphical alert prompting to install
+	    # developer tools.  Any system running Mac OS X 10.7 or
+	    # later (Darwin 11 and later) is required to have a 64-bit
+	    # processor. This is not true of the ARM version of Darwin
+	    # that Apple uses in portable devices.
+	    UNAME_PROCESSOR=x86_64
 	fi
 	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
 	exit ;;
@@ -1361,154 +1372,6 @@ EOF
 	exit ;;
 esac
 
-eval $set_cc_for_build
-cat >$dummy.c <<EOF
-#ifdef _SEQUENT_
-# include <sys/types.h>
-# include <sys/utsname.h>
-#endif
-main ()
-{
-#if defined (sony)
-#if defined (MIPSEB)
-  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
-     I don't know....  */
-  printf ("mips-sony-bsd\n"); exit (0);
-#else
-#include <sys/param.h>
-  printf ("m68k-sony-newsos%s\n",
-#ifdef NEWSOS4
-	"4"
-#else
-	""
-#endif
-	); exit (0);
-#endif
-#endif
-
-#if defined (__arm) && defined (__acorn) && defined (__unix)
-  printf ("arm-acorn-riscix\n"); exit (0);
-#endif
-
-#if defined (hp300) && !defined (hpux)
-  printf ("m68k-hp-bsd\n"); exit (0);
-#endif
-
-#if defined (NeXT)
-#if !defined (__ARCHITECTURE__)
-#define __ARCHITECTURE__ "m68k"
-#endif
-  int version;
-  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
-  if (version < 4)
-    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
-  else
-    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
-  exit (0);
-#endif
-
-#if defined (MULTIMAX) || defined (n16)
-#if defined (UMAXV)
-  printf ("ns32k-encore-sysv\n"); exit (0);
-#else
-#if defined (CMU)
-  printf ("ns32k-encore-mach\n"); exit (0);
-#else
-  printf ("ns32k-encore-bsd\n"); exit (0);
-#endif
-#endif
-#endif
-
-#if defined (__386BSD__)
-  printf ("i386-pc-bsd\n"); exit (0);
-#endif
-
-#if defined (sequent)
-#if defined (i386)
-  printf ("i386-sequent-dynix\n"); exit (0);
-#endif
-#if defined (ns32000)
-  printf ("ns32k-sequent-dynix\n"); exit (0);
-#endif
-#endif
-
-#if defined (_SEQUENT_)
-    struct utsname un;
-
-    uname(&un);
-
-    if (strncmp(un.version, "V2", 2) == 0) {
-	printf ("i386-sequent-ptx2\n"); exit (0);
-    }
-    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
-	printf ("i386-sequent-ptx1\n"); exit (0);
-    }
-    printf ("i386-sequent-ptx\n"); exit (0);
-
-#endif
-
-#if defined (vax)
-# if !defined (ultrix)
-#  include <sys/param.h>
-#  if defined (BSD)
-#   if BSD == 43
-      printf ("vax-dec-bsd4.3\n"); exit (0);
-#   else
-#    if BSD == 199006
-      printf ("vax-dec-bsd4.3reno\n"); exit (0);
-#    else
-      printf ("vax-dec-bsd\n"); exit (0);
-#    endif
-#   endif
-#  else
-    printf ("vax-dec-bsd\n"); exit (0);
-#  endif
-# else
-    printf ("vax-dec-ultrix\n"); exit (0);
-# endif
-#endif
-
-#if defined (alliant) && defined (i860)
-  printf ("i860-alliant-bsd\n"); exit (0);
-#endif
-
-  exit (1);
-}
-EOF
-
-$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
-	{ echo "$SYSTEM_NAME"; exit; }
-
-# Apollos put the system type in the environment.
-
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
-
-# Convex versions that predate uname can use getsysinfo(1)
-
-if [ -x /usr/convex/getsysinfo ]
-then
-    case `getsysinfo -f cpu_type` in
-    c1*)
-	echo c1-convex-bsd
-	exit ;;
-    c2*)
-	if getsysinfo -f scalar_acc
-	then echo c32-convex-bsd
-	else echo c2-convex-bsd
-	fi
-	exit ;;
-    c34*)
-	echo c34-convex-bsd
-	exit ;;
-    c38*)
-	echo c38-convex-bsd
-	exit ;;
-    c4*)
-	echo c4-convex-bsd
-	exit ;;
-    esac
-fi
-
 cat >&2 <<EOF
 $0: unable to guess system type
 
diff --git a/build-aux/config.sub b/build-aux/config.sub
index 8b612ab..7ffe373 100755
--- a/build-aux/config.sub
+++ b/build-aux/config.sub
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2013 Free Software Foundation, Inc.
+#   Copyright 1992-2014 Free Software Foundation, Inc.
 
-timestamp='2013-04-24'
+timestamp='2014-12-03'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@ timestamp='2013-04-24'
 # of the GNU General Public License, version 3 ("GPLv3").
 
 
-# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+# Please send patches to <config-patches@gnu.org>.
 #
 # Configuration subroutine to validate and canonicalize a configuration type.
 # Supply the specified configuration type as an argument.
@@ -68,7 +68,7 @@ Report bugs and patches to <config-patches@gnu.org>."
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2013 Free Software Foundation, Inc.
+Copyright 1992-2014 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -257,7 +257,7 @@ case $basic_machine in
 	| avr | avr32 \
 	| be32 | be64 \
 	| bfin \
-	| c4x | clipper \
+	| c4x | c8051 | clipper \
 	| d10v | d30v | dlx | dsp16xx \
 	| epiphany \
 	| fido | fr30 | frv \
@@ -265,6 +265,7 @@ case $basic_machine in
 	| hexagon \
 	| i370 | i860 | i960 | ia64 \
 	| ip2k | iq2000 \
+	| k1om \
 	| le32 | le64 \
 	| lm32 \
 	| m32c | m32r | m32rle | m68000 | m68k | m88k \
@@ -282,8 +283,10 @@ case $basic_machine in
 	| mips64vr5900 | mips64vr5900el \
 	| mipsisa32 | mipsisa32el \
 	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa32r6 | mipsisa32r6el \
 	| mipsisa64 | mipsisa64el \
 	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64r6 | mipsisa64r6el \
 	| mipsisa64sb1 | mipsisa64sb1el \
 	| mipsisa64sr71k | mipsisa64sr71kel \
 	| mipsr5900 | mipsr5900el \
@@ -295,11 +298,11 @@ case $basic_machine in
 	| nds32 | nds32le | nds32be \
 	| nios | nios2 | nios2eb | nios2el \
 	| ns16k | ns32k \
-	| open8 \
-	| or1k | or32 \
+	| open8 | or1k | or1knd | or32 \
 	| pdp10 | pdp11 | pj | pjl \
 	| powerpc | powerpc64 | powerpc64le | powerpcle \
 	| pyramid \
+	| riscv32 | riscv64 \
 	| rl78 | rx \
 	| score \
 	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
@@ -310,6 +313,7 @@ case $basic_machine in
 	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
 	| ubicom32 \
 	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+	| visium \
 	| we32k \
 	| x86 | xc16x | xstormy16 | xtensa \
 	| z8k | z80)
@@ -324,7 +328,10 @@ case $basic_machine in
 	c6x)
 		basic_machine=tic6x-unknown
 		;;
-	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
+	leon|leon[3-9])
+		basic_machine=sparc-$basic_machine
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
 		basic_machine=$basic_machine-unknown
 		os=-none
 		;;
@@ -372,7 +379,7 @@ case $basic_machine in
 	| be32-* | be64-* \
 	| bfin-* | bs2000-* \
 	| c[123]* | c30-* | [cjt]90-* | c4x-* \
-	| clipper-* | craynv-* | cydra-* \
+	| c8051-* | clipper-* | craynv-* | cydra-* \
 	| d10v-* | d30v-* | dlx-* \
 	| elxsi-* \
 	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
@@ -381,6 +388,7 @@ case $basic_machine in
 	| hexagon-* \
 	| i*86-* | i860-* | i960-* | ia64-* \
 	| ip2k-* | iq2000-* \
+	| k1om-* \
 	| le32-* | le64-* \
 	| lm32-* \
 	| m32c-* | m32r-* | m32rle-* \
@@ -400,8 +408,10 @@ case $basic_machine in
 	| mips64vr5900-* | mips64vr5900el-* \
 	| mipsisa32-* | mipsisa32el-* \
 	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa32r6-* | mipsisa32r6el-* \
 	| mipsisa64-* | mipsisa64el-* \
 	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64r6-* | mipsisa64r6el-* \
 	| mipsisa64sb1-* | mipsisa64sb1el-* \
 	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
 	| mipsr5900-* | mipsr5900el-* \
@@ -413,6 +423,7 @@ case $basic_machine in
 	| nios-* | nios2-* | nios2eb-* | nios2el-* \
 	| none-* | np1-* | ns16k-* | ns32k-* \
 	| open8-* \
+	| or1k*-* \
 	| orion-* \
 	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
 	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
@@ -430,6 +441,7 @@ case $basic_machine in
 	| ubicom32-* \
 	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
 	| vax-* \
+	| visium-* \
 	| we32k-* \
 	| x86-* | x86_64-* | xc16x-* | xps100-* \
 	| xstormy16-* | xtensa*-* \
@@ -767,6 +779,9 @@ case $basic_machine in
 		basic_machine=m68k-isi
 		os=-sysv
 		;;
+	leon-*|leon[3-9]-*)
+		basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
+		;;
 	m68knommu)
 		basic_machine=m68k-unknown
 		os=-linux
@@ -794,7 +809,7 @@ case $basic_machine in
 		os=-mingw64
 		;;
 	mingw32)
-		basic_machine=i386-pc
+		basic_machine=i686-pc
 		os=-mingw32
 		;;
 	mingw32ce)
@@ -822,6 +837,10 @@ case $basic_machine in
 		basic_machine=powerpc-unknown
 		os=-morphos
 		;;
+	moxiebox)
+		basic_machine=moxie-unknown
+		os=-moxiebox
+		;;
 	msdos)
 		basic_machine=i386-pc
 		os=-msdos
@@ -830,7 +849,7 @@ case $basic_machine in
 		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
 		;;
 	msys)
-		basic_machine=i386-pc
+		basic_machine=i686-pc
 		os=-msys
 		;;
 	mvs)
@@ -1367,14 +1386,14 @@ case $os in
 	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
 	      | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
 	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \
-	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
 	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
 	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
 	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
 	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
 	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
 	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
-	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
 	# Remember, each alternative MUST END IN *, to match a version number.
 		;;
 	-qnx*)
@@ -1546,6 +1565,9 @@ case $basic_machine in
 	c4x-* | tic4x-*)
 		os=-coff
 		;;
+	c8051-*)
+		os=-elf
+		;;
 	hexagon-*)
 		os=-elf
 		;;
@@ -1589,9 +1611,6 @@ case $basic_machine in
 	mips*-*)
 		os=-elf
 		;;
-	or1k-*)
-		os=-elf
-		;;
 	or32-*)
 		os=-coff
 		;;
diff --git a/build-aux/depcomp b/build-aux/depcomp
index 4ebd5b3..fc98710 100755
--- a/build-aux/depcomp
+++ b/build-aux/depcomp
@@ -3,7 +3,7 @@
 
 scriptversion=2013-05-30.07; # UTC
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 
 # 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
diff --git a/build-aux/install-sh b/build-aux/install-sh
index 377bb86..0b0fdcb 100755
--- a/build-aux/install-sh
+++ b/build-aux/install-sh
@@ -1,7 +1,7 @@
 #!/bin/sh
 # install - install a program, script, or datafile
 
-scriptversion=2011-11-20.07; # UTC
+scriptversion=2013-12-25.23; # UTC
 
 # This originates from X11R5 (mit/util/scripts/install.sh), which was
 # later released in X11R6 (xc/config/util/install.sh) with the
@@ -41,19 +41,15 @@ scriptversion=2011-11-20.07; # UTC
 # This script is compatible with the BSD install script, but was written
 # from scratch.
 
+tab='	'
 nl='
 '
-IFS=" ""	$nl"
+IFS=" $tab$nl"
 
-# set DOITPROG to echo to test this script
+# Set DOITPROG to "echo" to test this script.
 
-# Don't use :- since 4.3BSD and earlier shells don't like it.
 doit=${DOITPROG-}
-if test -z "$doit"; then
-  doit_exec=exec
-else
-  doit_exec=$doit
-fi
+doit_exec=${doit:-exec}
 
 # Put in absolute file names if you don't have them in your path;
 # or use environment vars.
@@ -68,17 +64,6 @@ mvprog=${MVPROG-mv}
 rmprog=${RMPROG-rm}
 stripprog=${STRIPPROG-strip}
 
-posix_glob='?'
-initialize_posix_glob='
-  test "$posix_glob" != "?" || {
-    if (set -f) 2>/dev/null; then
-      posix_glob=
-    else
-      posix_glob=:
-    fi
-  }
-'
-
 posix_mkdir=
 
 # Desired mode of installed file.
@@ -97,7 +82,7 @@ dir_arg=
 dst_arg=
 
 copy_on_change=false
-no_target_directory=
+is_target_a_directory=possibly
 
 usage="\
 Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
@@ -137,46 +122,57 @@ while test $# -ne 0; do
     -d) dir_arg=true;;
 
     -g) chgrpcmd="$chgrpprog $2"
-	shift;;
+        shift;;
 
     --help) echo "$usage"; exit $?;;
 
     -m) mode=$2
-	case $mode in
-	  *' '* | *'	'* | *'
-'*	  | *'*'* | *'?'* | *'['*)
-	    echo "$0: invalid mode: $mode" >&2
-	    exit 1;;
-	esac
-	shift;;
+        case $mode in
+          *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+            echo "$0: invalid mode: $mode" >&2
+            exit 1;;
+        esac
+        shift;;
 
     -o) chowncmd="$chownprog $2"
-	shift;;
+        shift;;
 
     -s) stripcmd=$stripprog;;
 
-    -t) dst_arg=$2
-	# Protect names problematic for 'test' and other utilities.
-	case $dst_arg in
-	  -* | [=\(\)!]) dst_arg=./$dst_arg;;
-	esac
-	shift;;
+    -t)
+        is_target_a_directory=always
+        dst_arg=$2
+        # Protect names problematic for 'test' and other utilities.
+        case $dst_arg in
+          -* | [=\(\)!]) dst_arg=./$dst_arg;;
+        esac
+        shift;;
 
-    -T) no_target_directory=true;;
+    -T) is_target_a_directory=never;;
 
     --version) echo "$0 $scriptversion"; exit $?;;
 
-    --)	shift
-	break;;
+    --) shift
+        break;;
 
-    -*)	echo "$0: invalid option: $1" >&2
-	exit 1;;
+    -*) echo "$0: invalid option: $1" >&2
+        exit 1;;
 
     *)  break;;
   esac
   shift
 done
 
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
+
+if test -n "$dir_arg"; then
+  if test -n "$dst_arg"; then
+    echo "$0: target directory not allowed when installing a directory." >&2
+    exit 1
+  fi
+fi
+
 if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
   # When -d is used, all remaining arguments are directories to create.
   # When -t is used, the destination is already specified.
@@ -207,6 +203,15 @@ if test $# -eq 0; then
   exit 0
 fi
 
+if test -z "$dir_arg"; then
+  if test $# -gt 1 || test "$is_target_a_directory" = always; then
+    if test ! -d "$dst_arg"; then
+      echo "$0: $dst_arg: Is not a directory." >&2
+      exit 1
+    fi
+  fi
+fi
+
 if test -z "$dir_arg"; then
   do_exit='(exit $ret); exit $ret'
   trap "ret=129; $do_exit" 1
@@ -223,16 +228,16 @@ if test -z "$dir_arg"; then
 
     *[0-7])
       if test -z "$stripcmd"; then
-	u_plus_rw=
+        u_plus_rw=
       else
-	u_plus_rw='% 200'
+        u_plus_rw='% 200'
       fi
       cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
     *)
       if test -z "$stripcmd"; then
-	u_plus_rw=
+        u_plus_rw=
       else
-	u_plus_rw=,u+rw
+        u_plus_rw=,u+rw
       fi
       cp_umask=$mode$u_plus_rw;;
   esac
@@ -269,41 +274,15 @@ do
     # If destination is a directory, append the input filename; won't work
     # if double slashes aren't ignored.
     if test -d "$dst"; then
-      if test -n "$no_target_directory"; then
-	echo "$0: $dst_arg: Is a directory" >&2
-	exit 1
+      if test "$is_target_a_directory" = never; then
+        echo "$0: $dst_arg: Is a directory" >&2
+        exit 1
       fi
       dstdir=$dst
       dst=$dstdir/`basename "$src"`
       dstdir_status=0
     else
-      # Prefer dirname, but fall back on a substitute if dirname fails.
-      dstdir=`
-	(dirname "$dst") 2>/dev/null ||
-	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-	     X"$dst" : 'X\(//\)[^/]' \| \
-	     X"$dst" : 'X\(//\)$' \| \
-	     X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
-	echo X"$dst" |
-	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-		   s//\1/
-		   q
-		 }
-		 /^X\(\/\/\)[^/].*/{
-		   s//\1/
-		   q
-		 }
-		 /^X\(\/\/\)$/{
-		   s//\1/
-		   q
-		 }
-		 /^X\(\/\).*/{
-		   s//\1/
-		   q
-		 }
-		 s/.*/./; q'
-      `
-
+      dstdir=`dirname "$dst"`
       test -d "$dstdir"
       dstdir_status=$?
     fi
@@ -314,74 +293,74 @@ do
   if test $dstdir_status != 0; then
     case $posix_mkdir in
       '')
-	# Create intermediate dirs using mode 755 as modified by the umask.
-	# This is like FreeBSD 'install' as of 1997-10-28.
-	umask=`umask`
-	case $stripcmd.$umask in
-	  # Optimize common cases.
-	  *[2367][2367]) mkdir_umask=$umask;;
-	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
-
-	  *[0-7])
-	    mkdir_umask=`expr $umask + 22 \
-	      - $umask % 100 % 40 + $umask % 20 \
-	      - $umask % 10 % 4 + $umask % 2
-	    `;;
-	  *) mkdir_umask=$umask,go-w;;
-	esac
-
-	# With -d, create the new directory with the user-specified mode.
-	# Otherwise, rely on $mkdir_umask.
-	if test -n "$dir_arg"; then
-	  mkdir_mode=-m$mode
-	else
-	  mkdir_mode=
-	fi
-
-	posix_mkdir=false
-	case $umask in
-	  *[123567][0-7][0-7])
-	    # POSIX mkdir -p sets u+wx bits regardless of umask, which
-	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
-	    ;;
-	  *)
-	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
-	    trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
-
-	    if (umask $mkdir_umask &&
-		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
-	    then
-	      if test -z "$dir_arg" || {
-		   # Check for POSIX incompatibilities with -m.
-		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
-		   # other-writable bit of parent directory when it shouldn't.
-		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
-		   ls_ld_tmpdir=`ls -ld "$tmpdir"`
-		   case $ls_ld_tmpdir in
-		     d????-?r-*) different_mode=700;;
-		     d????-?--*) different_mode=755;;
-		     *) false;;
-		   esac &&
-		   $mkdirprog -m$different_mode -p -- "$tmpdir" && {
-		     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
-		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
-		   }
-		 }
-	      then posix_mkdir=:
-	      fi
-	      rmdir "$tmpdir/d" "$tmpdir"
-	    else
-	      # Remove any dirs left behind by ancient mkdir implementations.
-	      rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
-	    fi
-	    trap '' 0;;
-	esac;;
+        # Create intermediate dirs using mode 755 as modified by the umask.
+        # This is like FreeBSD 'install' as of 1997-10-28.
+        umask=`umask`
+        case $stripcmd.$umask in
+          # Optimize common cases.
+          *[2367][2367]) mkdir_umask=$umask;;
+          .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+          *[0-7])
+            mkdir_umask=`expr $umask + 22 \
+              - $umask % 100 % 40 + $umask % 20 \
+              - $umask % 10 % 4 + $umask % 2
+            `;;
+          *) mkdir_umask=$umask,go-w;;
+        esac
+
+        # With -d, create the new directory with the user-specified mode.
+        # Otherwise, rely on $mkdir_umask.
+        if test -n "$dir_arg"; then
+          mkdir_mode=-m$mode
+        else
+          mkdir_mode=
+        fi
+
+        posix_mkdir=false
+        case $umask in
+          *[123567][0-7][0-7])
+            # POSIX mkdir -p sets u+wx bits regardless of umask, which
+            # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+            ;;
+          *)
+            tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+            trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+            if (umask $mkdir_umask &&
+                exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+            then
+              if test -z "$dir_arg" || {
+                   # Check for POSIX incompatibilities with -m.
+                   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+                   # other-writable bit of parent directory when it shouldn't.
+                   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+                   ls_ld_tmpdir=`ls -ld "$tmpdir"`
+                   case $ls_ld_tmpdir in
+                     d????-?r-*) different_mode=700;;
+                     d????-?--*) different_mode=755;;
+                     *) false;;
+                   esac &&
+                   $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+                     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+                     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+                   }
+                 }
+              then posix_mkdir=:
+              fi
+              rmdir "$tmpdir/d" "$tmpdir"
+            else
+              # Remove any dirs left behind by ancient mkdir implementations.
+              rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+            fi
+            trap '' 0;;
+        esac;;
     esac
 
     if
       $posix_mkdir && (
-	umask $mkdir_umask &&
-	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+        umask $mkdir_umask &&
+        $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
       )
     then :
     else
@@ -391,53 +370,51 @@ do
       # directory the slow way, step by step, checking for races as we go.
 
       case $dstdir in
-	/*) prefix='/';;
-	[-=\(\)!]*) prefix='./';;
-	*)  prefix='';;
+        /*) prefix='/';;
+        [-=\(\)!]*) prefix='./';;
+        *)  prefix='';;
       esac
 
-      eval "$initialize_posix_glob"
-
       oIFS=$IFS
       IFS=/
-      $posix_glob set -f
+      set -f
       set fnord $dstdir
       shift
-      $posix_glob set +f
+      set +f
       IFS=$oIFS
 
       prefixes=
 
       for d
       do
-	test X"$d" = X && continue
-
-	prefix=$prefix$d
-	if test -d "$prefix"; then
-	  prefixes=
-	else
-	  if $posix_mkdir; then
-	    (umask=$mkdir_umask &&
-	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
-	    # Don't fail if two instances are running concurrently.
-	    test -d "$prefix" || exit 1
-	  else
-	    case $prefix in
-	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
-	      *) qprefix=$prefix;;
-	    esac
-	    prefixes="$prefixes '$qprefix'"
-	  fi
-	fi
-	prefix=$prefix/
+        test X"$d" = X && continue
+
+        prefix=$prefix$d
+        if test -d "$prefix"; then
+          prefixes=
+        else
+          if $posix_mkdir; then
+            (umask=$mkdir_umask &&
+             $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+            # Don't fail if two instances are running concurrently.
+            test -d "$prefix" || exit 1
+          else
+            case $prefix in
+              *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+              *) qprefix=$prefix;;
+            esac
+            prefixes="$prefixes '$qprefix'"
+          fi
+        fi
+        prefix=$prefix/
       done
 
       if test -n "$prefixes"; then
-	# Don't fail if two instances are running concurrently.
-	(umask $mkdir_umask &&
-	 eval "\$doit_exec \$mkdirprog $prefixes") ||
-	  test -d "$dstdir" || exit 1
-	obsolete_mkdir_used=true
+        # Don't fail if two instances are running concurrently.
+        (umask $mkdir_umask &&
+         eval "\$doit_exec \$mkdirprog $prefixes") ||
+          test -d "$dstdir" || exit 1
+        obsolete_mkdir_used=true
       fi
     fi
   fi
@@ -472,15 +449,12 @@ do
 
     # If -C, don't bother to copy if it wouldn't change the file.
     if $copy_on_change &&
-       old=`LC_ALL=C ls -dlL "$dst"	2>/dev/null` &&
-       new=`LC_ALL=C ls -dlL "$dsttmp"	2>/dev/null` &&
-
-       eval "$initialize_posix_glob" &&
-       $posix_glob set -f &&
+       old=`LC_ALL=C ls -dlL "$dst"     2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp"  2>/dev/null` &&
+       set -f &&
        set X $old && old=:$2:$4:$5:$6 &&
        set X $new && new=:$2:$4:$5:$6 &&
-       $posix_glob set +f &&
-
+       set +f &&
        test "$old" = "$new" &&
        $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
     then
@@ -493,24 +467,24 @@ do
       # to itself, or perhaps because mv is so ancient that it does not
       # support -f.
       {
-	# Now remove or move aside any old file at destination location.
-	# We try this two ways since rm can't unlink itself on some
-	# systems and the destination file might be busy for other
-	# reasons.  In this case, the final cleanup might fail but the new
-	# file should still install successfully.
-	{
-	  test ! -f "$dst" ||
-	  $doit $rmcmd -f "$dst" 2>/dev/null ||
-	  { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
-	    { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
-	  } ||
-	  { echo "$0: cannot unlink or rename $dst" >&2
-	    (exit 1); exit 1
-	  }
-	} &&
-
-	# Now rename the file to the real destination.
-	$doit $mvcmd "$dsttmp" "$dst"
+        # Now remove or move aside any old file at destination location.
+        # We try this two ways since rm can't unlink itself on some
+        # systems and the destination file might be busy for other
+        # reasons.  In this case, the final cleanup might fail but the new
+        # file should still install successfully.
+        {
+          test ! -f "$dst" ||
+          $doit $rmcmd -f "$dst" 2>/dev/null ||
+          { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+            { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+          } ||
+          { echo "$0: cannot unlink or rename $dst" >&2
+            (exit 1); exit 1
+          }
+        } &&
+
+        # Now rename the file to the real destination.
+        $doit $mvcmd "$dsttmp" "$dst"
       }
     fi || exit 1
 
diff --git a/build-aux/mdate-sh b/build-aux/mdate-sh
index b3719cf..e8dfaca 100755
--- a/build-aux/mdate-sh
+++ b/build-aux/mdate-sh
@@ -3,7 +3,7 @@
 
 scriptversion=2010-08-21.06; # UTC
 
-# Copyright (C) 1995-2013 Free Software Foundation, Inc.
+# Copyright (C) 1995-2014 Free Software Foundation, Inc.
 # written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995
 #
 # This program is free software; you can redistribute it and/or modify
diff --git a/build-aux/missing b/build-aux/missing
index cdea514..f62bbae 100755
--- a/build-aux/missing
+++ b/build-aux/missing
@@ -1,9 +1,9 @@
 #! /bin/sh
 # Common wrapper for a few potentially missing GNU programs.
 
-scriptversion=2012-06-26.16; # UTC
+scriptversion=2013-10-28.13; # UTC
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 # Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
 
 # This program is free software; you can redistribute it and/or modify
@@ -160,7 +160,7 @@ give_advice ()
       ;;
    autom4te*)
       echo "You might have modified some maintainer files that require"
-      echo "the 'automa4te' program to be rebuilt."
+      echo "the 'autom4te' program to be rebuilt."
       program_details 'autom4te'
       ;;
     bison*|yacc*)
diff --git a/build-aux/ylwrap b/build-aux/ylwrap
index 8f072a8..7c2d927 100755
--- a/build-aux/ylwrap
+++ b/build-aux/ylwrap
@@ -3,7 +3,7 @@
 
 scriptversion=2013-01-12.17; # UTC
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 #
 # Written by Tom Tromey <tromey@cygnus.com>.
 #
diff --git a/configure b/configure
index 3c99f08..4120cbe 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for GNU Direvent 5.1.
+# Generated by GNU Autoconf 2.69 for GNU Direvent 5.2.
 #
 # Report bugs to <bug-direvent@gnu.org.ua>.
 #
@@ -580,8 +580,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='GNU Direvent'
 PACKAGE_TARNAME='direvent'
-PACKAGE_VERSION='5.1'
-PACKAGE_STRING='GNU Direvent 5.1'
+PACKAGE_VERSION='5.2'
+PACKAGE_STRING='GNU Direvent 5.2'
 PACKAGE_BUGREPORT='bug-direvent@gnu.org.ua'
 PACKAGE_URL='http://www.gnu.org.ua/software/direvent'
 
@@ -661,12 +661,14 @@ GRECS_COND_BUILD_INSTALL_FALSE
 GRECS_COND_BUILD_INSTALL_TRUE
 GRECS_INCLUDE_DIR
 GRECS_DISTDOC
+GRECS_HOST_PROJECT_LDADD
 GRECS_HOST_PROJECT_INCLUDES
 GRECS_README
 GRECS_DISTCK_AT
 GRECS_CHANGELOG
 GRECS_DOCDIR
 GRECS_LDADD
+GRECS_EXTRA_DIST
 GRECS_TESTDIR
 GRECS_INCLUDES
 GRECS_BUILD_AUX
@@ -1354,7 +1356,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures GNU Direvent 5.1 to adapt to many kinds of systems.
+\`configure' configures GNU Direvent 5.2 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1424,7 +1426,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of GNU Direvent 5.1:";;
+     short | recursive ) echo "Configuration of GNU Direvent 5.2:";;
    esac
   cat <<\_ACEOF
 
@@ -1538,7 +1540,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-GNU Direvent configure 5.1
+GNU Direvent configure 5.2
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1907,7 +1909,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by GNU Direvent $as_me 5.1, which was
+It was created by GNU Direvent $as_me 5.2, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2288,7 +2290,7 @@ ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
 ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
 
 
-am__api_version='1.14'
+am__api_version='1.15'
 
 # Find a good install program.  We prefer a C program (faster),
 # so one script is as good as another.  But avoid the broken or
@@ -2460,8 +2462,8 @@ test "$program_suffix" != NONE &&
 ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
 program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
 
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
 
 if test x"${MISSING+set}" != xset; then
   case $am_aux_dir in
@@ -2480,7 +2482,7 @@ else
 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
 fi
 
-if test x"${install_sh}" != xset; then
+if test x"${install_sh+set}" != xset; then
   case $am_aux_dir in
   *\ * | *\	*)
     install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -2774,7 +2776,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='direvent'
- VERSION='5.1'
+ VERSION='5.2'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -2808,8 +2810,8 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
 mkdir_p='$(MKDIR_P)'
 
-# We need awk for the "check" target.  The system "awk" is bad on
-# some platforms.
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
 # Always define AMTAR for backward compatibility.  Yes, it's still used
 # in the wild :-(  We should find a proper way to deprecate it ...
 AMTAR='$${TAR-tar}'
@@ -2983,6 +2985,7 @@ END
   fi
 fi
 
+
 # Enable silent rules by default:
 # Check whether --enable-silent-rules was given.
 if test "${enable_silent_rules+set}" = set; then :
@@ -5084,6 +5087,7 @@ $as_echo "$as_me: WARNING: preprocessing disabled" >&2;}
 AUTOM4TE=${AUTOM4TE-"${am_missing_run}autom4te"}
 
                         GRECS_TESTDIR=tests
+			GRECS_EXTRA_DIST='$(WORDSPLIT_TEST)'
 
 
     for ac_header in getopt.h
@@ -5187,7 +5191,9 @@ fi
 
 
 
-  GRECS_INCLUDES='-I$(top_srcdir)/grecs/include -I$(top_builddir)/grecs/include'
+
+  GRECS_INCLUDES='-I$(top_srcdir)/grecs/include -I$(top_srcdir)/grecs/wordsplit -I$(top_builddir)/grecs/include'
+
 
 
 
@@ -8212,7 +8218,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by GNU Direvent $as_me 5.1, which was
+This file was extended by GNU Direvent $as_me 5.2, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -8280,7 +8286,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-GNU Direvent config.status 5.1
+GNU Direvent config.status 5.2
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index 07da598..e8ed179 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
 # This file is part of Direvent -*- autoconf -*-
-# Copyright (C) 2012-2016 Sergey Poznyakoff
+# Copyright (C) 2012-2019 Sergey Poznyakoff
 #
 # Direvent is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
 # along with Direvent.  If not, see <http://www.gnu.org/licenses/>.
 
 AC_PREREQ([2.69])
-AC_INIT([GNU Direvent], [5.1], [bug-direvent@gnu.org.ua], [direvent],
+AC_INIT([GNU Direvent], [5.2], [bug-direvent@gnu.org.ua], [direvent],
         [http://www.gnu.org.ua/software/direvent])
 AC_CONFIG_SRCDIR([src/direvent.c])
 AC_CONFIG_HEADERS([config.h])
diff --git a/debian/changelog b/debian/changelog
index 9af16b4..1a31b94 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,9 +1,27 @@
+direvent (5.2-1) unstable; urgency=medium
+
+  * Moved debian/upstream-signing-key.pgp to debian/upstream/signing-key.asc
+    (also saved it in armored format)
+  * New upstream version 5.2
+  * Set compatibility to dh 12:
+    - Removed debian/compact file
+    - Replaced debhelper build-dependency with debhelper-compat virtual package
+  * Standards-Version pushed to 4.5.0 (d/control)
+  * Updated home pages to use https (d/control, d/copyright and d/watch)
+  * Updated copyright dates
+  * Removed "Ws_error" patch, it isn't needed anymore in this release
+  * Added unit tests (d/tests/*)
+  * Updated d/rules to match the latest dh version, it meant removing the 
+    autotools-dev and systemd
+
+ -- Alejandro Garrido Mota <alejandro@debian.org>  Sun, 16 Feb 2020 15:22:03 +0000
+
 direvent (5.1-1) unstable; urgency=medium
 
   * New upstream release
   * d/watch: update regex to avoid "latest" in watch.
   * d/copyright: update the copyright dates
-  * Add hardening to the binary in d/rules 
+  * Add hardening to the binary in d/rules
   * add debian/path dir and include a paths to:
      - Fix FTBFS
      - Spelling errors
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index ec63514..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-9
diff --git a/debian/control b/debian/control
index 5922ccf..c7fb08a 100644
--- a/debian/control
+++ b/debian/control
@@ -2,19 +2,20 @@ Source: direvent
 Section: utils
 Priority: optional
 Maintainer: Alejandro Garrido Mota <alejandro@debian.org>
-Build-Depends: debhelper (>= 9),
-               autotools-dev,
-               dh-systemd
-Standards-Version: 3.9.8
-Homepage: http://www.gnu.org.ua/software/direvent/
+Build-Depends: debhelper-compat (= 12),
+               texinfo
+Standards-Version: 4.5.0
+Homepage: https://www.gnu.org.ua/software/direvent/
 Vcs-Git: https://github.com/mogaal/direvent.git
 Vcs-Browser: https://github.com/mogaal/direvent
 
 Package: direvent
 Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}
+Depends: ${shlibs:Depends},
+         ${misc:Depends}
+Pre-Depends: ${misc:Pre-Depends}
 Description: monitors events in the file system directories
- For each event that occurs in a set of pre-configured directories, the 
+ For each event that occurs in a set of pre-configured directories, the
  program calls an external program associated with it, supplying it with
  the information about the event and the location within the file system
  where it occurred. This may be helpful, for example, to track changes in
diff --git a/debian/copyright b/debian/copyright
index 86bb064..e58f804 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,13 +1,13 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 Upstream-Name: direvent
-Source: http://www.gnu.org.ua/software/direvent
+Source: https://www.gnu.org.ua/software/direvent
 
 Files: *
 Copyright: 2012-2014 Sergey Poznyakoff <gray@gnu.org.ua>
 License: GPL-3+
 
 Files: debian/*
-Copyright: 2014-2016 Alejandro Garrido Mota <alejandro@debian.org>
+Copyright: 2014-2020 Alejandro Garrido Mota <alejandro@debian.org>
 License: GPL-3+
 
 Files: doc/*.info doc/*.texi
diff --git a/debian/patches/FixWs_error.path b/debian/patches/FixWs_error.path
deleted file mode 100644
index 5191485..0000000
--- a/debian/patches/FixWs_error.path
+++ /dev/null
@@ -1,30 +0,0 @@
-Description: Fix Ws_error error
-Author: Sergey Poznyakoff <gray@gnu.org.ua>
-Origin: vendor
-Last-Update: 2016-10-07
-
-Patch to fix the problem FTBFS:
-   error: format not a string literal and no format arguments [-Werror=format-security]
-
-Index: direvent/grecs/src/wordsplit.c
-===================================================================
---- direvent.orig/grecs/src/wordsplit.c
-+++ direvent/grecs/src/wordsplit.c
-@@ -59,7 +59,7 @@
- static void
- _wsplt_alloc_die (struct wordsplit *wsp)
- {
--  wsp->ws_error (_("memory exhausted"));
-+  wsp->ws_error ("%s", _("memory exhausted"));
-   abort ();
- }
- 
-@@ -2330,7 +2330,7 @@ wordsplit_perror (struct wordsplit *wsp)
-       break;
- 
-     default:
--      wsp->ws_error (wordsplit_strerror (wsp));
-+      wsp->ws_error ("%s", wordsplit_strerror (wsp));
-     }
- }
- 
diff --git a/debian/patches/series b/debian/patches/series
index 56a6cd4..b57739c 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1 @@
 FixSpelling.diff
-FixWs_error.path
diff --git a/debian/rules b/debian/rules
index 9d0a7a8..098338c 100755
--- a/debian/rules
+++ b/debian/rules
@@ -2,4 +2,4 @@
 export DEB_BUILD_MAINT_OPTIONS = hardening=+all
 
 %:
-	dh $@  --with autotools-dev,systemd
+	dh $@
diff --git a/debian/tests/control b/debian/tests/control
new file mode 100644
index 0000000..7082497
--- /dev/null
+++ b/debian/tests/control
@@ -0,0 +1,2 @@
+Tests: run-unit-test
+Depends: @
diff --git a/debian/tests/run-unit-test b/debian/tests/run-unit-test
new file mode 100644
index 0000000..1d868b4
--- /dev/null
+++ b/debian/tests/run-unit-test
@@ -0,0 +1,19 @@
+#!/bin/bash
+set -e
+
+pkg=#PACKAGENAME#
+
+export LC_ALL=C.UTF-8
+if [ "${AUTOPKGTEST_TMP}" = "" ] ; then
+  AUTOPKGTEST_TMP=$(mktemp -d /tmp/${pkg}-test.XXXXXX)
+  # Double quote below to expand the temporary directory variable now versus
+  # later is on purpose.
+  # shellcheck disable=SC2064
+  trap "rm -rf ${AUTOPKGTEST_TMP}" 0 INT QUIT ABRT PIPE TERM
+fi
+
+#cp -a /usr/share/doc/${pkg}/examples/* "${AUTOPKGTEST_TMP}"
+
+cd "${AUTOPKGTEST_TMP}"
+
+direvent -h
diff --git a/debian/upstream-signing-key.pgp b/debian/upstream-signing-key.pgp
deleted file mode 100644
index 795e457..0000000
--- a/debian/upstream-signing-key.pgp
+++ /dev/null
@@ -1,267 +0,0 @@
------BEGIN PGP PUBLIC KEY BLOCK-----
-Version: GnuPG v1
-
-mQGiBDxhQHkRBACyhJxCLQvLs70IUZSlYVKAm+u1Oa4RyUo5/ctCcMm2KOcjui3z
-xs+yUwlglo1n/de9NNJY98PJNLHniMVi5sPba8OKwYx9bilwuAWLgTsgfpX8UuuY
-TANQmTybmrxjzxrGqN7eyjBT3utgbK3ACKDo/JUCgZMkdFu2c2i7186sDwCgo9pQ
-ygxOOWEWBm70Rymdfvkon6EEAKY5h9nL1qYw46vM1+QY+vhyX2lHTD/E9QyFQv4L
-driY3CerLAZ07yk5p8I6T31d7HEUt9DZcl0ZD99Y9IH84wWvms1xtnCuoLlP4ntw
-FQ5ZUZtMY0AIVRtFbgkTDDLZsdanscqMu/LqnO2/QWjCQhaO/tcaIdPVgBIbCr28
-fuBJA/9KA5vbQBd4WnNFLVJsr47irnJBYdR+OqPQAUFUcQPO1metR76UZ7+7LwtO
-ldAjPN3RDJtRB8/JooHDNq+VCEzjs02JaBpQ+BCOzzqELnkoBPl26yHR56r4WbC5
-+FH/QxEaicjVGxIF/Z9crzG/XUMXwieTNcM6HoGCnMboGqCM4bQgU2VyZ2V5IFBv
-em55YWtvZmYgPGdyYXlAZ251Lm9yZz6IXgQTEQIAHgUCQ/CVtQIbAwYLCQgHAwID
-FQIDAxYCAQIeAQIXgAAKCRA2ArB/VdDHMkVKAJ41glKzudqU5UgxMkHdSLo28ov+
-cACeLUrGgtmv/6MbmICeG64v6KOrnga0I1NlcmdleSBQb3pueWFrb2ZmIDxncmF5
-QGdudS5vcmcudWE+iF4EExECAB4FAkPwlXcCGwMGCwkIBwMCAxUCAwMWAgECHgEC
-F4AACgkQNgKwf1XQxzLm6gCfbavgu1bRDHsaUQKvY83CqOX2RcsAnirapY4we57A
-iCr2TTldQ+H5+xw5tDJTZXJnZXkgUG96bnlha29mZiAoR3JheSkgPGdyYXlAbWly
-ZGRpbi5mYXJsZXAubmV0PohGBBARAgAGBQJClLMcAAoJEIvYLm8wuUtcoE4AnRDf
-vCNyheky5myvvIuPOnRoOLY3AKCfBIzNZgUabR7lPTwrkKud+DKQ2IhGBBIRAgAG
-BQI/W2BoAAoJEKMJ1nkZoiVHcawAn0gd/9GX/b55HTeZ0B74B5JNoF9qAJ9Swtzv
-/Cn59vtejqUpB7O8nMYGq4hXBBMRAgAXBQI8YUB5BQsHCgMEAxUDAgMWAgECF4AA
-CgkQNgKwf1XQxzIN4gCglbS1XsDcwg347otcE1ps+9yHFGkAnA4yuO+9QOhv8+ql
-+Ww7itci/2HkiF8EExECABcFAjxhQHkFCwcKAwQDFQMCAxYCAQIXgAASCRA2ArB/
-VdDHMgdlR1BHAAEBDeIAoJW0tV7A3MIN+O6LXBNabPvchxRpAJwOMrjvvUDob/Pq
-pflsO4rXIv9h5IkBIgQQAQIADAUCQj6y7AUDABJ1AAAKCRCXELibyletfFW7CACz
-qk4TKwf2Tes9n/b3WkuFN0on4fvhOh1pT4eM9t203f//S48RrAVB0M8o705zQOYC
-5OocOuA89BjE6jXeF3wW1zcSgLxYy5BL1LoCyeHv/vpX8+Bfi1g61iEM0dN99ork
-nymnIcsA8zsLTK3EJ3TQ6jCzOO/xKSArS+OkG9EUEoBEK6ow+Lx/H0wL2isxjpfz
-n4EyRhx8Tb/tVb0HvipSRXzEl68mEw6EHbmsYnS00iWNcWSwAsRZYXr78VngaUOA
-boULu8c3RdOk+eSG5WcNfK558r2TPqB9jeCLKyo9EVfVo3LViam+DlCOy1LpCZ3E
-qwyIEXUFq2LHr80Qn7EBiQEiBBABAgAMBQJCUD7MBQMAEnUAAAoJEJcQuJvKV618
-5aAH/1tkjj5pLiwiCDUEZ9BzM3pCp3NHi61Ei5Skb89iwBzORlG3JAsvP/BO/XY6
-bdDLuCH3XHtvp525gr/k8LDqacnO4/vSEM7+/qpU2WERVkAjtefBsPyxSw/mtRBa
-WEASZX0VoNsZLOcnjg+ov2egMTJVN3lr1pyqhivAeYjObF15ZfqcpiZXmIc+LwOy
-Al1NIWA6ZGPFQL/y0Ff3XCvl+GJrMR9rknsoE6XrBcZocJkTFZ1mwbdntg0pwvo4
-CJtF2WOKxSdzso6sZ5QC4pVj8Ud1tgJTjdlMhEKxtkg9i/NTc1uOfL86DcSTML3C
-NUP2JHlX6vGN8RQ0P0z+nioEkYyJASIEEAECAAwFAkJiDJYFAwASdQAACgkQlxC4
-m8pXrXzdgQf/S5FoKHVmyd/hzlq1Hbz9Re3ITJMTs6rQcyRfFV8UCb561McPJVQQ
-NTkqd0YhhZAc8MGq84UlaVFxOF7GAreK4PoKgUsfzbWrcMWOCyZIql4QgHV6sOnc
-dgJjy+5rOr8JY15F1vidPFMUxwgSo/GpCfyUTKDANlu7UnI0vRtn+8q+MtQkQW67
-5rNiZpBGTlbJdLjkMDaCDYxlISGS9dUvlGhrayYk8CyjXqOdOWM87Fy6rkVYdRsZ
-v4q6UaXuyuMBQA7W4RC1szBNNb5YTgQz/yVlcEfEUgdRiw/Ld7Jm3EA7wO1jptcM
-0gm7ZLK9fPB04OqQ1gp+MkbScgwGtZHjMYkBIgQQAQIADAUCQmK1GAUDABJ1AAAK
-CRCXELibyletfN5NCACg7SyHUFOjiI41Q+V6heTLFU3gnO7uBYROfBwGDvZzum9M
-MhaCvYh5QJM6KL+SjRlibQhQYFo2i0r9UOs3i4iGpQ/dW7VjBWHL7otrFi/8NviV
-PIlnBWnv8KqdNrLoV74cs0/esg3TXZnbJerymFLXKtBeoRNUZaFpIesU21GTUzIH
-yP4C8Jg6mZlRM80tA4oTVWOogSC3nmLoiAwx+xx6v/QBhQrKKNb7WAmqDOcO8h3T
-mPI1QTntRi+ljhX4h0Gq1leceYa+88kq32ieGtHB/R+YisE5NUdCB32L381Guybo
-+n5ZDCH2tL3gZ4XGxmfKGErBL/4LdYuG+ZawXk4MiQEiBBABAgAMBQJCdUutBQMA
-EnUAAAoJEJcQuJvKV618+MkIAILO+4vPDJARUOqgAfQlHDSpzpcAyAIBlByTMhI7
-3gzIpiQbxKagZWIAqa8FowcHsuojJ8sfYr8gdkpJ1YdiB0RcEKIfL9wQhn9LGdfw
-o/bZhgowE26L1YqpD8Kjy8FyNPbr/thaXV3YQVYAVQ2qZD1F0fEYLrf+mxY53JhK
-csDXVObWrzLoQJVPGcG7IZ+r8vht1MZb31Vt2EPwC6t9OT3io3R2nYxtnhRfCh9H
-zC3Pu/aPVuIAPqNPzc6TZNTvONB6yLF0w12y4OMHUrzCbHBathDA+Lnnb3OWZLpz
-9sNv/cISzxrx8Hr60cD78o3mb6B3yyen2BVX8Gy2JfvokT+JASIEEAECAAwFAkKH
-GEAFAwASdQAACgkQlxC4m8pXrXw/Nwf8DYchCfD6q0F3I8Xao99vCqzRBEM6wulj
-jF61qdU+ryBDE4OqxZ3awQ8oFcpbCq+eaN0ToLtFLIKggg0E1aFSZay7JCUAxNx0
-VShHVvQrqReC8DSmVjIsAJ5q8ho4o3MZL19bRzeDtSLiWVUMo3tHXJolaBdKIBty
-g0N/tNgM4LTPIRfFuVxWELPxce8ApBM/cSH3M8UgThQNcjkdcmTxNmyv5xdx9+qT
-M6lt03/ft0iSzLBPJ2BvEd6JN55+gUS5UGTCW4/euqg4fBKep1NPp4OlLnjfG2Ke
-tCGo+HBgNS3z+ctR7gMng1Odvaf2+qWDvbzAdudGpYrS+L0CLhS11okBIgQQAQIA
-DAUCQom/SgUDABJ1AAAKCRCXELibyletfLF0B/9AwsObANiamJG6b5adwlnoSAAB
-okQ1+YhLemP3yoeoz6TCjXEDjeKVr2oZF/9IymovMfO74xUr609PCPHsSx+8kH4/
-S1PFJpgJ7WpKzRSvAk7nhNLU534V0K8fQ0S/rd7y9XrnFyP+uQatx4Liu+lm3gro
-aC8VwWhnWavnXaGcme0rVkUfZDhwTtVyAR6hzuVBLrHr6iQzTjr778nVi0FOV18m
-0FOx1xeZhHbLLNhv0ZQ6rVikAV3fPV8/uNl1Yk/MxrddYSI5NBiITE93T2LEGIWa
-ObcRVItz3k7rkhpzPfJ3l7ZqKKt8sxwTv4/ZigxjKDTTnt7hXxrkZea7FPViiQEi
-BBABAgAMBQJCm3bHBQMAEnUAAAoJEJcQuJvKV618zGUIAMOAYUFUH+YlM9Yh/CvE
-sXtH7cdXaLsivd2K3tZrUxaMOzl+EXA+AMQWz5475G7FhV1a8RRQaDHXm4sueVJa
-VrdbyPuC/HsGj25R4+7fSaFwBOAT6gfkVzATbz2eJe6Qq51/VMlpCQQ9qWKUsVV3
-aYZvVXN6GL0PXbarkIv9Q7dCxEobRP6L1TGuc1G8xnOPhTJlxd/wgPoF/8KdIOiX
-VVPKvGd2uNrNjN46UMWBrx9yWJMsV9gt8IHMugAJ/1GHiQhps5Qy8RYPof23C5HO
-gXttV8vYfGNyV6Sten4ubVAPFdfuv+UCPa2SA/xN/ADxyBCPWdVqCfAYx2q4oDpP
-w1mJASIEEAECAAwFAkKcx/oFAwASdQAACgkQlxC4m8pXrXydiQf/S5yJQwEIRVg7
-SRRKub+//wC8LwrFE1Qeb15/NJOrjHqslWPdCeuWccukKFLaokJy/WBd9UyK+k9M
-TxwnVH7jIwoR6RIGPiS23CEDoSgCfxDDGQCQh5tuY2xwSaLRFhcezIGAbJYDVCjf
-w7guPVY1IZnW25Pe/NY+su9I1Hq0M+1zRrmzMB99wh9dwqFLIVq4CpYsAUdwlFgZ
-OuwnTPBP2E+lbgXOpdSaWHG2ehK06SMKpU5iRdp8bjuMkU83gb7+lHwB2sH9RJGR
-0K2O6A5I0UVYk6PJwPjB5gMTmzDod8IMm8FditTHCmoVvHjv7QzRuazMVWeM1+bU
-O/Na3bdwOIkBIgQQAQIADAUCQq/hkAUDABJ1AAAKCRCXELibyletfIAtCACSAu1N
-GXLdGiVO9WnOh59WEASHacxOeF96r1wx2+uk7ENMm+jTIfq2gpiwTI3mWZ+vG/gV
-tpaD2F1BGB/eGh4LycyFN2we2mB9FpqT0I87zAvaXk8VZwP5OiAJlL2PhRqK27HQ
-oGoUloTcMieB48hln8mFTpOM1SUg6blgp2ceqIghZw8hfUEwjCW4UAKUrJqFPktO
-Ku1+T9Gq5/05f/2wrEQ0P5v+3MnPOT1d6ilJHGnIU37Qi336aaaEujjzjE1Ld4QR
-gAgYzgtfe8EFkilNJDc7blLM/diDzYugWbTVT72Ree3MzMMahgU57kQpK/qtLjKS
-Ql3bEkwK0FFLgsSFiQEiBBABAgAMBQJCtSzlBQMAEnUAAAoJEJcQuJvKV618uAsH
-/ixHUob6l8hWzVNpfmNlIsB2ukC9+d6YcSbQXnPqBFd/M0qvMErYR/qPIZYhKOa0
-PYRVeV6HrmyTdhvRGh/5TgiGw9jKJu9ClsJ6ywRMORpb2BDwELx5Y2K7Ci/+IvlT
-A16fSCmMf3fR2Jp+FztsaefPvqEXnM2zpyBs0HT0MjrnhRKy0/LIcc2/VlrG2HgB
-29/hqmYEYyCqmanb+hAxbDm82EpyXSY98qmSeYXDc64cx1a19oZbk6SWM/MuZPE4
-E7I/Sxv2gU/qK5pvBxFEcfLDy1CxWjX0Fi5JYDivgeep8V8rXFyXnVwwvU6LxA8W
-30jby3d5uNh3pQoYJ1oUC6GJASIEEAECAAwFAkK3KE0FAwASdQAACgkQlxC4m8pX
-rXyHpQgAoBovhQ+++g35g2D1Oby200fxZ7+wq3iN61OTSquOe/WFfD8e6w3p6UEZ
-3MujEv8tgMMVjNwvezsD2Z/MDWv/fK8m3Ng83yLme77wE/rOkz37Id+Ehe1kojrj
-AV03zJr1VmhZfvx3e1Y/A00ipmfZPUzR1Jx82zmlfDeXavAScuQDUyORloLTEHv9
-bc9soospjYSFK1nWJ1t8C2DDYX2skcYoxGqyqVnBzAw6ozq9jZmOVaMlc7czjMQf
-fNwdwYXtSXo1NNjL+0eQdAWpOfMIlgKshkFymcd4cBbgE6RCw0r2brVkVtSt0+Zn
-ctvHQotxuNvwJXFRFVBh153l5IWdOYkBIgQQAQIADAUCQtEgTAUDABJ1AAAKCRCX
-ELibyletfI7CCACIWICj9ZkESfm+5iVbFc3JP+4mXaHaXfHAfYmdBdy4MK9BPx2d
-kS0scMiFWRH6jRi8Tzk3bH6M4wwS4MDXuSrlsOKPxNpiAVgDI+SflcPGM10VrSOy
-+8W9FF5F6onD0ojP7Fg4KG1ige4Rm6dM/YnEw7a2iWZ8Be7cCd8Bi77y/XN0SMpP
-EEjnEWhdpzH1esD0fc3N1A721C7NMWeCLEtm+e1YixFcoccegJniJ8QYNHzti+kV
-PR77EJFwgZechF/dNEXfnlAuyQSj6Wc90vPAH27+kaoxTiO2p/YzqTKwj4CJl/y6
-NOMQcoJ7CO2rf9fYrf0ZVwCdt7iL5s/JFfCviQEiBBABAgAMBQJC0cZ0BQMAEnUA
-AAoJEJcQuJvKV618kWoH/0zVrsTcYUOIM7ZUviejStEvRhX4dMTWzKPlJHVeMgKq
-qMF2ibMTlynrvj/K2ufFWM26maoOKoiADd4f1gBNLlMH60hrsxuMhAotB8RgfqL5
-4nBUj9CJmzGXToPrYEC7xlCJObIf9j6tzd07TZZcW0UtVQR1uNpy1G00psYd7oP9
-Db1OE7oKCqOKwcJwsdKpf59HcstbEe8CCjcHJQh9v0fyoz7U3OkAAOPmUTzh3YlW
-LZuqMl53CYGWqxTJvW6gOoEl1TdmsYIO9aXR7MGcz9j2pzwkJdc9uC9QTCXfU8bd
-Xi86P99e7TXakUr7koAwcFkYgQDUvJvO7Pda24Qnuh+JASIEEAECAAwFAkLj7sQF
-AwASdQAACgkQlxC4m8pXrXwEOQgAlmsoab76veaNTiiOClkeFX1Hzj1E/KBOlgky
-R3ObDE228X9LIk5iWhV1XaWEWA1v8o0UvD+hXIDL1XVZ9YjKQ+as5UQOadKqGVDp
-Iusmb6U/vL5JtdyCN1wbRgq2WnkkqgSK+C5qBNdI5ds6T7tU4eoO5DcZMQSyqHla
-LrgkAnXLEXOd5r78JhqKHOO06hEZGVI5jD/0Msmdld8lZPPO/5Leo4LU4RuM2BBA
-opR0kiQcbNbt0QUf+FOb9LAq4RQBn69uPPSRZF1lFkW6sAk20YdkrUyNvC14gFgJ
-sswLZBjBqHJ1IHNorJUTET/7bhywxCz1z7KLok7dDHaqTpWr8YkBIgQQAQIADAUC
-Qune5wUDABJ1AAAKCRCXELibyletfLeZB/9jvTYpufTVTc7OdTltkR8O0panwhG1
-6mJu0/yddXsdBROx6d6LBNSHn0ACx38b5GJoCXeX2QnoU5rjWbQDKbSvmJAoxn1R
-g+yRW78yXcE53PBFdjGAY7aC9WMF4eBfoIsCXTYFQVk3hNHkV3gvsnOtrLnYOTtA
-btERFE4Ftol5GbXF5atSyf9zclYMt6brx6PnxH2X4YhZ9aH3okN1mAzrPmZoefDG
-E0PMx0B/LWIzQBMHwoSnM/NLLloto7hcOus4wpwg136NeqgyKzdOqM1xNWHljJRn
-skrUb234rIR7WU3vXuQX7JmC0YvOkC4Gp43AScTjgO4dSWDb262mnGbQiQEiBBAB
-AgAMBQJC7IIMBQMAEnUAAAoJEJcQuJvKV618EfgH/iPsvwNYSsamkBTvBAAH8Eij
-R26NpNrO/f+fWc/FOfPIA9gZ1NAD8UWGt5ycqCy0ZHNhCPIERBj2hkrLu89d9ZrL
-CC1i6/plloCvhxdVaALjpPco/V8t/I+QRXXu5P/IUHDNnTxK4AK15CePCx8PKsqO
-2Rraej/pRnTxsvthWfMnwkXdRg68zkovO0OZE2OrXLLN5nx77uODWKvIALFNw+63
-7vw7EQyTa6yxE2TiK2iXd8J6TQaTdmO/rmGBv2/rkyLfapNzFAMRespnPXx0pk/F
-f7ITeWGQtMvcmggo6ersyGXpKXama7R4bV/CqdbAVXuzK65inkndEzunJMx8V/SJ
-ASIEEAECAAwFAkLtKhUFAwASdQAACgkQlxC4m8pXrXxVRAf8DcrZp6lr3knkQGhT
-KAgxO/k5Q3NtS4Cx07Xsrp+/eUqZWsctOLuMGz0YiZ//E+JCdBr5fZptgNW211Nj
-kRKOmvc4s6IrKXMhpywkYudNZZdzzNy/AIm3rkAsDr1pU7zZQ4zaawxBB1QXwu8t
-g/s6OcW8bk6y16nag0dX6FOhlv/Ual0zER2RUBlnFnG1Dtn4tmbOGYLNFYkdAJqn
-AA6QZvsMQCV3VgKmjbIk1GNhtJpoO3Cw2PjLXTiwlhVRNCHsX1XnUnnFjnx9bKXn
-Da4uNzh9BTQbhZ70GmnpcwUA2GPHrZievqnapFB2Y9TcCAyIEmQ5IPBctbeu2Z6U
-/FbNcIkBIgQQAQIADAUCQwBd/gUDABJ1AAAKCRCXELibyletfMkYB/9vvgca4wBj
-h3izodha1NVKS4XRs4p+vcze7SuH6n2K/Vs2bZ1K2uL6pHUGbVYJztQd5LERBmkW
-Me0o3sVeuZe6jSWT8UOYFcQIQWcr5QTLVvHinCg2jVFKtowJDXXO3ZxXQ3gSEWNy
-i18uA+3MQB2NPdCqoiK5u79TvTe1u07Vh14FpMIa/C7LyKBdVuiIJuTu9ARXBdmQ
-zdasve76rQ0cCEsgAyIVR3IkPPzhl631TlI85kbyEUJA1kerfEAGYYPWGUcARYL8
-/HUYBRv4oZXAVMmdtfIL6o0BKRfHwLxICRZ+pdy+8IKcuEVXUc+MU88m7ERmOfKB
-KNbUZhJKSkhYiQEiBBABAgAMBQJDCEmYBQMAEnUAAAoJEJcQuJvKV618HoQIAL1D
-V7lgbpGjD9Nvrp46/3lANw22BTinQJ0k3JvJXZBO7127/eztbtPuvFL6CSrpmcBZ
-I0GdJH8/lmK18eJLuNif/7LZvBrcX6FgjcsVXVzwadrSCAyAL5r0EnyTlso080aQ
-fzYLcwYpNU9cwuxmSpiId7GU1FmLwivPSe5qDrqYPrNZWsGC4u/v5e5D5Q5EQcGT
-EAt3G62yni6YhOZfZP/CxgkdkiNhJmubciEG6q75VqYrxlLiHSezL16mt+kFfkBr
-2fAOZFgJO9m6UTRWvwUTmr61sDeUfBXaFINhh4ccid/E4aurMNFKmPlx9R3nCdI4
-tGNWdn9hnCj032WdQi6JASIEEAECAAwFAkMMQ8QFAwASdQAACgkQlxC4m8pXrXy/
-FAf+JkU4QcZ8aBmrbv2p7BawhCWHDjmhIAfl0RqlVUoI/2FjopLgAo0oKrW65fkF
-cnVTZYanLVFl7Fuz2w2jjBXEqLFkQJsA6XOG9xIssRimeyD/lT1wAIz8JE9ezdG3
-oaS0SVhduMJ4byN/tKLYN0V5avxUbu/vtXgBr6PZlTmulOJjbWnrlb3e4QIMADzx
-DGyea+qsqQfyf8cwJvX5qFX0NGIU4LwvOBJDh4PkHOQkEfFsnNhO8jLBImHBw8tc
-keoafrt8zp8HsTGOKmDZzYPUnU9OwAYhezH4sS9YAbAcY6RZhyRr99H4vekI4ZJK
-pXGKgmCcfoWkzvAmfCZ1XtQ99okBIgQQAQIADAUCQxDbbAUDABJ1AAAKCRCXELib
-yletfOLsCACgR+14gUggcK6JuYLYa9pSyZOVmjRIBR6lVBg/aBkt46aGm9iHo1BH
-2EtyhjW5oihjWgQ+i25qZxhFp9unzPz/vXKXDLVKf8dLE9SE3dlCuv8a8DWRcWNb
-3ULtle5FaV7dvCp3g+8mMPBoAd98y+OIcyxdgoxdAZvMcHDgwVu6viV9UrFDbySW
-qqx3/wmbaijuzd3+CNluyWJ3pOmsCcobSp1J9UlBfo9wurayCF/U8z8ARqxYokwR
-WqLwzyJOciKDQwT4Og2PN3D6MfNrUc+vSK80tnX7iWes630qAWTaPHYcos7Y9nHF
-Srzt8I0hK0rnzUWhmPrlafjBxkc1u4GMiQEiBBABAgAMBQJDEizGBQMAEnUAAAoJ
-EJcQuJvKV618Um4H/0mzDk2raGBfNlGHGqmDEioiHkLlgUtlh9QVeKhg52SVrapA
-BKyIeVu51ztVbecGQEoFY3AwbkvzFgoJazWyUE5Ybf8I0xzfwDKWonJTUjR27/P5
-PNw19+KThPwesLCru1vayOkuO1WFJB/QqkWRfp4G75RBwxYVjWlEQ43JkM3HsfW3
-fn/HE6L3GmaEDfP42X9QjBG/vqWkXEq6ZR0YcBHc/L83zj3mJsgkYypoCYb4dWrY
-7iUUI4o6tS5TgTm1a5FIVTb5fjFKhvlRqZfvSyk20wxd9h+sExx5XGAKjWEWCzXE
-hFf8wQ7qsnjkG6s3KYvS5iXrC0+/PuesVNtGDk+JASIEEAECAAwFAkMUKM4FAwAS
-dQAACgkQlxC4m8pXrXw5mQgAhUf0zDvIEWHDy/c8/vKOJ0aK8B7M35C3tHhWW0xo
-GHSQ2Ofpkl79fUeZUcnkaOlGRmF1Xe9sKhTnnW4NeKlNeHMrwlqo+/ovagy6TC47
-pp+XAAbqh1lQIYYj2RaIpIk3TbOrLh9jYO8YUlscsUveTRL99JiyQL0332w/18tw
-j51bNG/cDNIAXGdxxLJJLGwlgvn90FYqvzSL7bDHVJHZSOY2FReXiB+wrKohTG4J
-6J1+X4dxj6I2e8DjzH/rilOG2Xcli9sITKRWprpI4P7Ld13pkXb4fPnPSSHal+aE
-6ocZY45mbhUqn1es1kSG7P0UcvF0iDKfBDvO0j08r7qp/YkBIgQQAQIADAUCQxYj
-KgUDABJ1AAAKCRCXELibyletfKe+B/4un5+FU1w5t7/ZtVdmRCm6UFe9QUAyQzjc
-Zlx9KxXhxuFzBk3hklgkunIBLCW8/e1Wf+rQzQCjD0Wwo6WHnxHoCiTBp1rZs45z
-miUCweNxkqYMAmAI2v8ywEY5MpYDbPmDAx2PmNaIgw9ZFRrArrVHHJJqq8R9q3DX
-zQA4C7jM98r+DgAAaiqldGe+cEZ/C9s/n33zNVKlFbnpwoR9gBvyKva4X7Nqu629
-ikPv0ichLCJbNr8hn86Oi/pyV7jxKNunPiD3iWLEAv0b4SFjoSqya+YndulQ+dLM
-X5ZwAKQ1AMRNwE/E6Cq85os8OJOTIDXrgTyCswtYF7lF4I1vQLLTiQEiBBABAgAM
-BQJDGMYWBQMAEnUAAAoJEJcQuJvKV6186MwH/jiHXFC+L/r1t5l90ewP+WaIeAwx
-gLodYfj2tHzOeTLsqJ8cQRvvRmbA+V8HYNaRi5uvabRKHc3Xz8A/4T0mGMBxC7zh
-AUGKZiij4lpEoecLmgMyLn4OcbKlw0vSF7uh8f0FtGXYAnMudC7fTGI9tEJAGVvO
-4wD3CDf0vvmFNhlMBhQ6N29naxKNQ43wvdEMS1bua+kHQEeBlnc69+JVy+JqaM8W
-IyBYU+od+gUK9Cj13Zy5J8CZRe517kNbyjH9YdMQN+6EcvbyQMQ+WAukSCYu5+RM
-Wh21YSjWX4LjHfAwYfBgtXLJYfD6+3qPTtgx3vjqDDeuQjlSK0Gz7kJV3GaJASIE
-EAECAAwFAkMbZ+MFAwASdQAACgkQlxC4m8pXrXzNZgf+Ozkz/PM4JVhRjWB/yr/F
-u65hHaVBbYhzqwYzJolwZ82NORG3T00IE4NwWDX1dVFqc7vulWk1dPDyPi/ZojLS
-PbO85IDQKPGNgql/XMt9MG2k3lSorxlsChUwwnL/T7p8atvJOz5FHFVwNdfFokoX
-oUffLeJ3GlQg+k9fzGjXSbvl68RSc1jJ+IxBqODiqZITE/yik7jid92YsFOCPlmY
-J504et7WBtQDCaaeqKQA5h+IaJYn/Wa4NnZMFkKEY0x55D0C732FAILED///////
-////////////////////////////////////////////////////////////////
-/4kBIgQQAQIADAUCQxtn4wUDABJ1AAAKCRCXELibyletfM1mB/47OTP88zglWFGN
-YH/Kv8W7rmEdpUFtiHOrBjMmiXBnzY05EbdPTQgTg3BYNfV1UWpzu+6VaTV08PI+
-L9miMtI9s7zkgNAo8Y2CqX9cy30wbaTeVKivGWwKFTDCcv9Punxq28k7PkUcVXA1
-18WiShehR98t4ncaVCD6T1/MaNdJu+XrxFJzWMn4jEGo4OKpkhMT/KKTuOJ33Ziw
-U4I+WZgnnTh63tYG1AMJpp6opADmH4holif9Zrg2dkwWSE6pts4WbPVi+uTJuh+I
-e1I8NLcnj28pKbuUsaqXKEg/cbRlnzhWgtydsiAa8F8ee2TZ0AIFHxGZ4/B02nEa
-HCLsSlubiQEiBBABAgAMBQJEmvWnBQMAEnUAAAoJEJcQuJvKV618w2UIAL3JIcgU
-8Y4bSdtSgk5/qIwsA1VCOfmkiXoHWkYlNIHpsMJiEGUuHdh7geozi4Mai2WDtOz6
-KCzKhuSIEWy0seDG44Oj1fJxgzLPPrGehp5TNfapTCS9gercEDdbZXS5OL4S3hM/
-a3ls2mISLRXTTsCKjzQExyKNJwQfxLznNxJJ+4qhUa+o46Z8fSfgLQGisztt2K4t
-ZzpoE0xx72wdLvWXdjfL9Hxjigu9GksGmdHwI1sxetR9go5tkyuEOFLisx7FvSjA
-1h9fV0YFLi8JhJhpKsHkToqUps3bt09+gx/G5e5foE9tU1Wz1TdjpIDieZ+HwhIr
-fABY+FGD4Z/kCWiJASIEEAECAAwFAkSsNcwFAwASdQAACgkQlxC4m8pXrXwRIAgA
-sylEiUunfvlTNrh/8AFtZKOa8XySqFDmPt0Rl54bNfGuEgrSGmfEmiXEsAdZG3xE
-oFdzkGz2l51JJCSjdV3kIDR+meMEoq4xNsTPBhCF6Pi+3Wy2tW66N4avw3ttN1Lv
-k409ly7N7XLFKIzsu/NIocKLELvbeTik3fFRPXaKnUwhuKpCCGxFBk/vJo0KNQEW
-4qJiMrnSwG/Gc14wbB36ueHFWu9L8XbHVLZrvqXZAzP9RBMNdaFo8HAD6GjWrdRd
-Tjf5T/n/IyUyeIGeOgkRvfbN10rKMCLCLKcn93nrbdGF4Z2ykssiDMQMvUq48ruL
-IS6hZdT8unmJCOQJsI0MJ4kBIgQQAQIADAUCRL6feQUDABJ1AAAKCRCXELibylet
-fEMYB/4w/o3voZMWgyuwk4yf+LAFXQsJrMfllXCKY3STMGKJPR2ebHJXSA+ZcOGK
-kqRU2MrVnH9bRB0Rklo2D/j6dxToKzeR0VBcmakgpNaRmx08ZuY8aJQ64rdTfEtx
-aGz6hOCmS8/rmY3QHbVq2A3vpBOcJ7DwHf3JPCpYuWUSSA/hRDrIALpv+euIc0dM
-N50HZhf0b0/31GMJcjLtJZUQWqrtSGZb3uKPmwrfC0i53LbvdBEpsO/HeLQkKWZj
-ZFbTj0UYDGFEarU0ZPTRCo8cNDdApLX3XE9onwprYQxd0POL4Z/TuM5am8vdp2So
-CNzRn3R3oHZYmfBAE8tT9DDmecuMiQEiBBABAgAMBQJEz9xYBQMAEnUAAAoJEJcQ
-uJvKV618xxUH/3+4X/oDJUfEciNd7qVmujg9pEYdGBRek4IwHcOHgyop1rfWODYm
-pIg13EFXjAvxiQvUgTsOXwCzQyMWMRvW2X4PkCK46sOgWGfsakA4BWXh0nGcuF2L
-htgF/DhRmSK4dxOXf9k+UN8ORGVxCNIgRSrlqHqxtI9XEa71/JcmVO1QzCjm08tf
-n2Dd79NbjB3Sc4PGrK0IKg+/ayywfVK0aLhlxRVRdgNYqZh1J5HoU44PrPcOGVF6
-qnzEoGhdajxV44pD3LQFiLNBVXNfS1A4kCqM9MsQAmjs4uATud4uSEsg/FQQXcI0
-SkDgcHXgPfYJoDPMw839jookk7IxqNFR2xeJASIEEAECAAwFAkTher8FAwASdQAA
-CgkQlxC4m8pXrXwGyAf/bWJhrNRunKQChvKnkvCUXrtjx6vvU6gFw93Ywrp/CWBf
-VhBQ6yFFjEx7jr+C4wJldcnXs/IKpFQh+V7pym4chlwOiNv2gB6AwYPar1aSGYqQ
-2SlSuxCZ1HCqzHhnSaKvyjvhQYzlF/Z6hR89wzJU9+IpHqW/8GezwQhLvIFTf9HI
-44Q60QcmtOPxtkScmo6yux7Z6njkAskVhNmEz3lcWoiCj1YwNYnGs16PI+sVLI2w
-d1cjSN///2V7l4Omw7Kzn/pAsqUsxbBLVwSenLX6ygYyyvsR8zJC2afbDCrzrezc
-F35Vl+DSbFdspBBLlCYtSTxQ9d6nn1KyucUZyAS3YokBIgQQAQIADAUCRPNnCwUD
-ABJ1AAAKCRCXELibyletfLwKB/474iq2pmpsJIG3kGMRD960BDH8P5JOIESmLxjx
-dYVzDIBBLmlnqmZTx8elHn1e1LHBh2vmEGW3K9cvBd+etGjJ7otIzBh4lqEGNNJ3
-Bmv8N3VYNlEhvNEQOSKCJ1F8mkUCRo9vyLgM7RfUQl5pNQdN0V64pxz55fZkWnok
-NLzSC8kiMCf43IjUEvLoErQbFGm3eqJR0vycNTcxuX3ilZolymKuZV8SpTp2GdiU
-3w67/cw3m+BIvhc3n1AM+iYRUPUNH5O7WIDnA6bGPs56x75hgxjGojSxpZawewzz
-02epuGkv6dpwwBCbs6FbYFMfc4HJhPsh146fbtQfcB/LQUq7iQEiBBABAgAMBQJF
-Bc0NBQMAEnUAAAoJEJcQuJvKV6188YIH/3AE8qRLIe675dUNP2awkIUsodgmU32c
-8aBxIDJs3DROJ15TefCdRP4vnlaIdvMenXQQk2npEviAq6+5szde8SNQ6QLOkd1Z
-6ktWEWueL7HNSEwsg4rKpFh1szeS7pLAJoeg/lCgILw6Vv+UJVg4u7fcTVa3tWwd
-LUvoFkjJcdUBzyPZrjUSfeh+Fl98IF70EMb7A7fSE6lgqJbzlnIruywFctGCDzmP
-T9WKALxBB8bRmTLt4/zsmKaJT1X1Wa8L7COMp4/b7ODWYtbOEsZsWttvFA9Btioe
-JlXz9gt0L9oDOAkkul5Ygna2qpqb4pCuqfwXo10dVDmuUfcGaebypl2JASIEEAEC
-AAwFAkVpHo0FAwASdQAACgkQlxC4m8pXrXxbmQf7BZzZhCyRSL6qa9U2kwhz7AVI
-nY4PDV3bXB6ENGwRQ5tUEKAzkmTfAN8VZWkQ3n69cpWMMdC1OwLKCqO51aDnHFa0
-WiTXfzGvaGO7agDPGM05h1b1PxGu7QqrLxBUk0hhonLr37JWXZ4zd/IEnL1yrrr3
-hPEK/xGnKFNJal0RTQGhA3BXehlKzlGfcgLrVw6ITTwDGqtWV1tNWpc7AnAjOpGm
-I/Yd19VEyOmYFi54AB2eVOFRIYHItn/tPuAkaOVTezcJ8x3GHDX4kBYykuJS4syo
-yjK/e6kL/juZkXSjGD6+JaqWT4PWmrkbriD8UfWr9XH84CdAJlOJFNmO6gX14okB
-IgQQAQIADAUCRXqGWQUDABJ1AAAKCRCXELibyletfBkBB/4sG83DUTEAsAWZ7IKv
-8gxP+iuky/tBDoDHqDqkeUoBxeJBfXbCVSPMAqzD5IkWhu1crUrgm8v6kAJvTJyw
-rQUZ7FDsjtez7C38o6JNiy8MDzBWHonXkF2hcUQxhksDEz844+9/aAo1fPMKMtsD
-+HAYjUoEwIXH7XdmYpHavraF/MbbRS34Uey28I2fS9wDSAWYtA0uySTX2hvPXq52
-bsDGLdGUiXR6ZlH8AvQXu4N6nFNtG2PwoGaTd5cAaiMAkKqkS4iKkmaJojLO9UZm
-nSIEwKD9WatqVuT+YbDdq9aIL8fOnkX4NSqlpObxiJZf14bIpZWzNOZtda7XZXu1
-Tf3uiQEiBBABAgAMBQJFnozOBQMAEnUAAAoJEJcQuJvKV618U7oH/AkvEKC2UuHv
-Vs1Z470xgY1lJ+4UMPC0cePytojXIrre2E8FMmVcihVMRKPWHcWLsjme2NMAGv5y
-TVS4reQyUzAUzeUmB8PLh6Dmwlvhfd85MONahm+dhSMLp2M+EKNwvZ3QWB3PHnJm
-ai4tfu+3+NMYytCQAJVwjKyJ/FfSGCiSEQ6TQq17gWA01+z/ehKX3WzzCHOAIKti
-7ak46Z6vq1fejWNpD7yfU0wsNjXfoMsRIF0sA28KlTvue7s1pKgeUKymBalAFpx3
-n4a6sEhCDugMj5/zff26ae2frseq7lWn1UZQcev76dPCgwSzjZuzuOSb9Gn/Miga
-F8YmGx5w4Ui5AQ0EPGFAfBAEAPeoSmFQ5ZGD0LyFImln1mjwX6FecXqa8xa7LvpH
-7IeqDgfkI9ZIfXXqU4qXnGkZ5d047Mzk7EaB0QKFv6MuizMz2tzcdB9woBCYUx3T
-chrLj/mMwBL682AJ8NX3yePqBTRjeS5R1OTIw8M5tBa/WCKcCeSg5VdvucBVb9fm
-fyLPAAMFA/wI+5FE6PYUL7Da1NcOBolqb08SbVygdEkCgd5/WcFl84A5kuNEPXTA
-GDabyrYRQnj+av/UPTCFMg1OEmS+ZmREZWS40gt4Ldfl0xDUBfh8g46dU5tZWuWD
-l60fyJyEg5g5Q6oLH9y5X0XoCmD08Tq9wWqaHgGg6VvSo5oh3M3WxYhOBBgRAgAG
-BQI8YUB8ABIJEDYCsH9V0McyB2VHUEcAAQFT4ACgjPRcbrX1lr2ajSlubqehpweM
-ulsAnjeZOJsXJPe+T1CzpPI6v2aixr50
-=6hmd
------END PGP PUBLIC KEY BLOCK-----
diff --git a/debian/upstream/signing-key.asc b/debian/upstream/signing-key.asc
new file mode 100644
index 0000000..a84c94e
--- /dev/null
+++ b/debian/upstream/signing-key.asc
@@ -0,0 +1,29 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQGiBDxhQHkRBACyhJxCLQvLs70IUZSlYVKAm+u1Oa4RyUo5/ctCcMm2KOcjui3z
+xs+yUwlglo1n/de9NNJY98PJNLHniMVi5sPba8OKwYx9bilwuAWLgTsgfpX8UuuY
+TANQmTybmrxjzxrGqN7eyjBT3utgbK3ACKDo/JUCgZMkdFu2c2i7186sDwCgo9pQ
+ygxOOWEWBm70Rymdfvkon6EEAKY5h9nL1qYw46vM1+QY+vhyX2lHTD/E9QyFQv4L
+driY3CerLAZ07yk5p8I6T31d7HEUt9DZcl0ZD99Y9IH84wWvms1xtnCuoLlP4ntw
+FQ5ZUZtMY0AIVRtFbgkTDDLZsdanscqMu/LqnO2/QWjCQhaO/tcaIdPVgBIbCr28
+fuBJA/9KA5vbQBd4WnNFLVJsr47irnJBYdR+OqPQAUFUcQPO1metR76UZ7+7LwtO
+ldAjPN3RDJtRB8/JooHDNq+VCEzjs02JaBpQ+BCOzzqELnkoBPl26yHR56r4WbC5
++FH/QxEaicjVGxIF/Z9crzG/XUMXwieTNcM6HoGCnMboGqCM4bQgU2VyZ2V5IFBv
+em55YWtvZmYgPGdyYXlAZ251Lm9yZz6IXgQTEQIAHgUCQ/CVtQIbAwYLCQgHAwID
+FQIDAxYCAQIeAQIXgAAKCRA2ArB/VdDHMkVKAJ41glKzudqU5UgxMkHdSLo28ov+
+cACeLUrGgtmv/6MbmICeG64v6KOrnga0I1NlcmdleSBQb3pueWFrb2ZmIDxncmF5
+QGdudS5vcmcudWE+iF4EExECAB4FAkPwlXcCGwMGCwkIBwMCAxUCAwMWAgECHgEC
+F4AACgkQNgKwf1XQxzLm6gCfbavgu1bRDHsaUQKvY83CqOX2RcsAnirapY4we57A
+iCr2TTldQ+H5+xw5tDJTZXJnZXkgUG96bnlha29mZiAoR3JheSkgPGdyYXlAbWly
+ZGRpbi5mYXJsZXAubmV0PohfBBMRAgAXBQI8YUB5BQsHCgMEAxUDAgMWAgECF4AA
+EgkQNgKwf1XQxzIHZUdQRwABAQ3iAKCVtLVewNzCDfjui1wTWmz73IcUaQCcDjK4
+771A6G/z6qX5bDuK1yL/YeS5AQ0EPGFAfBAEAPeoSmFQ5ZGD0LyFImln1mjwX6Fe
+cXqa8xa7LvpH7IeqDgfkI9ZIfXXqU4qXnGkZ5d047Mzk7EaB0QKFv6MuizMz2tzc
+dB9woBCYUx3TchrLj/mMwBL682AJ8NX3yePqBTRjeS5R1OTIw8M5tBa/WCKcCeSg
+5VdvucBVb9fmfyLPAAMFA/wI+5FE6PYUL7Da1NcOBolqb08SbVygdEkCgd5/WcFl
+84A5kuNEPXTAGDabyrYRQnj+av/UPTCFMg1OEmS+ZmREZWS40gt4Ldfl0xDUBfh8
+g46dU5tZWuWDl60fyJyEg5g5Q6oLH9y5X0XoCmD08Tq9wWqaHgGg6VvSo5oh3M3W
+xYhOBBgRAgAGBQI8YUB8ABIJEDYCsH9V0McyB2VHUEcAAQFT4ACgjPRcbrX1lr2a
+jSlubqehpweMulsAnjeZOJsXJPe+T1CzpPI6v2aixr50
+=eHW1
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/debian/watch b/debian/watch
index 4ad92d1..3b923e4 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,3 +1,3 @@
 version=3
 options=pgpsigurlmangle=s/$/.sig/ \
- http://ftp.gnu.org/gnu/direvent/direvent-(\d\S*)\.tar\.gz
+ https://ftp.gnu.org/gnu/direvent/direvent-(\d\S*)\.tar\.gz
diff --git a/doc/Makefile.in b/doc/Makefile.in
index 99eb230..c4ee879 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -30,7 +30,17 @@
 # You should have received a copy of the GNU General Public License
 # along with Direvent.  If not, see <http://www.gnu.org/licenses/>.
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -94,10 +104,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = doc
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(direvent_TEXINFOS) $(top_srcdir)/build-aux/mdate-sh \
-	$(srcdir)/version.texi $(srcdir)/stamp-vti \
-	$(top_srcdir)/build-aux/texinfo.tex $(dist_man_MANS)
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/am/gettext.m4 $(top_srcdir)/am/iconv.m4 \
@@ -108,6 +114,8 @@ am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/version.texi \
+	$(srcdir)/stamp-vti $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -205,6 +213,9 @@ man8dir = $(mandir)/man8
 NROFF = nroff
 MANS = $(dist_man_MANS)
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(direvent_TEXINFOS) $(dist_man_MANS) \
+	$(srcdir)/Makefile.in $(top_srcdir)/build-aux/mdate-sh \
+	$(top_srcdir)/build-aux/texinfo.tex
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -236,7 +247,9 @@ GRECS_CHANGELOG = @GRECS_CHANGELOG@
 GRECS_DISTCK_AT = @GRECS_DISTCK_AT@
 GRECS_DISTDOC = @GRECS_DISTDOC@
 GRECS_DOCDIR = @GRECS_DOCDIR@
+GRECS_EXTRA_DIST = @GRECS_EXTRA_DIST@
 GRECS_HOST_PROJECT_INCLUDES = @GRECS_HOST_PROJECT_INCLUDES@
+GRECS_HOST_PROJECT_LDADD = @GRECS_HOST_PROJECT_LDADD@
 GRECS_INCLUDES = @GRECS_INCLUDES@
 GRECS_INCLUDE_DIR = @GRECS_INCLUDE_DIR@
 GRECS_LDADD = @GRECS_LDADD@
@@ -372,7 +385,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits doc/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnits doc/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -445,15 +457,16 @@ $(srcdir)/stamp-vti: direvent.texi $(top_srcdir)/configure
 	echo "@set UPDATED $$1 $$2 $$3"; \
 	echo "@set UPDATED-MONTH $$2 $$3"; \
 	echo "@set EDITION $(VERSION)"; \
-	echo "@set VERSION $(VERSION)") > vti.tmp
-	@cmp -s vti.tmp $(srcdir)/version.texi \
-	  || (echo "Updating $(srcdir)/version.texi"; \
-	      cp vti.tmp $(srcdir)/version.texi)
-	-@rm -f vti.tmp
+	echo "@set VERSION $(VERSION)") > vti.tmp$$$$ && \
+	(cmp -s vti.tmp$$$$ $(srcdir)/version.texi \
+	  || (echo "Updating $(srcdir)/version.texi" && \
+	      cp vti.tmp$$$$ $(srcdir)/version.texi.tmp$$$$ && \
+	      mv $(srcdir)/version.texi.tmp$$$$ $(srcdir)/version.texi)) && \
+	rm -f vti.tmp$$$$ $(srcdir)/version.texi.$$$$
 	@cp $(srcdir)/version.texi $@
 
 mostlyclean-vti:
-	-rm -f vti.tmp
+	-rm -f vti.tmp* $(srcdir)/version.texi.tmp*
 
 maintainer-clean-vti:
 	-rm -f $(srcdir)/stamp-vti $(srcdir)/version.texi
@@ -892,6 +905,8 @@ uninstall-man: uninstall-man5 uninstall-man8
 	uninstall-html-am uninstall-info-am uninstall-man \
 	uninstall-man5 uninstall-man8 uninstall-pdf-am uninstall-ps-am
 
+.PRECIOUS: Makefile
+
 
 clean-local:
 	@rm -rf manual
diff --git a/doc/direvent.8 b/doc/direvent.8
index 03644ff..0d7f73f 100644
--- a/doc/direvent.8
+++ b/doc/direvent.8
@@ -13,7 +13,7 @@
 .\"
 .\" You should have received a copy of the GNU General Public License along
 .\" with direvent. If not, see <http://www.gnu.org/licenses/>.
-.TH DIREVENT 8 "June 20, 2016" "DIREVENT" "Direvent User Reference"
+.TH DIREVENT 8 "August 25, 2016" "DIREVENT" "Direvent User Reference"
 .SH NAME
 direvent \- directory event monitor
 .SH SYNOPSIS
@@ -255,6 +255,11 @@ it, \fBdirevent\fR will install a watcher similar to that of its parent
 directory.  The optional \fILEVEL\fR can be used to set up a cut-off
 nesting level, beyond which the recursive operation is disabled.
 .PP
+The \fIPATHNAME\fR is not required to be a directory, it can as well
+be a file of any type.  This file is not required to exist, either.  If
+it does not, \fBdirevent\fR will defer configuring the watcher until
+the file is eventually created.
+.PP
 The rest of statements are optional.  The \fBuser\fR statement can be
 used to execute the \fICOMMAND\-LINE\fR as the user \fINAME\fR
 (provided, of course, that \fBdirevent\fR is started with root
diff --git a/doc/direvent.info b/doc/direvent.info
index 7e62681..e1a561d 100644
--- a/doc/direvent.info
+++ b/doc/direvent.info
@@ -20,8 +20,8 @@ File: direvent.info,  Node: Top,  Next: Intro,  Up: (dir)
 Direvent
 ********
 
-This edition of the 'GNU Direvent' manual, last updated 4 July 2016,
-documents GNU Direvent Version 5.1.
+This edition of the 'GNU Direvent' manual, last updated 10 September
+2016, documents GNU Direvent Version 5.2.
 
 * Menu:
 
@@ -57,7 +57,7 @@ example, to track changes in important configuration files.
 
    Interfaces for tracking changes to file systems are highly
 system-specific.  GNU 'direvent' aims to provide a uniform and
-system-independent command-level interface.  As of version 5.1
+system-independent command-level interface.  As of version 5.2
 'direvent' works with modern Linux kernels (since v.  2.6.13) and BSD
 systems (FreeBSD, NetBSD, OpenBSD, Darwin).
 
@@ -100,7 +100,7 @@ obtain information about the event that triggered it from the
 environment variables, or from its command line.
 
    Watchers are defined in the configuration file, which 'direvent'
-reads at startup.  This file has a simple and easy to use syntax.
+reads at startup.  The following outlines its syntax:
 
    Three types of comments are allowed: inline comments, that begin with
 a '#' or '//' and extend to the end of line, and multi-line comments,
@@ -121,7 +121,7 @@ marks in order to represent a single token.
 by any amount of whitespace and is terminated with a semicolon.  A block
 statement is a collection of statements enclosed in curly braces.
 
-   The following block statement declares a watcher:
+   A watcher is declared using the following block statement:
 
      watcher {
          path PATHNAME [recursive [LEVEL]];
@@ -146,6 +146,13 @@ recursively.  This means that for each subdirectory created in it,
 directory.  Optional LEVEL statement can be used to set up a cut-off
 nesting level, beyond which the recursive operation is disabled.
 
+   It is a common practice for the 'path' statement to refer to a
+directory.  However, it is not a requirement.  The PATHNAME argument can
+as well point to any other type of file(1).  Moreover, it is not
+required to exist, either.  If it does not, GNU 'direvent' will remember
+the watcher definition and will set it up when the PATHNAME is
+eventually created.(2)
+
    The rest of statements are optional.  The 'file' statement instructs
 GNU 'direvent' to react only if the event concerned the file whose name
 matches one of the patterns given in its argument.  The 'user' statement
@@ -157,6 +164,13 @@ environment.  Finally, the 'option' statement supplies additional
 options.  It can be used, for example, to divert the command's output to
 syslog.
 
+   ---------- Footnotes ----------
+
+   (1) Obviously, the 'recursive' keyword is valid only if PATHNAME is a
+directory.
+
+   (2) *Note path::, for a detailed description.
+
 
 File: direvent.info,  Node: Quick start,  Next: Invocation,  Prev: Overview,  Up: Top
 
@@ -415,7 +429,7 @@ newline character.
      standard include search path is scanned.  It is defined at the
      compile time and by default consists of two directories:
 
-        * 'PREFIX/share/direvent/5.1/include'
+        * 'PREFIX/share/direvent/5.2/include'
         * 'PREFIX/share/direvent/include'
 
      where PREFIX is the installation prefix.  The default can be
@@ -694,8 +708,8 @@ File: direvent.info,  Node: watcher,  Prev: syslog,  Up: Configuration
 
 The 'watcher' statement configures a single event watcher.  A watcher
 can control several events in multiple pathnames.  Any number of
-'watcher' statements is allowed in the configuration file, each one of
-them declaring a separate watcher.
+'watcher' statements is allowed in the configuration file, each of them
+declaring a separate watcher.
 
      watcher {
          path PATHNAME [recursive [LEVEL]];
@@ -712,16 +726,34 @@ them declaring a separate watcher.
 
  -- Config: path PATHNAME [recursive [NUMBER]]
      Defines a pathname to watch.  The PATHNAME argument must be the
-     name of an existing directory in the file system.  The watcher will
-     watch events occurring for all files within that directory.  If the
-     optional 'recursive' clause is specified, this directory will be
-     watched recursively, i.e.  when any subdirectory is created in it,
-     'direvent' will set up a watcher for files in this subdirectory.
-     This new watcher will be an exact copy of the parent watcher,
-     excepting for the pathnames.  The optional NUMBER parameter defines
-     a cut-off nesting level for recursive watching.  If supplied, the
-     recursive behaviour will apply only to the directories that are
-     nested below that level.
+     name of a directory or file in the file system.  If PATHNAME refers
+     to a directory, the watcher will watch events occurring for all
+     files within that directory.  If the optional 'recursive' clause is
+     specified, this directory will be watched recursively, i.e.  when
+     any subdirectory is created in it, 'direvent' will set up a watcher
+     for files in this subdirectory.  This new watcher will be an exact
+     copy of the parent watcher, excepting for the pathnames.  The
+     optional NUMBER parameter defines a cut-off nesting level for
+     recursive watching.  If supplied, the recursive behaviour will
+     apply only to the directories that are nested below that level.
+
+     If PATHNAME refers to a regular file, the changes to that file will
+     be monitored.  Obviously, in that case the 'recursive' keyword
+     makes no sense.  If present, it will be silently ignored.
+
+     If the PATHNAME does not exist, GNU 'direvent' will defer setting
+     up the watcher until it is created.  In order to do so, it will
+     find the longest directory prefix that exists in the file system
+     and will construct a "sentinel watcher" to monitor creation of the
+     next directory component.  When this component is created, the
+     sentinel wakes up to set up a similar watcher for the next
+     directory component.  Once it is done, the sentinel removes itself.
+     This process continues until the PATHNAME is eventually created.
+     When it happens, the last sentinel will activate the configured
+     watcher.
+
+     These actions are performed in reverse order upon removal of
+     PATHNAME or any of its trailing directory components.
 
      Any number of 'path' statements can appear in a 'watcher' block.
      At least one 'path' must be defined.
@@ -880,6 +912,8 @@ them declaring a separate watcher.
           with a punctuation character, this character is removed from
           it before assignment.
 
+     Multiple 'environ' statements accumulate.
+
 
 File: direvent.info,  Node: System dependencies,  Next: Reporting Bugs,  Prev: Configuration,  Up: Top
 
@@ -1494,7 +1528,7 @@ This is a general index of all issues discussed in this manual
 * BSD:                                   bsd.                 (line   6)
 * CLOSE_NOWRITE, linux event:            linux.               (line  30)
 * CLOSE_WRITE, linux event:              linux.               (line  28)
-* command:                               watcher.             (line  77)
+* command:                               watcher.             (line  95)
 * Comments in a configuration file:      Comments.            (line   6)
 * comments, pragmatic:                   Pragmatic Comments.  (line   6)
 * configuration file statements:         Statements.          (line   6)
@@ -1505,16 +1539,16 @@ This is a general index of all issues discussed in this manual
 * DELETE, BSD:                           bsd.                 (line  25)
 * delete, generic event:                 Overview.            (line  22)
 * DELETE, linux event:                   linux.               (line  34)
-* DIREVENT_FILE, environment variable:   watcher.             (line 135)
-* DIREVENT_GENEV_CODE, environment variable: watcher.         (line 129)
-* DIREVENT_GENEV_NAME, environment variable: watcher.         (line 132)
-* DIREVENT_SYSEV_CODE, environment variable: watcher.         (line 124)
-* DIREVENT_SYSEV_NAME, environment variable: watcher.         (line 126)
-* environ:                               watcher.             (line 120)
-* environment modification:              watcher.             (line 140)
-* environment, handler:                  watcher.             (line 124)
+* DIREVENT_FILE, environment variable:   watcher.             (line 153)
+* DIREVENT_GENEV_CODE, environment variable: watcher.         (line 147)
+* DIREVENT_GENEV_NAME, environment variable: watcher.         (line 150)
+* DIREVENT_SYSEV_CODE, environment variable: watcher.         (line 142)
+* DIREVENT_SYSEV_NAME, environment variable: watcher.         (line 144)
+* environ:                               watcher.             (line 138)
+* environment modification:              watcher.             (line 158)
+* environment, handler:                  watcher.             (line 142)
 * escape sequence:                       Statements.          (line  33)
-* event:                                 watcher.             (line  65)
+* event:                                 watcher.             (line  83)
 * events:                                Overview.            (line  12)
 * events, generic:                       Overview.            (line  19)
 * events, system-dependent, on BSD:      bsd.                 (line  23)
@@ -1524,7 +1558,7 @@ This is a general index of all issues discussed in this manual
 * facility:                              syslog.              (line  22)
 * facility, syslog:                      syslog.              (line  23)
 * FDL, GNU Free Documentation License:   Copying This Manual. (line   6)
-* file:                                  watcher.             (line  40)
+* file:                                  watcher.             (line  58)
 * file system events:                    Overview.            (line  12)
 * file, macro variable:                  macro expansion.     (line  16)
 * foreground:                            general settings.    (line  10)
@@ -1533,9 +1567,9 @@ This is a general index of all issues discussed in this manual
 * genev_code, macro variable:            macro expansion.     (line  19)
 * genev_name, macro variable:            macro expansion.     (line  23)
 * GNU/Linux:                             linux.               (line   6)
-* Handler environment variables:         watcher.             (line 124)
+* Handler environment variables:         watcher.             (line 142)
 * handler execution environment:         Quick start.         (line  43)
-* handler, defining:                     watcher.             (line  78)
+* handler, defining:                     watcher.             (line  96)
 * handler, introduced:                   Overview.            (line  31)
 * here-document:                         Statements.          (line  73)
 * include directories, preprocessor:     Pragmatic Comments.  (line  28)
@@ -1555,7 +1589,7 @@ This is a general index of all issues discussed in this manual
 * number of open file descriptors:       bsd.                 (line  10)
 * number of watches, linux:              linux.               (line   9)
 * OPEN, linux event:                     linux.               (line  42)
-* option:                                watcher.             (line 101)
+* option:                                watcher.             (line 119)
 * path:                                  watcher.             (line  24)
 * pidfile:                               general settings.    (line  13)
 * pragmatic comments:                    Pragmatic Comments.  (line   6)
@@ -1565,14 +1599,15 @@ This is a general index of all issues discussed in this manual
 * RENAME, BSD:                           bsd.                 (line  34)
 * self-test mode:                        Invocation.          (line  41)
 * self_test_pid:                         macro expansion.     (line  29)
-* shell, watcher option:                 watcher.             (line 105)
+* sentinel:                              watcher.             (line  41)
+* shell, watcher option:                 watcher.             (line 123)
 * simple statements:                     Statements.          (line   6)
 * single-line comments:                  Comments.            (line   6)
 * statement, block:                      Statements.          (line 129)
 * statement, simple:                     Statements.          (line   6)
 * statements, configuration file:        Statements.          (line   6)
-* stdout, watcher option:                watcher.             (line 113)
-* strerr, watcher option:                watcher.             (line 117)
+* stdout, watcher option:                watcher.             (line 131)
+* strerr, watcher option:                watcher.             (line 135)
 * string, quoted:                        Statements.          (line  33)
 * string, unquoted:                      Statements.          (line  29)
 * sysctl:                                linux.               (line   9)
@@ -1587,10 +1622,10 @@ This is a general index of all issues discussed in this manual
 * system-dependent events, linux:        linux.               (line  22)
 * tag:                                   syslog.              (line  27)
 * tag, syslog:                           syslog.              (line  28)
-* timeout:                               watcher.             (line  97)
+* timeout:                               watcher.             (line 115)
 * user:                                  general settings.    (line   6)
-* user <1>:                              watcher.             (line  94)
-* wait, watcher option:                  watcher.             (line 108)
+* user <1>:                              watcher.             (line 112)
+* wait, watcher option:                  watcher.             (line 126)
 * watcher declaration:                   watcher.             (line  11)
 * watcher declaration, summary:          Overview.            (line  60)
 * watcher, complete description:         watcher.             (line   6)
@@ -1602,38 +1637,41 @@ This is a general index of all issues discussed in this manual
 
 Tag Table:
 Node: Top645
-Node: Intro1137
-Node: Overview2045
-Ref: handler3059
-Node: Quick start6046
-Ref: handler environment7740
-Node: Invocation8774
-Ref: include option9280
-Ref: self-test mode10044
-Node: Configuration12119
-Node: syntax12339
-Node: Comments12882
-Node: Pragmatic Comments13556
-Ref: include search path14729
-Node: Statements16322
-Ref: backslash-interpretation17521
-Ref: here-document18884
-Node: macro expansion21300
-Ref: $file21968
-Ref: $genev_code22022
-Ref: $genev_name22157
-Ref: $sysev_code22601
-Ref: $sysev_name22726
-Node: general settings23028
-Node: syslog23570
-Node: watcher24783
-Ref: environ29081
-Node: System dependencies32046
-Node: linux32371
-Node: bsd33705
-Node: darwin35159
-Node: Reporting Bugs35546
-Node: Copying This Manual36408
-Node: Concept Index58838
+Node: Intro1143
+Node: Overview2051
+Ref: handler3065
+Ref: Overview-Footnote-16449
+Ref: Overview-Footnote-26534
+Node: Quick start6584
+Ref: handler environment8278
+Node: Invocation9312
+Ref: include option9818
+Ref: self-test mode10582
+Node: Configuration12657
+Node: syntax12877
+Node: Comments13420
+Node: Pragmatic Comments14094
+Ref: include search path15267
+Node: Statements16860
+Ref: backslash-interpretation18059
+Ref: here-document19422
+Node: macro expansion21838
+Ref: $file22506
+Ref: $genev_code22560
+Ref: $genev_name22695
+Ref: $sysev_code23139
+Ref: $sysev_name23264
+Node: general settings23566
+Node: syslog24108
+Node: watcher25321
+Ref: path25960
+Ref: environ30621
+Node: System dependencies33634
+Node: linux33959
+Node: bsd35293
+Node: darwin36747
+Node: Reporting Bugs37134
+Node: Copying This Manual37996
+Node: Concept Index60426
 
 End Tag Table
diff --git a/doc/direvent.texi b/doc/direvent.texi
index 91a5921..e307bf2 100644
--- a/doc/direvent.texi
+++ b/doc/direvent.texi
@@ -155,8 +155,8 @@ can obtain information about the event that triggered it
 from the environment variables, or from its command line.
 
 Watchers are defined in the configuration file, which
-@command{direvent} reads at startup.  This file has a simple and easy
-to use syntax.
+@command{direvent} reads at startup.  The following outlines its
+syntax:
 
 Three types of comments are allowed: inline comments, that begin with
 a @samp{#} or @samp{//} and extend to the end of line, and multi-line
@@ -179,7 +179,7 @@ any amount of whitespace and is terminated with a semicolon.  A block
 statement is a collection of statements enclosed in curly braces.
 
 @cindex watcher declaration, summary
-The following block statement declares a watcher:
+A watcher is declared using the following block statement:
 
 @example
 @group
@@ -208,6 +208,15 @@ it, @command{direvent} will install a watcher similar to that of its parent
 directory.  Optional @var{level} statement can be used to set up a cut-off
 nesting level, beyond which the recursive operation is disabled.
 
+It is a common practice for the @code{path} statement to refer to a
+directory.  However, it is not a requirement.  The @var{pathname}
+argument can as well point to any other type of
+file@footnote{Obviously, the @samp{recursive} keyword is valid only if
+@var{pathname} is a directory.}.  Moreover, it is not required to
+exist, either.  If it does not, @GNUDIREVENT{} will remember the
+watcher definition and will set it up when the @var{pathname} is
+eventually created.@footnote{@xref{path}, for a detailed description.}
+
 The rest of statements are optional.  The @code{file} statement
 instructs @GNUDIREVENT{} to react only if the event concerned the
 file whose name matches one of the patterns given in its argument.
@@ -881,7 +890,7 @@ syslog @{
 @cindex watcher, complete description
 The @samp{watcher} statement configures a single event watcher.  A watcher can
 control several events in multiple pathnames.  Any number of @code{watcher}
-statements is allowed in the configuration file, each one of them declaring
+statements is allowed in the configuration file, each of them declaring
 a separate watcher.
 
 @cindex watcher declaration
@@ -902,18 +911,38 @@ watcher @{
 
 The statements within a @code{watcher} block are:
 
+@anchor{path}
 @deffn {Config} path @var{pathname} [recursive [@var{number}]]
 Defines a pathname to watch.  The @var{pathname} argument must be the
-name of an existing directory in the file system.  The watcher will
-watch events occurring for all files within that directory.  If the
-optional @code{recursive} clause is specified, this directory will be
-watched recursively, i.e. when any subdirectory is created in it,
-@command{direvent} will set up a watcher for files in this
-subdirectory.  This new watcher will be an exact copy of the parent
-watcher, excepting for the pathnames.  The optional @var{number}
-parameter defines a cut-off nesting level for recursive watching.  If
-supplied, the recursive behaviour will apply only to the directories
-that are nested below that level. 
+name of a directory or file in the file system.  If @var{pathname}
+refers to a directory, the watcher will watch events occurring for all
+files within that directory.  If the optional @code{recursive} clause
+is specified, this directory will be watched recursively, i.e. when
+any subdirectory is created in it, @command{direvent} will set up a
+watcher for files in this subdirectory.  This new watcher will be an
+exact copy of the parent watcher, excepting for the pathnames.  The
+optional @var{number} parameter defines a cut-off nesting level for
+recursive watching.  If supplied, the recursive behaviour will apply
+only to the directories that are nested below that level.
+
+If @var{pathname} refers to a regular file, the changes to that file
+will be monitored.  Obviously, in that case the @samp{recursive}
+keyword makes no sense.  If present, it will be silently ignored.
+
+@cindex sentinel
+If the @var{pathname} does not exist, @GNUDIREVENT{} will defer
+setting up the watcher until it is created.  In order to do so,
+it will find the longest directory prefix that exists in the file
+system and will construct a @dfn{sentinel watcher} to monitor
+creation of the next directory component.  When this component is
+created, the sentinel wakes up to set up a similar watcher for the
+next directory component.  Once it is done, the sentinel removes
+itself.  This process continues until the @var{pathname} is eventually
+created.  When it happens, the last sentinel will activate the
+configured watcher.
+
+These actions are performed in reverse order upon removal of
+@var{pathname} or any of its trailing directory components.
 
 Any number of @code{path} statements can appear in a @code{watcher} block.
 At least one @code{path} must be defined.
@@ -1105,6 +1134,8 @@ created and @var{value} is assigned to it.  However, if @var{value}
 ends with a punctuation character, this character is removed from it
 before assignment.
 @end table
+
+Multiple @code{environ} statements accumulate.
 @end deffn
 
 @node System dependencies
diff --git a/doc/stamp-vti b/doc/stamp-vti
index 6f2e2e1..6764904 100644
--- a/doc/stamp-vti
+++ b/doc/stamp-vti
@@ -1,4 +1,4 @@
-@set UPDATED 4 July 2016
-@set UPDATED-MONTH July 2016
-@set EDITION 5.1
-@set VERSION 5.1
+@set UPDATED 10 September 2016
+@set UPDATED-MONTH September 2016
+@set EDITION 5.2
+@set VERSION 5.2
diff --git a/doc/version.texi b/doc/version.texi
index 6f2e2e1..6764904 100644
--- a/doc/version.texi
+++ b/doc/version.texi
@@ -1,4 +1,4 @@
-@set UPDATED 4 July 2016
-@set UPDATED-MONTH July 2016
-@set EDITION 5.1
-@set VERSION 5.1
+@set UPDATED 10 September 2016
+@set UPDATED-MONTH September 2016
+@set EDITION 5.2
+@set VERSION 5.2
diff --git a/grecs/Makefile.am b/grecs/Makefile.am
index 3eaa8df..38c8782 100644
--- a/grecs/Makefile.am
+++ b/grecs/Makefile.am
@@ -1,5 +1,5 @@
 # This file is part of Grecs
-# Copyright (C) 2007-2016 Sergey Poznyakoff
+# Copyright (C) 2007-2019 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
@@ -16,7 +16,14 @@
 
 ACLOCAL_AMFLAGS = -I am
 SUBDIRS=. include src @GRECS_TESTDIR@ @GRECS_DOCDIR@
-EXTRA_DIST=build-aux/yyrename @GRECS_BUILD_AUX@ @GRECS_DISTDOC@ gitid.h
+
+# Wordsplit components. 
+WORDSPLIT_SRC = wordsplit/wordsplit.c wordsplit/wordsplit.h
+WORDSPLIT_TEST = wordsplit/wordsplit.at wordsplit/wsp.c
+WORDSPLIT_DOC = wordsplit/wordsplit.3
+
+EXTRA_DIST=build-aux/yyrename @GRECS_BUILD_AUX@ @GRECS_DISTDOC@ gitid.h\
+           $(WORDSPLIT_SRC) @GRECS_EXTRA_DIST@
 
 noinst_HEADERS = gitid.h
 BUILT_SOURCES = gitid.h README
diff --git a/grecs/Makefile.in b/grecs/Makefile.in
index 225b2f3..505fdf9 100644
--- a/grecs/Makefile.in
+++ b/grecs/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,7 @@
 @SET_MAKE@
 
 # This file is part of Grecs
-# Copyright (C) 2007-2016 Sergey Poznyakoff
+# Copyright (C) 2007-2019 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
@@ -31,7 +31,17 @@
 # along with Grecs.  If not, see <http://www.gnu.org/licenses/>.
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -95,8 +105,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = grecs
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(noinst_HEADERS) AUTHORS COPYING NEWS README
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/am/gettext.m4 $(top_srcdir)/am/iconv.m4 \
@@ -107,6 +115,8 @@ am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+	$(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -167,6 +177,7 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in AUTHORS COPYING NEWS README
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -223,7 +234,9 @@ GRECS_CHANGELOG = @GRECS_CHANGELOG@
 GRECS_DISTCK_AT = @GRECS_DISTCK_AT@
 GRECS_DISTDOC = @GRECS_DISTDOC@
 GRECS_DOCDIR = @GRECS_DOCDIR@
+GRECS_EXTRA_DIST = @GRECS_EXTRA_DIST@
 GRECS_HOST_PROJECT_INCLUDES = @GRECS_HOST_PROJECT_INCLUDES@
+GRECS_HOST_PROJECT_LDADD = @GRECS_HOST_PROJECT_LDADD@
 GRECS_INCLUDES = @GRECS_INCLUDES@
 GRECS_INCLUDE_DIR = @GRECS_INCLUDE_DIR@
 GRECS_LDADD = @GRECS_LDADD@
@@ -334,7 +347,14 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 ACLOCAL_AMFLAGS = -I am
 SUBDIRS = . include src @GRECS_TESTDIR@ @GRECS_DOCDIR@
-EXTRA_DIST = build-aux/yyrename @GRECS_BUILD_AUX@ @GRECS_DISTDOC@ gitid.h
+
+# Wordsplit components. 
+WORDSPLIT_SRC = wordsplit/wordsplit.c wordsplit/wordsplit.h
+WORDSPLIT_TEST = wordsplit/wordsplit.at wordsplit/wsp.c
+WORDSPLIT_DOC = wordsplit/wordsplit.3
+EXTRA_DIST = build-aux/yyrename @GRECS_BUILD_AUX@ @GRECS_DISTDOC@ gitid.h\
+           $(WORDSPLIT_SRC) @GRECS_EXTRA_DIST@
+
 noinst_HEADERS = gitid.h
 BUILT_SOURCES = gitid.h README
 all: $(BUILT_SOURCES)
@@ -353,7 +373,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits grecs/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnits grecs/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -645,6 +664,8 @@ uninstall-am:
 	maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
 	pdf-am ps ps-am tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 .PHONY: gitid.h
 gitid.h:
diff --git a/grecs/README b/grecs/README
index 042e89c..e04a4ec 100644
--- a/grecs/README
+++ b/grecs/README
@@ -1,5 +1,5 @@
 Grecs README
-Copyright (C) 2011-2012 Sergey Poznyakoff
+Copyright (C) 2011-2016 Sergey Poznyakoff
 See the end of file for copying conditions.
 
 * Introduction
diff --git a/grecs/am/grecs.m4 b/grecs/am/grecs.m4
index 60244a1..f453079 100644
--- a/grecs/am/grecs.m4
+++ b/grecs/am/grecs.m4
@@ -1,5 +1,5 @@
 # This file is part of grecs - Gray's Extensible Configuration System -*- autoconf -*-
-# Copyright (C) 2007-2016 Sergey Poznyakoff
+# Copyright (C) 2007-2019 Sergey Poznyakoff
 #
 # Grex is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -155,6 +155,7 @@ AC_DEFUN([GRECS_SETUP],[
 			m4_popdef([TESTDIR])
 		        AM_MISSING_PROG([AUTOM4TE], [autom4te])
                         GRECS_TESTDIR=tests
+			GRECS_EXTRA_DIST='$(WORDSPLIT_TEST)'
 		       ])
   _GRECS_IF_OPTION_SET([getopt],[
     AC_CHECK_HEADERS([getopt.h])
@@ -197,13 +198,15 @@ AC_DEFUN([GRECS_SETUP],[
   AC_SUBST([GRECS_BUILD_AUX])
   AC_SUBST([GRECS_INCLUDES])
   AC_SUBST([GRECS_TESTDIR])
+  AC_SUBST([GRECS_EXTRA_DIST])
   AC_SUBST([GRECS_LDADD])
   AC_SUBST([GRECS_DOCDIR])
   AC_SUBST([GRECS_CHANGELOG])
   AC_SUBST([GRECS_DISTCK_AT])
   AC_SUBST([GRECS_README])
-  AC_SUBST([GRECS_INCLUDES],['-I$(top_srcdir)/]grecsdir[include] [-I$(top_builddir)/]grecsdir[include]')
+  AC_SUBST([GRECS_INCLUDES],['-I$(top_srcdir)/]grecsdir[include] [-I$(top_srcdir)/]grecsdir[wordsplit] [-I$(top_builddir)/]grecsdir[include]')
   AC_SUBST([GRECS_HOST_PROJECT_INCLUDES])
+  AC_SUBST([GRECS_HOST_PROJECT_LDADD])
   AC_SUBST([GRECS_DISTDOC])
   AC_SUBST([GRECS_INCLUDE_DIR],['$(pkgincludedir)'])
 
@@ -212,6 +215,7 @@ AC_DEFUN([GRECS_SETUP],[
     GRECS_BUILD_TYPE=install
     GRECS_LDADD=['$(top_builddir)/]grecsdir[src/libgrecs.la']
     GRECS_DOCDIR='doc'
+    GRECS_EXTRA_DIST="${GRECS_EXTRA_DIST}${GRECS_EXTRA_DIST:+ }\$(WORDSPLIT_DOC)"
     GRECS_CHANGELOG=
     GRECS_DISTCK_AT=distck.at
     GRECS_README=README.standalone
diff --git a/grecs/build-aux/getopt.m4 b/grecs/build-aux/getopt.m4
index cf375ca..2398932 100644
--- a/grecs/build-aux/getopt.m4
+++ b/grecs/build-aux/getopt.m4
@@ -1,5 +1,5 @@
 dnl This file is part of grecs
-dnl Copyright (C) 2007-2016 Sergey Poznyakoff
+dnl Copyright (C) 2007-2018 Sergey Poznyakoff
 dnl
 dnl Grecs is free software; you can redistribute it and/or modify
 dnl it under the terms of the GNU General Public License as published by
@@ -17,6 +17,27 @@ divert(-1)
 changequote([<,>])
 changecom(/*,*/)
 
+dnl Diversion channels
+define([<__DIV_OPTKEYS__>],1)dnl	option keys
+define([<__DIV_OPTDECL__>],2)dnl	struct option declarations
+define([<__DIV_HELPDECL__>],3)dnl	grecs_opthelp declarations
+define([<__DIV_SWITCH__>],4)dnl		switch statement body
+define([<__DIV_STATIC__>],5)dnl		module static data
+
+dnl Special macros that can be set during expansion
+pushdef([<__GETOPT_DEFINED__>])
+pushdef([<__OPTIONS_END_DEFINED__>])
+pushdef([<__GETOPT_LASTOPT_LABEL__>])
+
+define([<__GETOPT_LONG_TAG>])
+define([<__GETOPT_SHORT_TAG>])
+
+define([<WITH_DIVERSION>],[<ifelse([<$#>],0,[<[<$0>]>],[<dnl
+pushdef([<__GETOPT_DIVERSION__>],divnum)dnl
+divert([<$1>])$2dnl
+divert(__GETOPT_DIVERSION__)dnl
+popdef([<__GETOPT_DIVERSION__>])>])>])
+
 dnl _getopt_mangle_option(NAME)
 dnl ---------------------------
 dnl Convert NAME to a valid m4 identifier, by replacing invalid characters
@@ -33,7 +54,7 @@ define([<_getopt_set_option>],
              [<_getopt_mangle_option(\1),[<\2>]>]))>])>])
 
 dnl _getopt_get_option(NAME[,DEFAULT])
-dnl ------------------------------
+dnl ----------------------------------
 define([<_getopt_get_option>],
   [<_getopt_if_option_set($1,[<indir(_getopt_mangle_option($1))>],[<$2>])>])
   
@@ -44,7 +65,7 @@ define([<_getopt_if_option_set>],
   [<ifdef(_getopt_mangle_option([<$1>]),[<$2>],[<$3>])>])
 
 dnl _getopt_if_option_null(NAME,IF-NULL,IF-NOT-NULL)
-dnl ---------------------------------------------
+dnl ------------------------------------------------
 dnl Check if option NAME is set.
 define([<_getopt_if_option_null>],
   [<ifelse(indir(_getopt_mangle_option([<$1>])),,[<$2>],[<$3>])>])
@@ -61,7 +82,7 @@ define([<_getopt_option_switch>],
                              [<_getopt_option_switch(shift(shift($@)))>])>])>])
 
 dnl _getopt_if_option_val(NAME,val,IF-TRUE,IF-FALSE)
-dnl ---------------------------------------------
+dnl ------------------------------------------------
 dnl Check if option NAME is set.
 define([<_getopt_if_option_val>],
   [<ifelse(_getopt_get_option([<$1>]),[<$2>],[<$3>],[<$4>])>])
@@ -89,34 +110,39 @@ define([<_getopt_set_options>],
        _getopt_set_options(shift($@))>])>])
 
 dnl __getopt_format_authors(name[,name...])
-dnl ------------------------------
+dnl ---------------------------------------
 define([<__getopt_format_authors>],dnl
 	[<ifelse([<$1>],,NULL,[<"$1",
 __getopt_format_authors(shift($@))>])>])
        
 dnl __getopt_upcase(ARGS...)
+dnl ------------------------
 dnl Concatenate and convert ARGS to upper case.
 dnl
 define([<__getopt_upcase>], [<translit([<$*>], [<a-z>], [<A-Z>])>])
 
 dnl __getopt_concat(ARGS...)
+dnl ------------------------	
 dnl Concatenate arguments, inserting ", " between each pair of them.
 dnl
 define([<__getopt_concat>],[<ifelse([<$#>],1,[<$1>],[<$1, __getopt_concat(shift($@))>])>])
 
 dnl __getopt_flushleft(ARGS...)
+dnl ---------------------------
 dnl Concatenate ARGS and remove any leading whitespace
 dnl
 define([<__getopt_flushleft>],
  [<patsubst([<__getopt_concat($*)>], [<^[	]+>])>])
 
 dnl __getopt_chop(ARGS...)
+dnl ----------------------
 dnl Concatenate ARGS and remove any trailing whitespace
 dnl
 define([<__getopt_chop>],
  [<patsubst([<$*>], [<[	]+$>])>])
 
 dnl __getopt_escape(ARGS...)
+dnl ------------------------
 dnl Concatenate ARGS and escape any occurrences of double-quotes with
 dnl backslashes.
 dnl
@@ -124,6 +150,7 @@ define([<__getopt_escape>],
 [<patsubst([<__getopt_concat($*)>],[<[\"]>],[<\\\&>])>])
 
 dnl __getopt_prep(ARG)
+dnl ------------------
 dnl Prepare ARG for including in C strings: replace newlines and any 
 dnl preceding and following whitespace by a single space character, remove
 dnl leading whitespace, and escape double-quotes.
@@ -133,46 +160,76 @@ define([<__getopt_prep>],
 +[	]*>],[< >])))>])
 
 dnl __GETOPT_SHORT_OPTS
+dnl -------------------
 dnl Accumulator for the 3rd argument of getopt_long
 dnl
 define([<__GETOPT_SHORT_OPTS>],[<_getopt_if_option_set([<nopermute>],+)>])
 
 dnl GROUP(STRING)
+dnl -------------
 dnl Begin a named group of options
 dnl
-define([<GROUP>],[<dnl
-divert(3)
+define([<GROUP>],[<ifelse([<$#>],0,[<[<$0>]>],[<dnl
+WITH_DIVERSION(__DIV_HELPDECL__,[<dnl
 	{ NULL, NULL, 0, N_("__getopt_prep([<$1>])") },
-divert(-1)>])
+>])>])>])	
 
 # __getopt_quote(args) - convert args to single-quoted string
-define([<__getopt_quote>], [<ifelse([<$#>], [<0>], [<>], [<[<$*>]>])>])
-define([<__getopt_dquote>], [<[<$@>]>])
+define([<__getopt_quote>], [<ifelse([<$*>], [<>], [<>], [<[<$*>]>])>])
+define([<__getopt_dquote>], [<ifelse([<$*>], [<>], [<>], [<[<$@>]>])>])
+
+# __getopt_ifempty(LIST, IF-TRUE [, IF-FALSE])
+# --------------------------------------------
+# Expands to IF-TRUE if LIST is not empty, otherwise to IF-FALSE.
+#
+define([<__getopt_ifempty>], [<ifelse([<$1>],[<>],[<$2>],[<$3>])>])
 
 define([<__GATHER_OPTIONS>],[<
 pushdef([<__GETOPT_KEY>],ifelse([<$2>],,[<OPTION_>]__getopt_upcase(patsubst($1,-,_)),'$2'))
 ifelse([<$2>],,[<
-divert(1)
+WITH_DIVERSION(__DIV_OPTKEYS__,[<dnl
 	__GETOPT_KEY,
-divert(-1)
->])
+>])>])
 define([<__GETOPT_SELECTOR>],ifdef([<__GETOPT_SELECTOR>],__GETOPT_SELECTOR) case __GETOPT_KEY:)
 ifelse([<$1>],,,[<
-divert(2)
+WITH_DIVERSION(__DIV_OPTDECL__,[<dnl
 	{ "$1", __GETOPT_ARGTYPE, 0, __GETOPT_KEY },
-divert(-1)>])
+>])>])
 dnl
 define([<__GETOPT_SHORT_OPTS>],__getopt_dquote(__GETOPT_SHORT_OPTS[<>]dnl
 ifelse([<$2>],,,[<$2>]ifelse(__GETOPT_ARGTYPE,[<no_argument>],,__GETOPT_ARGTYPE,[<required_argument>],:,__GETOPT_ARGTYPE,[<optional_argument>],::))))
 dnl
 ifelse([<$1>],,,dnl
-[<define([<__GETOPT_LONG_TAG>],ifelse(__GETOPT_LONG_TAG,,[<--$1>],[<__GETOPT_LONG_TAG; --$1>]))>])
+[<define([<__GETOPT_LONG_TAG>],
+__getopt_ifempty(__getopt_quote(__GETOPT_LONG_TAG),__getopt_dquote(__getopt_dquote(--$1)),[<__getopt_quote(__getopt_dquote(__GETOPT_LONG_TAG), __getopt_dquote([< --$1>]))>]))>])
 ifelse([<$2>],,,dnl
-[<define([<__GETOPT_SHORT_TAG>],ifelse(__GETOPT_SHORT_TAG,,[<-$2>],[<__GETOPT_SHORT_TAG; -$2>]))>])
+[<define([<__GETOPT_SHORT_TAG>],
+__getopt_ifempty(__getopt_quote(__GETOPT_SHORT_TAG),__getopt_dquote(__getopt_dquote(-$2)),[<__getopt_quote(__getopt_dquote(__GETOPT_SHORT_TAG), __getopt_dquote([< -$2>]))>]))>])
 popdef([<__GETOPT_KEY>])
 >])
 
+dnl CPP(statement)
+dnl --------------
+dnl Inserts a CPP statement to all diversions
+dnl
+define([<CPP>],[<WITH_DIVERSION(__DIV_OPTKEYS__,[<dnl
+$1
+>])
+WITH_DIVERSION(__DIV_OPTDECL__,[<dnl
+$1
+>])
+WITH_DIVERSION(__DIV_HELPDECL__,[<dnl
+$1
+>])
+WITH_DIVERSION(__DIV_SWITCH__,[<dnl
+$1
+>])
+WITH_DIVERSION(__DIV_STATIC__,[<dnl
+$1
+>])>])
+
 dnl OPTION(long-opt, short-opt, [arg], [descr])
+dnl -------------------------------------------
 dnl Introduce a command line option. Arguments:
 dnl   long-opt     Long option.
 dnl   short-opt    Short option (a single char)
@@ -189,7 +246,7 @@ dnl
 dnl If descr is not given the option will not appear in the --help and
 dnl --usage outputs.
 dnl
-define([<OPTION>],[<
+define([<OPTION>],[<ifelse([<$#>],0,[<[<$0>]>],[<
 pushdef([<__GETOPT_LONG_TAG>])
 pushdef([<__GETOPT_SHORT_TAG>])
 pushdef([<__GETOPT_SELECTOR>])
@@ -200,43 +257,47 @@ pushdef([<__GETOPT_ARGTYPE>],[<ifelse([<$3>],,[<no_argument>],dnl
 patsubst([<$3>],[<\[.*\]>]),,[<optional_argument>],dnl
 [<required_argument>])>])
 __GATHER_OPTIONS($@)
->])
+define([<BEGIN>],[<__GETOPT_API_BEGIN>])
+>])>])
 
 dnl ALIAS(long-opt, short-opt)
+dnl --------------------------
 dnl Declare aliases for the previous OPTION statement.
 dnl   long-opt     Long option.
 dnl   short-opt    Short option (a single char)
 dnl   (At least one of long-opt or short-opt must be present)
 dnl An OPTION statement may be followed by any number of ALIAS statements.
 dnl
-define([<ALIAS>],[<
+define([<ALIAS>],[<ifelse([<$#>],0,[<[<$0>]>],[<
 __GATHER_OPTIONS($1,$2)
->])
+>])>])
 
 dnl BEGIN
+dnl -----
 dnl Start an action associated with the declared option. Must follow OPTION
 dnl statement, with optional ALIAS statements in between.
 dnl
-define([<BEGIN>],[<
+define([<__GETOPT_API_BEGIN>],[<
+undefine([<BEGIN>])
+define([<END>],[<__GETOPT_API_END>])
+define([<LASTOPT>],[<__GETOPT_API_LASTOPT>])
 ifelse(__GETOPT_HIDDEN,1,,[<
-divert(3)
+WITH_DIVERSION(__DIV_HELPDECL__,[<dnl
 	{
 #ifdef HAVE_GETOPT_LONG
-	  "translit(dnl
-ifelse(__GETOPT_SHORT_TAG,,__GETOPT_LONG_TAG,[<__GETOPT_SHORT_TAG[<>]ifelse(__GETOPT_LONG_TAG,,,; __GETOPT_LONG_TAG)>]),
-		    [<;>],[<,>])",
+	  "__getopt_ifempty(__getopt_quote(__GETOPT_SHORT_TAG),__getopt_quote(__GETOPT_LONG_TAG),[<__getopt_quote(__GETOPT_SHORT_TAG)__getopt_ifempty(__getopt_quote(__GETOPT_LONG_TAG),,[<, __getopt_quote(__GETOPT_LONG_TAG)>])>])",
 #else
-	  "translit(__GETOPT_SHORT_TAG, [<;>],[<,>])",
+	  "__GETOPT_SHORT_TAG",
 #endif
 				   ifelse(__GETOPT_ARGNAME,,[<NULL, 0>],
 [<ifelse(__GETOPT_ARGTYPE,[<optional_argument>],
 [<N_(>]"[<patsubst(__GETOPT_ARGNAME,[<\[\(.*\)\]>],[<\1>])>][<"), 1>],[<N_("__GETOPT_ARGNAME"), 0>])>]), N_("__GETOPT_DOCSTRING") },
-divert(-1)>])
+>])>])
 popdef([<__GETOPT_ARGTYPE>])
 popdef([<__GETOPT_ARGNAME>])
 popdef([<__GETOPT_DOCSTRING>])
 popdef([<__GETOPT_HIDDEN>])
-divert(4)dnl
+divert(__DIV_SWITCH__)dnl
 popdef([<__GETOPT_LONG_TAG>])dnl
 popdef([<__GETOPT_SHORT_TAG>])dnl
 	__GETOPT_SELECTOR
@@ -244,25 +305,43 @@ popdef([<__GETOPT_SHORT_TAG>])dnl
 >])
 
 dnl END
+dnl ---
 dnl Finish the associated action
 dnl
-define([<END>],[<
+define([<__GETOPT_API_END>],[<
 	     break;
 	  }
 divert(-1)
+undefine([<END>])
+undefine([<ALIAS>])
+undefine([<LASTOPT>])
 popdef([<__GETOPT_SELECTOR>])>])
 
 dnl OPTNODE(name, value)
-define([<OPTNODE>],[<do {
+dnl --------------------
+define([<OPTNODE>],[<ifelse([<$#>],0,[<[<$0>]>],[<dnl
+WITH_DIVERSION(__DIV_STATIC__,[<
+static struct grecs_node *cmdline_tree;
+>]);
+do {
    struct grecs_node *node = grecs_node_from_path($1, $2);
    if (!cmdline_tree)
 	cmdline_tree = node;
    else
 	grecs_node_bind(cmdline_tree, node, 0);
 } while(0)
->])
+>])>])
+
+dnl LASTOPT()
+dnl ---------
+dnl Stop option processing (as if "--" has been encountered)
+define([<__GETOPT_API_LASTOPT>],[<dnl
+pushdef([<__GETOPT_LASTOPT_LABEL__>],[<lastoptlab:
+popdef([<__GETOPT_LASTOPT_LABEL__>])>])dnl
+goto lastoptlab>])
 
 dnl GETOPT(argc, argv, [long_index], [onerr])
+dnl -----------------------------------------
 dnl Emit option parsing code. Arguments:
 dnl
 dnl  argc        Name of the 1st argument to getopt_long.
@@ -271,7 +350,8 @@ dnl  long_index  5th argument to getopt_long.  If not given,
 dnl              NULL will be passed.
 dnl  onerr       Action to take if parsing fails.
 dnl
-define([<GETOPT>],[<
+define([<GETOPT>],[<ifelse([<$#>],0,[<[<$0>]>],[<dnl
+pushdef([<__GETOPT_DEFINED__>],1)
  {
   int c;
 
@@ -288,34 +368,40 @@ define([<GETOPT>],[<
 	default:
 	   ifelse([<$4>],,,[<$4;>])dnl
 	   exit(EX_USAGE);
-	undivert(4)
+	undivert(__DIV_SWITCH__)
 	}
     }
+__GETOPT_LASTOPT_LABEL__()dnl
   ifelse([<$3>],,[<
     if (optind < argc) {
 	fprintf(stderr, "%s: unexpected arguments\n", $2[0]);
 	exit(EX_USAGE);
     }
 >],[<$3 = optind;>])
+ifelse(__GETOPT_CMDLINE_TREE_NEEDED__,1,[<
   if (cmdline_tree)
     {
       struct grecs_node *rn = grecs_node_create(grecs_node_root, NULL);
       rn->down = cmdline_tree;
       cmdline_tree = rn;
     }
+>])dnl
  }
->])
+>])>])
 
 define([<_getopt_sc_array>],
   [<ifelse([<$1>],,,[<[<"$1", >]_getopt_sc_array(shift($@))>])>])
 
-define([<STDFUNC>],[<
-divert(5)
+define([<STDFUNC>],[<ifelse([<$#>],0,[<[<$0>]>],[<
+WITH_DIVERSION(__DIV_STATIC__,[<
 ifelse([<$3>],,,[<
 static char *subcommands[] = {
 	_getopt_sc_array($3)
 	NULL
 };>])
+#ifndef PACKAGE_URL
+# define PACKAGE_URL NULL
+#endif
 static struct grecs_proginfo proginfo = {
 	$2, /* progname */
 	ifelse([<$3>],,NULL,subcommands), /* subcommands */
@@ -337,31 +423,59 @@ _getopt_if_option_set([<copyright_holder>],dnl
 	PACKAGE_URL, /* url */
 	NULL  /* epilogue */
 };
-static struct grecs_node *cmdline_tree;
 
 _getopt_if_option_set([<program_version>],dnl
 [<const char *_getopt_if_option_null(program_version,program_version,[<_getopt_get_option(program_version)>]) = $2 " (" PACKAGE_NAME ") " PACKAGE_VERSION;
->])
-divert(-1)
->])
-
-define([<OPTIONS_BEGIN>],
-   [<divert(-1)
+>])>])>])>])
+
+dnl OPTIONS_BEGIN(PROGNAME, DOCSTR, [ARGDOC], [OPTS...])
+dnl ----------------------------------------------------
+dnl Begins option definition section. Arguments:
+dnl   PROGNAME    -  canonical program name,
+dnl   DOCSTR      -  usage string to be displayed in --help output.
+dnl   ARGDOC      -  docstring for arguments
+dnl
+dnl Optional arguments (OPTS):
+dnl   nostdincl   -  don't emit C include statements for standard include files
+dnl   nopermute   -  don't permute arguments, i.e. don't accept intermixed
+dnl                  optional and positional arguments
+dnl
+dnl   gnu         -  emit code for --help (-h), --version (-V) and --usage
+dnl                  options.
+dnl Options bellow modify the effect of the 'gnu' option:
+dnl
+dnl   nousage     -  disable support for the --usage option
+dnl   noversion   -  disable support for the --version option
+dnl
+dnl   copyright_year=Y
+dnl               Year, or range, or list of years to display in
+dnl               the copyright statement. Default is 2012 (why?)
+dnl   copyright_holder=NAME
+dnl               Copyright holder name. Default is 'Free Software Foundation,
+dnl               inc.'
+dnl   program_version=V
+dnl               Version string. Defaults to PACKAGE_VERSION autoconf define.
+dnl
+define([<OPTIONS_BEGIN>],[<ifelse([<$#>],0,[<[<$0>]>],
+    [<divert(-1)
      _getopt_set_options(shift(shift(shift($@))))
+     pushdef([<__GETOPT_EXPECT_ARGS__>],ifelse(__getopt_quote($3),,0,1))
      _getopt_if_option_set([<gnu>],
         [<STDFUNC([<$1 " (" PACKAGE_NAME ") " PACKAGE_VERSION>],
-	          [<$1>], [<>], [<$2>], [<$3>])>])
->])
+	          [<$1>], [<>], [<$2>], [<$3>])>])>])>])
+
 
-define([<OPTIONS_COMMAND_BEGIN>],
+define([<OPTIONS_COMMAND_BEGIN>],[<ifelse([<$#>],0,[<[<$0>]>],
    [<divert(-1)
      _getopt_set_options(shift(shift(shift(shift($@)))))
+     pushdef([<__GETOPT_EXPECT_ARGS__>],ifelse(__getopt_quote($3),,0,1))
      _getopt_if_option_set([<gnu>],
         [<STDFUNC([<$1 " (" PACKAGE_NAME ") " PACKAGE_VERSION>],
 	          [<$1>], [<$2>], [<$3>], [<$4>])>])
->])
+>])>])
 
 define([<OPTIONS_END>],[<
+pushdef([<__OPTIONS_END_DEFINED__>],1)
 _getopt_if_option_set([<gnu>],[<
 	 GROUP([<Other options>])
 	 OPTION([<help>],h,,[<Give this help list>])
@@ -378,40 +492,69 @@ _getopt_if_option_set([<nousage>],,[<
 _getopt_if_option_set([<noversion>],,[<	 
 	 OPTION([<version>],V,,[<Print program version>])
 	 BEGIN
-		/* Give version */
+	        /* Give version */
 		grecs_print_version(&proginfo, stdout);
 		exit(0);
 	 END>])>])
-divert
-_getopt_if_option_set([<nostdincl>],,[<
-#ifdef HAVE_CONFIG_H
+divert(0)dnl
+_getopt_if_option_set([<nostdincl>],,
+[<#ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
 #ifdef HAVE_GETOPT_H
 # include <getopt.h>
 #endif
 #include <unistd.h>
->])
+#include <stdlib.h>
+>])dnl
 #include <grecs.h>
 #include <grecs/opt.h>
+#ifndef [<EX_USAGE>]
+# define [<EX_USAGE>] 64
+#endif
 /* Option codes */
 enum {
 	_OPTION_INIT=255,
-	undivert(1)
+undivert(__DIV_OPTKEYS__)dnl
 	MAX_OPTION
 };
 #ifdef HAVE_GETOPT_LONG
 static struct option long_options[] = {
-	undivert(2)
+undivert(__DIV_OPTDECL__)dnl
 	{0, 0, 0, 0}
 };
 #endif
+_getopt_if_option_set([<gnu>],[<
 static struct grecs_opthelp opthelp[] = {
-	undivert(3)
+undivert(__DIV_HELPDECL__)dnl
 };
-undivert(5)
+>],[<WITH_DIVERSION(-1,[<undivert(__DIV_HELPDECL__)>])>])dnl
+undivert(__DIV_STATIC__)
 >])
 
+m4wrap([<ifelse(__OPTIONS_END_DEFINED__,1,,[<OPTIONS_END()>])dnl
+ifelse(__GETOPT_DEFINED__,1,,[<divert(0)dnl
+ifelse(__GETOPT_EXPECT_ARGS__,1,[<
+int
+parse_options(int argc, char **argv, int *idx)
+{
+  GETOPT(argc, argv, *idx)
+  return 0;
+}
+>],[<
+int
+parse_options(int argc, char **argv)
+{
+  GETOPT(argc, argv)
+  return 0;
+}
+>])
+divert(-1)
+popdef([<__GETOPT_DEFINED__>])
+popdef([<__GETOPT_EXPECT_ARGS__>])
+popdef([<__OPTIONS_END_DEFINED__>])
+popdef([<__GETOPT_LASTOPT_LABEL__>])>])>])
+
 divert(0)dnl
 /* -*- buffer-read-only: t -*- vi: set ro:
    THIS FILE IS GENERATED AUTOMATICALLY.  PLEASE DO NOT EDIT.
diff --git a/grecs/gitid.h b/grecs/gitid.h
index b01da0c..04e5886 100644
--- a/grecs/gitid.h
+++ b/grecs/gitid.h
@@ -1 +1 @@
-#define GRECS_GIT_ID "6201e61fb932dbe6153f92ede836e07247d04b7c-1467636407-gray@gnu.org.ua"
+#define GRECS_GIT_ID "b06fb7d30415eec1d2efb39286ab96070c724fd4-1562766431-gray@gnu.org"
diff --git a/grecs/include/Makefile.am b/grecs/include/Makefile.am
index 21a51e7..5934d40 100644
--- a/grecs/include/Makefile.am
+++ b/grecs/include/Makefile.am
@@ -1,17 +1,17 @@
 SUBDIRS = grecs
-GRECS_HDR = grecs.h wordsplit.h
+GRECS_HDR = grecs.h $(top_srcdir)/@GRECS_SUBDIR@/wordsplit/wordsplit.h
 
 if GRECS_COND_BUILD_INSTALL
   include_HEADERS = $(GRECS_HDR)
 endif
 
 if GRECS_COND_BUILD_SHARED
-  if GRECS_COND_INSTALLHEADERS
-    grecsincludedir = @GRECS_INCLUDE_DIR@
-    grecsinclude_HEADERS = $(GRECS_HDR)
-  else 
-    noinst_HEADERS = $(GRECS_HDR)
-  endif
+if GRECS_COND_INSTALLHEADERS
+  grecsincludedir = @GRECS_INCLUDE_DIR@
+  grecsinclude_HEADERS = $(GRECS_HDR)
+else 
+  noinst_HEADERS = $(GRECS_HDR)
+endif
 endif
 
 if GRECS_COND_BUILD_STATIC
diff --git a/grecs/include/Makefile.in b/grecs/include/Makefile.in
index b3614f5..c931bf8 100644
--- a/grecs/include/Makefile.in
+++ b/grecs/include/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,9 +89,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = grecs/include
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(am__grecsinclude_HEADERS_DIST) $(am__include_HEADERS_DIST) \
-	$(am__noinst_HEADERS_DIST)
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/am/gettext.m4 $(top_srcdir)/am/iconv.m4 \
@@ -92,6 +99,9 @@ am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__grecsinclude_HEADERS_DIST) \
+	$(am__include_HEADERS_DIST) $(am__noinst_HEADERS_DIST) \
+	$(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -123,7 +133,8 @@ am__can_run_installinfo = \
     n|no|NO) false;; \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
-am__grecsinclude_HEADERS_DIST = grecs.h wordsplit.h
+am__grecsinclude_HEADERS_DIST = grecs.h \
+	$(top_srcdir)/@GRECS_SUBDIR@/wordsplit/wordsplit.h
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
     $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@@ -153,8 +164,10 @@ am__uninstall_files_from_dir = { \
   }
 am__installdirs = "$(DESTDIR)$(grecsincludedir)" \
 	"$(DESTDIR)$(includedir)"
-am__include_HEADERS_DIST = grecs.h wordsplit.h
-am__noinst_HEADERS_DIST = grecs.h wordsplit.h
+am__include_HEADERS_DIST = grecs.h \
+	$(top_srcdir)/@GRECS_SUBDIR@/wordsplit/wordsplit.h
+am__noinst_HEADERS_DIST = grecs.h \
+	$(top_srcdir)/@GRECS_SUBDIR@/wordsplit/wordsplit.h
 HEADERS = $(grecsinclude_HEADERS) $(include_HEADERS) $(noinst_HEADERS)
 RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
   distclean-recursive maintainer-clean-recursive
@@ -184,6 +197,7 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -240,7 +254,9 @@ GRECS_CHANGELOG = @GRECS_CHANGELOG@
 GRECS_DISTCK_AT = @GRECS_DISTCK_AT@
 GRECS_DISTDOC = @GRECS_DISTDOC@
 GRECS_DOCDIR = @GRECS_DOCDIR@
+GRECS_EXTRA_DIST = @GRECS_EXTRA_DIST@
 GRECS_HOST_PROJECT_INCLUDES = @GRECS_HOST_PROJECT_INCLUDES@
+GRECS_HOST_PROJECT_LDADD = @GRECS_HOST_PROJECT_LDADD@
 GRECS_INCLUDES = @GRECS_INCLUDES@
 GRECS_INCLUDE_DIR = @GRECS_INCLUDE_DIR@
 GRECS_LDADD = @GRECS_LDADD@
@@ -350,11 +366,11 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 SUBDIRS = grecs
-GRECS_HDR = grecs.h wordsplit.h
+GRECS_HDR = grecs.h $(top_srcdir)/@GRECS_SUBDIR@/wordsplit/wordsplit.h
 @GRECS_COND_BUILD_INSTALL_TRUE@include_HEADERS = $(GRECS_HDR)
-@GRECS_COND_BUILD_SHARED_TRUE@grecsincludedir = @GRECS_INCLUDE_DIR@
-@GRECS_COND_BUILD_SHARED_TRUE@grecsinclude_HEADERS = $(GRECS_HDR)
-@GRECS_COND_BUILD_SHARED_TRUE@noinst_HEADERS = $(GRECS_HDR)
+@GRECS_COND_BUILD_SHARED_TRUE@@GRECS_COND_INSTALLHEADERS_TRUE@grecsincludedir = @GRECS_INCLUDE_DIR@
+@GRECS_COND_BUILD_SHARED_TRUE@@GRECS_COND_INSTALLHEADERS_TRUE@grecsinclude_HEADERS = $(GRECS_HDR)
+@GRECS_COND_BUILD_SHARED_TRUE@@GRECS_COND_INSTALLHEADERS_FALSE@noinst_HEADERS = $(GRECS_HDR)
 @GRECS_COND_BUILD_STATIC_TRUE@noinst_HEADERS = $(GRECS_HDR)
 all: all-recursive
 
@@ -371,7 +387,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits grecs/include/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnits grecs/include/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -706,10 +721,8 @@ uninstall-am: uninstall-grecsincludeHEADERS uninstall-includeHEADERS
 	pdf-am ps ps-am tags tags-am uninstall uninstall-am \
 	uninstall-grecsincludeHEADERS uninstall-includeHEADERS
 
+.PRECIOUS: Makefile
 
-@GRECS_COND_BUILD_SHARED_TRUE@  if GRECS_COND_INSTALLHEADERS
-@GRECS_COND_BUILD_SHARED_TRUE@  else 
-@GRECS_COND_BUILD_SHARED_TRUE@  endif
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/grecs/include/grecs/Makefile.am b/grecs/include/grecs/Makefile.am
index c239c1b..e81bd21 100644
--- a/grecs/include/grecs/Makefile.am
+++ b/grecs/include/grecs/Makefile.am
@@ -30,12 +30,12 @@ if GRECS_COND_BUILD_INSTALL
 endif
 
 if GRECS_COND_BUILD_SHARED
-  if GRECS_COND_INSTALLHEADERS
-    grecsincludedir = @GRECS_INCLUDE_DIR@
-    grecsinclude_HEADERS = $(GRECS_PKG_HDR)
-  else 
-    noinst_HEADERS = $(GRECS_PKG_HDR)
-  endif
+if GRECS_COND_INSTALLHEADERS
+  grecsincludedir = @GRECS_INCLUDE_DIR@
+  grecsinclude_HEADERS = $(GRECS_PKG_HDR)
+else 
+  noinst_HEADERS = $(GRECS_PKG_HDR)
+endif
 endif
 
 if GRECS_COND_BUILD_STATIC
diff --git a/grecs/include/grecs/Makefile.in b/grecs/include/grecs/Makefile.in
index 08bd801..3380006 100644
--- a/grecs/include/grecs/Makefile.in
+++ b/grecs/include/grecs/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -80,9 +90,6 @@ build_triplet = @build@
 host_triplet = @host@
 @GRECS_COND_JSON_TRUE@am__append_1 = json.h
 subdir = grecs/include/grecs
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(srcdir)/types.h.in $(am__grecsinclude_HEADERS_DIST) \
-	$(am__noinst_HEADERS_DIST)
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/am/gettext.m4 $(top_srcdir)/am/iconv.m4 \
@@ -93,6 +100,8 @@ am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__grecsinclude_HEADERS_DIST) \
+	$(am__noinst_HEADERS_DIST) $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES = types.h
@@ -172,6 +181,7 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/types.h.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -203,7 +213,9 @@ GRECS_CHANGELOG = @GRECS_CHANGELOG@
 GRECS_DISTCK_AT = @GRECS_DISTCK_AT@
 GRECS_DISTDOC = @GRECS_DISTDOC@
 GRECS_DOCDIR = @GRECS_DOCDIR@
+GRECS_EXTRA_DIST = @GRECS_EXTRA_DIST@
 GRECS_HOST_PROJECT_INCLUDES = @GRECS_HOST_PROJECT_INCLUDES@
+GRECS_HOST_PROJECT_LDADD = @GRECS_HOST_PROJECT_LDADD@
 GRECS_INCLUDES = @GRECS_INCLUDES@
 GRECS_INCLUDE_DIR = @GRECS_INCLUDE_DIR@
 GRECS_LDADD = @GRECS_LDADD@
@@ -317,10 +329,10 @@ GRECS_PKG_HDR = doc.h error.h format.h lex.h list.h locus.h mem.h \
 	tree.h txtacc.h types.h util.h value.h version.h \
 	$(am__append_1)
 @GRECS_COND_BUILD_INSTALL_TRUE@grecsincludedir = @GRECS_INCLUDE_DIR@
-@GRECS_COND_BUILD_SHARED_TRUE@grecsincludedir = @GRECS_INCLUDE_DIR@
+@GRECS_COND_BUILD_SHARED_TRUE@@GRECS_COND_INSTALLHEADERS_TRUE@grecsincludedir = @GRECS_INCLUDE_DIR@
 @GRECS_COND_BUILD_INSTALL_TRUE@grecsinclude_HEADERS = $(GRECS_PKG_HDR)
-@GRECS_COND_BUILD_SHARED_TRUE@grecsinclude_HEADERS = $(GRECS_PKG_HDR)
-@GRECS_COND_BUILD_SHARED_TRUE@noinst_HEADERS = $(GRECS_PKG_HDR)
+@GRECS_COND_BUILD_SHARED_TRUE@@GRECS_COND_INSTALLHEADERS_TRUE@grecsinclude_HEADERS = $(GRECS_PKG_HDR)
+@GRECS_COND_BUILD_SHARED_TRUE@@GRECS_COND_INSTALLHEADERS_FALSE@noinst_HEADERS = $(GRECS_PKG_HDR)
 @GRECS_COND_BUILD_STATIC_TRUE@noinst_HEADERS = $(GRECS_PKG_HDR)
 all: all-am
 
@@ -337,7 +349,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits grecs/include/grecs/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnits grecs/include/grecs/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -579,10 +590,8 @@ uninstall-am: uninstall-grecsincludeHEADERS
 	pdf-am ps ps-am tags tags-am uninstall uninstall-am \
 	uninstall-grecsincludeHEADERS
 
+.PRECIOUS: Makefile
 
-@GRECS_COND_BUILD_SHARED_TRUE@  if GRECS_COND_INSTALLHEADERS
-@GRECS_COND_BUILD_SHARED_TRUE@  else 
-@GRECS_COND_BUILD_SHARED_TRUE@  endif
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/grecs/include/grecs/json.h b/grecs/include/grecs/json.h
index f8402e7..49a6b87 100644
--- a/grecs/include/grecs/json.h
+++ b/grecs/include/grecs/json.h
@@ -54,6 +54,7 @@ extern struct grecs_locus json_err_locus;
 extern struct json_value *json_return_obj;
 
 void jsonlex_setup(char const *s, size_t l);
+void jsonlex_cleanup(void);
 void jsonlex_diag(const char *s);
 int json_unescape(char c, char *o);
 
diff --git a/grecs/include/grecs/list.h b/grecs/include/grecs/list.h
index a5840db..f950176 100644
--- a/grecs/include/grecs/list.h
+++ b/grecs/include/grecs/list.h
@@ -41,6 +41,7 @@ void *grecs_list_locate(grecs_list_ptr_t, void *);
 void *grecs_list_index(grecs_list_ptr_t, size_t);
 void *grecs_list_remove_tail(grecs_list_ptr_t);
 void grecs_list_remove_entry(grecs_list_ptr_t, grecs_list_entry_ptr_t);
+int grecs_list_remove(struct grecs_list *lp, void *data);
 void grecs_list_clear(grecs_list_ptr_t);
 void grecs_list_free(grecs_list_ptr_t);
 void grecs_list_add(grecs_list_ptr_t, grecs_list_ptr_t);
diff --git a/grecs/include/grecs/node.h b/grecs/include/grecs/node.h
index 2d879ad..752b002 100644
--- a/grecs/include/grecs/node.h
+++ b/grecs/include/grecs/node.h
@@ -35,7 +35,7 @@ typedef struct grecs_node {
 	struct grecs_node *next;
 	struct grecs_node *prev;
 	char *ident;
-	grecs_locus_t idloc;
+	grecs_locus_t idloc;       /* Location of the identifier */
 	union {
 		grecs_value_t *value;
 		grecs_symtab_ptr_t texttab;
diff --git a/grecs/include/grecs/parser.h b/grecs/include/grecs/parser.h
index 00878f4..41b3ae4 100644
--- a/grecs/include/grecs/parser.h
+++ b/grecs/include/grecs/parser.h
@@ -28,9 +28,12 @@ extern int grecs_default_port;
 
 extern struct grecs_locus_point grecs_current_locus_point;
 extern grecs_locus_t grecs_locus;
-extern int grecs_adjust_string_locations;
 extern int grecs_error_count;    
 
+#define GRECS_OPTION_ADJUST_STRING_LOCATIONS 0x01
+#define GRECS_OPTION_QUOTED_STRING_CONCAT    0x02
+extern int grecs_parser_options;
+
 /* Main entry point */
 struct grecs_node *grecs_parse(const char *name);
 void grecs_gram_trace(int n);
diff --git a/grecs/include/grecs/sockaddr.h b/grecs/include/grecs/sockaddr.h
index c8a3de2..b999364 100644
--- a/grecs/include/grecs/sockaddr.h
+++ b/grecs/include/grecs/sockaddr.h
@@ -1,5 +1,5 @@
 /* grecs - Gray's Extensible Configuration System -*- c -*-
-   Copyright (C) 2007-2016 Sergey Poznyakoff
+   Copyright (C) 2007-2017 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
@@ -20,6 +20,7 @@
 struct grecs_sockaddr {
 #if GRECS_SOCKADDR_LIST
 	struct grecs_sockaddr *next;
+	char *str;
 #endif
 	int len;
 	struct sockaddr *sa;
@@ -45,6 +46,7 @@ void grecs_sockaddr_free(struct grecs_sockaddr *p);
 int grecs_str_to_sockaddr(struct grecs_sockaddr **sap,
 			  const char *arg, struct grecs_sockaddr_hints *gh,
 			  grecs_locus_t const *locus);
+char const *grecs_sockaddr_str(struct grecs_sockaddr *);
 #endif
 
 #define GRECS_INADDR_BYTES 16
diff --git a/grecs/include/grecs/symtab.h b/grecs/include/grecs/symtab.h
index 3008b17..e079ea5 100644
--- a/grecs/include/grecs/symtab.h
+++ b/grecs/include/grecs/symtab.h
@@ -42,10 +42,10 @@ grecs_symtab_ptr_t grecs_symtab_create_default(size_t elsize);
 void grecs_symtab_free(grecs_symtab_ptr_t pst);
 int grecs_symtab_remove(grecs_symtab_ptr_t st, void *elt);
 int grecs_symtab_replace(grecs_symtab_ptr_t st, void *ent, void **old_ent);
-int grecs_symtab_enumerate(grecs_symtab_ptr_t st,
-			   grecs_symtab_enumerator_t fun, void *data);
+int grecs_symtab_foreach(grecs_symtab_ptr_t st,
+			 grecs_symtab_enumerator_t fun, void *data);
 
-size_t grecs_symtab_count_entries(grecs_symtab_ptr_t st);
+size_t grecs_symtab_count(grecs_symtab_ptr_t st);
 
 unsigned grecs_hash_string(const char *name, unsigned long hashsize);
 unsigned grecs_hash_string_ci(const char *name, unsigned long hashsize);
diff --git a/grecs/include/grecs/tree.h b/grecs/include/grecs/tree.h
index 2fb26dd..f13a74b 100644
--- a/grecs/include/grecs/tree.h
+++ b/grecs/include/grecs/tree.h
@@ -67,5 +67,13 @@ struct grecs_node *grecs_match_buf_get_node(grecs_match_buf_t buf);
 size_t grecs_match_buf_get_args(grecs_match_buf_t buf, char ***argv);
 struct grecs_node *grecs_match_buf_get_root(grecs_match_buf_t buf);
 void grecs_match_buf_set_root(grecs_match_buf_t buf, struct grecs_node *root);
+
+/* Assertions */
+int grecs_assert_value_type(const grecs_value_t *value, int type,
+			    grecs_locus_t *refloc);
+int grecs_assert_scalar_stmt(grecs_locus_t *locus,
+			     enum grecs_callback_command cmd);
+int grecs_assert_node_value_type(enum grecs_callback_command cmd,
+				 grecs_node_t *node, int type);
 
 #endif
diff --git a/grecs/include/grecs/value.h b/grecs/include/grecs/value.h
index 8cd2800..480db9d 100644
--- a/grecs/include/grecs/value.h
+++ b/grecs/include/grecs/value.h
@@ -44,6 +44,7 @@ typedef struct grecs_value {
 void grecs_value_free(struct grecs_value *val);
 void grecs_value_free_content(struct grecs_value *val);
 grecs_value_t *grecs_value_ptr_from_static(grecs_value_t *input);
+const char *grecs_value_type_string(int t);
 
 int grecs_value_eq(struct grecs_value *a, struct grecs_value *b);
 int grecs_value_match(struct grecs_value *pat, struct grecs_value *b,
diff --git a/grecs/src/Make-inst.am b/grecs/src/Make-inst.am
index a4b6aea..1eb04bb 100644
--- a/grecs/src/Make-inst.am
+++ b/grecs/src/Make-inst.am
@@ -1,5 +1,5 @@
 # This file is part of grecs - Gray's Extensible Configuration System
-# Copyright (C) 2007-2016 Sergey Poznyakoff
+# Copyright (C) 2007-2019 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
@@ -19,3 +19,5 @@ lib_LTLIBRARIES=libgrecs.la
 libgrecs_la_SOURCES = $(GRECS_SRC)
 m4datadir = $(datadir)/aclocal
 dist_m4data_DATA = libgrecs.m4
+nodist_libgrecs_la_SOURCES = $(NODIST_GRECS_SRC)
+
diff --git a/grecs/src/Make-shared.am b/grecs/src/Make-shared.am
index 9a762a4..f080e46 100644
--- a/grecs/src/Make-shared.am
+++ b/grecs/src/Make-shared.am
@@ -1,5 +1,5 @@
 # This file is part of grecs - Gray's Extensible Configuration System
-# Copyright (C) 2007-2016 Sergey Poznyakoff
+# Copyright (C) 2007-2019 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
@@ -16,4 +16,5 @@
 include Make.am
 noinst_LTLIBRARIES=libgrecs.la
 libgrecs_la_SOURCES = $(GRECS_SRC)
+nodist_libgrecs_la_SOURCES = $(NODIST_GRECS_SRC)
 
diff --git a/grecs/src/Make-static.am b/grecs/src/Make-static.am
index 2688b40..1f4cd3e 100644
--- a/grecs/src/Make-static.am
+++ b/grecs/src/Make-static.am
@@ -1,5 +1,5 @@
 # This file is part of grecs - Gray's Extensible Configuration System
-# Copyright (C) 2007-2016 Sergey Poznyakoff
+# Copyright (C) 2007-2019 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
@@ -16,5 +16,6 @@
 include Make.am
 noinst_LIBRARIES=libgrecs.a
 libgrecs_a_SOURCES = $(GRECS_SRC)
+nodist_libgrecs_a_SOURCES = $(NODIST_GRECS_SRC)
 
 
diff --git a/grecs/src/Make-static.in b/grecs/src/Make-static.in
index 62298f6..f0d2596 100644
--- a/grecs/src/Make-static.in
+++ b/grecs/src/Make-static.in
@@ -1,7 +1,7 @@
-# Make-static.in generated by automake 1.14 from Make-static.am.
+# Make-static.in generated by automake 1.15 from Make-static.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,7 @@
 @SET_MAKE@
 
 # This file is part of grecs - Gray's Extensible Configuration System
-# Copyright (C) 2007-2016 Sergey Poznyakoff
+# Copyright (C) 2007-2019 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
@@ -31,8 +31,17 @@
 # along with Grecs.  If not, see <http://www.gnu.org/licenses/>.
 
 
-VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -95,11 +104,6 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-DIST_COMMON = $(srcdir)/Make.am $(srcdir)/Make-static.in \
-	$(srcdir)/Make-static.am grecs-gram.c grecs-lex.c json-gram.c \
-	json-lex.c bind-gram.c bind-lex.c dhcpd-gram.c dhcpd-lex.c \
-	meta1-gram.c meta1-lex.c $(top_srcdir)/build-aux/depcomp \
-	$(top_srcdir)/build-aux/ylwrap
 @GRECS_COND_META1_PARSER_TRUE@am__append_1 = -DENABLE_META1_PARSER
 @GRECS_COND_BIND_PARSER_TRUE@am__append_2 = -DENABLE_BIND_PARSER
 @GRECS_COND_DHCPD_PARSER_TRUE@am__append_3 = -DENABLE_DHCPD_PARSER
@@ -116,6 +120,7 @@ am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Make-static.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -129,11 +134,11 @@ am__v_AR_0 = @echo "  AR      " $@;
 am__v_AR_1 = 
 libgrecs_a_AR = $(AR) $(ARFLAGS)
 libgrecs_a_LIBADD =
-am__libgrecs_a_SOURCES_DIST = asprintf.c cidr.c diag.c format.c \
-	grecs-gram.y grecs-lex.l ipstr.c join.c lineacc.c list.c \
-	lookup.c mem.c opthelp.c parser.c parsertab.c path-parser.c \
-	preproc.c sort.c symtab.c text.c tree.c txtacc.c version.c \
-	wordsplit.c json-gram.y json-lex.l jsonfmt.c bind-gram.y \
+am__libgrecs_a_SOURCES_DIST = asprintf.c assert.c cidr.c diag.c \
+	format.c grecs-gram.y grecs-lex.l ipstr.c join.c lineacc.c \
+	list.c lookup.c mem.c opthelp.c parser.c parsertab.c \
+	path-parser.c preproc.c sort.c symtab.c text.c tree.c txtacc.c \
+	version.c json-gram.y json-lex.l jsonfmt.c bind-gram.y \
 	bind-lex.l dhcpd-gram.y dhcpd-lex.l git-parser.c meta1-gram.y \
 	meta1-lex.l sockaddr.c
 @GRECS_COND_JSON_TRUE@am__objects_1 = json-gram.$(OBJEXT) \
@@ -146,18 +151,21 @@ am__libgrecs_a_SOURCES_DIST = asprintf.c cidr.c diag.c format.c \
 @GRECS_COND_META1_PARSER_TRUE@am__objects_5 = meta1-gram.$(OBJEXT) \
 @GRECS_COND_META1_PARSER_TRUE@	meta1-lex.$(OBJEXT)
 @GRECS_COND_SOCKADDR_LIST_TRUE@am__objects_6 = sockaddr.$(OBJEXT)
-am__objects_7 = asprintf.$(OBJEXT) cidr.$(OBJEXT) diag.$(OBJEXT) \
-	format.$(OBJEXT) grecs-gram.$(OBJEXT) grecs-lex.$(OBJEXT) \
-	ipstr.$(OBJEXT) join.$(OBJEXT) lineacc.$(OBJEXT) \
-	list.$(OBJEXT) lookup.$(OBJEXT) mem.$(OBJEXT) \
-	opthelp.$(OBJEXT) parser.$(OBJEXT) parsertab.$(OBJEXT) \
-	path-parser.$(OBJEXT) preproc.$(OBJEXT) sort.$(OBJEXT) \
-	symtab.$(OBJEXT) text.$(OBJEXT) tree.$(OBJEXT) \
-	txtacc.$(OBJEXT) version.$(OBJEXT) wordsplit.$(OBJEXT) \
-	$(am__objects_1) $(am__objects_2) $(am__objects_3) \
-	$(am__objects_4) $(am__objects_5) $(am__objects_6)
+am__objects_7 = asprintf.$(OBJEXT) assert.$(OBJEXT) cidr.$(OBJEXT) \
+	diag.$(OBJEXT) format.$(OBJEXT) grecs-gram.$(OBJEXT) \
+	grecs-lex.$(OBJEXT) ipstr.$(OBJEXT) join.$(OBJEXT) \
+	lineacc.$(OBJEXT) list.$(OBJEXT) lookup.$(OBJEXT) \
+	mem.$(OBJEXT) opthelp.$(OBJEXT) parser.$(OBJEXT) \
+	parsertab.$(OBJEXT) path-parser.$(OBJEXT) preproc.$(OBJEXT) \
+	sort.$(OBJEXT) symtab.$(OBJEXT) text.$(OBJEXT) tree.$(OBJEXT) \
+	txtacc.$(OBJEXT) version.$(OBJEXT) $(am__objects_1) \
+	$(am__objects_2) $(am__objects_3) $(am__objects_4) \
+	$(am__objects_5) $(am__objects_6)
 am_libgrecs_a_OBJECTS = $(am__objects_7)
-libgrecs_a_OBJECTS = $(am_libgrecs_a_OBJECTS)
+am__objects_8 = wordsplit.$(OBJEXT)
+nodist_libgrecs_a_OBJECTS = $(am__objects_8)
+libgrecs_a_OBJECTS = $(am_libgrecs_a_OBJECTS) \
+	$(nodist_libgrecs_a_OBJECTS)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -197,7 +205,7 @@ AM_V_YACC = $(am__v_YACC_@AM_V@)
 am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@)
 am__v_YACC_0 = @echo "  YACC    " $@;
 am__v_YACC_1 = 
-SOURCES = $(libgrecs_a_SOURCES)
+SOURCES = $(libgrecs_a_SOURCES) $(nodist_libgrecs_a_SOURCES)
 DIST_SOURCES = $(am__libgrecs_a_SOURCES_DIST)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
@@ -252,7 +260,12 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Make-static.in $(srcdir)/Make.am \
+	$(top_srcdir)/build-aux/depcomp $(top_srcdir)/build-aux/ylwrap \
+	bind-gram.c bind-lex.c dhcpd-gram.c dhcpd-lex.c grecs-gram.c \
+	grecs-lex.c json-gram.c json-lex.c meta1-gram.c meta1-lex.c
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+VPATH = @srcdir@ $(top_srcdir)/@GRECS_SUBDIR@/wordsplit
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
@@ -283,7 +296,9 @@ GRECS_CHANGELOG = @GRECS_CHANGELOG@
 GRECS_DISTCK_AT = @GRECS_DISTCK_AT@
 GRECS_DISTDOC = @GRECS_DISTDOC@
 GRECS_DOCDIR = @GRECS_DOCDIR@
+GRECS_EXTRA_DIST = @GRECS_EXTRA_DIST@
 GRECS_HOST_PROJECT_INCLUDES = @GRECS_HOST_PROJECT_INCLUDES@
+GRECS_HOST_PROJECT_LDADD = @GRECS_HOST_PROJECT_LDADD@
 GRECS_INCLUDES = @GRECS_INCLUDES@
 GRECS_INCLUDE_DIR = @GRECS_INCLUDE_DIR@
 GRECS_LDADD = @GRECS_LDADD@
@@ -403,12 +418,13 @@ PARSER_DEFS = $(am__append_1) $(am__append_2) $(am__append_3) \
 @GRECS_COND_GIT_PARSER_TRUE@GRECS_PARSER_GIT = git-parser.c
 @GRECS_COND_JSON_TRUE@GRECS_JSON = json-gram.y json-lex.l jsonfmt.c
 @GRECS_COND_JSON_TRUE@GRECS_EXTRA_JSON = json-gram.h
-GRECS_SRC = asprintf.c cidr.c diag.c format.c grecs-gram.y grecs-lex.l \
-	ipstr.c join.c lineacc.c list.c lookup.c mem.c opthelp.c \
-	parser.c parsertab.c path-parser.c preproc.c sort.c symtab.c \
-	text.c tree.c txtacc.c version.c wordsplit.c $(GRECS_JSON) \
+GRECS_SRC = asprintf.c assert.c cidr.c diag.c format.c grecs-gram.y \
+	grecs-lex.l ipstr.c join.c lineacc.c list.c lookup.c mem.c \
+	opthelp.c parser.c parsertab.c path-parser.c preproc.c sort.c \
+	symtab.c text.c tree.c txtacc.c version.c $(GRECS_JSON) \
 	$(GRECS_PARSER_BIND) $(GRECS_PARSER_DHCPD) $(GRECS_PARSER_GIT) \
 	$(GRECS_PARSER_META1) $(am__append_5)
+NODIST_GRECS_SRC = wordsplit.c
 EXTRA_DIST = \
  grecs-gram.h\
  $(GRECS_EXTRA_BIND)\
@@ -433,7 +449,7 @@ LEXCOMPILE = $(top_srcdir)/@GRECS_SUBDIR@/build-aux/yyrename '$(LEX) $(LFLAGS) $
 YACCCOMPILE = $(top_srcdir)/@GRECS_SUBDIR@/build-aux/yyrename '$(YACC) $(YFLAGS) $(AM_YFLAGS)'
 
 # This file is part of grecs - Gray's Extensible Configuration System
-# Copyright (C) 2007-2016 Sergey Poznyakoff
+# Copyright (C) 2007-2019 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
@@ -449,6 +465,7 @@ YACCCOMPILE = $(top_srcdir)/@GRECS_SUBDIR@/build-aux/yyrename '$(YACC) $(YFLAGS)
 # along with Grecs.  If not, see <http://www.gnu.org/licenses/>.
 noinst_LIBRARIES = libgrecs.a
 libgrecs_a_SOURCES = $(GRECS_SRC)
+nodist_libgrecs_a_SOURCES = $(NODIST_GRECS_SRC)
 all: all-am
 
 .SUFFIXES:
@@ -465,7 +482,6 @@ $(srcdir)/Make-static.in:  $(srcdir)/Make-static.am $(srcdir)/Make.am $(am__conf
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits grecs/src/Makefile:grecs/src/Make-static.in'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnits grecs/src/Makefile:grecs/src/Make-static.in
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Make-static.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -474,7 +490,7 @@ Makefile: $(srcdir)/Make-static.in $(top_builddir)/config.status
 	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
 	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
 	esac;
-$(srcdir)/Make.am:
+$(srcdir)/Make.am $(am__empty):
 
 $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
@@ -500,6 +516,7 @@ distclean-compile:
 	-rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asprintf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/assert.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bind-gram.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bind-lex.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cidr.Po@am__quote@
@@ -789,6 +806,8 @@ uninstall-am: uninstall-incDATA
 	mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am uninstall-incDATA
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/grecs/src/Make.am b/grecs/src/Make.am
index 227973e..5199991 100644
--- a/grecs/src/Make.am
+++ b/grecs/src/Make.am
@@ -1,5 +1,5 @@
 # This file is part of grecs - Gray's Extensible Configuration System
-# Copyright (C) 2007-2016 Sergey Poznyakoff
+# Copyright (C) 2007-2019 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
@@ -46,6 +46,7 @@ endif
 
 GRECS_SRC = \
  asprintf.c\
+ assert.c\
  cidr.c\
  diag.c\
  format.c\
@@ -68,13 +69,15 @@ GRECS_SRC = \
  tree.c\
  txtacc.c\
  version.c\
- wordsplit.c\
  $(GRECS_JSON)\
  $(GRECS_PARSER_BIND)\
  $(GRECS_PARSER_DHCPD)\
  $(GRECS_PARSER_GIT)\
  $(GRECS_PARSER_META1)
 
+VPATH += $(top_srcdir)/@GRECS_SUBDIR@/wordsplit
+NODIST_GRECS_SRC = wordsplit.c
+
 if GRECS_COND_SOCKADDR_LIST
   GRECS_SRC += sockaddr.c
 endif  
diff --git a/grecs/src/assert.c b/grecs/src/assert.c
new file mode 100644
index 0000000..c1cfc01
--- /dev/null
+++ b/grecs/src/assert.c
@@ -0,0 +1,58 @@
+/* grecs - Gray's Extensible Configuration System
+   Copyright (C) 2007-2019 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 <errno.h>
+#include <grecs.h>
+
+int
+grecs_assert_value_type(const grecs_value_t *value, int type,
+			grecs_locus_t *refloc)
+{
+	if (GRECS_VALUE_EMPTY_P(value)) {
+		grecs_error(refloc, 0, _("expected %s"),
+			    gettext(grecs_value_type_string(type)));
+		return 1;
+	}
+	if (value->type != type) {
+		grecs_error(&value->locus, 0, _("expected %s, but found %s"),
+			    gettext(grecs_value_type_string(type)),
+			    gettext(grecs_value_type_string(value->type)));
+		return 1;
+	}
+	return 0;
+}
+
+int
+grecs_assert_scalar_stmt(grecs_locus_t *locus, enum grecs_callback_command cmd)
+{
+	if (cmd != grecs_callback_set_value) {
+		grecs_error(locus, 0, _("unexpected block statement"));
+		return 1;
+	}
+	return 0;
+}
+
+int
+grecs_assert_node_value_type(enum grecs_callback_command cmd,
+			     grecs_node_t *node, int type)
+{
+	return grecs_assert_scalar_stmt(&node->locus, cmd)
+		|| grecs_assert_value_type(node->v.value, type,
+					   &node->locus);
+}
diff --git a/grecs/src/bind-gram.c b/grecs/src/bind-gram.c
index bc85fe2..c38eddf 100644
--- a/grecs/src/bind-gram.c
+++ b/grecs/src/bind-gram.c
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 2.5.1.  */
+/* A Bison parser, made by GNU Bison 2.7.  */
 
 /* Bison implementation for Yacc-like parsers in C
    
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.5.1"
+#define YYBISON_VERSION "2.7"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -58,14 +58,11 @@
 /* Pull parsers.  */
 #define YYPULL 1
 
-/* Using locations.  */
-#define YYLSP_NEEDED 1
 
 
 
 /* Copy the first part of user declarations.  */
-
-/* Line 268 of yacc.c  */
+/* Line 371 of yacc.c  */
 #line 1 "bind-gram.y"
 
 /* grecs - Gray's Extensible Configuration System
@@ -104,9 +101,8 @@ extern void grecs_bind_close_sources(void);
 
 static struct grecs_value *stmtlist_to_value(struct grecs_node *node);
 
-
-/* Line 268 of yacc.c  */
-#line 110 "bind-gram.c"
+/* Line 371 of yacc.c  */
+#line 106 "bind-gram.c"
 
 # ifndef YY_NULL
 #  if defined __cplusplus && 201103L <= __cplusplus
@@ -116,11 +112,6 @@ static struct grecs_value *stmtlist_to_value(struct grecs_node *node);
 #  endif
 # endif
 
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 1
-#endif
-
 /* Enabling verbose error messages.  */
 #ifdef YYERROR_VERBOSE
 # undef YYERROR_VERBOSE
@@ -129,11 +120,17 @@ static struct grecs_value *stmtlist_to_value(struct grecs_node *node);
 # define YYERROR_VERBOSE 1
 #endif
 
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
+/* In a future release of Bison, this section will be replaced
+   by #include "y.tab.h".  */
+#ifndef YY_YY_Y_TAB_H_INCLUDED
+# define YY_YY_Y_TAB_H_INCLUDED
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int grecs_bind_debug;
 #endif
-
 
 /* Tokens.  */
 #ifndef YYTOKENTYPE
@@ -153,12 +150,10 @@ static struct grecs_value *stmtlist_to_value(struct grecs_node *node);
 
 
 
-
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
 {
-
-/* Line 295 of yacc.c  */
+/* Line 387 of yacc.c  */
 #line 42 "bind-gram.y"
 
 	char *string;
@@ -169,9 +164,8 @@ typedef union YYSTYPE
 	struct { struct grecs_node *head, *tail; } node_list;
 
 
-
-/* Line 295 of yacc.c  */
-#line 175 "bind-gram.c"
+/* Line 387 of yacc.c  */
+#line 169 "bind-gram.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define grecs_bind_stype YYSTYPE /* obsolescent; will be withdrawn */
@@ -191,12 +185,28 @@ typedef struct YYLTYPE
 # define YYLTYPE_IS_TRIVIAL 1
 #endif
 
+extern YYSTYPE grecs_bind_lval;
+extern YYLTYPE grecs_bind_lloc;
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int grecs_bind_parse (void *YYPARSE_PARAM);
+#else
+int grecs_bind_parse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int grecs_bind_parse (void);
+#else
+int grecs_bind_parse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_YY_Y_TAB_H_INCLUDED  */
 
 /* Copy the second part of user declarations.  */
 
-
-/* Line 345 of yacc.c  */
-#line 200 "bind-gram.c"
+/* Line 390 of yacc.c  */
+#line 210 "bind-gram.c"
 
 #ifdef short
 # undef short
@@ -249,24 +259,24 @@ typedef short int grecs_bind_type_int16;
 # if defined YYENABLE_NLS && YYENABLE_NLS
 #  if ENABLE_NLS
 #   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
 #  endif
 # endif
 # ifndef YY_
-#  define YY_(msgid) msgid
+#  define YY_(Msgid) Msgid
 # endif
 #endif
 
 /* Suppress unused-variable warnings by "using" E.  */
 #if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
+# define YYUSE(E) ((void) (E))
 #else
-# define YYUSE(e) /* empty */
+# define YYUSE(E) /* empty */
 #endif
 
 /* Identity function, used to suppress warnings about constant conditions.  */
 #ifndef lint
-# define YYID(n) (n)
+# define YYID(N) (N)
 #else
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
@@ -499,7 +509,7 @@ static const grecs_bind_type_uint8 grecs_bind_rline[] =
 };
 #endif
 
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+#if YYDEBUG || YYERROR_VERBOSE || 1
 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const grecs_bind_tname[] =
@@ -585,10 +595,10 @@ static const grecs_bind_type_int8 grecs_bind_table[] =
        0,     0,     0,    37
 };
 
-#define grecs_bind_pact_value_is_default(grecs_bind_state) \
-  ((grecs_bind_state) == (-14))
+#define grecs_bind_pact_value_is_default(Yystate) \
+  (!!((Yystate) == (-14)))
 
-#define grecs_bind_table_value_is_error(grecs_bind_table_value) \
+#define grecs_bind_table_value_is_error(Yytable_value) \
   YYID (0)
 
 static const grecs_bind_type_int8 grecs_bind_check[] =
@@ -654,7 +664,7 @@ do                                                              \
     }								\
 while (YYID (0))
 
-
+/* Error token number */
 #define YYTERROR	1
 #define YYERRCODE	256
 
@@ -663,27 +673,28 @@ while (YYID (0))
    If N is 0, then set CURRENT to the empty location which ends
    the previous symbol: RHS[0] (always defined).  */
 
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
 #ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)				\
-    do									\
-      if (YYID (N))                                                    \
-	{								\
-	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
-	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
-	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
-	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
-	}								\
-      else								\
-	{								\
-	  (Current).first_line   = (Current).last_line   =		\
-	    YYRHSLOC (Rhs, 0).last_line;				\
-	  (Current).first_column = (Current).last_column =		\
-	    YYRHSLOC (Rhs, 0).last_column;				\
-	}								\
+# define YYLLOC_DEFAULT(Current, Rhs, N)                                \
+    do                                                                  \
+      if (YYID (N))                                                     \
+        {                                                               \
+          (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
+          (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
+          (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
+          (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
+        }                                                               \
+      else                                                              \
+        {                                                               \
+          (Current).first_line   = (Current).last_line   =              \
+            YYRHSLOC (Rhs, 0).last_line;                                \
+          (Current).first_column = (Current).last_column =              \
+            YYRHSLOC (Rhs, 0).last_column;                              \
+        }                                                               \
     while (YYID (0))
 #endif
 
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
 
 /* YY_LOCATION_PRINT -- Print the location on the stream.
    This macro was not mandated originally: define only if we know
@@ -691,10 +702,46 @@ while (YYID (0))
 
 #ifndef YY_LOCATION_PRINT
 # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)			\
-     fprintf (File, "%d.%d-%d.%d",			\
-	      (Loc).first_line, (Loc).first_column,	\
-	      (Loc).last_line,  (Loc).last_column)
+
+/* Print *YYLOCP on YYO.  Private, do not rely on its existence. */
+
+__attribute__((__unused__))
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static unsigned
+grecs_bind__location_print_ (FILE *grecs_bind_o, YYLTYPE const * const grecs_bind_locp)
+#else
+static unsigned
+grecs_bind__location_print_ (grecs_bind_o, grecs_bind_locp)
+    FILE *grecs_bind_o;
+    YYLTYPE const * const grecs_bind_locp;
+#endif
+{
+  unsigned res = 0;
+  int end_col = 0 != grecs_bind_locp->last_column ? grecs_bind_locp->last_column - 1 : 0;
+  if (0 <= grecs_bind_locp->first_line)
+    {
+      res += fprintf (grecs_bind_o, "%d", grecs_bind_locp->first_line);
+      if (0 <= grecs_bind_locp->first_column)
+        res += fprintf (grecs_bind_o, ".%d", grecs_bind_locp->first_column);
+    }
+  if (0 <= grecs_bind_locp->last_line)
+    {
+      if (grecs_bind_locp->first_line < grecs_bind_locp->last_line)
+        {
+          res += fprintf (grecs_bind_o, "-%d", grecs_bind_locp->last_line);
+          if (0 <= end_col)
+            res += fprintf (grecs_bind_o, ".%d", end_col);
+        }
+      else if (0 <= end_col && grecs_bind_locp->first_column < end_col)
+        res += fprintf (grecs_bind_o, "-%d", end_col);
+    }
+  return res;
+ }
+
+#  define YY_LOCATION_PRINT(File, Loc)          \
+  grecs_bind__location_print_ (File, &(Loc))
+
 # else
 #  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
 # endif
@@ -702,7 +749,6 @@ while (YYID (0))
 
 
 /* YYLEX -- calling `grecs_bind_lex' with the right arguments.  */
-
 #ifdef YYLEX_PARAM
 # define YYLEX grecs_bind_lex (YYLEX_PARAM)
 #else
@@ -767,7 +813,7 @@ grecs_bind__symbol_value_print (grecs_bind_output, grecs_bind_type, grecs_bind_v
   switch (grecs_bind_type)
     {
       default:
-	break;
+        break;
     }
 }
 
@@ -1013,7 +1059,6 @@ grecs_bind_syntax_error (YYSIZE_T *grecs_bind_msg_alloc, char **grecs_bind_msg,
 {
   YYSIZE_T grecs_bind_size0 = grecs_bind_tnamerr (YY_NULL, grecs_bind_tname[grecs_bind_token]);
   YYSIZE_T grecs_bind_size = grecs_bind_size0;
-  YYSIZE_T grecs_bind_size1;
   enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
   /* Internationalized format string. */
   const char *grecs_bind_format = YY_NULL;
@@ -1076,11 +1121,13 @@ grecs_bind_syntax_error (YYSIZE_T *grecs_bind_msg_alloc, char **grecs_bind_msg,
                     break;
                   }
                 grecs_bind_arg[grecs_bind_count++] = grecs_bind_tname[grecs_bind_x];
-                grecs_bind_size1 = grecs_bind_size + grecs_bind_tnamerr (YY_NULL, grecs_bind_tname[grecs_bind_x]);
-                if (! (grecs_bind_size <= grecs_bind_size1
-                       && grecs_bind_size1 <= YYSTACK_ALLOC_MAXIMUM))
-                  return 2;
-                grecs_bind_size = grecs_bind_size1;
+                {
+                  YYSIZE_T grecs_bind_size1 = grecs_bind_size + grecs_bind_tnamerr (YY_NULL, grecs_bind_tname[grecs_bind_x]);
+                  if (! (grecs_bind_size <= grecs_bind_size1
+                         && grecs_bind_size1 <= YYSTACK_ALLOC_MAXIMUM))
+                    return 2;
+                  grecs_bind_size = grecs_bind_size1;
+                }
               }
         }
     }
@@ -1100,10 +1147,12 @@ grecs_bind_syntax_error (YYSIZE_T *grecs_bind_msg_alloc, char **grecs_bind_msg,
 # undef YYCASE_
     }
 
-  grecs_bind_size1 = grecs_bind_size + grecs_bind_strlen (grecs_bind_format);
-  if (! (grecs_bind_size <= grecs_bind_size1 && grecs_bind_size1 <= YYSTACK_ALLOC_MAXIMUM))
-    return 2;
-  grecs_bind_size = grecs_bind_size1;
+  {
+    YYSIZE_T grecs_bind_size1 = grecs_bind_size + grecs_bind_strlen (grecs_bind_format);
+    if (! (grecs_bind_size <= grecs_bind_size1 && grecs_bind_size1 <= YYSTACK_ALLOC_MAXIMUM))
+      return 2;
+    grecs_bind_size = grecs_bind_size1;
+  }
 
   if (*grecs_bind_msg_alloc < grecs_bind_size)
     {
@@ -1165,35 +1214,35 @@ grecs_bind_destruct (grecs_bind_msg, grecs_bind_type, grecs_bind_valuep, grecs_b
     {
 
       default:
-	break;
+        break;
     }
 }
 
 
-/* Prevent warnings from -Wmissing-prototypes.  */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int grecs_bind_parse (void *YYPARSE_PARAM);
-#else
-int grecs_bind_parse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int grecs_bind_parse (void);
-#else
-int grecs_bind_parse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
 
 
 /* The lookahead symbol.  */
 int grecs_bind_char;
 
+
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
 /* The semantic value of the lookahead symbol.  */
-YYSTYPE grecs_bind_lval;
+YYSTYPE grecs_bind_lval YY_INITIAL_VALUE(grecs_bind_val_default);
 
 /* Location data for the lookahead symbol.  */
-YYLTYPE grecs_bind_lloc;
+YYLTYPE grecs_bind_lloc
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  = { 1, 1, 1, 1 }
+# endif
+;
+
 
 /* Number of syntax errors so far.  */
 int grecs_bind_nerrs;
@@ -1260,7 +1309,7 @@ grecs_bind_parse ()
   int grecs_bind_n;
   int grecs_bind_result;
   /* Lookahead token as an internal (translated) token number.  */
-  int grecs_bind_token;
+  int grecs_bind_token = 0;
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE grecs_bind_val;
@@ -1279,10 +1328,9 @@ grecs_bind_parse ()
      Keep to zero when no symbol should be popped.  */
   int grecs_bind_len = 0;
 
-  grecs_bind_token = 0;
-  grecs_bind_ss = grecs_bind_ssa;
-  grecs_bind_vs = grecs_bind_vsa;
-  grecs_bind_ls = grecs_bind_lsa;
+  grecs_bind_ssp = grecs_bind_ss = grecs_bind_ssa;
+  grecs_bind_vsp = grecs_bind_vs = grecs_bind_vsa;
+  grecs_bind_lsp = grecs_bind_ls = grecs_bind_lsa;
   grecs_bind_stacksize = YYINITDEPTH;
 
   YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1291,21 +1339,7 @@ grecs_bind_parse ()
   grecs_bind_errstatus = 0;
   grecs_bind_nerrs = 0;
   grecs_bind_char = YYEMPTY; /* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-  grecs_bind_ssp = grecs_bind_ss;
-  grecs_bind_vsp = grecs_bind_vs;
-  grecs_bind_lsp = grecs_bind_ls;
-
-#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-  /* Initialize the default location before parsing starts.  */
-  grecs_bind_lloc.first_line   = grecs_bind_lloc.last_line   = 1;
-  grecs_bind_lloc.first_column = grecs_bind_lloc.last_column = 1;
-#endif
-
+  grecs_bind_lsp[0] = grecs_bind_lloc;
   goto grecs_bind_setstate;
 
 /*------------------------------------------------------------.
@@ -1451,7 +1485,9 @@ grecs_bind_backup:
   grecs_bind_char = YYEMPTY;
 
   grecs_bind_state = grecs_bind_n;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++grecs_bind_vsp = grecs_bind_lval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
   *++grecs_bind_lsp = grecs_bind_lloc;
   goto grecs_bind_newstate;
 
@@ -1489,8 +1525,7 @@ grecs_bind_reduce:
   switch (grecs_bind_n)
     {
         case 2:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 62 "bind-gram.y"
     {
 		  parse_tree = grecs_node_create(grecs_node_root, &(grecs_bind_lsp[(1) - (1)]));
@@ -1500,8 +1535,7 @@ grecs_bind_reduce:
     break;
 
   case 3:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 71 "bind-gram.y"
     {
 		  (grecs_bind_val.node) = NULL;
@@ -1509,8 +1543,7 @@ grecs_bind_reduce:
     break;
 
   case 4:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 75 "bind-gram.y"
     {
 		  (grecs_bind_val.node) = (grecs_bind_vsp[(1) - (1)].node_list).head;
@@ -1518,8 +1551,7 @@ grecs_bind_reduce:
     break;
 
   case 5:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 81 "bind-gram.y"
     {
 		  (grecs_bind_val.node_list).head = (grecs_bind_val.node_list).tail = (grecs_bind_vsp[(1) - (1)].node);
@@ -1527,8 +1559,7 @@ grecs_bind_reduce:
     break;
 
   case 6:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 85 "bind-gram.y"
     {
 		  if ((grecs_bind_vsp[(2) - (2)].node)) {
@@ -1542,8 +1573,7 @@ grecs_bind_reduce:
     break;
 
   case 9:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 101 "bind-gram.y"
     {
 		  if (strcmp((grecs_bind_vsp[(1) - (3)].string), "include") == 0 &&
@@ -1561,8 +1591,7 @@ grecs_bind_reduce:
     break;
 
   case 10:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 115 "bind-gram.y"
     {
 		  (grecs_bind_val.node) = grecs_node_create(grecs_node_stmt, &(grecs_bind_lsp[(1) - (2)]));
@@ -1573,8 +1602,7 @@ grecs_bind_reduce:
     break;
 
   case 11:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 122 "bind-gram.y"
     {
 		  (grecs_bind_val.node) = grecs_node_create_points(grecs_node_stmt,
@@ -1589,8 +1617,7 @@ grecs_bind_reduce:
     break;
 
   case 12:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 135 "bind-gram.y"
     {
 		  (grecs_bind_val.node) = grecs_node_create_points(grecs_node_block,
@@ -1603,8 +1630,7 @@ grecs_bind_reduce:
     break;
 
   case 13:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 156 "bind-gram.y"
     {
 		  (grecs_bind_val.node) = grecs_node_create_points(grecs_node_stmt,
@@ -1616,8 +1642,7 @@ grecs_bind_reduce:
     break;
 
   case 14:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 166 "bind-gram.y"
     {
 		  (grecs_bind_val.pvalue) = NULL;
@@ -1625,8 +1650,7 @@ grecs_bind_reduce:
     break;
 
   case 16:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 173 "bind-gram.y"
     {
 		  size_t n;
@@ -1652,8 +1676,7 @@ grecs_bind_reduce:
     break;
 
   case 17:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 197 "bind-gram.y"
     {
 		  (grecs_bind_val.list) = grecs_value_list_create();
@@ -1662,8 +1685,7 @@ grecs_bind_reduce:
     break;
 
   case 18:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 202 "bind-gram.y"
     {
 		  grecs_list_append((grecs_bind_vsp[(1) - (2)].list), grecs_value_ptr_from_static(&(grecs_bind_vsp[(2) - (2)].svalue)));
@@ -1671,8 +1693,7 @@ grecs_bind_reduce:
     break;
 
   case 19:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 208 "bind-gram.y"
     {
 		  (grecs_bind_val.svalue).type = GRECS_TYPE_STRING;
@@ -1682,8 +1703,7 @@ grecs_bind_reduce:
     break;
 
   case 22:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 220 "bind-gram.y"
     {
 		  (grecs_bind_val.svalue).type = GRECS_TYPE_LIST;
@@ -1693,8 +1713,7 @@ grecs_bind_reduce:
     break;
 
   case 23:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 228 "bind-gram.y"
     {
 		  (grecs_bind_val.list) = grecs_value_list_create();
@@ -1703,8 +1722,7 @@ grecs_bind_reduce:
     break;
 
   case 24:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 233 "bind-gram.y"
     {
 		  grecs_list_append((grecs_bind_vsp[(1) - (2)].list), grecs_value_ptr_from_static(&(grecs_bind_vsp[(2) - (2)].svalue)));
@@ -1712,8 +1730,7 @@ grecs_bind_reduce:
     break;
 
   case 25:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 237 "bind-gram.y"
     {
 		  grecs_list_append((grecs_bind_vsp[(1) - (4)].list), stmtlist_to_value((grecs_bind_vsp[(3) - (4)].node_list).head));
@@ -1722,9 +1739,8 @@ grecs_bind_reduce:
     break;
 
 
-
-/* Line 1810 of yacc.c  */
-#line 1728 "bind-gram.c"
+/* Line 1792 of yacc.c  */
+#line 1744 "bind-gram.c"
       default: break;
     }
   /* User semantic actions sometimes alter grecs_bind_char, and that requires
@@ -1889,7 +1905,9 @@ grecs_bind_errlab1:
       YY_STACK_PRINT (grecs_bind_ss, grecs_bind_ssp);
     }
 
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++grecs_bind_vsp = grecs_bind_lval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
 
   grecs_bind_error_range[2] = grecs_bind_lloc;
   /* Using YYLLOC is tempting, but would change the location of
@@ -1960,8 +1978,7 @@ grecs_bind_return:
 }
 
 
-
-/* Line 2071 of yacc.c  */
+/* Line 2055 of yacc.c  */
 #line 243 "bind-gram.y"
 
 
@@ -2044,4 +2061,3 @@ stmtlist_to_value(struct grecs_node *node)
 	grecs_txtacc_free(acc);
 	return val;
 }
-
diff --git a/grecs/src/bind-lex.c b/grecs/src/bind-lex.c
index 70369f5..d36009b 100644
--- a/grecs/src/bind-lex.c
+++ b/grecs/src/bind-lex.c
@@ -23,7 +23,7 @@
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
+#define YY_FLEX_SUBMINOR_VERSION 37
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -84,7 +84,6 @@ typedef int flex_int32_t;
 typedef unsigned char flex_uint8_t; 
 typedef unsigned short int flex_uint16_t;
 typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
 
 /* Limits of integral types. */
 #ifndef INT8_MIN
@@ -115,6 +114,8 @@ typedef unsigned int flex_uint32_t;
 #define UINT32_MAX             (4294967295U)
 #endif
 
+#endif /* ! C99 */
+
 #endif /* ! FLEXINT_H */
 
 /* %endif */
@@ -201,8 +202,13 @@ typedef unsigned int flex_uint32_t;
 typedef struct grecs_bind__buffer_state *YY_BUFFER_STATE;
 #endif
 
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t grecs_bind__size_t;
+#endif
+
 /* %if-not-reentrant */
-extern int grecs_bind_leng;
+extern grecs_bind__size_t grecs_bind_leng;
 /* %endif */
 
 /* %if-c-only */
@@ -233,11 +239,6 @@ extern FILE *grecs_bind_in, *grecs_bind_out;
 
 #define unput(c) grecs_bind_unput( c, (grecs_bind_text_ptr)  )
 
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t grecs_bind__size_t;
-#endif
-
 #ifndef YY_STRUCT_YY_BUFFER_STATE
 #define YY_STRUCT_YY_BUFFER_STATE
 struct grecs_bind__buffer_state
@@ -260,7 +261,7 @@ struct grecs_bind__buffer_state
 	/* Number of characters read into grecs_bind__ch_buf, not including EOB
 	 * characters.
 	 */
-	int grecs_bind__n_chars;
+	grecs_bind__size_t grecs_bind__n_chars;
 
 	/* Whether we "own" the buffer - i.e., we know we created it,
 	 * and can realloc() it to grow it, and should free() it to
@@ -344,8 +345,8 @@ static YY_BUFFER_STATE * grecs_bind__buffer_stack = 0; /**< Stack as an array. *
 
 /* grecs_bind__hold_char holds the character lost when grecs_bind_text is formed. */
 static char grecs_bind__hold_char;
-static int grecs_bind__n_chars;		/* number of characters read into grecs_bind__ch_buf */
-int grecs_bind_leng;
+static grecs_bind__size_t grecs_bind__n_chars;		/* number of characters read into grecs_bind__ch_buf */
+grecs_bind__size_t grecs_bind_leng;
 
 /* Points to current character in buffer. */
 static char *grecs_bind__c_buf_p = (char *) 0;
@@ -376,7 +377,7 @@ static void grecs_bind__init_buffer (YY_BUFFER_STATE b,FILE *file  );
 
 YY_BUFFER_STATE grecs_bind__scan_buffer (char *base,grecs_bind__size_t size  );
 YY_BUFFER_STATE grecs_bind__scan_string (grecs_bind_const char *grecs_bind__str  );
-YY_BUFFER_STATE grecs_bind__scan_bytes (grecs_bind_const char *bytes,int len  );
+YY_BUFFER_STATE grecs_bind__scan_bytes (grecs_bind_const char *bytes,grecs_bind__size_t len  );
 
 /* %endif */
 
@@ -690,7 +691,7 @@ char *grecs_bind_text;
  		grecs_bind_lloc.end = grecs_current_locus_point;			\
    	} while (0);
 
-#line 694 "bind-lex.c"
+#line 695 "bind-lex.c"
 
 #define INITIAL 0
 #define COMMENT 1
@@ -744,7 +745,7 @@ FILE *grecs_bind_get_out (void );
 
 void grecs_bind_set_out  (FILE * out_str  );
 
-int grecs_bind_get_leng (void );
+grecs_bind__size_t grecs_bind_get_leng (void );
 
 char *grecs_bind_get_text (void );
 
@@ -810,7 +811,7 @@ static int input (void );
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO fwrite( grecs_bind_text, grecs_bind_leng, 1, grecs_bind_out )
+#define ECHO do { if (fwrite( grecs_bind_text, grecs_bind_leng, 1, grecs_bind_out )) {} } while (0)
 /* %endif */
 /* %if-c++-only C++ definition */
 /* %endif */
@@ -825,7 +826,7 @@ static int input (void );
 	if ( YY_CURRENT_BUFFER_LVALUE->grecs_bind__is_interactive ) \
 		{ \
 		int c = '*'; \
-		int n; \
+		size_t n; \
 		for ( n = 0; n < max_size && \
 			     (c = getc( grecs_bind_in )) != EOF && c != '\n'; ++n ) \
 			buf[n] = (char) c; \
@@ -938,7 +939,7 @@ YY_DECL
 #line 53 "bind-lex.l"
 
          /* C-style comments */
-#line 942 "bind-lex.c"
+#line 943 "bind-lex.c"
 
 	if ( !(grecs_bind__init) )
 		{
@@ -1230,7 +1231,7 @@ YY_RULE_SETUP
 #line 121 "bind-lex.l"
 ECHO;
 	YY_BREAK
-#line 1234 "bind-lex.c"
+#line 1235 "bind-lex.c"
 case YY_STATE_EOF(INITIAL):
 case YY_STATE_EOF(COMMENT):
 case YY_STATE_EOF(STR):
@@ -1431,21 +1432,21 @@ static int grecs_bind__get_next_buffer (void)
 
 	else
 		{
-			int num_to_read =
+			grecs_bind__size_t num_to_read =
 			YY_CURRENT_BUFFER_LVALUE->grecs_bind__buf_size - number_to_move - 1;
 
 		while ( num_to_read <= 0 )
 			{ /* Not enough room in the buffer - grow it. */
 
 			/* just a shorter name for the current buffer */
-			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
 
 			int grecs_bind__c_buf_p_offset =
 				(int) ((grecs_bind__c_buf_p) - b->grecs_bind__ch_buf);
 
 			if ( b->grecs_bind__is_our_buffer )
 				{
-				int new_size = b->grecs_bind__buf_size * 2;
+				grecs_bind__size_t new_size = b->grecs_bind__buf_size * 2;
 
 				if ( new_size <= 0 )
 					b->grecs_bind__buf_size += b->grecs_bind__buf_size / 8;
@@ -1476,7 +1477,7 @@ static int grecs_bind__get_next_buffer (void)
 
 		/* Read in more data. */
 		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->grecs_bind__ch_buf[number_to_move]),
-			(grecs_bind__n_chars), (size_t) num_to_read );
+			(grecs_bind__n_chars), num_to_read );
 
 		YY_CURRENT_BUFFER_LVALUE->grecs_bind__n_chars = (grecs_bind__n_chars);
 		}
@@ -1585,7 +1586,7 @@ static int grecs_bind__get_next_buffer (void)
 	grecs_bind__current_state = grecs_bind__nxt[grecs_bind__base[grecs_bind__current_state] + (unsigned int) grecs_bind__c];
 	grecs_bind__is_jam = (grecs_bind__current_state == 93);
 
-	return grecs_bind__is_jam ? 0 : grecs_bind__current_state;
+		return grecs_bind__is_jam ? 0 : grecs_bind__current_state;
 }
 
 /* %if-c-only */
@@ -1620,7 +1621,7 @@ static int grecs_bind__get_next_buffer (void)
 
 		else
 			{ /* need more input */
-			int offset = (grecs_bind__c_buf_p) - (grecs_bind_text_ptr);
+			grecs_bind__size_t offset = (grecs_bind__c_buf_p) - (grecs_bind_text_ptr);
 			++(grecs_bind__c_buf_p);
 
 			switch ( grecs_bind__get_next_buffer(  ) )
@@ -1805,17 +1806,6 @@ static void grecs_bind__load_buffer_state  (void)
 	grecs_bind_free((void *) b  );
 }
 
-/* %if-c-only */
-
-#ifndef __cplusplus
-extern int isatty (int );
-#endif /* __cplusplus */
-    
-/* %endif */
-
-/* %if-c++-only */
-/* %endif */
-
 /* Initializes or reinitializes a buffer.
  * This function is sometimes called more than once on the same buffer,
  * such as during a grecs_bind_restart() or at EOF.
@@ -1958,7 +1948,7 @@ static void grecs_bind_ensure_buffer_stack (void)
 /* %if-c++-only */
 /* %endif */
 {
-	int num_to_alloc;
+	grecs_bind__size_t num_to_alloc;
     
 	if (!(grecs_bind__buffer_stack)) {
 
@@ -2056,12 +2046,12 @@ YY_BUFFER_STATE grecs_bind__scan_string (grecs_bind_const char * grecs_bind_str
 /* %if-c-only */
 /** Setup the input buffer state to scan the given bytes. The next call to grecs_bind_lex() will
  * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param grecs_bind_bytes the byte buffer to scan
+ * @param _grecs_bind_bytes_len the number of bytes in the buffer pointed to by @a bytes.
  * 
  * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE grecs_bind__scan_bytes  (grecs_bind_const char * grecs_bind_bytes, int  _grecs_bind_bytes_len )
+YY_BUFFER_STATE grecs_bind__scan_bytes  (grecs_bind_const char * grecs_bind_bytes, grecs_bind__size_t  _grecs_bind_bytes_len )
 {
 	YY_BUFFER_STATE b;
 	char *buf;
@@ -2157,7 +2147,7 @@ FILE *grecs_bind_get_out  (void)
 /** Get the length of the current token.
  * 
  */
-int grecs_bind_get_leng  (void)
+grecs_bind__size_t grecs_bind_get_leng  (void)
 {
         return grecs_bind_leng;
 }
diff --git a/grecs/src/cidr.c b/grecs/src/cidr.c
index 7566fa6..d81baa4 100644
--- a/grecs/src/cidr.c
+++ b/grecs/src/cidr.c
@@ -23,6 +23,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <stdlib.h>
+#include <string.h>
 #include "grecs.h"
 
 static void
diff --git a/grecs/src/dhcpd-gram.c b/grecs/src/dhcpd-gram.c
index 3b5bb72..8e5c9e6 100644
--- a/grecs/src/dhcpd-gram.c
+++ b/grecs/src/dhcpd-gram.c
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 2.5.1.  */
+/* A Bison parser, made by GNU Bison 2.7.  */
 
 /* Bison implementation for Yacc-like parsers in C
    
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.5.1"
+#define YYBISON_VERSION "2.7"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -58,14 +58,11 @@
 /* Pull parsers.  */
 #define YYPULL 1
 
-/* Using locations.  */
-#define YYLSP_NEEDED 1
 
 
 
 /* Copy the first part of user declarations.  */
-
-/* Line 268 of yacc.c  */
+/* Line 371 of yacc.c  */
 #line 1 "dhcpd-gram.y"
 
 /* grecs - Gray's Extensible Configuration System
@@ -117,9 +114,8 @@ make_string_value(char *string)
 }
 
 
-
-/* Line 268 of yacc.c  */
-#line 123 "dhcpd-gram.c"
+/* Line 371 of yacc.c  */
+#line 119 "dhcpd-gram.c"
 
 # ifndef YY_NULL
 #  if defined __cplusplus && 201103L <= __cplusplus
@@ -129,11 +125,6 @@ make_string_value(char *string)
 #  endif
 # endif
 
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 1
-#endif
-
 /* Enabling verbose error messages.  */
 #ifdef YYERROR_VERBOSE
 # undef YYERROR_VERBOSE
@@ -142,11 +133,17 @@ make_string_value(char *string)
 # define YYERROR_VERBOSE 1
 #endif
 
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
+/* In a future release of Bison, this section will be replaced
+   by #include "y.tab.h".  */
+#ifndef YY_YY_Y_TAB_H_INCLUDED
+# define YY_YY_Y_TAB_H_INCLUDED
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int grecs_dhcpddebug;
 #endif
-
 
 /* Tokens.  */
 #ifndef YYTOKENTYPE
@@ -172,12 +169,10 @@ make_string_value(char *string)
 
 
 
-
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
 {
-
-/* Line 295 of yacc.c  */
+/* Line 387 of yacc.c  */
 #line 55 "dhcpd-gram.y"
 
 	char *string;
@@ -188,9 +183,8 @@ typedef union YYSTYPE
 	struct { struct grecs_node *head, *tail; } node_list;
 
 
-
-/* Line 295 of yacc.c  */
-#line 194 "dhcpd-gram.c"
+/* Line 387 of yacc.c  */
+#line 188 "dhcpd-gram.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define grecs_dhcpdstype YYSTYPE /* obsolescent; will be withdrawn */
@@ -210,12 +204,28 @@ typedef struct YYLTYPE
 # define YYLTYPE_IS_TRIVIAL 1
 #endif
 
+extern YYSTYPE grecs_dhcpdlval;
+extern YYLTYPE grecs_dhcpdlloc;
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int grecs_dhcpdparse (void *YYPARSE_PARAM);
+#else
+int grecs_dhcpdparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int grecs_dhcpdparse (void);
+#else
+int grecs_dhcpdparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_YY_Y_TAB_H_INCLUDED  */
 
 /* Copy the second part of user declarations.  */
 
-
-/* Line 345 of yacc.c  */
-#line 219 "dhcpd-gram.c"
+/* Line 390 of yacc.c  */
+#line 229 "dhcpd-gram.c"
 
 #ifdef short
 # undef short
@@ -268,24 +278,24 @@ typedef short int grecs_dhcpdtype_int16;
 # if defined YYENABLE_NLS && YYENABLE_NLS
 #  if ENABLE_NLS
 #   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
 #  endif
 # endif
 # ifndef YY_
-#  define YY_(msgid) msgid
+#  define YY_(Msgid) Msgid
 # endif
 #endif
 
 /* Suppress unused-variable warnings by "using" E.  */
 #if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
+# define YYUSE(E) ((void) (E))
 #else
-# define YYUSE(e) /* empty */
+# define YYUSE(E) /* empty */
 #endif
 
 /* Identity function, used to suppress warnings about constant conditions.  */
 #ifndef lint
-# define YYID(n) (n)
+# define YYID(N) (N)
 #else
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
@@ -524,7 +534,7 @@ static const grecs_dhcpdtype_uint16 grecs_dhcpdrline[] =
 };
 #endif
 
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+#if YYDEBUG || YYERROR_VERBOSE || 1
 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const grecs_dhcpdtname[] =
@@ -620,10 +630,10 @@ static const grecs_dhcpdtype_int8 grecs_dhcpdtable[] =
       40,    48,    53,    49,    57,    54,    23,    58,    30,    52
 };
 
-#define grecs_dhcpdpact_value_is_default(grecs_dhcpdstate) \
-  ((grecs_dhcpdstate) == (-29))
+#define grecs_dhcpdpact_value_is_default(Yystate) \
+  (!!((Yystate) == (-29)))
 
-#define grecs_dhcpdtable_value_is_error(grecs_dhcpdtable_value) \
+#define grecs_dhcpdtable_value_is_error(Yytable_value) \
   YYID (0)
 
 static const grecs_dhcpdtype_uint8 grecs_dhcpdcheck[] =
@@ -690,7 +700,7 @@ do                                                              \
     }								\
 while (YYID (0))
 
-
+/* Error token number */
 #define YYTERROR	1
 #define YYERRCODE	256
 
@@ -699,27 +709,28 @@ while (YYID (0))
    If N is 0, then set CURRENT to the empty location which ends
    the previous symbol: RHS[0] (always defined).  */
 
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
 #ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)				\
-    do									\
-      if (YYID (N))                                                    \
-	{								\
-	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
-	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
-	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
-	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
-	}								\
-      else								\
-	{								\
-	  (Current).first_line   = (Current).last_line   =		\
-	    YYRHSLOC (Rhs, 0).last_line;				\
-	  (Current).first_column = (Current).last_column =		\
-	    YYRHSLOC (Rhs, 0).last_column;				\
-	}								\
+# define YYLLOC_DEFAULT(Current, Rhs, N)                                \
+    do                                                                  \
+      if (YYID (N))                                                     \
+        {                                                               \
+          (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
+          (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
+          (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
+          (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
+        }                                                               \
+      else                                                              \
+        {                                                               \
+          (Current).first_line   = (Current).last_line   =              \
+            YYRHSLOC (Rhs, 0).last_line;                                \
+          (Current).first_column = (Current).last_column =              \
+            YYRHSLOC (Rhs, 0).last_column;                              \
+        }                                                               \
     while (YYID (0))
 #endif
 
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
 
 /* YY_LOCATION_PRINT -- Print the location on the stream.
    This macro was not mandated originally: define only if we know
@@ -727,10 +738,46 @@ while (YYID (0))
 
 #ifndef YY_LOCATION_PRINT
 # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)			\
-     fprintf (File, "%d.%d-%d.%d",			\
-	      (Loc).first_line, (Loc).first_column,	\
-	      (Loc).last_line,  (Loc).last_column)
+
+/* Print *YYLOCP on YYO.  Private, do not rely on its existence. */
+
+__attribute__((__unused__))
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static unsigned
+grecs_dhcpd_location_print_ (FILE *grecs_dhcpdo, YYLTYPE const * const grecs_dhcpdlocp)
+#else
+static unsigned
+grecs_dhcpd_location_print_ (grecs_dhcpdo, grecs_dhcpdlocp)
+    FILE *grecs_dhcpdo;
+    YYLTYPE const * const grecs_dhcpdlocp;
+#endif
+{
+  unsigned res = 0;
+  int end_col = 0 != grecs_dhcpdlocp->last_column ? grecs_dhcpdlocp->last_column - 1 : 0;
+  if (0 <= grecs_dhcpdlocp->first_line)
+    {
+      res += fprintf (grecs_dhcpdo, "%d", grecs_dhcpdlocp->first_line);
+      if (0 <= grecs_dhcpdlocp->first_column)
+        res += fprintf (grecs_dhcpdo, ".%d", grecs_dhcpdlocp->first_column);
+    }
+  if (0 <= grecs_dhcpdlocp->last_line)
+    {
+      if (grecs_dhcpdlocp->first_line < grecs_dhcpdlocp->last_line)
+        {
+          res += fprintf (grecs_dhcpdo, "-%d", grecs_dhcpdlocp->last_line);
+          if (0 <= end_col)
+            res += fprintf (grecs_dhcpdo, ".%d", end_col);
+        }
+      else if (0 <= end_col && grecs_dhcpdlocp->first_column < end_col)
+        res += fprintf (grecs_dhcpdo, "-%d", end_col);
+    }
+  return res;
+ }
+
+#  define YY_LOCATION_PRINT(File, Loc)          \
+  grecs_dhcpd_location_print_ (File, &(Loc))
+
 # else
 #  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
 # endif
@@ -738,7 +785,6 @@ while (YYID (0))
 
 
 /* YYLEX -- calling `grecs_dhcpdlex' with the right arguments.  */
-
 #ifdef YYLEX_PARAM
 # define YYLEX grecs_dhcpdlex (YYLEX_PARAM)
 #else
@@ -803,7 +849,7 @@ grecs_dhcpd_symbol_value_print (grecs_dhcpdoutput, grecs_dhcpdtype, grecs_dhcpdv
   switch (grecs_dhcpdtype)
     {
       default:
-	break;
+        break;
     }
 }
 
@@ -1049,7 +1095,6 @@ grecs_dhcpdsyntax_error (YYSIZE_T *grecs_dhcpdmsg_alloc, char **grecs_dhcpdmsg,
 {
   YYSIZE_T grecs_dhcpdsize0 = grecs_dhcpdtnamerr (YY_NULL, grecs_dhcpdtname[grecs_dhcpdtoken]);
   YYSIZE_T grecs_dhcpdsize = grecs_dhcpdsize0;
-  YYSIZE_T grecs_dhcpdsize1;
   enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
   /* Internationalized format string. */
   const char *grecs_dhcpdformat = YY_NULL;
@@ -1112,11 +1157,13 @@ grecs_dhcpdsyntax_error (YYSIZE_T *grecs_dhcpdmsg_alloc, char **grecs_dhcpdmsg,
                     break;
                   }
                 grecs_dhcpdarg[grecs_dhcpdcount++] = grecs_dhcpdtname[grecs_dhcpdx];
-                grecs_dhcpdsize1 = grecs_dhcpdsize + grecs_dhcpdtnamerr (YY_NULL, grecs_dhcpdtname[grecs_dhcpdx]);
-                if (! (grecs_dhcpdsize <= grecs_dhcpdsize1
-                       && grecs_dhcpdsize1 <= YYSTACK_ALLOC_MAXIMUM))
-                  return 2;
-                grecs_dhcpdsize = grecs_dhcpdsize1;
+                {
+                  YYSIZE_T grecs_dhcpdsize1 = grecs_dhcpdsize + grecs_dhcpdtnamerr (YY_NULL, grecs_dhcpdtname[grecs_dhcpdx]);
+                  if (! (grecs_dhcpdsize <= grecs_dhcpdsize1
+                         && grecs_dhcpdsize1 <= YYSTACK_ALLOC_MAXIMUM))
+                    return 2;
+                  grecs_dhcpdsize = grecs_dhcpdsize1;
+                }
               }
         }
     }
@@ -1136,10 +1183,12 @@ grecs_dhcpdsyntax_error (YYSIZE_T *grecs_dhcpdmsg_alloc, char **grecs_dhcpdmsg,
 # undef YYCASE_
     }
 
-  grecs_dhcpdsize1 = grecs_dhcpdsize + grecs_dhcpdstrlen (grecs_dhcpdformat);
-  if (! (grecs_dhcpdsize <= grecs_dhcpdsize1 && grecs_dhcpdsize1 <= YYSTACK_ALLOC_MAXIMUM))
-    return 2;
-  grecs_dhcpdsize = grecs_dhcpdsize1;
+  {
+    YYSIZE_T grecs_dhcpdsize1 = grecs_dhcpdsize + grecs_dhcpdstrlen (grecs_dhcpdformat);
+    if (! (grecs_dhcpdsize <= grecs_dhcpdsize1 && grecs_dhcpdsize1 <= YYSTACK_ALLOC_MAXIMUM))
+      return 2;
+    grecs_dhcpdsize = grecs_dhcpdsize1;
+  }
 
   if (*grecs_dhcpdmsg_alloc < grecs_dhcpdsize)
     {
@@ -1201,35 +1250,35 @@ grecs_dhcpddestruct (grecs_dhcpdmsg, grecs_dhcpdtype, grecs_dhcpdvaluep, grecs_d
     {
 
       default:
-	break;
+        break;
     }
 }
 
 
-/* Prevent warnings from -Wmissing-prototypes.  */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int grecs_dhcpdparse (void *YYPARSE_PARAM);
-#else
-int grecs_dhcpdparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int grecs_dhcpdparse (void);
-#else
-int grecs_dhcpdparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
 
 
 /* The lookahead symbol.  */
 int grecs_dhcpdchar;
 
+
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
 /* The semantic value of the lookahead symbol.  */
-YYSTYPE grecs_dhcpdlval;
+YYSTYPE grecs_dhcpdlval YY_INITIAL_VALUE(grecs_dhcpdval_default);
 
 /* Location data for the lookahead symbol.  */
-YYLTYPE grecs_dhcpdlloc;
+YYLTYPE grecs_dhcpdlloc
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  = { 1, 1, 1, 1 }
+# endif
+;
+
 
 /* Number of syntax errors so far.  */
 int grecs_dhcpdnerrs;
@@ -1296,7 +1345,7 @@ grecs_dhcpdparse ()
   int grecs_dhcpdn;
   int grecs_dhcpdresult;
   /* Lookahead token as an internal (translated) token number.  */
-  int grecs_dhcpdtoken;
+  int grecs_dhcpdtoken = 0;
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE grecs_dhcpdval;
@@ -1315,10 +1364,9 @@ grecs_dhcpdparse ()
      Keep to zero when no symbol should be popped.  */
   int grecs_dhcpdlen = 0;
 
-  grecs_dhcpdtoken = 0;
-  grecs_dhcpdss = grecs_dhcpdssa;
-  grecs_dhcpdvs = grecs_dhcpdvsa;
-  grecs_dhcpdls = grecs_dhcpdlsa;
+  grecs_dhcpdssp = grecs_dhcpdss = grecs_dhcpdssa;
+  grecs_dhcpdvsp = grecs_dhcpdvs = grecs_dhcpdvsa;
+  grecs_dhcpdlsp = grecs_dhcpdls = grecs_dhcpdlsa;
   grecs_dhcpdstacksize = YYINITDEPTH;
 
   YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1327,21 +1375,7 @@ grecs_dhcpdparse ()
   grecs_dhcpderrstatus = 0;
   grecs_dhcpdnerrs = 0;
   grecs_dhcpdchar = YYEMPTY; /* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-  grecs_dhcpdssp = grecs_dhcpdss;
-  grecs_dhcpdvsp = grecs_dhcpdvs;
-  grecs_dhcpdlsp = grecs_dhcpdls;
-
-#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-  /* Initialize the default location before parsing starts.  */
-  grecs_dhcpdlloc.first_line   = grecs_dhcpdlloc.last_line   = 1;
-  grecs_dhcpdlloc.first_column = grecs_dhcpdlloc.last_column = 1;
-#endif
-
+  grecs_dhcpdlsp[0] = grecs_dhcpdlloc;
   goto grecs_dhcpdsetstate;
 
 /*------------------------------------------------------------.
@@ -1487,7 +1521,9 @@ grecs_dhcpdbackup:
   grecs_dhcpdchar = YYEMPTY;
 
   grecs_dhcpdstate = grecs_dhcpdn;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++grecs_dhcpdvsp = grecs_dhcpdlval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
   *++grecs_dhcpdlsp = grecs_dhcpdlloc;
   goto grecs_dhcpdnewstate;
 
@@ -1525,8 +1561,7 @@ grecs_dhcpdreduce:
   switch (grecs_dhcpdn)
     {
         case 2:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 78 "dhcpd-gram.y"
     {
 		  parse_tree = grecs_node_create(grecs_node_root, &(grecs_dhcpdlsp[(1) - (1)]));
@@ -1536,8 +1571,7 @@ grecs_dhcpdreduce:
     break;
 
   case 3:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 87 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.node) = NULL;
@@ -1545,8 +1579,7 @@ grecs_dhcpdreduce:
     break;
 
   case 4:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 91 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.node) = (grecs_dhcpdvsp[(1) - (1)].node_list).head;
@@ -1554,8 +1587,7 @@ grecs_dhcpdreduce:
     break;
 
   case 5:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 97 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.node_list).head = (grecs_dhcpdval.node_list).tail = (grecs_dhcpdvsp[(1) - (1)].node);
@@ -1563,8 +1595,7 @@ grecs_dhcpdreduce:
     break;
 
   case 6:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 101 "dhcpd-gram.y"
     {
 		  if ((grecs_dhcpdvsp[(2) - (2)].node)) {
@@ -1578,8 +1609,7 @@ grecs_dhcpdreduce:
     break;
 
   case 10:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 118 "dhcpd-gram.y"
     {
 		  if (strcmp((grecs_dhcpdvsp[(1) - (3)].string), "include") == 0 &&
@@ -1597,15 +1627,13 @@ grecs_dhcpdreduce:
     break;
 
   case 11:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 131 "dhcpd-gram.y"
     { grecs_dhcpd_begin_expr(); }
     break;
 
   case 12:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 132 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.node) = grecs_node_create_points(grecs_node_stmt,
@@ -1617,8 +1645,7 @@ grecs_dhcpdreduce:
     break;
 
   case 13:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 140 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.node) = grecs_node_create(grecs_node_stmt, &(grecs_dhcpdlsp[(1) - (2)]));
@@ -1629,8 +1656,7 @@ grecs_dhcpdreduce:
     break;
 
   case 14:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 149 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.node) = grecs_node_create_points(grecs_node_block,
@@ -1643,8 +1669,7 @@ grecs_dhcpdreduce:
     break;
 
   case 17:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 164 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.pvalue) = NULL;
@@ -1652,8 +1677,7 @@ grecs_dhcpdreduce:
     break;
 
   case 19:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 171 "dhcpd-gram.y"
     {
 		  size_t n;
@@ -1679,8 +1703,7 @@ grecs_dhcpdreduce:
     break;
 
   case 20:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 195 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.list) = grecs_value_list_create();
@@ -1689,8 +1712,7 @@ grecs_dhcpdreduce:
     break;
 
   case 21:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 200 "dhcpd-gram.y"
     {
 		  grecs_list_append((grecs_dhcpdvsp[(1) - (2)].list), grecs_value_ptr_from_static(&(grecs_dhcpdvsp[(2) - (2)].svalue)));
@@ -1698,8 +1720,7 @@ grecs_dhcpdreduce:
     break;
 
   case 22:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 206 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.svalue).type = GRECS_TYPE_STRING;
@@ -1709,8 +1730,7 @@ grecs_dhcpdreduce:
     break;
 
   case 23:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 212 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.svalue).type = GRECS_TYPE_LIST;
@@ -1720,8 +1740,7 @@ grecs_dhcpdreduce:
     break;
 
   case 26:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 224 "dhcpd-gram.y"
     {
 		  grecs_value_t val;
@@ -1741,8 +1760,7 @@ grecs_dhcpdreduce:
     break;
 
   case 27:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 240 "dhcpd-gram.y"
     {
 		  grecs_value_t val;
@@ -1755,8 +1773,7 @@ grecs_dhcpdreduce:
     break;
 
   case 28:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 251 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.node) = grecs_node_create_points(grecs_node_block,
@@ -1779,8 +1796,7 @@ grecs_dhcpdreduce:
     break;
 
   case 29:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 272 "dhcpd-gram.y"
     {
 		  grecs_dhcpd_begin_bool();
@@ -1788,8 +1804,7 @@ grecs_dhcpdreduce:
     break;
 
   case 30:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 278 "dhcpd-gram.y"
     {
 		  grecs_dhcpd_begin_bool();
@@ -1797,8 +1812,7 @@ grecs_dhcpdreduce:
     break;
 
   case 31:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 284 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.node_list).head = (grecs_dhcpdval.node_list).tail = NULL;
@@ -1806,8 +1820,7 @@ grecs_dhcpdreduce:
     break;
 
   case 33:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 291 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.node_list).head = (grecs_dhcpdval.node_list).tail = (grecs_dhcpdvsp[(1) - (1)].node);
@@ -1815,8 +1828,7 @@ grecs_dhcpdreduce:
     break;
 
   case 34:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 295 "dhcpd-gram.y"
     {
 		  if ((grecs_dhcpdvsp[(2) - (2)].node)) {
@@ -1830,8 +1842,7 @@ grecs_dhcpdreduce:
     break;
 
   case 35:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 307 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.node) = grecs_node_create_points(grecs_node_block,
@@ -1848,8 +1859,7 @@ grecs_dhcpdreduce:
     break;
 
   case 36:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 322 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.node) = NULL;
@@ -1857,8 +1867,7 @@ grecs_dhcpdreduce:
     break;
 
   case 38:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 329 "dhcpd-gram.y"
     {
 		  (grecs_dhcpdval.node) = grecs_node_create_points(grecs_node_block,
@@ -1875,9 +1884,8 @@ grecs_dhcpdreduce:
     break;
 
 
-
-/* Line 1810 of yacc.c  */
-#line 1881 "dhcpd-gram.c"
+/* Line 1792 of yacc.c  */
+#line 1889 "dhcpd-gram.c"
       default: break;
     }
   /* User semantic actions sometimes alter grecs_dhcpdchar, and that requires
@@ -2042,7 +2050,9 @@ grecs_dhcpderrlab1:
       YY_STACK_PRINT (grecs_dhcpdss, grecs_dhcpdssp);
     }
 
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++grecs_dhcpdvsp = grecs_dhcpdlval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
 
   grecs_dhcpderror_range[2] = grecs_dhcpdlloc;
   /* Using YYLLOC is tempting, but would change the location of
@@ -2113,8 +2123,7 @@ grecs_dhcpdreturn:
 }
 
 
-
-/* Line 2071 of yacc.c  */
+/* Line 2055 of yacc.c  */
 #line 343 "dhcpd-gram.y"
 
 
@@ -2148,4 +2157,3 @@ grecs_dhcpd_parser(const char *name, int traceflags)
 	return parse_tree;
 }
 
-
diff --git a/grecs/src/dhcpd-lex.c b/grecs/src/dhcpd-lex.c
index f72ba01..e192741 100644
--- a/grecs/src/dhcpd-lex.c
+++ b/grecs/src/dhcpd-lex.c
@@ -23,7 +23,7 @@
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
+#define YY_FLEX_SUBMINOR_VERSION 37
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -84,7 +84,6 @@ typedef int flex_int32_t;
 typedef unsigned char flex_uint8_t; 
 typedef unsigned short int flex_uint16_t;
 typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
 
 /* Limits of integral types. */
 #ifndef INT8_MIN
@@ -115,6 +114,8 @@ typedef unsigned int flex_uint32_t;
 #define UINT32_MAX             (4294967295U)
 #endif
 
+#endif /* ! C99 */
+
 #endif /* ! FLEXINT_H */
 
 /* %endif */
@@ -201,8 +202,13 @@ typedef unsigned int flex_uint32_t;
 typedef struct grecs_dhcpd_buffer_state *YY_BUFFER_STATE;
 #endif
 
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t grecs_dhcpd_size_t;
+#endif
+
 /* %if-not-reentrant */
-extern int grecs_dhcpdleng;
+extern grecs_dhcpd_size_t grecs_dhcpdleng;
 /* %endif */
 
 /* %if-c-only */
@@ -233,11 +239,6 @@ extern FILE *grecs_dhcpdin, *grecs_dhcpdout;
 
 #define unput(c) grecs_dhcpdunput( c, (grecs_dhcpdtext_ptr)  )
 
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t grecs_dhcpd_size_t;
-#endif
-
 #ifndef YY_STRUCT_YY_BUFFER_STATE
 #define YY_STRUCT_YY_BUFFER_STATE
 struct grecs_dhcpd_buffer_state
@@ -260,7 +261,7 @@ struct grecs_dhcpd_buffer_state
 	/* Number of characters read into grecs_dhcpd_ch_buf, not including EOB
 	 * characters.
 	 */
-	int grecs_dhcpd_n_chars;
+	grecs_dhcpd_size_t grecs_dhcpd_n_chars;
 
 	/* Whether we "own" the buffer - i.e., we know we created it,
 	 * and can realloc() it to grow it, and should free() it to
@@ -344,8 +345,8 @@ static YY_BUFFER_STATE * grecs_dhcpd_buffer_stack = 0; /**< Stack as an array. *
 
 /* grecs_dhcpd_hold_char holds the character lost when grecs_dhcpdtext is formed. */
 static char grecs_dhcpd_hold_char;
-static int grecs_dhcpd_n_chars;		/* number of characters read into grecs_dhcpd_ch_buf */
-int grecs_dhcpdleng;
+static grecs_dhcpd_size_t grecs_dhcpd_n_chars;		/* number of characters read into grecs_dhcpd_ch_buf */
+grecs_dhcpd_size_t grecs_dhcpdleng;
 
 /* Points to current character in buffer. */
 static char *grecs_dhcpd_c_buf_p = (char *) 0;
@@ -376,7 +377,7 @@ static void grecs_dhcpd_init_buffer (YY_BUFFER_STATE b,FILE *file  );
 
 YY_BUFFER_STATE grecs_dhcpd_scan_buffer (char *base,grecs_dhcpd_size_t size  );
 YY_BUFFER_STATE grecs_dhcpd_scan_string (grecs_dhcpdconst char *grecs_dhcpd_str  );
-YY_BUFFER_STATE grecs_dhcpd_scan_bytes (grecs_dhcpdconst char *bytes,int len  );
+YY_BUFFER_STATE grecs_dhcpd_scan_bytes (grecs_dhcpdconst char *bytes,grecs_dhcpd_size_t len  );
 
 /* %endif */
 
@@ -692,7 +693,7 @@ char *grecs_dhcpdtext;
 
 #define ISWS(c) ((c)==' '||(c)=='\t')	
 
-#line 696 "dhcpd-lex.c"
+#line 697 "dhcpd-lex.c"
 
 #define INITIAL 0
 #define COMMENT 1
@@ -748,7 +749,7 @@ FILE *grecs_dhcpdget_out (void );
 
 void grecs_dhcpdset_out  (FILE * out_str  );
 
-int grecs_dhcpdget_leng (void );
+grecs_dhcpd_size_t grecs_dhcpdget_leng (void );
 
 char *grecs_dhcpdget_text (void );
 
@@ -816,7 +817,7 @@ static int input (void );
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO fwrite( grecs_dhcpdtext, grecs_dhcpdleng, 1, grecs_dhcpdout )
+#define ECHO do { if (fwrite( grecs_dhcpdtext, grecs_dhcpdleng, 1, grecs_dhcpdout )) {} } while (0)
 /* %endif */
 /* %if-c++-only C++ definition */
 /* %endif */
@@ -831,7 +832,7 @@ static int input (void );
 	if ( YY_CURRENT_BUFFER_LVALUE->grecs_dhcpd_is_interactive ) \
 		{ \
 		int c = '*'; \
-		int n; \
+		size_t n; \
 		for ( n = 0; n < max_size && \
 			     (c = getc( grecs_dhcpdin )) != EOF && c != '\n'; ++n ) \
 			buf[n] = (char) c; \
@@ -944,7 +945,7 @@ YY_DECL
 #line 55 "dhcpd-lex.l"
 
          /* Line directive */
-#line 948 "dhcpd-lex.c"
+#line 949 "dhcpd-lex.c"
 
 	if ( !(grecs_dhcpd_init) )
 		{
@@ -1291,7 +1292,7 @@ YY_RULE_SETUP
 #line 171 "dhcpd-lex.l"
 ECHO;
 	YY_BREAK
-#line 1295 "dhcpd-lex.c"
+#line 1296 "dhcpd-lex.c"
 case YY_STATE_EOF(INITIAL):
 case YY_STATE_EOF(COMMENT):
 case YY_STATE_EOF(STR):
@@ -1494,21 +1495,21 @@ static int grecs_dhcpd_get_next_buffer (void)
 
 	else
 		{
-			int num_to_read =
+			grecs_dhcpd_size_t num_to_read =
 			YY_CURRENT_BUFFER_LVALUE->grecs_dhcpd_buf_size - number_to_move - 1;
 
 		while ( num_to_read <= 0 )
 			{ /* Not enough room in the buffer - grow it. */
 
 			/* just a shorter name for the current buffer */
-			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
 
 			int grecs_dhcpd_c_buf_p_offset =
 				(int) ((grecs_dhcpd_c_buf_p) - b->grecs_dhcpd_ch_buf);
 
 			if ( b->grecs_dhcpd_is_our_buffer )
 				{
-				int new_size = b->grecs_dhcpd_buf_size * 2;
+				grecs_dhcpd_size_t new_size = b->grecs_dhcpd_buf_size * 2;
 
 				if ( new_size <= 0 )
 					b->grecs_dhcpd_buf_size += b->grecs_dhcpd_buf_size / 8;
@@ -1539,7 +1540,7 @@ static int grecs_dhcpd_get_next_buffer (void)
 
 		/* Read in more data. */
 		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->grecs_dhcpd_ch_buf[number_to_move]),
-			(grecs_dhcpd_n_chars), (size_t) num_to_read );
+			(grecs_dhcpd_n_chars), num_to_read );
 
 		YY_CURRENT_BUFFER_LVALUE->grecs_dhcpd_n_chars = (grecs_dhcpd_n_chars);
 		}
@@ -1648,7 +1649,7 @@ static int grecs_dhcpd_get_next_buffer (void)
 	grecs_dhcpd_current_state = grecs_dhcpd_nxt[grecs_dhcpd_base[grecs_dhcpd_current_state] + (unsigned int) grecs_dhcpd_c];
 	grecs_dhcpd_is_jam = (grecs_dhcpd_current_state == 110);
 
-	return grecs_dhcpd_is_jam ? 0 : grecs_dhcpd_current_state;
+		return grecs_dhcpd_is_jam ? 0 : grecs_dhcpd_current_state;
 }
 
 /* %if-c-only */
@@ -1668,7 +1669,7 @@ static int grecs_dhcpd_get_next_buffer (void)
 	if ( grecs_dhcpd_cp < YY_CURRENT_BUFFER_LVALUE->grecs_dhcpd_ch_buf + 2 )
 		{ /* need to shift things up to make room */
 		/* +2 for EOB chars. */
-		register int number_to_move = (grecs_dhcpd_n_chars) + 2;
+		register grecs_dhcpd_size_t number_to_move = (grecs_dhcpd_n_chars) + 2;
 		register char *dest = &YY_CURRENT_BUFFER_LVALUE->grecs_dhcpd_ch_buf[
 					YY_CURRENT_BUFFER_LVALUE->grecs_dhcpd_buf_size + 2];
 		register char *source =
@@ -1726,7 +1727,7 @@ static int grecs_dhcpd_get_next_buffer (void)
 
 		else
 			{ /* need more input */
-			int offset = (grecs_dhcpd_c_buf_p) - (grecs_dhcpdtext_ptr);
+			grecs_dhcpd_size_t offset = (grecs_dhcpd_c_buf_p) - (grecs_dhcpdtext_ptr);
 			++(grecs_dhcpd_c_buf_p);
 
 			switch ( grecs_dhcpd_get_next_buffer(  ) )
@@ -1911,17 +1912,6 @@ static void grecs_dhcpd_load_buffer_state  (void)
 	grecs_dhcpdfree((void *) b  );
 }
 
-/* %if-c-only */
-
-#ifndef __cplusplus
-extern int isatty (int );
-#endif /* __cplusplus */
-    
-/* %endif */
-
-/* %if-c++-only */
-/* %endif */
-
 /* Initializes or reinitializes a buffer.
  * This function is sometimes called more than once on the same buffer,
  * such as during a grecs_dhcpdrestart() or at EOF.
@@ -2064,7 +2054,7 @@ static void grecs_dhcpdensure_buffer_stack (void)
 /* %if-c++-only */
 /* %endif */
 {
-	int num_to_alloc;
+	grecs_dhcpd_size_t num_to_alloc;
     
 	if (!(grecs_dhcpd_buffer_stack)) {
 
@@ -2162,12 +2152,12 @@ YY_BUFFER_STATE grecs_dhcpd_scan_string (grecs_dhcpdconst char * grecs_dhcpdstr
 /* %if-c-only */
 /** Setup the input buffer state to scan the given bytes. The next call to grecs_dhcpdlex() will
  * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param grecs_dhcpdbytes the byte buffer to scan
+ * @param _grecs_dhcpdbytes_len the number of bytes in the buffer pointed to by @a bytes.
  * 
  * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE grecs_dhcpd_scan_bytes  (grecs_dhcpdconst char * grecs_dhcpdbytes, int  _grecs_dhcpdbytes_len )
+YY_BUFFER_STATE grecs_dhcpd_scan_bytes  (grecs_dhcpdconst char * grecs_dhcpdbytes, grecs_dhcpd_size_t  _grecs_dhcpdbytes_len )
 {
 	YY_BUFFER_STATE b;
 	char *buf;
@@ -2263,7 +2253,7 @@ FILE *grecs_dhcpdget_out  (void)
 /** Get the length of the current token.
  * 
  */
-int grecs_dhcpdget_leng  (void)
+grecs_dhcpd_size_t grecs_dhcpdget_leng  (void)
 {
         return grecs_dhcpdleng;
 }
diff --git a/grecs/src/diag.c b/grecs/src/diag.c
index bdbb407..39089c4 100644
--- a/grecs/src/diag.c
+++ b/grecs/src/diag.c
@@ -37,7 +37,7 @@ default_print_diag(grecs_locus_t const *locus, int err, int errcode,
 		fprintf(stderr, "warning: ");
 	fprintf(stderr, "%s", msg);
 	if (errcode)
-		fprintf(stderr, ": %s", strerror(errno));
+		fprintf(stderr, ": %s", strerror(errcode));
 	fputc('\n', stderr);
 }
 
@@ -96,11 +96,17 @@ grecs_asprint_locus(char **locstr, size_t *size, grecs_locus_t const *locus)
 				    locus->beg.file,
 				    locus->beg.line, locus->beg.col,
 				    locus->end.line, locus->end.col);
-	else
+	else if (locus->beg.col != locus->end.col)
 		rc = grecs_asprintf(locstr, size, "%s:%u.%u-%u",
 				    locus->beg.file,
 				    locus->beg.line, locus->beg.col,
 				    locus->end.col);
+	else
+		rc = grecs_asprintf(locstr, size, "%s:%u.%u",
+				    locus->beg.file,
+				    locus->beg.line,
+				    locus->beg.col);
+
 	return rc;
 }
 
diff --git a/grecs/src/format.c b/grecs/src/format.c
index af87329..d7cdb0f 100644
--- a/grecs/src/format.c
+++ b/grecs/src/format.c
@@ -30,10 +30,10 @@ grecs_data_type_string(enum grecs_data_type type)
 {
 	switch (type) {
 	case grecs_type_void:
-		return "void";
+		return N_("void");
 
 	case grecs_type_string:
-		return "string";
+		return N_("string");
 
 	case grecs_type_short:
 	case grecs_type_ushort:
@@ -43,31 +43,31 @@ grecs_data_type_string(enum grecs_data_type type)
 	case grecs_type_ulong:
 	case grecs_type_size:
 		/*FIXME case  grecs_type_off:*/
-		return "number";
+		return N_("number");
 
 	case grecs_type_time:
-		return "time";
+		return N_("time");
 
 	case grecs_type_bool:
-		return "boolean";
+		return N_("boolean");
 
 	case grecs_type_ipv4:
-		return "IPv4";
+		return N_("IPv4");
 
 	case grecs_type_cidr:
-		return "CIDR";
+		return N_("CIDR");
 
 	case grecs_type_host:
-		return "hostname";
+		return N_("hostname");
 
 	case grecs_type_sockaddr:
-		return "sockaddr";
+		return N_("sockaddr");
 
 	case grecs_type_section:
-		return "section";
+		return N_("section");
 
 	case grecs_type_null:
-		return "null";
+		return N_("null");
 	}
 	return "UNKNOWN?";
 }
diff --git a/grecs/src/grecs-gram.c b/grecs/src/grecs-gram.c
index 50689c0..7288635 100644
--- a/grecs/src/grecs-gram.c
+++ b/grecs/src/grecs-gram.c
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 2.5.1.  */
+/* A Bison parser, made by GNU Bison 2.7.  */
 
 /* Bison implementation for Yacc-like parsers in C
    
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.5.1"
+#define YYBISON_VERSION "2.7"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -58,14 +58,11 @@
 /* Pull parsers.  */
 #define YYPULL 1
 
-/* Using locations.  */
-#define YYLSP_NEEDED 1
 
 
 
 /* Copy the first part of user declarations.  */
-
-/* Line 268 of yacc.c  */
+/* Line 371 of yacc.c  */
 #line 1 "grecs-gram.y"
 
 /* grecs - Gray's Extensible Configuration System
@@ -99,9 +96,8 @@ int grecs_grecs_error(char const *s);
 
 static struct grecs_node *parse_tree;
 
-
-/* Line 268 of yacc.c  */
-#line 105 "grecs-gram.c"
+/* Line 371 of yacc.c  */
+#line 101 "grecs-gram.c"
 
 # ifndef YY_NULL
 #  if defined __cplusplus && 201103L <= __cplusplus
@@ -111,11 +107,6 @@ static struct grecs_node *parse_tree;
 #  endif
 # endif
 
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 1
-#endif
-
 /* Enabling verbose error messages.  */
 #ifdef YYERROR_VERBOSE
 # undef YYERROR_VERBOSE
@@ -124,11 +115,17 @@ static struct grecs_node *parse_tree;
 # define YYERROR_VERBOSE 1
 #endif
 
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
+/* In a future release of Bison, this section will be replaced
+   by #include "y.tab.h".  */
+#ifndef YY_YY_Y_TAB_H_INCLUDED
+# define YY_YY_Y_TAB_H_INCLUDED
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int grecs_grecs_debug;
 #endif
-
 
 /* Tokens.  */
 #ifndef YYTOKENTYPE
@@ -150,12 +147,10 @@ static struct grecs_node *parse_tree;
 
 
 
-
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
 {
-
-/* Line 295 of yacc.c  */
+/* Line 387 of yacc.c  */
 #line 37 "grecs-gram.y"
 
 	char *string;
@@ -166,9 +161,8 @@ typedef union YYSTYPE
 	struct { struct grecs_node *head, *tail; } node_list;
 
 
-
-/* Line 295 of yacc.c  */
-#line 172 "grecs-gram.c"
+/* Line 387 of yacc.c  */
+#line 166 "grecs-gram.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define grecs_grecs_stype YYSTYPE /* obsolescent; will be withdrawn */
@@ -188,12 +182,28 @@ typedef struct YYLTYPE
 # define YYLTYPE_IS_TRIVIAL 1
 #endif
 
+extern YYSTYPE grecs_grecs_lval;
+extern YYLTYPE grecs_grecs_lloc;
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int grecs_grecs_parse (void *YYPARSE_PARAM);
+#else
+int grecs_grecs_parse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int grecs_grecs_parse (void);
+#else
+int grecs_grecs_parse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_YY_Y_TAB_H_INCLUDED  */
 
 /* Copy the second part of user declarations.  */
 
-
-/* Line 345 of yacc.c  */
-#line 197 "grecs-gram.c"
+/* Line 390 of yacc.c  */
+#line 207 "grecs-gram.c"
 
 #ifdef short
 # undef short
@@ -246,24 +256,24 @@ typedef short int grecs_grecs_type_int16;
 # if defined YYENABLE_NLS && YYENABLE_NLS
 #  if ENABLE_NLS
 #   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
 #  endif
 # endif
 # ifndef YY_
-#  define YY_(msgid) msgid
+#  define YY_(Msgid) Msgid
 # endif
 #endif
 
 /* Suppress unused-variable warnings by "using" E.  */
 #if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
+# define YYUSE(E) ((void) (E))
 #else
-# define YYUSE(e) /* empty */
+# define YYUSE(E) /* empty */
 #endif
 
 /* Identity function, used to suppress warnings about constant conditions.  */
 #ifndef lint
-# define YYID(n) (n)
+# define YYID(N) (N)
 #else
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
@@ -500,7 +510,7 @@ static const grecs_grecs_type_uint8 grecs_grecs_rline[] =
 };
 #endif
 
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+#if YYDEBUG || YYERROR_VERBOSE || 1
 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const grecs_grecs_tname[] =
@@ -589,10 +599,10 @@ static const grecs_grecs_type_uint8 grecs_grecs_table[] =
       13,     8,     9,    10,    11,    27,     1,     0,    13,    36
 };
 
-#define grecs_grecs_pact_value_is_default(grecs_grecs_state) \
-  ((grecs_grecs_state) == (-13))
+#define grecs_grecs_pact_value_is_default(Yystate) \
+  (!!((Yystate) == (-13)))
 
-#define grecs_grecs_table_value_is_error(grecs_grecs_table_value) \
+#define grecs_grecs_table_value_is_error(Yytable_value) \
   YYID (0)
 
 static const grecs_grecs_type_int8 grecs_grecs_check[] =
@@ -657,7 +667,7 @@ do                                                              \
     }								\
 while (YYID (0))
 
-
+/* Error token number */
 #define YYTERROR	1
 #define YYERRCODE	256
 
@@ -666,27 +676,28 @@ while (YYID (0))
    If N is 0, then set CURRENT to the empty location which ends
    the previous symbol: RHS[0] (always defined).  */
 
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
 #ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)				\
-    do									\
-      if (YYID (N))                                                    \
-	{								\
-	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
-	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
-	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
-	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
-	}								\
-      else								\
-	{								\
-	  (Current).first_line   = (Current).last_line   =		\
-	    YYRHSLOC (Rhs, 0).last_line;				\
-	  (Current).first_column = (Current).last_column =		\
-	    YYRHSLOC (Rhs, 0).last_column;				\
-	}								\
+# define YYLLOC_DEFAULT(Current, Rhs, N)                                \
+    do                                                                  \
+      if (YYID (N))                                                     \
+        {                                                               \
+          (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
+          (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
+          (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
+          (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
+        }                                                               \
+      else                                                              \
+        {                                                               \
+          (Current).first_line   = (Current).last_line   =              \
+            YYRHSLOC (Rhs, 0).last_line;                                \
+          (Current).first_column = (Current).last_column =              \
+            YYRHSLOC (Rhs, 0).last_column;                              \
+        }                                                               \
     while (YYID (0))
 #endif
 
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
 
 /* YY_LOCATION_PRINT -- Print the location on the stream.
    This macro was not mandated originally: define only if we know
@@ -694,10 +705,46 @@ while (YYID (0))
 
 #ifndef YY_LOCATION_PRINT
 # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)			\
-     fprintf (File, "%d.%d-%d.%d",			\
-	      (Loc).first_line, (Loc).first_column,	\
-	      (Loc).last_line,  (Loc).last_column)
+
+/* Print *YYLOCP on YYO.  Private, do not rely on its existence. */
+
+__attribute__((__unused__))
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static unsigned
+grecs_grecs__location_print_ (FILE *grecs_grecs_o, YYLTYPE const * const grecs_grecs_locp)
+#else
+static unsigned
+grecs_grecs__location_print_ (grecs_grecs_o, grecs_grecs_locp)
+    FILE *grecs_grecs_o;
+    YYLTYPE const * const grecs_grecs_locp;
+#endif
+{
+  unsigned res = 0;
+  int end_col = 0 != grecs_grecs_locp->last_column ? grecs_grecs_locp->last_column - 1 : 0;
+  if (0 <= grecs_grecs_locp->first_line)
+    {
+      res += fprintf (grecs_grecs_o, "%d", grecs_grecs_locp->first_line);
+      if (0 <= grecs_grecs_locp->first_column)
+        res += fprintf (grecs_grecs_o, ".%d", grecs_grecs_locp->first_column);
+    }
+  if (0 <= grecs_grecs_locp->last_line)
+    {
+      if (grecs_grecs_locp->first_line < grecs_grecs_locp->last_line)
+        {
+          res += fprintf (grecs_grecs_o, "-%d", grecs_grecs_locp->last_line);
+          if (0 <= end_col)
+            res += fprintf (grecs_grecs_o, ".%d", end_col);
+        }
+      else if (0 <= end_col && grecs_grecs_locp->first_column < end_col)
+        res += fprintf (grecs_grecs_o, "-%d", end_col);
+    }
+  return res;
+ }
+
+#  define YY_LOCATION_PRINT(File, Loc)          \
+  grecs_grecs__location_print_ (File, &(Loc))
+
 # else
 #  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
 # endif
@@ -705,7 +752,6 @@ while (YYID (0))
 
 
 /* YYLEX -- calling `grecs_grecs_lex' with the right arguments.  */
-
 #ifdef YYLEX_PARAM
 # define YYLEX grecs_grecs_lex (YYLEX_PARAM)
 #else
@@ -770,7 +816,7 @@ grecs_grecs__symbol_value_print (grecs_grecs_output, grecs_grecs_type, grecs_gre
   switch (grecs_grecs_type)
     {
       default:
-	break;
+        break;
     }
 }
 
@@ -1016,7 +1062,6 @@ grecs_grecs_syntax_error (YYSIZE_T *grecs_grecs_msg_alloc, char **grecs_grecs_ms
 {
   YYSIZE_T grecs_grecs_size0 = grecs_grecs_tnamerr (YY_NULL, grecs_grecs_tname[grecs_grecs_token]);
   YYSIZE_T grecs_grecs_size = grecs_grecs_size0;
-  YYSIZE_T grecs_grecs_size1;
   enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
   /* Internationalized format string. */
   const char *grecs_grecs_format = YY_NULL;
@@ -1079,11 +1124,13 @@ grecs_grecs_syntax_error (YYSIZE_T *grecs_grecs_msg_alloc, char **grecs_grecs_ms
                     break;
                   }
                 grecs_grecs_arg[grecs_grecs_count++] = grecs_grecs_tname[grecs_grecs_x];
-                grecs_grecs_size1 = grecs_grecs_size + grecs_grecs_tnamerr (YY_NULL, grecs_grecs_tname[grecs_grecs_x]);
-                if (! (grecs_grecs_size <= grecs_grecs_size1
-                       && grecs_grecs_size1 <= YYSTACK_ALLOC_MAXIMUM))
-                  return 2;
-                grecs_grecs_size = grecs_grecs_size1;
+                {
+                  YYSIZE_T grecs_grecs_size1 = grecs_grecs_size + grecs_grecs_tnamerr (YY_NULL, grecs_grecs_tname[grecs_grecs_x]);
+                  if (! (grecs_grecs_size <= grecs_grecs_size1
+                         && grecs_grecs_size1 <= YYSTACK_ALLOC_MAXIMUM))
+                    return 2;
+                  grecs_grecs_size = grecs_grecs_size1;
+                }
               }
         }
     }
@@ -1103,10 +1150,12 @@ grecs_grecs_syntax_error (YYSIZE_T *grecs_grecs_msg_alloc, char **grecs_grecs_ms
 # undef YYCASE_
     }
 
-  grecs_grecs_size1 = grecs_grecs_size + grecs_grecs_strlen (grecs_grecs_format);
-  if (! (grecs_grecs_size <= grecs_grecs_size1 && grecs_grecs_size1 <= YYSTACK_ALLOC_MAXIMUM))
-    return 2;
-  grecs_grecs_size = grecs_grecs_size1;
+  {
+    YYSIZE_T grecs_grecs_size1 = grecs_grecs_size + grecs_grecs_strlen (grecs_grecs_format);
+    if (! (grecs_grecs_size <= grecs_grecs_size1 && grecs_grecs_size1 <= YYSTACK_ALLOC_MAXIMUM))
+      return 2;
+    grecs_grecs_size = grecs_grecs_size1;
+  }
 
   if (*grecs_grecs_msg_alloc < grecs_grecs_size)
     {
@@ -1168,35 +1217,35 @@ grecs_grecs_destruct (grecs_grecs_msg, grecs_grecs_type, grecs_grecs_valuep, gre
     {
 
       default:
-	break;
+        break;
     }
 }
 
 
-/* Prevent warnings from -Wmissing-prototypes.  */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int grecs_grecs_parse (void *YYPARSE_PARAM);
-#else
-int grecs_grecs_parse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int grecs_grecs_parse (void);
-#else
-int grecs_grecs_parse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
 
 
 /* The lookahead symbol.  */
 int grecs_grecs_char;
 
+
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
 /* The semantic value of the lookahead symbol.  */
-YYSTYPE grecs_grecs_lval;
+YYSTYPE grecs_grecs_lval YY_INITIAL_VALUE(grecs_grecs_val_default);
 
 /* Location data for the lookahead symbol.  */
-YYLTYPE grecs_grecs_lloc;
+YYLTYPE grecs_grecs_lloc
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  = { 1, 1, 1, 1 }
+# endif
+;
+
 
 /* Number of syntax errors so far.  */
 int grecs_grecs_nerrs;
@@ -1263,7 +1312,7 @@ grecs_grecs_parse ()
   int grecs_grecs_n;
   int grecs_grecs_result;
   /* Lookahead token as an internal (translated) token number.  */
-  int grecs_grecs_token;
+  int grecs_grecs_token = 0;
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE grecs_grecs_val;
@@ -1282,10 +1331,9 @@ grecs_grecs_parse ()
      Keep to zero when no symbol should be popped.  */
   int grecs_grecs_len = 0;
 
-  grecs_grecs_token = 0;
-  grecs_grecs_ss = grecs_grecs_ssa;
-  grecs_grecs_vs = grecs_grecs_vsa;
-  grecs_grecs_ls = grecs_grecs_lsa;
+  grecs_grecs_ssp = grecs_grecs_ss = grecs_grecs_ssa;
+  grecs_grecs_vsp = grecs_grecs_vs = grecs_grecs_vsa;
+  grecs_grecs_lsp = grecs_grecs_ls = grecs_grecs_lsa;
   grecs_grecs_stacksize = YYINITDEPTH;
 
   YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1294,21 +1342,7 @@ grecs_grecs_parse ()
   grecs_grecs_errstatus = 0;
   grecs_grecs_nerrs = 0;
   grecs_grecs_char = YYEMPTY; /* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-  grecs_grecs_ssp = grecs_grecs_ss;
-  grecs_grecs_vsp = grecs_grecs_vs;
-  grecs_grecs_lsp = grecs_grecs_ls;
-
-#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-  /* Initialize the default location before parsing starts.  */
-  grecs_grecs_lloc.first_line   = grecs_grecs_lloc.last_line   = 1;
-  grecs_grecs_lloc.first_column = grecs_grecs_lloc.last_column = 1;
-#endif
-
+  grecs_grecs_lsp[0] = grecs_grecs_lloc;
   goto grecs_grecs_setstate;
 
 /*------------------------------------------------------------.
@@ -1454,7 +1488,9 @@ grecs_grecs_backup:
   grecs_grecs_char = YYEMPTY;
 
   grecs_grecs_state = grecs_grecs_n;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++grecs_grecs_vsp = grecs_grecs_lval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
   *++grecs_grecs_lsp = grecs_grecs_lloc;
   goto grecs_grecs_newstate;
 
@@ -1492,8 +1528,7 @@ grecs_grecs_reduce:
   switch (grecs_grecs_n)
     {
         case 2:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 58 "grecs-gram.y"
     {
 		  parse_tree = grecs_node_create(grecs_node_root, &(grecs_grecs_lsp[(1) - (1)]));
@@ -1503,8 +1538,7 @@ grecs_grecs_reduce:
     break;
 
   case 3:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 67 "grecs-gram.y"
     {
 		  (grecs_grecs_val.node) = NULL;
@@ -1512,8 +1546,7 @@ grecs_grecs_reduce:
     break;
 
   case 4:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 71 "grecs-gram.y"
     {
 		  (grecs_grecs_val.node) = (grecs_grecs_vsp[(1) - (1)].node_list).head;
@@ -1521,8 +1554,7 @@ grecs_grecs_reduce:
     break;
 
   case 5:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 77 "grecs-gram.y"
     {
 		  (grecs_grecs_val.node_list).head = (grecs_grecs_val.node_list).tail = (grecs_grecs_vsp[(1) - (1)].node);
@@ -1530,8 +1562,7 @@ grecs_grecs_reduce:
     break;
 
   case 6:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 81 "grecs-gram.y"
     {
 		  grecs_node_bind((grecs_grecs_vsp[(1) - (2)].node_list).tail, (grecs_grecs_vsp[(2) - (2)].node), 0);
@@ -1539,8 +1570,7 @@ grecs_grecs_reduce:
     break;
 
   case 9:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 91 "grecs-gram.y"
     {
 		  (grecs_grecs_val.node) = grecs_node_create_points(grecs_node_stmt,
@@ -1552,8 +1582,7 @@ grecs_grecs_reduce:
     break;
 
   case 10:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 99 "grecs-gram.y"
     {
 		  (grecs_grecs_val.node) = grecs_node_create(grecs_node_stmt, &(grecs_grecs_lsp[(1) - (2)]));
@@ -1564,8 +1593,7 @@ grecs_grecs_reduce:
     break;
 
   case 11:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 108 "grecs-gram.y"
     {
 		  (grecs_grecs_val.node) = grecs_node_create_points(grecs_node_block,
@@ -1578,8 +1606,7 @@ grecs_grecs_reduce:
     break;
 
   case 12:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 119 "grecs-gram.y"
     {
 		  (grecs_grecs_val.pvalue) = NULL;
@@ -1587,8 +1614,7 @@ grecs_grecs_reduce:
     break;
 
   case 14:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 126 "grecs-gram.y"
     {
 		  size_t n;
@@ -1614,8 +1640,7 @@ grecs_grecs_reduce:
     break;
 
   case 15:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 150 "grecs-gram.y"
     {
 		  (grecs_grecs_val.list) = grecs_value_list_create();
@@ -1624,8 +1649,7 @@ grecs_grecs_reduce:
     break;
 
   case 16:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 155 "grecs-gram.y"
     {
 		  grecs_list_append((grecs_grecs_vsp[(1) - (2)].list), grecs_value_ptr_from_static(&(grecs_grecs_vsp[(2) - (2)].svalue)));
@@ -1633,8 +1657,7 @@ grecs_grecs_reduce:
     break;
 
   case 17:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 161 "grecs-gram.y"
     {
 		  (grecs_grecs_val.svalue).type = GRECS_TYPE_STRING;
@@ -1644,8 +1667,7 @@ grecs_grecs_reduce:
     break;
 
   case 18:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 167 "grecs-gram.y"
     {
 		  (grecs_grecs_val.svalue).type = GRECS_TYPE_LIST;
@@ -1655,8 +1677,7 @@ grecs_grecs_reduce:
     break;
 
   case 19:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 173 "grecs-gram.y"
     {
 		  (grecs_grecs_val.svalue).type = GRECS_TYPE_STRING;
@@ -1666,8 +1687,7 @@ grecs_grecs_reduce:
     break;
 
   case 23:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 186 "grecs-gram.y"
     {
 		  struct grecs_list_entry *ep;
@@ -1684,8 +1704,7 @@ grecs_grecs_reduce:
     break;
 
   case 24:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 201 "grecs-gram.y"
     {
 		  (grecs_grecs_val.list) = grecs_list_create();
@@ -1694,8 +1713,7 @@ grecs_grecs_reduce:
     break;
 
   case 25:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 206 "grecs-gram.y"
     {
 		  grecs_list_append((grecs_grecs_vsp[(1) - (2)].list), (grecs_grecs_vsp[(2) - (2)].string));
@@ -1704,8 +1722,7 @@ grecs_grecs_reduce:
     break;
 
   case 26:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 213 "grecs-gram.y"
     {
 		  (grecs_grecs_val.list) = NULL;
@@ -1713,8 +1730,7 @@ grecs_grecs_reduce:
     break;
 
   case 27:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 217 "grecs-gram.y"
     {
 		  (grecs_grecs_val.list) = (grecs_grecs_vsp[(2) - (3)].list);
@@ -1722,8 +1738,7 @@ grecs_grecs_reduce:
     break;
 
   case 28:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 221 "grecs-gram.y"
     {
 		  (grecs_grecs_val.list) = (grecs_grecs_vsp[(2) - (4)].list);
@@ -1731,8 +1746,7 @@ grecs_grecs_reduce:
     break;
 
   case 29:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 227 "grecs-gram.y"
     {
 		  (grecs_grecs_val.list) = grecs_value_list_create();
@@ -1741,8 +1755,7 @@ grecs_grecs_reduce:
     break;
 
   case 30:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 232 "grecs-gram.y"
     {
 		  grecs_list_append((grecs_grecs_vsp[(1) - (3)].list), grecs_value_ptr_from_static(&(grecs_grecs_vsp[(3) - (3)].svalue)));
@@ -1751,9 +1764,8 @@ grecs_grecs_reduce:
     break;
 
 
-
-/* Line 1810 of yacc.c  */
-#line 1757 "grecs-gram.c"
+/* Line 1792 of yacc.c  */
+#line 1769 "grecs-gram.c"
       default: break;
     }
   /* User semantic actions sometimes alter grecs_grecs_char, and that requires
@@ -1918,7 +1930,9 @@ grecs_grecs_errlab1:
       YY_STACK_PRINT (grecs_grecs_ss, grecs_grecs_ssp);
     }
 
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++grecs_grecs_vsp = grecs_grecs_lval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
 
   grecs_grecs_error_range[2] = grecs_grecs_lloc;
   /* Using YYLLOC is tempting, but would change the location of
@@ -1989,8 +2003,7 @@ grecs_grecs_return:
 }
 
 
-
-/* Line 2071 of yacc.c  */
+/* Line 2055 of yacc.c  */
 #line 242 "grecs-gram.y"
 
 
@@ -2025,4 +2038,3 @@ grecs_grecs_parser(const char *name, int traceflags)
 
     
 
-
diff --git a/grecs/src/grecs-gram.h b/grecs/src/grecs-gram.h
index e7d4290..4e518db 100644
--- a/grecs/src/grecs-gram.h
+++ b/grecs/src/grecs-gram.h
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 2.5.1.  */
+/* A Bison parser, made by GNU Bison 2.7.  */
 
 /* Bison interface for Yacc-like parsers in C
    
@@ -30,6 +30,15 @@
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
+#ifndef YY_YY_GRECS_GRAM_H_INCLUDED
+# define YY_YY_GRECS_GRAM_H_INCLUDED
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int grecs_grecs_debug;
+#endif
 
 /* Tokens.  */
 #ifndef YYTOKENTYPE
@@ -51,12 +60,10 @@
 
 
 
-
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
 {
-
-/* Line 2072 of yacc.c  */
+/* Line 2058 of yacc.c  */
 #line 37 "grecs-gram.y"
 
 	char *string;
@@ -67,17 +74,14 @@ typedef union YYSTYPE
 	struct { struct grecs_node *head, *tail; } node_list;
 
 
-
-/* Line 2072 of yacc.c  */
-#line 73 "grecs-gram.h"
+/* Line 2058 of yacc.c  */
+#line 79 "grecs-gram.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define grecs_grecs_stype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 #endif
 
-extern YYSTYPE grecs_grecs_lval;
-
 #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
 typedef struct YYLTYPE
 {
@@ -91,5 +95,20 @@ typedef struct YYLTYPE
 # define YYLTYPE_IS_TRIVIAL 1
 #endif
 
+extern YYSTYPE grecs_grecs_lval;
 extern YYLTYPE grecs_grecs_lloc;
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int grecs_grecs_parse (void *YYPARSE_PARAM);
+#else
+int grecs_grecs_parse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int grecs_grecs_parse (void);
+#else
+int grecs_grecs_parse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
 
+#endif /* !YY_YY_GRECS_GRAM_H_INCLUDED  */
diff --git a/grecs/src/grecs-lex.c b/grecs/src/grecs-lex.c
index 4fd0f04..43c2b59 100644
--- a/grecs/src/grecs-lex.c
+++ b/grecs/src/grecs-lex.c
@@ -23,7 +23,7 @@
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
+#define YY_FLEX_SUBMINOR_VERSION 37
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -84,7 +84,6 @@ typedef int flex_int32_t;
 typedef unsigned char flex_uint8_t; 
 typedef unsigned short int flex_uint16_t;
 typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
 
 /* Limits of integral types. */
 #ifndef INT8_MIN
@@ -115,6 +114,8 @@ typedef unsigned int flex_uint32_t;
 #define UINT32_MAX             (4294967295U)
 #endif
 
+#endif /* ! C99 */
+
 #endif /* ! FLEXINT_H */
 
 /* %endif */
@@ -201,8 +202,13 @@ typedef unsigned int flex_uint32_t;
 typedef struct grecs_grecs__buffer_state *YY_BUFFER_STATE;
 #endif
 
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t grecs_grecs__size_t;
+#endif
+
 /* %if-not-reentrant */
-extern int grecs_grecs_leng;
+extern grecs_grecs__size_t grecs_grecs_leng;
 /* %endif */
 
 /* %if-c-only */
@@ -233,11 +239,6 @@ extern FILE *grecs_grecs_in, *grecs_grecs_out;
 
 #define unput(c) grecs_grecs_unput( c, (grecs_grecs_text_ptr)  )
 
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t grecs_grecs__size_t;
-#endif
-
 #ifndef YY_STRUCT_YY_BUFFER_STATE
 #define YY_STRUCT_YY_BUFFER_STATE
 struct grecs_grecs__buffer_state
@@ -260,7 +261,7 @@ struct grecs_grecs__buffer_state
 	/* Number of characters read into grecs_grecs__ch_buf, not including EOB
 	 * characters.
 	 */
-	int grecs_grecs__n_chars;
+	grecs_grecs__size_t grecs_grecs__n_chars;
 
 	/* Whether we "own" the buffer - i.e., we know we created it,
 	 * and can realloc() it to grow it, and should free() it to
@@ -344,8 +345,8 @@ static YY_BUFFER_STATE * grecs_grecs__buffer_stack = 0; /**< Stack as an array.
 
 /* grecs_grecs__hold_char holds the character lost when grecs_grecs_text is formed. */
 static char grecs_grecs__hold_char;
-static int grecs_grecs__n_chars;		/* number of characters read into grecs_grecs__ch_buf */
-int grecs_grecs_leng;
+static grecs_grecs__size_t grecs_grecs__n_chars;		/* number of characters read into grecs_grecs__ch_buf */
+grecs_grecs__size_t grecs_grecs_leng;
 
 /* Points to current character in buffer. */
 static char *grecs_grecs__c_buf_p = (char *) 0;
@@ -376,7 +377,7 @@ static void grecs_grecs__init_buffer (YY_BUFFER_STATE b,FILE *file  );
 
 YY_BUFFER_STATE grecs_grecs__scan_buffer (char *base,grecs_grecs__size_t size  );
 YY_BUFFER_STATE grecs_grecs__scan_string (grecs_grecs_const char *grecs_grecs__str  );
-YY_BUFFER_STATE grecs_grecs__scan_bytes (grecs_grecs_const char *bytes,int len  );
+YY_BUFFER_STATE grecs_grecs__scan_bytes (grecs_grecs_const char *bytes,grecs_grecs__size_t len  );
 
 /* %endif */
 
@@ -695,10 +696,10 @@ int grecs_grecs__flex_debug = 1;
 
 static grecs_grecs_const flex_int16_t grecs_grecs__rule_linenum[32] =
     {   0,
-       87,   88,   89,   90,   91,   93,   97,  102,  103,  104,
-      105,  107,  109,  115,  120,  126,  131,  134,  136,  143,
-      144,  145,  146,  147,  148,  152,  155,  176,  178,  179,
-      180
+       91,   92,   93,   94,   95,   97,  101,  106,  107,  108,
+      109,  111,  113,  119,  124,  130,  135,  138,  140,  147,
+      148,  149,  150,  151,  152,  156,  159,  180,  182,  183,
+      184
     } ;
 
 /* The intent behind this definition is that it'll catch
@@ -763,6 +764,10 @@ static int ident(void);
 static int isemptystr(int off);
 static void qstring_locus_fixup(void);
 
+#define qstring() \
+	((grecs_parser_options & GRECS_OPTION_QUOTED_STRING_CONCAT)	\
+	 ? QSTRING : STRING)
+
 #undef YY_INPUT
 #define YY_INPUT(buf,result,max_size)					\
 	do {								\
@@ -782,7 +787,7 @@ static void qstring_locus_fixup(void);
    	} while (0);
 
 
-#line 786 "grecs-lex.c"
+#line 791 "grecs-lex.c"
 
 #define INITIAL 0
 #define COMMENT 1
@@ -837,7 +842,7 @@ FILE *grecs_grecs_get_out (void );
 
 void grecs_grecs_set_out  (FILE * out_str  );
 
-int grecs_grecs_get_leng (void );
+grecs_grecs__size_t grecs_grecs_get_leng (void );
 
 char *grecs_grecs_get_text (void );
 
@@ -903,7 +908,7 @@ static int input (void );
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO fwrite( grecs_grecs_text, grecs_grecs_leng, 1, grecs_grecs_out )
+#define ECHO do { if (fwrite( grecs_grecs_text, grecs_grecs_leng, 1, grecs_grecs_out )) {} } while (0)
 /* %endif */
 /* %if-c++-only C++ definition */
 /* %endif */
@@ -918,7 +923,7 @@ static int input (void );
 	if ( YY_CURRENT_BUFFER_LVALUE->grecs_grecs__is_interactive ) \
 		{ \
 		int c = '*'; \
-		int n; \
+		size_t n; \
 		for ( n = 0; n < max_size && \
 			     (c = getc( grecs_grecs_in )) != EOF && c != '\n'; ++n ) \
 			buf[n] = (char) c; \
@@ -1028,10 +1033,10 @@ YY_DECL
 	register int grecs_grecs__act;
     
 /* %% [7.0] user's declarations go here */
-#line 85 "grecs-lex.l"
+#line 89 "grecs-lex.l"
 
          /* C-style comments */
-#line 1035 "grecs-lex.c"
+#line 1040 "grecs-lex.c"
 
 	if ( !(grecs_grecs__init) )
 		{
@@ -1148,35 +1153,35 @@ do_action:	/* This label is used only to access EOF actions. */
 
 case 1:
 YY_RULE_SETUP
-#line 87 "grecs-lex.l"
+#line 91 "grecs-lex.l"
 BEGIN(COMMENT);
 	YY_BREAK
 case 2:
 YY_RULE_SETUP
-#line 88 "grecs-lex.l"
+#line 92 "grecs-lex.l"
 /* eat anything that's not a '*' */
 	YY_BREAK
 case 3:
 YY_RULE_SETUP
-#line 89 "grecs-lex.l"
+#line 93 "grecs-lex.l"
 /* eat up '*'s not followed by '/'s */
 	YY_BREAK
 case 4:
 /* rule 4 can match eol */
 YY_RULE_SETUP
-#line 90 "grecs-lex.l"
+#line 94 "grecs-lex.l"
 grecs_locus_point_advance_line(grecs_current_locus_point);
 	YY_BREAK
 case 5:
 YY_RULE_SETUP
-#line 91 "grecs-lex.l"
+#line 95 "grecs-lex.l"
 BEGIN(INITIAL);
 	YY_BREAK
 /* Line directive */
 case 6:
 /* rule 6 can match eol */
 YY_RULE_SETUP
-#line 93 "grecs-lex.l"
+#line 97 "grecs-lex.l"
 { grecs_parse_line_directive_cpp(grecs_grecs_text,
 						    &grecs_grecs_lloc,
 						    &grecs_current_locus_point,
@@ -1185,7 +1190,7 @@ YY_RULE_SETUP
 case 7:
 /* rule 7 can match eol */
 YY_RULE_SETUP
-#line 97 "grecs-lex.l"
+#line 101 "grecs-lex.l"
 { grecs_parse_line_directive(grecs_grecs_text,
 							       &grecs_grecs_lloc,
 							       &grecs_current_locus_point,
@@ -1195,35 +1200,35 @@ YY_RULE_SETUP
 case 8:
 /* rule 8 can match eol */
 YY_RULE_SETUP
-#line 102 "grecs-lex.l"
+#line 106 "grecs-lex.l"
 { grecs_locus_point_advance_line(grecs_current_locus_point); }
 	YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 103 "grecs-lex.l"
+#line 107 "grecs-lex.l"
 /* end-of-file comment */;
 	YY_BREAK
 case 10:
 /* rule 10 can match eol */
 YY_RULE_SETUP
-#line 104 "grecs-lex.l"
+#line 108 "grecs-lex.l"
 { grecs_locus_point_advance_line(grecs_current_locus_point); }
 	YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 105 "grecs-lex.l"
+#line 109 "grecs-lex.l"
 /* end-of-file comment */;
 	YY_BREAK
 /* Identifiers */
 case 12:
 YY_RULE_SETUP
-#line 107 "grecs-lex.l"
+#line 111 "grecs-lex.l"
 return ident();
 	YY_BREAK
 /* Strings */
 case 13:
 YY_RULE_SETUP
-#line 109 "grecs-lex.l"
+#line 113 "grecs-lex.l"
 {
 	                   grecs_line_begin();
 	                   grecs_line_add(grecs_grecs_text, grecs_grecs_leng);
@@ -1233,17 +1238,17 @@ YY_RULE_SETUP
 /* Quoted strings */
 case 14:
 YY_RULE_SETUP
-#line 115 "grecs-lex.l"
+#line 119 "grecs-lex.l"
 { grecs_line_begin();
                         grecs_line_add(grecs_grecs_text + 1, grecs_grecs_leng - 2);
                         grecs_grecs_lval.string = grecs_line_finish();
                         qstring_locus_fixup();
-                        return QSTRING; }
+                        return qstring(); }
 	YY_BREAK
 case 15:
 /* rule 15 can match eol */
 YY_RULE_SETUP
-#line 120 "grecs-lex.l"
+#line 124 "grecs-lex.l"
 { BEGIN(STR);
                          grecs_line_begin();
 		         grecs_line_acc_grow_unescape_last(grecs_grecs_text + 1,
@@ -1253,7 +1258,7 @@ YY_RULE_SETUP
 	YY_BREAK
 case 16:
 YY_RULE_SETUP
-#line 126 "grecs-lex.l"
+#line 130 "grecs-lex.l"
 { BEGIN(STR);
                          grecs_line_begin();
 		         grecs_line_acc_grow_unescape_last(grecs_grecs_text + 1,
@@ -1263,47 +1268,47 @@ YY_RULE_SETUP
 case 17:
 /* rule 17 can match eol */
 YY_RULE_SETUP
-#line 131 "grecs-lex.l"
+#line 135 "grecs-lex.l"
 { grecs_line_acc_grow_unescape_last(grecs_grecs_text, grecs_grecs_leng, 
                                                           &grecs_grecs_lloc);
                         grecs_locus_point_advance_line(grecs_current_locus_point); }
 	YY_BREAK
 case 18:
 YY_RULE_SETUP
-#line 134 "grecs-lex.l"
+#line 138 "grecs-lex.l"
 { grecs_line_acc_grow_unescape_last(grecs_grecs_text, grecs_grecs_leng, 
                                                           &grecs_grecs_lloc); }
 	YY_BREAK
 case 19:
 YY_RULE_SETUP
-#line 136 "grecs-lex.l"
+#line 140 "grecs-lex.l"
 { BEGIN(INITIAL);
                         if (grecs_grecs_leng > 1) 
 				grecs_line_add(grecs_grecs_text, grecs_grecs_leng - 1); 
                         grecs_grecs_lval.string = grecs_line_finish();
 			qstring_locus_fixup();    
-		        return QSTRING; }
+		        return qstring(); }
 	YY_BREAK
 /* Multiline strings */
 case 20:
 /* rule 20 can match eol */
-#line 144 "grecs-lex.l"
+#line 148 "grecs-lex.l"
 case 21:
 /* rule 21 can match eol */
-#line 145 "grecs-lex.l"
+#line 149 "grecs-lex.l"
 case 22:
 /* rule 22 can match eol */
-#line 146 "grecs-lex.l"
+#line 150 "grecs-lex.l"
 case 23:
 /* rule 23 can match eol */
-#line 147 "grecs-lex.l"
+#line 151 "grecs-lex.l"
 case 24:
 /* rule 24 can match eol */
-#line 148 "grecs-lex.l"
+#line 152 "grecs-lex.l"
 case 25:
 /* rule 25 can match eol */
 YY_RULE_SETUP
-#line 148 "grecs-lex.l"
+#line 152 "grecs-lex.l"
 {
                 BEGIN(ML);
 		multiline_begin(grecs_grecs_text+2); }
@@ -1312,7 +1317,7 @@ YY_RULE_SETUP
 case 26:
 /* rule 26 can match eol */
 YY_RULE_SETUP
-#line 152 "grecs-lex.l"
+#line 156 "grecs-lex.l"
 {
 	grecs_locus_point_advance_line(grecs_current_locus_point);
 }
@@ -1320,7 +1325,7 @@ YY_RULE_SETUP
 case 27:
 /* rule 27 can match eol */
 YY_RULE_SETUP
-#line 155 "grecs-lex.l"
+#line 159 "grecs-lex.l"
 { char *p = multiline_strip_tabs(grecs_grecs_text);
 	   
            if (!strncmp(p, multiline_delimiter, multiline_delimiter_len)
@@ -1345,24 +1350,24 @@ YY_RULE_SETUP
 	YY_BREAK
 case 28:
 YY_RULE_SETUP
-#line 176 "grecs-lex.l"
+#line 180 "grecs-lex.l"
 ;
 	YY_BREAK
 /* Other tokens */
 case 29:
 /* rule 29 can match eol */
 YY_RULE_SETUP
-#line 178 "grecs-lex.l"
+#line 182 "grecs-lex.l"
 { grecs_locus_point_advance_line(grecs_current_locus_point); } 
 	YY_BREAK
 case 30:
 YY_RULE_SETUP
-#line 179 "grecs-lex.l"
+#line 183 "grecs-lex.l"
 return grecs_grecs_text[0];
 	YY_BREAK
 case 31:
 YY_RULE_SETUP
-#line 180 "grecs-lex.l"
+#line 184 "grecs-lex.l"
 { if (isascii(grecs_grecs_text[0]) && isprint(grecs_grecs_text[0]))
 		grecs_error(&grecs_grecs_lloc, 0,
 			     _("stray character %c"), grecs_grecs_text[0]);
@@ -1373,10 +1378,10 @@ YY_RULE_SETUP
 	YY_BREAK
 case 32:
 YY_RULE_SETUP
-#line 187 "grecs-lex.l"
+#line 191 "grecs-lex.l"
 ECHO;
 	YY_BREAK
-#line 1380 "grecs-lex.c"
+#line 1385 "grecs-lex.c"
 case YY_STATE_EOF(INITIAL):
 case YY_STATE_EOF(COMMENT):
 case YY_STATE_EOF(ML):
@@ -1578,21 +1583,21 @@ static int grecs_grecs__get_next_buffer (void)
 
 	else
 		{
-			int num_to_read =
+			grecs_grecs__size_t num_to_read =
 			YY_CURRENT_BUFFER_LVALUE->grecs_grecs__buf_size - number_to_move - 1;
 
 		while ( num_to_read <= 0 )
 			{ /* Not enough room in the buffer - grow it. */
 
 			/* just a shorter name for the current buffer */
-			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
 
 			int grecs_grecs__c_buf_p_offset =
 				(int) ((grecs_grecs__c_buf_p) - b->grecs_grecs__ch_buf);
 
 			if ( b->grecs_grecs__is_our_buffer )
 				{
-				int new_size = b->grecs_grecs__buf_size * 2;
+				grecs_grecs__size_t new_size = b->grecs_grecs__buf_size * 2;
 
 				if ( new_size <= 0 )
 					b->grecs_grecs__buf_size += b->grecs_grecs__buf_size / 8;
@@ -1623,7 +1628,7 @@ static int grecs_grecs__get_next_buffer (void)
 
 		/* Read in more data. */
 		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->grecs_grecs__ch_buf[number_to_move]),
-			(grecs_grecs__n_chars), (size_t) num_to_read );
+			(grecs_grecs__n_chars), num_to_read );
 
 		YY_CURRENT_BUFFER_LVALUE->grecs_grecs__n_chars = (grecs_grecs__n_chars);
 		}
@@ -1732,7 +1737,7 @@ static int grecs_grecs__get_next_buffer (void)
 	grecs_grecs__current_state = grecs_grecs__nxt[grecs_grecs__base[grecs_grecs__current_state] + (unsigned int) grecs_grecs__c];
 	grecs_grecs__is_jam = (grecs_grecs__current_state == 133);
 
-	return grecs_grecs__is_jam ? 0 : grecs_grecs__current_state;
+		return grecs_grecs__is_jam ? 0 : grecs_grecs__current_state;
 }
 
 /* %if-c-only */
@@ -1767,7 +1772,7 @@ static int grecs_grecs__get_next_buffer (void)
 
 		else
 			{ /* need more input */
-			int offset = (grecs_grecs__c_buf_p) - (grecs_grecs_text_ptr);
+			grecs_grecs__size_t offset = (grecs_grecs__c_buf_p) - (grecs_grecs_text_ptr);
 			++(grecs_grecs__c_buf_p);
 
 			switch ( grecs_grecs__get_next_buffer(  ) )
@@ -1952,17 +1957,6 @@ static void grecs_grecs__load_buffer_state  (void)
 	grecs_grecs_free((void *) b  );
 }
 
-/* %if-c-only */
-
-#ifndef __cplusplus
-extern int isatty (int );
-#endif /* __cplusplus */
-    
-/* %endif */
-
-/* %if-c++-only */
-/* %endif */
-
 /* Initializes or reinitializes a buffer.
  * This function is sometimes called more than once on the same buffer,
  * such as during a grecs_grecs_restart() or at EOF.
@@ -2105,7 +2099,7 @@ static void grecs_grecs_ensure_buffer_stack (void)
 /* %if-c++-only */
 /* %endif */
 {
-	int num_to_alloc;
+	grecs_grecs__size_t num_to_alloc;
     
 	if (!(grecs_grecs__buffer_stack)) {
 
@@ -2203,12 +2197,12 @@ YY_BUFFER_STATE grecs_grecs__scan_string (grecs_grecs_const char * grecs_grecs_s
 /* %if-c-only */
 /** Setup the input buffer state to scan the given bytes. The next call to grecs_grecs_lex() will
  * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param grecs_grecs_bytes the byte buffer to scan
+ * @param _grecs_grecs_bytes_len the number of bytes in the buffer pointed to by @a bytes.
  * 
  * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE grecs_grecs__scan_bytes  (grecs_grecs_const char * grecs_grecs_bytes, int  _grecs_grecs_bytes_len )
+YY_BUFFER_STATE grecs_grecs__scan_bytes  (grecs_grecs_const char * grecs_grecs_bytes, grecs_grecs__size_t  _grecs_grecs_bytes_len )
 {
 	YY_BUFFER_STATE b;
 	char *buf;
@@ -2304,7 +2298,7 @@ FILE *grecs_grecs_get_out  (void)
 /** Get the length of the current token.
  * 
  */
-int grecs_grecs_get_leng  (void)
+grecs_grecs__size_t grecs_grecs_get_leng  (void)
 {
         return grecs_grecs_leng;
 }
@@ -2473,7 +2467,7 @@ void grecs_grecs_free (void * ptr )
 
 /* %ok-for-header */
 
-#line 187 "grecs-lex.l"
+#line 191 "grecs-lex.l"
 
 
 
@@ -2639,7 +2633,7 @@ ident()
 static void
 qstring_locus_fixup()
 {
-	if (grecs_adjust_string_locations) {
+	if (grecs_parser_options & GRECS_OPTION_ADJUST_STRING_LOCATIONS) {
 		grecs_grecs_lloc.beg.col++;
 		grecs_grecs_lloc.end.col--;
 	}
diff --git a/grecs/src/grecs-lex.l b/grecs/src/grecs-lex.l
index 113ee88..f7be62f 100644
--- a/grecs/src/grecs-lex.l
+++ b/grecs/src/grecs-lex.l
@@ -56,6 +56,10 @@ static int ident(void);
 static int isemptystr(int off);
 static void qstring_locus_fixup(void);
 
+#define qstring() \
+	((grecs_parser_options & GRECS_OPTION_QUOTED_STRING_CONCAT)	\
+	 ? QSTRING : STRING)
+
 #undef YY_INPUT
 #define YY_INPUT(buf,result,max_size)					\
 	do {								\
@@ -116,7 +120,7 @@ P [1-9][0-9]*
                         grecs_line_add(yytext + 1, yyleng - 2);
                         yylval.string = grecs_line_finish();
                         qstring_locus_fixup();
-                        return QSTRING; }
+                        return qstring(); }
 \"[^\\"\n]*\\\n        { BEGIN(STR);
                          grecs_line_begin();
 		         grecs_line_acc_grow_unescape_last(yytext + 1,
@@ -138,7 +142,7 @@ P [1-9][0-9]*
 				grecs_line_add(yytext, yyleng - 1); 
                         yylval.string = grecs_line_finish();
 			qstring_locus_fixup();    
-		        return QSTRING; }
+		        return qstring(); }
          /* Multiline strings */
 "<<"(-" "?)?\\?{ID}[ \t]*#.*\n |
 "<<"(-" "?)?\\?{ID}[ \t]*"//".*\n |
@@ -348,7 +352,7 @@ ident()
 static void
 qstring_locus_fixup()
 {
-	if (grecs_adjust_string_locations) {
+	if (grecs_parser_options & GRECS_OPTION_ADJUST_STRING_LOCATIONS) {
 		yylloc.beg.col++;
 		yylloc.end.col--;
 	}
diff --git a/grecs/src/json-gram.c b/grecs/src/json-gram.c
index 0c39440..6a1a63e 100644
--- a/grecs/src/json-gram.c
+++ b/grecs/src/json-gram.c
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 2.5.1.  */
+/* A Bison parser, made by GNU Bison 2.7.  */
 
 /* Bison implementation for Yacc-like parsers in C
    
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.5.1"
+#define YYBISON_VERSION "2.7"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -58,14 +58,11 @@
 /* Pull parsers.  */
 #define YYPULL 1
 
-/* Using locations.  */
-#define YYLSP_NEEDED 1
 
 
 
 /* Copy the first part of user declarations.  */
-
-/* Line 268 of yacc.c  */
+/* Line 371 of yacc.c  */
 #line 1 "json-gram.y"
 
 /* This file is part of Grecs.
@@ -116,9 +113,8 @@ objfree(void *ptr)
 }
 
 
-
-/* Line 268 of yacc.c  */
-#line 122 "json-gram.c"
+/* Line 371 of yacc.c  */
+#line 118 "json-gram.c"
 
 # ifndef YY_NULL
 #  if defined __cplusplus && 201103L <= __cplusplus
@@ -128,11 +124,6 @@ objfree(void *ptr)
 #  endif
 # endif
 
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 1
-#endif
-
 /* Enabling verbose error messages.  */
 #ifdef YYERROR_VERBOSE
 # undef YYERROR_VERBOSE
@@ -141,11 +132,17 @@ objfree(void *ptr)
 # define YYERROR_VERBOSE 1
 #endif
 
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
+/* In a future release of Bison, this section will be replaced
+   by #include "y.tab.h".  */
+#ifndef YY_YY_JSON_GRAM_H_INCLUDED
+# define YY_YY_JSON_GRAM_H_INCLUDED
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int grecs_json_debug;
 #endif
-
 
 /* Tokens.  */
 #ifndef YYTOKENTYPE
@@ -169,12 +166,10 @@ objfree(void *ptr)
 
 
 
-
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
 {
-
-/* Line 295 of yacc.c  */
+/* Line 387 of yacc.c  */
 #line 64 "json-gram.y"
 
 	int b;
@@ -186,9 +181,8 @@ typedef union YYSTYPE
 	struct json_pair *p;
 
 
-
-/* Line 295 of yacc.c  */
-#line 192 "json-gram.c"
+/* Line 387 of yacc.c  */
+#line 186 "json-gram.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define grecs_json_stype YYSTYPE /* obsolescent; will be withdrawn */
@@ -208,12 +202,28 @@ typedef struct YYLTYPE
 # define YYLTYPE_IS_TRIVIAL 1
 #endif
 
+extern YYSTYPE grecs_json_lval;
+extern YYLTYPE grecs_json_lloc;
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int grecs_json_parse (void *YYPARSE_PARAM);
+#else
+int grecs_json_parse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int grecs_json_parse (void);
+#else
+int grecs_json_parse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
 
-/* Copy the second part of user declarations.  */
+#endif /* !YY_YY_JSON_GRAM_H_INCLUDED  */
 
+/* Copy the second part of user declarations.  */
 
-/* Line 345 of yacc.c  */
-#line 217 "json-gram.c"
+/* Line 390 of yacc.c  */
+#line 227 "json-gram.c"
 
 #ifdef short
 # undef short
@@ -266,24 +276,24 @@ typedef short int grecs_json_type_int16;
 # if defined YYENABLE_NLS && YYENABLE_NLS
 #  if ENABLE_NLS
 #   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
 #  endif
 # endif
 # ifndef YY_
-#  define YY_(msgid) msgid
+#  define YY_(Msgid) Msgid
 # endif
 #endif
 
 /* Suppress unused-variable warnings by "using" E.  */
 #if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
+# define YYUSE(E) ((void) (E))
 #else
-# define YYUSE(e) /* empty */
+# define YYUSE(E) /* empty */
 #endif
 
 /* Identity function, used to suppress warnings about constant conditions.  */
 #ifndef lint
-# define YYID(n) (n)
+# define YYID(N) (N)
 #else
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
@@ -512,7 +522,7 @@ static const grecs_json_type_uint8 grecs_json_rline[] =
 };
 #endif
 
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+#if YYDEBUG || YYERROR_VERBOSE || 1
 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const grecs_json_tname[] =
@@ -590,10 +600,10 @@ static const grecs_json_type_uint8 grecs_json_table[] =
       20,    26,     0,    23,    22,    24,    25,    21
 };
 
-#define grecs_json_pact_value_is_default(grecs_json_state) \
-  ((grecs_json_state) == (-13))
+#define grecs_json_pact_value_is_default(Yystate) \
+  (!!((Yystate) == (-13)))
 
-#define grecs_json_table_value_is_error(grecs_json_table_value) \
+#define grecs_json_table_value_is_error(Yytable_value) \
   YYID (0)
 
 static const grecs_json_type_int8 grecs_json_check[] =
@@ -655,7 +665,7 @@ do                                                              \
     }								\
 while (YYID (0))
 
-
+/* Error token number */
 #define YYTERROR	1
 #define YYERRCODE	256
 
@@ -664,27 +674,28 @@ while (YYID (0))
    If N is 0, then set CURRENT to the empty location which ends
    the previous symbol: RHS[0] (always defined).  */
 
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
 #ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)				\
-    do									\
-      if (YYID (N))                                                    \
-	{								\
-	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
-	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
-	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
-	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
-	}								\
-      else								\
-	{								\
-	  (Current).first_line   = (Current).last_line   =		\
-	    YYRHSLOC (Rhs, 0).last_line;				\
-	  (Current).first_column = (Current).last_column =		\
-	    YYRHSLOC (Rhs, 0).last_column;				\
-	}								\
+# define YYLLOC_DEFAULT(Current, Rhs, N)                                \
+    do                                                                  \
+      if (YYID (N))                                                     \
+        {                                                               \
+          (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
+          (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
+          (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
+          (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
+        }                                                               \
+      else                                                              \
+        {                                                               \
+          (Current).first_line   = (Current).last_line   =              \
+            YYRHSLOC (Rhs, 0).last_line;                                \
+          (Current).first_column = (Current).last_column =              \
+            YYRHSLOC (Rhs, 0).last_column;                              \
+        }                                                               \
     while (YYID (0))
 #endif
 
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
 
 /* YY_LOCATION_PRINT -- Print the location on the stream.
    This macro was not mandated originally: define only if we know
@@ -692,10 +703,46 @@ while (YYID (0))
 
 #ifndef YY_LOCATION_PRINT
 # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)			\
-     fprintf (File, "%d.%d-%d.%d",			\
-	      (Loc).first_line, (Loc).first_column,	\
-	      (Loc).last_line,  (Loc).last_column)
+
+/* Print *YYLOCP on YYO.  Private, do not rely on its existence. */
+
+__attribute__((__unused__))
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static unsigned
+grecs_json__location_print_ (FILE *grecs_json_o, YYLTYPE const * const grecs_json_locp)
+#else
+static unsigned
+grecs_json__location_print_ (grecs_json_o, grecs_json_locp)
+    FILE *grecs_json_o;
+    YYLTYPE const * const grecs_json_locp;
+#endif
+{
+  unsigned res = 0;
+  int end_col = 0 != grecs_json_locp->last_column ? grecs_json_locp->last_column - 1 : 0;
+  if (0 <= grecs_json_locp->first_line)
+    {
+      res += fprintf (grecs_json_o, "%d", grecs_json_locp->first_line);
+      if (0 <= grecs_json_locp->first_column)
+        res += fprintf (grecs_json_o, ".%d", grecs_json_locp->first_column);
+    }
+  if (0 <= grecs_json_locp->last_line)
+    {
+      if (grecs_json_locp->first_line < grecs_json_locp->last_line)
+        {
+          res += fprintf (grecs_json_o, "-%d", grecs_json_locp->last_line);
+          if (0 <= end_col)
+            res += fprintf (grecs_json_o, ".%d", end_col);
+        }
+      else if (0 <= end_col && grecs_json_locp->first_column < end_col)
+        res += fprintf (grecs_json_o, "-%d", end_col);
+    }
+  return res;
+ }
+
+#  define YY_LOCATION_PRINT(File, Loc)          \
+  grecs_json__location_print_ (File, &(Loc))
+
 # else
 #  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
 # endif
@@ -703,7 +750,6 @@ while (YYID (0))
 
 
 /* YYLEX -- calling `grecs_json_lex' with the right arguments.  */
-
 #ifdef YYLEX_PARAM
 # define YYLEX grecs_json_lex (YYLEX_PARAM)
 #else
@@ -768,7 +814,7 @@ grecs_json__symbol_value_print (grecs_json_output, grecs_json_type, grecs_json_v
   switch (grecs_json_type)
     {
       default:
-	break;
+        break;
     }
 }
 
@@ -1014,7 +1060,6 @@ grecs_json_syntax_error (YYSIZE_T *grecs_json_msg_alloc, char **grecs_json_msg,
 {
   YYSIZE_T grecs_json_size0 = grecs_json_tnamerr (YY_NULL, grecs_json_tname[grecs_json_token]);
   YYSIZE_T grecs_json_size = grecs_json_size0;
-  YYSIZE_T grecs_json_size1;
   enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
   /* Internationalized format string. */
   const char *grecs_json_format = YY_NULL;
@@ -1077,11 +1122,13 @@ grecs_json_syntax_error (YYSIZE_T *grecs_json_msg_alloc, char **grecs_json_msg,
                     break;
                   }
                 grecs_json_arg[grecs_json_count++] = grecs_json_tname[grecs_json_x];
-                grecs_json_size1 = grecs_json_size + grecs_json_tnamerr (YY_NULL, grecs_json_tname[grecs_json_x]);
-                if (! (grecs_json_size <= grecs_json_size1
-                       && grecs_json_size1 <= YYSTACK_ALLOC_MAXIMUM))
-                  return 2;
-                grecs_json_size = grecs_json_size1;
+                {
+                  YYSIZE_T grecs_json_size1 = grecs_json_size + grecs_json_tnamerr (YY_NULL, grecs_json_tname[grecs_json_x]);
+                  if (! (grecs_json_size <= grecs_json_size1
+                         && grecs_json_size1 <= YYSTACK_ALLOC_MAXIMUM))
+                    return 2;
+                  grecs_json_size = grecs_json_size1;
+                }
               }
         }
     }
@@ -1101,10 +1148,12 @@ grecs_json_syntax_error (YYSIZE_T *grecs_json_msg_alloc, char **grecs_json_msg,
 # undef YYCASE_
     }
 
-  grecs_json_size1 = grecs_json_size + grecs_json_strlen (grecs_json_format);
-  if (! (grecs_json_size <= grecs_json_size1 && grecs_json_size1 <= YYSTACK_ALLOC_MAXIMUM))
-    return 2;
-  grecs_json_size = grecs_json_size1;
+  {
+    YYSIZE_T grecs_json_size1 = grecs_json_size + grecs_json_strlen (grecs_json_format);
+    if (! (grecs_json_size <= grecs_json_size1 && grecs_json_size1 <= YYSTACK_ALLOC_MAXIMUM))
+      return 2;
+    grecs_json_size = grecs_json_size1;
+  }
 
   if (*grecs_json_msg_alloc < grecs_json_size)
     {
@@ -1166,35 +1215,35 @@ grecs_json_destruct (grecs_json_msg, grecs_json_type, grecs_json_valuep, grecs_j
     {
 
       default:
-	break;
+        break;
     }
 }
 
 
-/* Prevent warnings from -Wmissing-prototypes.  */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int grecs_json_parse (void *YYPARSE_PARAM);
-#else
-int grecs_json_parse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int grecs_json_parse (void);
-#else
-int grecs_json_parse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
 
 
 /* The lookahead symbol.  */
 int grecs_json_char;
 
+
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
 /* The semantic value of the lookahead symbol.  */
-YYSTYPE grecs_json_lval;
+YYSTYPE grecs_json_lval YY_INITIAL_VALUE(grecs_json_val_default);
 
 /* Location data for the lookahead symbol.  */
-YYLTYPE grecs_json_lloc;
+YYLTYPE grecs_json_lloc
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  = { 1, 1, 1, 1 }
+# endif
+;
+
 
 /* Number of syntax errors so far.  */
 int grecs_json_nerrs;
@@ -1261,7 +1310,7 @@ grecs_json_parse ()
   int grecs_json_n;
   int grecs_json_result;
   /* Lookahead token as an internal (translated) token number.  */
-  int grecs_json_token;
+  int grecs_json_token = 0;
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE grecs_json_val;
@@ -1280,10 +1329,9 @@ grecs_json_parse ()
      Keep to zero when no symbol should be popped.  */
   int grecs_json_len = 0;
 
-  grecs_json_token = 0;
-  grecs_json_ss = grecs_json_ssa;
-  grecs_json_vs = grecs_json_vsa;
-  grecs_json_ls = grecs_json_lsa;
+  grecs_json_ssp = grecs_json_ss = grecs_json_ssa;
+  grecs_json_vsp = grecs_json_vs = grecs_json_vsa;
+  grecs_json_lsp = grecs_json_ls = grecs_json_lsa;
   grecs_json_stacksize = YYINITDEPTH;
 
   YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1292,21 +1340,7 @@ grecs_json_parse ()
   grecs_json_errstatus = 0;
   grecs_json_nerrs = 0;
   grecs_json_char = YYEMPTY; /* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-  grecs_json_ssp = grecs_json_ss;
-  grecs_json_vsp = grecs_json_vs;
-  grecs_json_lsp = grecs_json_ls;
-
-#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-  /* Initialize the default location before parsing starts.  */
-  grecs_json_lloc.first_line   = grecs_json_lloc.last_line   = 1;
-  grecs_json_lloc.first_column = grecs_json_lloc.last_column = 1;
-#endif
-
+  grecs_json_lsp[0] = grecs_json_lloc;
   goto grecs_json_setstate;
 
 /*------------------------------------------------------------.
@@ -1452,7 +1486,9 @@ grecs_json_backup:
   grecs_json_char = YYEMPTY;
 
   grecs_json_state = grecs_json_n;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++grecs_json_vsp = grecs_json_lval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
   *++grecs_json_lsp = grecs_json_lloc;
   goto grecs_json_newstate;
 
@@ -1490,8 +1526,7 @@ grecs_json_reduce:
   switch (grecs_json_n)
     {
         case 2:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 76 "json-gram.y"
     {
   	      json_return_obj = (grecs_json_vsp[(1) - (1)].obj);
@@ -1499,8 +1534,7 @@ grecs_json_reduce:
     break;
 
   case 3:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 82 "json-gram.y"
     {
 	      (grecs_json_val.obj) = json_value_create(json_number);
@@ -1509,8 +1543,7 @@ grecs_json_reduce:
     break;
 
   case 4:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 87 "json-gram.y"
     {
 	      (grecs_json_val.obj) = json_value_create(json_string);
@@ -1519,8 +1552,7 @@ grecs_json_reduce:
     break;
 
   case 5:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 92 "json-gram.y"
     {
 	      (grecs_json_val.obj) = json_value_create(json_bool);
@@ -1529,8 +1561,7 @@ grecs_json_reduce:
     break;
 
   case 6:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 97 "json-gram.y"
     {
 	      (grecs_json_val.obj) = json_value_create(json_null);
@@ -1538,8 +1569,7 @@ grecs_json_reduce:
     break;
 
   case 8:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 102 "json-gram.y"
     {
 	      (grecs_json_val.obj) = json_value_create(json_object);
@@ -1548,8 +1578,7 @@ grecs_json_reduce:
     break;
 
   case 9:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 109 "json-gram.y"
     {
 	       (grecs_json_val.obj) = json_new_array();
@@ -1558,8 +1587,7 @@ grecs_json_reduce:
     break;
 
   case 10:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 116 "json-gram.y"
     {
 	       (grecs_json_val.list) = NULL;
@@ -1567,8 +1595,7 @@ grecs_json_reduce:
     break;
 
   case 12:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 123 "json-gram.y"
     {
 	       (grecs_json_val.list) = grecs_list_create();
@@ -1577,8 +1604,7 @@ grecs_json_reduce:
     break;
 
   case 13:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 128 "json-gram.y"
     {
  	       grecs_list_append((grecs_json_vsp[(1) - (3)].list), (grecs_json_vsp[(3) - (3)].obj));
@@ -1586,8 +1612,7 @@ grecs_json_reduce:
     break;
 
   case 14:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 134 "json-gram.y"
     {
 	      struct grecs_symtab *s;
@@ -1611,8 +1636,7 @@ grecs_json_reduce:
     break;
 
   case 15:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 156 "json-gram.y"
     {
 	       (grecs_json_val.list) = NULL;
@@ -1620,8 +1644,7 @@ grecs_json_reduce:
     break;
 
   case 17:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 163 "json-gram.y"
     {
 	       (grecs_json_val.list) = grecs_list_create();
@@ -1631,8 +1654,7 @@ grecs_json_reduce:
     break;
 
   case 18:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 169 "json-gram.y"
     {
  	       grecs_list_append((grecs_json_vsp[(1) - (3)].list), (grecs_json_vsp[(3) - (3)].p));
@@ -1640,8 +1662,7 @@ grecs_json_reduce:
     break;
 
   case 19:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 175 "json-gram.y"
     {
 	       struct json_pair *p = grecs_malloc(sizeof(*p));
@@ -1652,9 +1673,8 @@ grecs_json_reduce:
     break;
 
 
-
-/* Line 1810 of yacc.c  */
-#line 1658 "json-gram.c"
+/* Line 1792 of yacc.c  */
+#line 1678 "json-gram.c"
       default: break;
     }
   /* User semantic actions sometimes alter grecs_json_char, and that requires
@@ -1819,7 +1839,9 @@ grecs_json_errlab1:
       YY_STACK_PRINT (grecs_json_ss, grecs_json_ssp);
     }
 
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++grecs_json_vsp = grecs_json_lval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
 
   grecs_json_error_range[2] = grecs_json_lloc;
   /* Using YYLLOC is tempting, but would change the location of
@@ -1890,8 +1912,7 @@ grecs_json_return:
 }
 
 
-
-/* Line 2071 of yacc.c  */
+/* Line 2055 of yacc.c  */
 #line 182 "json-gram.y"
 
 
@@ -1994,6 +2015,7 @@ json_parse_string(char const *input, size_t len)
 		/* FIXME: error recovery */
 		return NULL;
 	}
+	jsonlex_cleanup();
 	return json_return_obj;
 }
 
@@ -2243,4 +2265,3 @@ json_array_get(struct json_value *j, size_t idx, struct json_value **retval)
 	*retval = j->v.a->ov[idx];
 	return 0;
 }
-
diff --git a/grecs/src/json-gram.y b/grecs/src/json-gram.y
index fe8996b..d5b0248 100644
--- a/grecs/src/json-gram.y
+++ b/grecs/src/json-gram.y
@@ -280,6 +280,7 @@ json_parse_string(char const *input, size_t len)
 		/* FIXME: error recovery */
 		return NULL;
 	}
+	jsonlex_cleanup();
 	return json_return_obj;
 }
 
diff --git a/grecs/src/json-lex.c b/grecs/src/json-lex.c
index f39e6b0..4ce3da3 100644
--- a/grecs/src/json-lex.c
+++ b/grecs/src/json-lex.c
@@ -22,8 +22,8 @@
 
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 0
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -84,7 +84,6 @@ typedef int flex_int32_t;
 typedef unsigned char flex_uint8_t; 
 typedef unsigned short int flex_uint16_t;
 typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
 
 /* Limits of integral types. */
 #ifndef INT8_MIN
@@ -115,6 +114,8 @@ typedef unsigned int flex_uint32_t;
 #define UINT32_MAX             (4294967295U)
 #endif
 
+#endif /* ! C99 */
+
 #endif /* ! FLEXINT_H */
 
 /* %endif */
@@ -189,7 +190,15 @@ typedef unsigned int flex_uint32_t;
 
 /* Size of default input buffer. */
 #ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
 #define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
 #endif
 
 /* The state buf must be large enough to hold one state per character in the main buffer.
@@ -201,8 +210,13 @@ typedef unsigned int flex_uint32_t;
 typedef struct grecs_json__buffer_state *YY_BUFFER_STATE;
 #endif
 
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t grecs_json__size_t;
+#endif
+
 /* %if-not-reentrant */
-extern int grecs_json_leng;
+extern grecs_json__size_t grecs_json_leng;
 /* %endif */
 
 /* %if-c-only */
@@ -216,6 +230,7 @@ extern FILE *grecs_json_in, *grecs_json_out;
 #define EOB_ACT_LAST_MATCH 2
 
     #define YY_LESS_LINENO(n)
+    #define YY_LINENO_REWIND_TO(ptr)
     
 /* Return all but the first "n" matched characters back to the input stream. */
 #define grecs_json_less(n) \
@@ -233,11 +248,6 @@ extern FILE *grecs_json_in, *grecs_json_out;
 
 #define unput(c) grecs_json_unput( c, (grecs_json_text_ptr)  )
 
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t grecs_json__size_t;
-#endif
-
 #ifndef YY_STRUCT_YY_BUFFER_STATE
 #define YY_STRUCT_YY_BUFFER_STATE
 struct grecs_json__buffer_state
@@ -260,7 +270,7 @@ struct grecs_json__buffer_state
 	/* Number of characters read into grecs_json__ch_buf, not including EOB
 	 * characters.
 	 */
-	int grecs_json__n_chars;
+	grecs_json__size_t grecs_json__n_chars;
 
 	/* Whether we "own" the buffer - i.e., we know we created it,
 	 * and can realloc() it to grow it, and should free() it to
@@ -344,8 +354,8 @@ static YY_BUFFER_STATE * grecs_json__buffer_stack = 0; /**< Stack as an array. *
 
 /* grecs_json__hold_char holds the character lost when grecs_json_text is formed. */
 static char grecs_json__hold_char;
-static int grecs_json__n_chars;		/* number of characters read into grecs_json__ch_buf */
-int grecs_json_leng;
+static grecs_json__size_t grecs_json__n_chars;		/* number of characters read into grecs_json__ch_buf */
+grecs_json__size_t grecs_json_leng;
 
 /* Points to current character in buffer. */
 static char *grecs_json__c_buf_p = (char *) 0;
@@ -376,7 +386,7 @@ static void grecs_json__init_buffer (YY_BUFFER_STATE b,FILE *file  );
 
 YY_BUFFER_STATE grecs_json__scan_buffer (char *base,grecs_json__size_t size  );
 YY_BUFFER_STATE grecs_json__scan_string (grecs_json_const char *grecs_json__str  );
-YY_BUFFER_STATE grecs_json__scan_bytes (grecs_json_const char *bytes,int len  );
+YY_BUFFER_STATE grecs_json__scan_bytes (grecs_json_const char *bytes,grecs_json__size_t len  );
 
 /* %endif */
 
@@ -409,6 +419,7 @@ void grecs_json_free (void *  );
 #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->grecs_json__at_bol)
 
 /* %% [1.0] grecs_json_text/grecs_json_in/grecs_json_out/grecs_json__state_type/grecs_json_lineno etc. def's & init go here */
+/* Begin user sect3 */
 
 #define FLEX_DEBUG
 
@@ -423,13 +434,21 @@ extern int grecs_json_lineno;
 int grecs_json_lineno = 1;
 
 extern char *grecs_json_text;
+#ifdef grecs_json_text_ptr
+#undef grecs_json_text_ptr
+#endif
 #define grecs_json_text_ptr grecs_json_text
 
+/* %% [1.5] DFA */
+
 /* %if-c-only Standard (non-C++) definition */
 
 static grecs_json__state_type grecs_json__get_previous_state (void );
 static grecs_json__state_type grecs_json__try_NUL_trans (grecs_json__state_type current_state  );
 static int grecs_json__get_next_buffer (void );
+#if defined(__GNUC__) && __GNUC__ >= 3
+__attribute__((__noreturn__))
+#endif
 static void grecs_json__fatal_error (grecs_json_const char msg[]  );
 
 /* %endif */
@@ -466,7 +485,7 @@ static grecs_json_const flex_int16_t grecs_json__accept[61] =
         0,    8,    9,    0,    0,    1,   10,    6,    3,    0
     } ;
 
-static grecs_json_const flex_int32_t grecs_json__ec[256] =
+static grecs_json_const YY_CHAR grecs_json__ec[256] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -498,14 +517,14 @@ static grecs_json_const flex_int32_t grecs_json__ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static grecs_json_const flex_int32_t grecs_json__meta[26] =
+static grecs_json_const YY_CHAR grecs_json__meta[26] =
     {   0,
         1,    1,    2,    1,    1,    1,    1,    3,    1,    3,
         3,    1,    1,    1,    3,    3,    3,    1,    1,    1,
         1,    1,    1,    1,    1
     } ;
 
-static grecs_json_const flex_int16_t grecs_json__base[73] =
+static grecs_json_const flex_uint16_t grecs_json__base[73] =
     {   0,
         0,    0,   22,   23,  110,  131,  107,  131,   24,  131,
       100,   22,   83,   70,   72,   27,  131,   33,   80,   38,
@@ -529,7 +548,7 @@ static grecs_json_const flex_int16_t grecs_json__def[73] =
        60,   60
     } ;
 
-static grecs_json_const flex_int16_t grecs_json__nxt[157] =
+static grecs_json_const flex_uint16_t grecs_json__nxt[157] =
     {   0,
         6,    7,    8,    9,    6,   10,   11,   12,   10,    6,
         6,   10,    6,   10,    6,    6,   13,    6,   14,    6,
@@ -579,8 +598,8 @@ int grecs_json__flex_debug = 1;
 
 static grecs_json_const flex_int16_t grecs_json__rule_linenum[15] =
     {   0,
-      181,  185,  189,  194,  204,  209,  213,  222,  223,  224,
-      225,  226,  227,  228
+      169,  173,  177,  182,  192,  197,  201,  210,  211,  212,
+      213,  214,  215,  216
     } ;
 
 /* The intent behind this definition is that it'll catch
@@ -643,18 +662,6 @@ struct grecs_locus json_err_locus;
  		grecs_json_lloc.end = json_current_locus_point;			\
    	} while (0);
 
-void
-jsonlex_setup(char const *s, size_t l)
-{
-	input_ptr = s;
-	input_size = l;
-	json_current_locus_point.file = NULL;
-	json_current_locus_point.line = 1;
-	json_current_locus_point.col = 0;
-	json_err_diag = NULL;
-	grecs_json__flex_debug = 0;
-}
-
 void
 jsonlex_diag(const char *s)
 {
@@ -763,7 +770,7 @@ json_line_grow(char const *text, size_t len)
 	grecs_txtacc_grow(json_line_acc, text, len);
 }	
 
-#line 767 "json-lex.c"
+#line 774 "json-lex.c"
 
 #define INITIAL 0
 #define STR 1
@@ -810,19 +817,19 @@ void grecs_json_set_extra (YY_EXTRA_TYPE user_defined  );
 
 FILE *grecs_json_get_in (void );
 
-void grecs_json_set_in  (FILE * in_str  );
+void grecs_json_set_in  (FILE * _in_str  );
 
 FILE *grecs_json_get_out (void );
 
-void grecs_json_set_out  (FILE * out_str  );
+void grecs_json_set_out  (FILE * _out_str  );
 
-int grecs_json_get_leng (void );
+grecs_json__size_t grecs_json_get_leng (void );
 
 char *grecs_json_get_text (void );
 
 int grecs_json_get_lineno (void );
 
-void grecs_json_set_lineno (int line_number  );
+void grecs_json_set_lineno (int _line_number  );
 
 /* %if-bison-bridge */
 /* %endif */
@@ -841,6 +848,9 @@ extern int grecs_json_wrap (void );
 
 /* %not-for-header */
 
+#ifndef YY_NO_UNPUT
+    
+#endif
 /* %ok-for-header */
 
 /* %endif */
@@ -873,7 +883,12 @@ static int input (void );
 
 /* Amount of stuff to slurp up with each read. */
 #ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
 #define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
 #endif
 
 /* Copy whatever the last rule matched to the standard output. */
@@ -882,7 +897,7 @@ static int input (void );
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO fwrite( grecs_json_text, grecs_json_leng, 1, grecs_json_out )
+#define ECHO do { if (fwrite( grecs_json_text, grecs_json_leng, 1, grecs_json_out )) {} } while (0)
 /* %endif */
 /* %if-c++-only C++ definition */
 /* %endif */
@@ -897,7 +912,7 @@ static int input (void );
 	if ( YY_CURRENT_BUFFER_LVALUE->grecs_json__is_interactive ) \
 		{ \
 		int c = '*'; \
-		int n; \
+		size_t n; \
 		for ( n = 0; n < max_size && \
 			     (c = getc( grecs_json_in )) != EOF && c != '\n'; ++n ) \
 			buf[n] = (char) c; \
@@ -986,7 +1001,7 @@ extern int grecs_json_lex (void);
 
 /* Code executed at the end of each rule. */
 #ifndef YY_BREAK
-#define YY_BREAK break;
+#define YY_BREAK /*LINTED*/break;
 #endif
 
 /* %% [6.0] YY_RULE_SETUP definition goes here */
@@ -999,15 +1014,10 @@ extern int grecs_json_lex (void);
  */
 YY_DECL
 {
-	register grecs_json__state_type grecs_json__current_state;
-	register char *grecs_json__cp, *grecs_json__bp;
-	register int grecs_json__act;
+	grecs_json__state_type grecs_json__current_state;
+	char *grecs_json__cp, *grecs_json__bp;
+	int grecs_json__act;
     
-/* %% [7.0] user's declarations go here */
-#line 180 "json-lex.l"
-
-#line 1010 "json-lex.c"
-
 	if ( !(grecs_json__init) )
 		{
 		(grecs_json__init) = 1;
@@ -1042,7 +1052,13 @@ YY_DECL
 		grecs_json__load_buffer_state( );
 		}
 
-	while ( 1 )		/* loops until end-of-file is reached */
+	{
+/* %% [7.0] user's declarations go here */
+#line 168 "json-lex.l"
+
+#line 1060 "json-lex.c"
+
+	while ( /*CONSTCOND*/1 )		/* loops until end-of-file is reached */
 		{
 /* %% [8.0] grecs_json_more()-related code goes here */
 		grecs_json__cp = (grecs_json__c_buf_p);
@@ -1060,7 +1076,7 @@ YY_DECL
 grecs_json__match:
 		do
 			{
-			register YY_CHAR grecs_json__c = grecs_json__ec[YY_SC_TO_UI(*grecs_json__cp)];
+			YY_CHAR grecs_json__c = grecs_json__ec[YY_SC_TO_UI(*grecs_json__cp)] ;
 			if ( grecs_json__accept[grecs_json__current_state] )
 				{
 				(grecs_json__last_accepting_state) = grecs_json__current_state;
@@ -1122,7 +1138,7 @@ do_action:	/* This label is used only to access EOF actions. */
 
 case 1:
 YY_RULE_SETUP
-#line 181 "json-lex.l"
+#line 169 "json-lex.l"
 {
 	grecs_json_lval.n = strtod(grecs_json_text, NULL);
 	return T_NUMBER;
@@ -1131,7 +1147,7 @@ YY_RULE_SETUP
 case 2:
 /* rule 2 can match eol */
 YY_RULE_SETUP
-#line 185 "json-lex.l"
+#line 173 "json-lex.l"
 { json_line_begin();
                      json_line_grow(grecs_json_text + 1, grecs_json_leng - 2);
                      grecs_json_lval.s = json_line_finish();
@@ -1140,7 +1156,7 @@ YY_RULE_SETUP
 case 3:
 /* rule 3 can match eol */
 YY_RULE_SETUP
-#line 189 "json-lex.l"
+#line 177 "json-lex.l"
 { BEGIN(STR);
                      json_line_begin();
                      json_line_grow(grecs_json_text + 1, grecs_json_leng - 5);
@@ -1150,7 +1166,7 @@ YY_RULE_SETUP
 case 4:
 /* rule 4 can match eol */
 YY_RULE_SETUP
-#line 194 "json-lex.l"
+#line 182 "json-lex.l"
 { char c;
                      BEGIN(STR);
                      json_line_begin();
@@ -1165,7 +1181,7 @@ YY_RULE_SETUP
 case 5:
 /* rule 5 can match eol */
 YY_RULE_SETUP
-#line 204 "json-lex.l"
+#line 192 "json-lex.l"
 { BEGIN(INITIAL);
                         if (grecs_json_leng > 1)
 				json_line_grow(grecs_json_text, grecs_json_leng - 1); 
@@ -1175,7 +1191,7 @@ YY_RULE_SETUP
 case 6:
 /* rule 6 can match eol */
 YY_RULE_SETUP
-#line 209 "json-lex.l"
+#line 197 "json-lex.l"
 {
                      json_line_grow(grecs_json_text, grecs_json_leng - 5);
                      utf8_wctomb(grecs_json_text + grecs_json_leng - 4);
@@ -1184,7 +1200,7 @@ YY_RULE_SETUP
 case 7:
 /* rule 7 can match eol */
 YY_RULE_SETUP
-#line 213 "json-lex.l"
+#line 201 "json-lex.l"
 {
                      char c;
                      json_line_grow(grecs_json_text, grecs_json_leng - 2);
@@ -1196,47 +1212,47 @@ YY_RULE_SETUP
 	YY_BREAK
 case 8:
 YY_RULE_SETUP
-#line 222 "json-lex.l"
+#line 210 "json-lex.l"
 { return T_NULL; }
 	YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 223 "json-lex.l"
+#line 211 "json-lex.l"
 { grecs_json_lval.b = 1; return T_BOOL; }
 	YY_BREAK
 case 10:
 YY_RULE_SETUP
-#line 224 "json-lex.l"
+#line 212 "json-lex.l"
 { grecs_json_lval.b = 0; return T_BOOL; }
 	YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 225 "json-lex.l"
+#line 213 "json-lex.l"
 return grecs_json_text[0];
 	YY_BREAK
 case 12:
 YY_RULE_SETUP
-#line 226 "json-lex.l"
+#line 214 "json-lex.l"
 ;
 	YY_BREAK
 case 13:
 /* rule 13 can match eol */
 YY_RULE_SETUP
-#line 227 "json-lex.l"
+#line 215 "json-lex.l"
 grecs_locus_point_advance_line(json_current_locus_point);
 	YY_BREAK
 case 14:
 YY_RULE_SETUP
-#line 228 "json-lex.l"
+#line 216 "json-lex.l"
 { jsonlex_diag("bogus character");
             return T_ERR; }
 	YY_BREAK
 case 15:
 YY_RULE_SETUP
-#line 230 "json-lex.l"
+#line 218 "json-lex.l"
 ECHO;
 	YY_BREAK
-#line 1240 "json-lex.c"
+#line 1256 "json-lex.c"
 case YY_STATE_EOF(INITIAL):
 case YY_STATE_EOF(STR):
 	grecs_json_terminate();
@@ -1262,7 +1278,11 @@ case YY_STATE_EOF(STR):
 			 * back-up) that will match for the new input source.
 			 */
 			(grecs_json__n_chars) = YY_CURRENT_BUFFER_LVALUE->grecs_json__n_chars;
+/* %if-c-only */
 			YY_CURRENT_BUFFER_LVALUE->grecs_json__input_file = grecs_json_in;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
 			YY_CURRENT_BUFFER_LVALUE->grecs_json__buffer_status = YY_BUFFER_NORMAL;
 			}
 
@@ -1369,6 +1389,7 @@ case YY_STATE_EOF(STR):
 			"fatal flex scanner internal error--no action found" );
 	} /* end of action switch */
 		} /* end of scanning one token */
+	} /* end of user's declarations */
 } /* end of grecs_json_lex */
 /* %ok-for-header */
 
@@ -1392,9 +1413,9 @@ static int grecs_json__get_next_buffer (void)
 /* %if-c++-only */
 /* %endif */
 {
-    	register char *dest = YY_CURRENT_BUFFER_LVALUE->grecs_json__ch_buf;
-	register char *source = (grecs_json_text_ptr);
-	register int number_to_move, i;
+    	char *dest = YY_CURRENT_BUFFER_LVALUE->grecs_json__ch_buf;
+	char *source = (grecs_json_text_ptr);
+	grecs_json__size_t number_to_move, i;
 	int ret_val;
 
 	if ( (grecs_json__c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->grecs_json__ch_buf[(grecs_json__n_chars) + 1] )
@@ -1423,7 +1444,7 @@ static int grecs_json__get_next_buffer (void)
 	/* Try to read more data. */
 
 	/* First move last chars to start of buffer. */
-	number_to_move = (int) ((grecs_json__c_buf_p) - (grecs_json_text_ptr)) - 1;
+	number_to_move = (grecs_json__size_t) ((grecs_json__c_buf_p) - (grecs_json_text_ptr)) - 1;
 
 	for ( i = 0; i < number_to_move; ++i )
 		*(dest++) = *(source++);
@@ -1436,21 +1457,21 @@ static int grecs_json__get_next_buffer (void)
 
 	else
 		{
-			int num_to_read =
+			grecs_json__size_t num_to_read =
 			YY_CURRENT_BUFFER_LVALUE->grecs_json__buf_size - number_to_move - 1;
 
 		while ( num_to_read <= 0 )
 			{ /* Not enough room in the buffer - grow it. */
 
 			/* just a shorter name for the current buffer */
-			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
 
 			int grecs_json__c_buf_p_offset =
 				(int) ((grecs_json__c_buf_p) - b->grecs_json__ch_buf);
 
 			if ( b->grecs_json__is_our_buffer )
 				{
-				int new_size = b->grecs_json__buf_size * 2;
+				grecs_json__size_t new_size = b->grecs_json__buf_size * 2;
 
 				if ( new_size <= 0 )
 					b->grecs_json__buf_size += b->grecs_json__buf_size / 8;
@@ -1481,7 +1502,7 @@ static int grecs_json__get_next_buffer (void)
 
 		/* Read in more data. */
 		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->grecs_json__ch_buf[number_to_move]),
-			(grecs_json__n_chars), (size_t) num_to_read );
+			(grecs_json__n_chars), num_to_read );
 
 		YY_CURRENT_BUFFER_LVALUE->grecs_json__n_chars = (grecs_json__n_chars);
 		}
@@ -1532,8 +1553,8 @@ static int grecs_json__get_next_buffer (void)
 /* %if-c++-only */
 /* %endif */
 {
-	register grecs_json__state_type grecs_json__current_state;
-	register char *grecs_json__cp;
+	grecs_json__state_type grecs_json__current_state;
+	char *grecs_json__cp;
     
 /* %% [15.0] code to get the start state into grecs_json__current_state goes here */
 	grecs_json__current_state = (grecs_json__start);
@@ -1541,7 +1562,7 @@ static int grecs_json__get_next_buffer (void)
 	for ( grecs_json__cp = (grecs_json_text_ptr) + YY_MORE_ADJ; grecs_json__cp < (grecs_json__c_buf_p); ++grecs_json__cp )
 		{
 /* %% [16.0] code to find the next state goes here */
-		register YY_CHAR grecs_json__c = (*grecs_json__cp ? grecs_json__ec[YY_SC_TO_UI(*grecs_json__cp)] : 1);
+		YY_CHAR grecs_json__c = (*grecs_json__cp ? grecs_json__ec[YY_SC_TO_UI(*grecs_json__cp)] : 1);
 		if ( grecs_json__accept[grecs_json__current_state] )
 			{
 			(grecs_json__last_accepting_state) = grecs_json__current_state;
@@ -1570,11 +1591,11 @@ static int grecs_json__get_next_buffer (void)
 /* %if-c++-only */
 /* %endif */
 {
-	register int grecs_json__is_jam;
+	int grecs_json__is_jam;
     /* %% [17.0] code to find the next state, and perhaps do backing up, goes here */
-	register char *grecs_json__cp = (grecs_json__c_buf_p);
+	char *grecs_json__cp = (grecs_json__c_buf_p);
 
-	register YY_CHAR grecs_json__c = 1;
+	YY_CHAR grecs_json__c = 1;
 	if ( grecs_json__accept[grecs_json__current_state] )
 		{
 		(grecs_json__last_accepting_state) = grecs_json__current_state;
@@ -1589,12 +1610,14 @@ static int grecs_json__get_next_buffer (void)
 	grecs_json__current_state = grecs_json__nxt[grecs_json__base[grecs_json__current_state] + (unsigned int) grecs_json__c];
 	grecs_json__is_jam = (grecs_json__current_state == 60);
 
-	return grecs_json__is_jam ? 0 : grecs_json__current_state;
+		return grecs_json__is_jam ? 0 : grecs_json__current_state;
 }
 
+#ifndef YY_NO_UNPUT
 /* %if-c-only */
 
 /* %endif */
+#endif
 
 /* %if-c-only */
 #ifndef YY_NO_INPUT
@@ -1624,7 +1647,7 @@ static int grecs_json__get_next_buffer (void)
 
 		else
 			{ /* need more input */
-			int offset = (grecs_json__c_buf_p) - (grecs_json_text_ptr);
+			grecs_json__size_t offset = (grecs_json__c_buf_p) - (grecs_json_text_ptr);
 			++(grecs_json__c_buf_p);
 
 			switch ( grecs_json__get_next_buffer(  ) )
@@ -1700,6 +1723,9 @@ static int grecs_json__get_next_buffer (void)
 	grecs_json__load_buffer_state( );
 }
 
+/* %if-c++-only */
+/* %endif */
+
 /** Switch to a different input buffer.
  * @param new_buffer The new input buffer.
  * 
@@ -1747,7 +1773,11 @@ static void grecs_json__load_buffer_state  (void)
 {
     	(grecs_json__n_chars) = YY_CURRENT_BUFFER_LVALUE->grecs_json__n_chars;
 	(grecs_json_text_ptr) = (grecs_json__c_buf_p) = YY_CURRENT_BUFFER_LVALUE->grecs_json__buf_pos;
+/* %if-c-only */
 	grecs_json_in = YY_CURRENT_BUFFER_LVALUE->grecs_json__input_file;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
 	(grecs_json__hold_char) = *(grecs_json__c_buf_p);
 }
 
@@ -1769,7 +1799,7 @@ static void grecs_json__load_buffer_state  (void)
 	if ( ! b )
 		YY_FATAL_ERROR( "out of dynamic memory in grecs_json__create_buffer()" );
 
-	b->grecs_json__buf_size = size;
+	b->grecs_json__buf_size = (grecs_json__size_t)size;
 
 	/* grecs_json__ch_buf has to be 2 characters longer than the size given because
 	 * we need to put in 2 end-of-buffer characters.
@@ -1785,6 +1815,9 @@ static void grecs_json__load_buffer_state  (void)
 	return b;
 }
 
+/* %if-c++-only */
+/* %endif */
+
 /** Destroy the buffer.
  * @param b a buffer created with grecs_json__create_buffer()
  * 
@@ -1808,17 +1841,6 @@ static void grecs_json__load_buffer_state  (void)
 	grecs_json_free((void *) b  );
 }
 
-/* %if-c-only */
-
-#ifndef __cplusplus
-extern int isatty (int );
-#endif /* __cplusplus */
-    
-/* %endif */
-
-/* %if-c++-only */
-/* %endif */
-
 /* Initializes or reinitializes a buffer.
  * This function is sometimes called more than once on the same buffer,
  * such as during a grecs_json_restart() or at EOF.
@@ -1834,7 +1856,11 @@ extern int isatty (int );
     
 	grecs_json__flush_buffer(b );
 
+/* %if-c-only */
 	b->grecs_json__input_file = file;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
 	b->grecs_json__fill_buffer = 1;
 
     /* If b is the current buffer, then grecs_json__init_buffer was _probably_
@@ -1961,7 +1987,7 @@ static void grecs_json_ensure_buffer_stack (void)
 /* %if-c++-only */
 /* %endif */
 {
-	int num_to_alloc;
+	grecs_json__size_t num_to_alloc;
     
 	if (!(grecs_json__buffer_stack)) {
 
@@ -1969,7 +1995,7 @@ static void grecs_json_ensure_buffer_stack (void)
 		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
 		 * immediate realloc on the next call.
          */
-		num_to_alloc = 1;
+		num_to_alloc = 1; // After all that talk, this was set to 1 anyways...
 		(grecs_json__buffer_stack) = (struct grecs_json__buffer_state**)grecs_json_alloc
 								(num_to_alloc * sizeof(struct grecs_json__buffer_state*)
 								);
@@ -1986,7 +2012,7 @@ static void grecs_json_ensure_buffer_stack (void)
 	if ((grecs_json__buffer_stack_top) >= ((grecs_json__buffer_stack_max)) - 1){
 
 		/* Increase the buffer to prepare for a possible push. */
-		int grow_size = 8 /* arbitrary grow size */;
+		grecs_json__size_t grow_size = 8 /* arbitrary grow size */;
 
 		num_to_alloc = (grecs_json__buffer_stack_max) + grow_size;
 		(grecs_json__buffer_stack) = (struct grecs_json__buffer_state**)grecs_json_realloc
@@ -2059,17 +2085,17 @@ YY_BUFFER_STATE grecs_json__scan_string (grecs_json_const char * grecs_json_str
 /* %if-c-only */
 /** Setup the input buffer state to scan the given bytes. The next call to grecs_json_lex() will
  * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param grecs_json_bytes the byte buffer to scan
+ * @param _grecs_json_bytes_len the number of bytes in the buffer pointed to by @a bytes.
  * 
  * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE grecs_json__scan_bytes  (grecs_json_const char * grecs_json_bytes, int  _grecs_json_bytes_len )
+YY_BUFFER_STATE grecs_json__scan_bytes  (grecs_json_const char * grecs_json_bytes, grecs_json__size_t  _grecs_json_bytes_len )
 {
 	YY_BUFFER_STATE b;
 	char *buf;
 	grecs_json__size_t n;
-	int i;
+	grecs_json__size_t i;
     
 	/* Get memory for full buffer, including space for trailing EOB's. */
 	n = _grecs_json_bytes_len + 2;
@@ -2102,7 +2128,7 @@ YY_BUFFER_STATE grecs_json__scan_bytes  (grecs_json_const char * grecs_json_byte
 /* %if-c-only */
 static void grecs_json__fatal_error (grecs_json_const char* msg )
 {
-    	(void) fprintf( stderr, "%s\n", msg );
+			(void) fprintf( stderr, "%s\n", msg );
 	exit( YY_EXIT_FAILURE );
 }
 /* %endif */
@@ -2160,7 +2186,7 @@ FILE *grecs_json_get_out  (void)
 /** Get the length of the current token.
  * 
  */
-int grecs_json_get_leng  (void)
+grecs_json__size_t grecs_json_get_leng  (void)
 {
         return grecs_json_leng;
 }
@@ -2178,29 +2204,29 @@ char *grecs_json_get_text  (void)
 /* %endif */
 
 /** Set the current line number.
- * @param line_number
+ * @param _line_number line number
  * 
  */
-void grecs_json_set_lineno (int  line_number )
+void grecs_json_set_lineno (int  _line_number )
 {
     
-    grecs_json_lineno = line_number;
+    grecs_json_lineno = _line_number;
 }
 
 /** Set the input stream. This does not discard the current
  * input buffer.
- * @param in_str A readable stream.
+ * @param _in_str A readable stream.
  * 
  * @see grecs_json__switch_to_buffer
  */
-void grecs_json_set_in (FILE *  in_str )
+void grecs_json_set_in (FILE *  _in_str )
 {
-        grecs_json_in = in_str ;
+        grecs_json_in = _in_str ;
 }
 
-void grecs_json_set_out (FILE *  out_str )
+void grecs_json_set_out (FILE *  _out_str )
 {
-        grecs_json_out = out_str ;
+        grecs_json_out = _out_str ;
 }
 
 int grecs_json_get_debug  (void)
@@ -2208,9 +2234,9 @@ int grecs_json_get_debug  (void)
         return grecs_json__flex_debug;
 }
 
-void grecs_json_set_debug (int  bdebug )
+void grecs_json_set_debug (int  _bdebug )
 {
-        grecs_json__flex_debug = bdebug ;
+        grecs_json__flex_debug = _bdebug ;
 }
 
 /* %endif */
@@ -2283,7 +2309,8 @@ int grecs_json_lex_destroy  (void)
 #ifndef grecs_json_text_ptr
 static void grecs_json__flex_strncpy (char* s1, grecs_json_const char * s2, int n )
 {
-	register int i;
+		
+	int i;
 	for ( i = 0; i < n; ++i )
 		s1[i] = s2[i];
 }
@@ -2292,7 +2319,7 @@ static void grecs_json__flex_strncpy (char* s1, grecs_json_const char * s2, int
 #ifdef YY_NEED_STRLEN
 static int grecs_json__flex_strlen (grecs_json_const char * s )
 {
-	register int n;
+	int n;
 	for ( n = 0; s[n]; ++n )
 		;
 
@@ -2302,11 +2329,12 @@ static int grecs_json__flex_strlen (grecs_json_const char * s )
 
 void *grecs_json_alloc (grecs_json__size_t  size )
 {
-	return (void *) malloc( size );
+			return (void *) malloc( size );
 }
 
 void *grecs_json_realloc  (void * ptr, grecs_json__size_t  size )
 {
+		
 	/* The cast to (char *) in the following accommodates both
 	 * implementations that use char* generic pointers, and those
 	 * that use void* generic pointers.  It works with the latter
@@ -2319,7 +2347,7 @@ void *grecs_json_realloc  (void * ptr, grecs_json__size_t  size )
 
 void grecs_json_free (void * ptr )
 {
-	free( (char *) ptr );	/* see grecs_json_realloc() for (char *) cast */
+			free( (char *) ptr );	/* see grecs_json_realloc() for (char *) cast */
 }
 
 /* %if-tables-serialization definitions */
@@ -2329,4 +2357,29 @@ void grecs_json_free (void * ptr )
 
 /* %ok-for-header */
 
-#line 230 "json-lex.l"
+#line 218 "json-lex.l"
+
+
+void
+jsonlex_setup(char const *s, size_t l)
+{
+	input_ptr = s;
+	input_size = l;
+	json_current_locus_point.file = "input";
+	json_current_locus_point.line = 1;
+	json_current_locus_point.col = 0;
+	json_err_diag = NULL;
+        grecs_json__flex_debug = 0;
+        BEGIN(INITIAL);
+        grecs_json_restart(NULL);
+}
+
+void
+jsonlex_cleanup(void)
+{
+        if (json_line_acc) {
+	        grecs_txtacc_free(json_line_acc);
+                json_line_acc = NULL;
+	}
+}
+
diff --git a/grecs/src/json-lex.l b/grecs/src/json-lex.l
index 169cf32..4bbdedf 100644
--- a/grecs/src/json-lex.l
+++ b/grecs/src/json-lex.l
@@ -54,18 +54,6 @@ struct grecs_locus json_err_locus;
  		yylloc.end = json_current_locus_point;			\
    	} while (0);
 
-void
-jsonlex_setup(char const *s, size_t l)
-{
-	input_ptr = s;
-	input_size = l;
-	json_current_locus_point.file = NULL;
-	json_current_locus_point.line = 1;
-	json_current_locus_point.col = 0;
-	json_err_diag = NULL;
-	yy_flex_debug = 0;
-}
-
 void
 jsonlex_diag(const char *s)
 {
@@ -227,3 +215,26 @@ false     { yylval.b = 0; return T_BOOL; }
 \n        grecs_locus_point_advance_line(json_current_locus_point);
 .         { jsonlex_diag("bogus character");
             return T_ERR; }
+%%
+void
+jsonlex_setup(char const *s, size_t l)
+{
+	input_ptr = s;
+	input_size = l;
+	json_current_locus_point.file = "input";
+	json_current_locus_point.line = 1;
+	json_current_locus_point.col = 0;
+	json_err_diag = NULL;
+        yy_flex_debug = 0;
+        BEGIN(INITIAL);
+        yyrestart(NULL);
+}
+
+void
+jsonlex_cleanup(void)
+{
+        if (json_line_acc) {
+	        grecs_txtacc_free(json_line_acc);
+                json_line_acc = NULL;
+	}
+}
diff --git a/grecs/src/jsonfmt.c b/grecs/src/jsonfmt.c
index 9ccac37..9d900ca 100644
--- a/grecs/src/jsonfmt.c
+++ b/grecs/src/jsonfmt.c
@@ -124,10 +124,10 @@ json_format_obj(struct json_format *fmt, struct json_value *obj, size_t level)
 	size_t count, i;
 	struct json_pair **keypairs, **kp;
 	
-	count = grecs_symtab_count_entries(obj->v.o);
+	count = grecs_symtab_count(obj->v.o);
 	keypairs = grecs_calloc(count, sizeof(*keypairs));
 	kp = keypairs;
-	grecs_symtab_enumerate(obj->v.o, collect_keypairs, &kp);
+	grecs_symtab_foreach(obj->v.o, collect_keypairs, &kp);
 	qsort(keypairs, count, sizeof(*keypairs), keypair_cmp_name);
 
 	json_writec(fmt, '{');
diff --git a/grecs/src/list.c b/grecs/src/list.c
index b2d9f13..afd1b5d 100644
--- a/grecs/src/list.c
+++ b/grecs/src/list.c
@@ -86,6 +86,46 @@ grecs_list_remove_entry(struct grecs_list *lp, struct grecs_list_entry *ent)
 	lp->count--;
 }
 
+void *
+grecs_list_remove_tail(struct grecs_list *lp)
+{
+	void *data;
+	struct grecs_list_entry *ep;
+  
+	if (!lp || !lp->tail)
+		return NULL;
+	ep = lp->tail;
+	data = lp->tail->data;
+	grecs_list_remove_entry(lp, ep);
+	return data;
+}
+
+static int
+_ptrcmp(const void *a, const void *b)
+{
+	return a != b;
+}
+
+int
+grecs_list_remove(struct grecs_list *lp, void *data)
+{
+	struct grecs_list_entry *ep;
+	int (*cmp)(const void *, const void *);
+
+
+	if (!lp)
+		return 1;
+	
+	cmp = lp->cmp ? lp->cmp : _ptrcmp;
+	for (ep = lp->head; ep; ep = ep->next) {
+		if (cmp(ep->data, data) == 0) {
+			grecs_list_remove_entry(lp, ep);
+			return 0;
+		}
+	}
+	return 1;
+}
+
 void
 grecs_list_append(struct grecs_list *lp, void *val)
 {
@@ -123,7 +163,11 @@ void *
 grecs_list_pop(struct grecs_list *lp)
 {
 	void *data;
-	struct grecs_list_entry *ep = lp->head;
+	struct grecs_list_entry *ep;
+
+	if (!lp)
+		return NULL;
+	ep = lp->head;
 	if (ep)	{
 		data = ep->data;
 		grecs_list_remove_entry(lp, ep);
@@ -132,25 +176,14 @@ grecs_list_pop(struct grecs_list *lp)
 	return data;
 }
 
-void *
-grecs_list_remove_tail(struct grecs_list *lp)
-{
-	void *data;
-	struct grecs_list_entry *ep;
-  
-	if (!lp->tail)
-		return NULL;
-	ep = lp->tail;
-	data = lp->tail->data;
-	grecs_list_remove_entry(lp, ep);
-	return data;
-}
-
 void
 grecs_list_clear(struct grecs_list *lp)
 {
-	struct grecs_list_entry *ep = lp->head;
+	struct grecs_list_entry *ep;
 
+	if (!lp)
+		return;
+	ep = lp->head;
 	while (ep) {
 		struct grecs_list_entry *next = ep->next;
 		if (lp->free_entry)
@@ -171,17 +204,16 @@ grecs_list_free(struct grecs_list *lp)
 	}
 }
 
-static int
-_ptrcmp(const void *a, const void *b)
-{
-	return a != b;
-}
-
 void *
 grecs_list_locate(struct grecs_list *lp, void *data)
 {
 	struct grecs_list_entry *ep;
-	int (*cmp)(const void *, const void *) = lp->cmp ? lp->cmp : _ptrcmp;
+	int (*cmp)(const void *, const void *);
+
+	if (!lp)
+		return NULL;
+	
+	cmp = lp->cmp ? lp->cmp : _ptrcmp;
 
 	for (ep = lp->head; ep; ep = ep->next) {
 		if (cmp(ep->data, data) == 0)
@@ -194,7 +226,9 @@ void *
 grecs_list_index(struct grecs_list *lp, size_t idx)
 {
 	struct grecs_list_entry *ep;
-	
+
+	if (!lp)
+		return NULL;
 	for (ep = lp->head; ep && idx; ep = ep->next, idx--)
 		;
 	return ep ? ep->data : NULL;
@@ -219,7 +253,7 @@ grecs_list_compare(struct grecs_list *a, struct grecs_list *b)
 	cmp = a->cmp ? a->cmp : _ptrcmp;
 	
 	for (ap = a->head, bp = b->head; ap; ap = ap->next, bp = bp->next)
-		if (cmp (ap->data, bp->data))
+		if (cmp(ap->data, bp->data))
 			return 1;
 	
 	return 0;
diff --git a/grecs/src/meta1-gram.c b/grecs/src/meta1-gram.c
index 71c3488..8684329 100644
--- a/grecs/src/meta1-gram.c
+++ b/grecs/src/meta1-gram.c
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 2.5.1.  */
+/* A Bison parser, made by GNU Bison 2.7.  */
 
 /* Bison implementation for Yacc-like parsers in C
    
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.5.1"
+#define YYBISON_VERSION "2.7"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -58,14 +58,11 @@
 /* Pull parsers.  */
 #define YYPULL 1
 
-/* Using locations.  */
-#define YYLSP_NEEDED 1
 
 
 
 /* Copy the first part of user declarations.  */
-
-/* Line 268 of yacc.c  */
+/* Line 371 of yacc.c  */
 #line 1 "meta1-gram.y"
 
 /* MeTA1 configuration parser for Grecs.
@@ -98,9 +95,8 @@ static struct grecs_node *parse_tree;
 extern int grecs_meta1__flex_debug;
 extern void grecs_meta1_set_in(FILE *);
 
-
-/* Line 268 of yacc.c  */
-#line 104 "meta1-gram.c"
+/* Line 371 of yacc.c  */
+#line 100 "meta1-gram.c"
 
 # ifndef YY_NULL
 #  if defined __cplusplus && 201103L <= __cplusplus
@@ -110,11 +106,6 @@ extern void grecs_meta1_set_in(FILE *);
 #  endif
 # endif
 
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 1
-#endif
-
 /* Enabling verbose error messages.  */
 #ifdef YYERROR_VERBOSE
 # undef YYERROR_VERBOSE
@@ -123,11 +114,17 @@ extern void grecs_meta1_set_in(FILE *);
 # define YYERROR_VERBOSE 1
 #endif
 
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
+/* In a future release of Bison, this section will be replaced
+   by #include "y.tab.h".  */
+#ifndef YY_YY_Y_TAB_H_INCLUDED
+# define YY_YY_Y_TAB_H_INCLUDED
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int grecs_meta1_debug;
 #endif
-
 
 /* Tokens.  */
 #ifndef YYTOKENTYPE
@@ -145,12 +142,10 @@ extern void grecs_meta1_set_in(FILE *);
 
 
 
-
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
 {
-
-/* Line 295 of yacc.c  */
+/* Line 387 of yacc.c  */
 #line 36 "meta1-gram.y"
 
 	char *string;
@@ -160,9 +155,8 @@ typedef union YYSTYPE
 	struct grecs_node *node;
 
 
-
-/* Line 295 of yacc.c  */
-#line 166 "meta1-gram.c"
+/* Line 387 of yacc.c  */
+#line 160 "meta1-gram.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define grecs_meta1_stype YYSTYPE /* obsolescent; will be withdrawn */
@@ -182,12 +176,28 @@ typedef struct YYLTYPE
 # define YYLTYPE_IS_TRIVIAL 1
 #endif
 
+extern YYSTYPE grecs_meta1_lval;
+extern YYLTYPE grecs_meta1_lloc;
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int grecs_meta1_parse (void *YYPARSE_PARAM);
+#else
+int grecs_meta1_parse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int grecs_meta1_parse (void);
+#else
+int grecs_meta1_parse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
 
-/* Copy the second part of user declarations.  */
+#endif /* !YY_YY_Y_TAB_H_INCLUDED  */
 
+/* Copy the second part of user declarations.  */
 
-/* Line 345 of yacc.c  */
-#line 191 "meta1-gram.c"
+/* Line 390 of yacc.c  */
+#line 201 "meta1-gram.c"
 
 #ifdef short
 # undef short
@@ -240,24 +250,24 @@ typedef short int grecs_meta1_type_int16;
 # if defined YYENABLE_NLS && YYENABLE_NLS
 #  if ENABLE_NLS
 #   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
 #  endif
 # endif
 # ifndef YY_
-#  define YY_(msgid) msgid
+#  define YY_(Msgid) Msgid
 # endif
 #endif
 
 /* Suppress unused-variable warnings by "using" E.  */
 #if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
+# define YYUSE(E) ((void) (E))
 #else
-# define YYUSE(e) /* empty */
+# define YYUSE(E) /* empty */
 #endif
 
 /* Identity function, used to suppress warnings about constant conditions.  */
 #ifndef lint
-# define YYID(n) (n)
+# define YYID(N) (N)
 #else
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
@@ -489,7 +499,7 @@ static const grecs_meta1_type_uint8 grecs_meta1_rline[] =
 };
 #endif
 
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+#if YYDEBUG || YYERROR_VERBOSE || 1
 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const grecs_meta1_tname[] =
@@ -573,10 +583,10 @@ static const grecs_meta1_type_uint8 grecs_meta1_table[] =
       26,    33,    27,    12
 };
 
-#define grecs_meta1_pact_value_is_default(grecs_meta1_state) \
-  ((grecs_meta1_state) == (-15))
+#define grecs_meta1_pact_value_is_default(Yystate) \
+  (!!((Yystate) == (-15)))
 
-#define grecs_meta1_table_value_is_error(grecs_meta1_table_value) \
+#define grecs_meta1_table_value_is_error(Yytable_value) \
   YYID (0)
 
 static const grecs_meta1_type_uint8 grecs_meta1_check[] =
@@ -640,7 +650,7 @@ do                                                              \
     }								\
 while (YYID (0))
 
-
+/* Error token number */
 #define YYTERROR	1
 #define YYERRCODE	256
 
@@ -649,27 +659,28 @@ while (YYID (0))
    If N is 0, then set CURRENT to the empty location which ends
    the previous symbol: RHS[0] (always defined).  */
 
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
 #ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)				\
-    do									\
-      if (YYID (N))                                                    \
-	{								\
-	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
-	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
-	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
-	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
-	}								\
-      else								\
-	{								\
-	  (Current).first_line   = (Current).last_line   =		\
-	    YYRHSLOC (Rhs, 0).last_line;				\
-	  (Current).first_column = (Current).last_column =		\
-	    YYRHSLOC (Rhs, 0).last_column;				\
-	}								\
+# define YYLLOC_DEFAULT(Current, Rhs, N)                                \
+    do                                                                  \
+      if (YYID (N))                                                     \
+        {                                                               \
+          (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
+          (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
+          (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
+          (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
+        }                                                               \
+      else                                                              \
+        {                                                               \
+          (Current).first_line   = (Current).last_line   =              \
+            YYRHSLOC (Rhs, 0).last_line;                                \
+          (Current).first_column = (Current).last_column =              \
+            YYRHSLOC (Rhs, 0).last_column;                              \
+        }                                                               \
     while (YYID (0))
 #endif
 
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
 
 /* YY_LOCATION_PRINT -- Print the location on the stream.
    This macro was not mandated originally: define only if we know
@@ -677,10 +688,46 @@ while (YYID (0))
 
 #ifndef YY_LOCATION_PRINT
 # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)			\
-     fprintf (File, "%d.%d-%d.%d",			\
-	      (Loc).first_line, (Loc).first_column,	\
-	      (Loc).last_line,  (Loc).last_column)
+
+/* Print *YYLOCP on YYO.  Private, do not rely on its existence. */
+
+__attribute__((__unused__))
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static unsigned
+grecs_meta1__location_print_ (FILE *grecs_meta1_o, YYLTYPE const * const grecs_meta1_locp)
+#else
+static unsigned
+grecs_meta1__location_print_ (grecs_meta1_o, grecs_meta1_locp)
+    FILE *grecs_meta1_o;
+    YYLTYPE const * const grecs_meta1_locp;
+#endif
+{
+  unsigned res = 0;
+  int end_col = 0 != grecs_meta1_locp->last_column ? grecs_meta1_locp->last_column - 1 : 0;
+  if (0 <= grecs_meta1_locp->first_line)
+    {
+      res += fprintf (grecs_meta1_o, "%d", grecs_meta1_locp->first_line);
+      if (0 <= grecs_meta1_locp->first_column)
+        res += fprintf (grecs_meta1_o, ".%d", grecs_meta1_locp->first_column);
+    }
+  if (0 <= grecs_meta1_locp->last_line)
+    {
+      if (grecs_meta1_locp->first_line < grecs_meta1_locp->last_line)
+        {
+          res += fprintf (grecs_meta1_o, "-%d", grecs_meta1_locp->last_line);
+          if (0 <= end_col)
+            res += fprintf (grecs_meta1_o, ".%d", end_col);
+        }
+      else if (0 <= end_col && grecs_meta1_locp->first_column < end_col)
+        res += fprintf (grecs_meta1_o, "-%d", end_col);
+    }
+  return res;
+ }
+
+#  define YY_LOCATION_PRINT(File, Loc)          \
+  grecs_meta1__location_print_ (File, &(Loc))
+
 # else
 #  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
 # endif
@@ -688,7 +735,6 @@ while (YYID (0))
 
 
 /* YYLEX -- calling `grecs_meta1_lex' with the right arguments.  */
-
 #ifdef YYLEX_PARAM
 # define YYLEX grecs_meta1_lex (YYLEX_PARAM)
 #else
@@ -753,7 +799,7 @@ grecs_meta1__symbol_value_print (grecs_meta1_output, grecs_meta1_type, grecs_met
   switch (grecs_meta1_type)
     {
       default:
-	break;
+        break;
     }
 }
 
@@ -999,7 +1045,6 @@ grecs_meta1_syntax_error (YYSIZE_T *grecs_meta1_msg_alloc, char **grecs_meta1_ms
 {
   YYSIZE_T grecs_meta1_size0 = grecs_meta1_tnamerr (YY_NULL, grecs_meta1_tname[grecs_meta1_token]);
   YYSIZE_T grecs_meta1_size = grecs_meta1_size0;
-  YYSIZE_T grecs_meta1_size1;
   enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
   /* Internationalized format string. */
   const char *grecs_meta1_format = YY_NULL;
@@ -1062,11 +1107,13 @@ grecs_meta1_syntax_error (YYSIZE_T *grecs_meta1_msg_alloc, char **grecs_meta1_ms
                     break;
                   }
                 grecs_meta1_arg[grecs_meta1_count++] = grecs_meta1_tname[grecs_meta1_x];
-                grecs_meta1_size1 = grecs_meta1_size + grecs_meta1_tnamerr (YY_NULL, grecs_meta1_tname[grecs_meta1_x]);
-                if (! (grecs_meta1_size <= grecs_meta1_size1
-                       && grecs_meta1_size1 <= YYSTACK_ALLOC_MAXIMUM))
-                  return 2;
-                grecs_meta1_size = grecs_meta1_size1;
+                {
+                  YYSIZE_T grecs_meta1_size1 = grecs_meta1_size + grecs_meta1_tnamerr (YY_NULL, grecs_meta1_tname[grecs_meta1_x]);
+                  if (! (grecs_meta1_size <= grecs_meta1_size1
+                         && grecs_meta1_size1 <= YYSTACK_ALLOC_MAXIMUM))
+                    return 2;
+                  grecs_meta1_size = grecs_meta1_size1;
+                }
               }
         }
     }
@@ -1086,10 +1133,12 @@ grecs_meta1_syntax_error (YYSIZE_T *grecs_meta1_msg_alloc, char **grecs_meta1_ms
 # undef YYCASE_
     }
 
-  grecs_meta1_size1 = grecs_meta1_size + grecs_meta1_strlen (grecs_meta1_format);
-  if (! (grecs_meta1_size <= grecs_meta1_size1 && grecs_meta1_size1 <= YYSTACK_ALLOC_MAXIMUM))
-    return 2;
-  grecs_meta1_size = grecs_meta1_size1;
+  {
+    YYSIZE_T grecs_meta1_size1 = grecs_meta1_size + grecs_meta1_strlen (grecs_meta1_format);
+    if (! (grecs_meta1_size <= grecs_meta1_size1 && grecs_meta1_size1 <= YYSTACK_ALLOC_MAXIMUM))
+      return 2;
+    grecs_meta1_size = grecs_meta1_size1;
+  }
 
   if (*grecs_meta1_msg_alloc < grecs_meta1_size)
     {
@@ -1151,35 +1200,35 @@ grecs_meta1_destruct (grecs_meta1_msg, grecs_meta1_type, grecs_meta1_valuep, gre
     {
 
       default:
-	break;
+        break;
     }
 }
 
 
-/* Prevent warnings from -Wmissing-prototypes.  */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int grecs_meta1_parse (void *YYPARSE_PARAM);
-#else
-int grecs_meta1_parse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int grecs_meta1_parse (void);
-#else
-int grecs_meta1_parse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
 
 
 /* The lookahead symbol.  */
 int grecs_meta1_char;
 
+
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
 /* The semantic value of the lookahead symbol.  */
-YYSTYPE grecs_meta1_lval;
+YYSTYPE grecs_meta1_lval YY_INITIAL_VALUE(grecs_meta1_val_default);
 
 /* Location data for the lookahead symbol.  */
-YYLTYPE grecs_meta1_lloc;
+YYLTYPE grecs_meta1_lloc
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  = { 1, 1, 1, 1 }
+# endif
+;
+
 
 /* Number of syntax errors so far.  */
 int grecs_meta1_nerrs;
@@ -1246,7 +1295,7 @@ grecs_meta1_parse ()
   int grecs_meta1_n;
   int grecs_meta1_result;
   /* Lookahead token as an internal (translated) token number.  */
-  int grecs_meta1_token;
+  int grecs_meta1_token = 0;
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE grecs_meta1_val;
@@ -1265,10 +1314,9 @@ grecs_meta1_parse ()
      Keep to zero when no symbol should be popped.  */
   int grecs_meta1_len = 0;
 
-  grecs_meta1_token = 0;
-  grecs_meta1_ss = grecs_meta1_ssa;
-  grecs_meta1_vs = grecs_meta1_vsa;
-  grecs_meta1_ls = grecs_meta1_lsa;
+  grecs_meta1_ssp = grecs_meta1_ss = grecs_meta1_ssa;
+  grecs_meta1_vsp = grecs_meta1_vs = grecs_meta1_vsa;
+  grecs_meta1_lsp = grecs_meta1_ls = grecs_meta1_lsa;
   grecs_meta1_stacksize = YYINITDEPTH;
 
   YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1277,21 +1325,7 @@ grecs_meta1_parse ()
   grecs_meta1_errstatus = 0;
   grecs_meta1_nerrs = 0;
   grecs_meta1_char = YYEMPTY; /* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-  grecs_meta1_ssp = grecs_meta1_ss;
-  grecs_meta1_vsp = grecs_meta1_vs;
-  grecs_meta1_lsp = grecs_meta1_ls;
-
-#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-  /* Initialize the default location before parsing starts.  */
-  grecs_meta1_lloc.first_line   = grecs_meta1_lloc.last_line   = 1;
-  grecs_meta1_lloc.first_column = grecs_meta1_lloc.last_column = 1;
-#endif
-
+  grecs_meta1_lsp[0] = grecs_meta1_lloc;
   goto grecs_meta1_setstate;
 
 /*------------------------------------------------------------.
@@ -1437,7 +1471,9 @@ grecs_meta1_backup:
   grecs_meta1_char = YYEMPTY;
 
   grecs_meta1_state = grecs_meta1_n;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++grecs_meta1_vsp = grecs_meta1_lval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
   *++grecs_meta1_lsp = grecs_meta1_lloc;
   goto grecs_meta1_newstate;
 
@@ -1475,8 +1511,7 @@ grecs_meta1_reduce:
   switch (grecs_meta1_n)
     {
         case 2:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 54 "meta1-gram.y"
     {
 		  parse_tree = grecs_node_create(grecs_node_root, &(grecs_meta1_lsp[(1) - (1)]));
@@ -1486,8 +1521,7 @@ grecs_meta1_reduce:
     break;
 
   case 3:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 63 "meta1-gram.y"
     {
 		  (grecs_meta1_val.node) = NULL;
@@ -1495,8 +1529,7 @@ grecs_meta1_reduce:
     break;
 
   case 4:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 67 "meta1-gram.y"
     {
 		  (grecs_meta1_val.node) = (grecs_meta1_vsp[(1) - (1)].node_list).head;
@@ -1504,8 +1537,7 @@ grecs_meta1_reduce:
     break;
 
   case 5:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 73 "meta1-gram.y"
     {
 		  (grecs_meta1_val.node_list).head = (grecs_meta1_val.node_list).tail = (grecs_meta1_vsp[(1) - (1)].node);
@@ -1513,8 +1545,7 @@ grecs_meta1_reduce:
     break;
 
   case 6:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 77 "meta1-gram.y"
     {
 		  grecs_node_bind((grecs_meta1_vsp[(1) - (2)].node_list).tail, (grecs_meta1_vsp[(2) - (2)].node), 0);
@@ -1522,8 +1553,7 @@ grecs_meta1_reduce:
     break;
 
   case 9:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 87 "meta1-gram.y"
     {
 		  (grecs_meta1_val.node) = grecs_node_create_points(grecs_node_stmt,
@@ -1535,8 +1565,7 @@ grecs_meta1_reduce:
     break;
 
   case 10:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 97 "meta1-gram.y"
     {
 		  (grecs_meta1_val.node) = grecs_node_create_points(grecs_node_block,
@@ -1549,8 +1578,7 @@ grecs_meta1_reduce:
     break;
 
   case 11:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 108 "meta1-gram.y"
     {
 		  (grecs_meta1_val.pvalue) = NULL;
@@ -1558,8 +1586,7 @@ grecs_meta1_reduce:
     break;
 
   case 12:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 112 "meta1-gram.y"
     {
 		  (grecs_meta1_val.pvalue) = grecs_malloc(sizeof((grecs_meta1_val.pvalue)[0]));
@@ -1569,8 +1596,7 @@ grecs_meta1_reduce:
     break;
 
   case 13:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 120 "meta1-gram.y"
     {
 		  (grecs_meta1_val.pvalue) = grecs_malloc(sizeof((grecs_meta1_val.pvalue)[0]));
@@ -1581,8 +1607,7 @@ grecs_meta1_reduce:
     break;
 
   case 14:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 127 "meta1-gram.y"
     {
 		  (grecs_meta1_val.pvalue) = grecs_malloc(sizeof((grecs_meta1_val.pvalue)[0]));
@@ -1593,8 +1618,7 @@ grecs_meta1_reduce:
     break;
 
   case 17:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 140 "meta1-gram.y"
     {
 		  struct grecs_list_entry *ep;
@@ -1611,8 +1635,7 @@ grecs_meta1_reduce:
     break;
 
   case 18:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 154 "meta1-gram.y"
     {
 		  (grecs_meta1_val.list) = grecs_list_create();
@@ -1621,8 +1644,7 @@ grecs_meta1_reduce:
     break;
 
   case 19:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 159 "meta1-gram.y"
     {
 		  grecs_list_append((grecs_meta1_vsp[(1) - (2)].list), (grecs_meta1_vsp[(2) - (2)].string));
@@ -1631,8 +1653,7 @@ grecs_meta1_reduce:
     break;
 
   case 20:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 166 "meta1-gram.y"
     {
 		  (grecs_meta1_val.list) = (grecs_meta1_vsp[(2) - (3)].list);
@@ -1640,8 +1661,7 @@ grecs_meta1_reduce:
     break;
 
   case 21:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 170 "meta1-gram.y"
     {
 		  (grecs_meta1_val.list) = (grecs_meta1_vsp[(2) - (4)].list);
@@ -1649,8 +1669,7 @@ grecs_meta1_reduce:
     break;
 
   case 22:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 176 "meta1-gram.y"
     {
 		  (grecs_meta1_val.list) = grecs_value_list_create();
@@ -1659,8 +1678,7 @@ grecs_meta1_reduce:
     break;
 
   case 23:
-
-/* Line 1810 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 181 "meta1-gram.y"
     {
 		  grecs_list_append((grecs_meta1_vsp[(1) - (3)].list), (grecs_meta1_vsp[(3) - (3)].pvalue));
@@ -1669,9 +1687,8 @@ grecs_meta1_reduce:
     break;
 
 
-
-/* Line 1810 of yacc.c  */
-#line 1675 "meta1-gram.c"
+/* Line 1792 of yacc.c  */
+#line 1692 "meta1-gram.c"
       default: break;
     }
   /* User semantic actions sometimes alter grecs_meta1_char, and that requires
@@ -1836,7 +1853,9 @@ grecs_meta1_errlab1:
       YY_STACK_PRINT (grecs_meta1_ss, grecs_meta1_ssp);
     }
 
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++grecs_meta1_vsp = grecs_meta1_lval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
 
   grecs_meta1_error_range[2] = grecs_meta1_lloc;
   /* Using YYLLOC is tempting, but would change the location of
@@ -1907,8 +1926,7 @@ grecs_meta1_return:
 }
 
 
-
-/* Line 2071 of yacc.c  */
+/* Line 2055 of yacc.c  */
 #line 191 "meta1-gram.y"
 
 int
@@ -1946,4 +1964,3 @@ grecs_meta1_parser(const char *name, int traceflags)
 	return parse_tree;
 }
 	
-
diff --git a/grecs/src/meta1-lex.c b/grecs/src/meta1-lex.c
index 82af932..6381aa5 100644
--- a/grecs/src/meta1-lex.c
+++ b/grecs/src/meta1-lex.c
@@ -45,7 +45,7 @@
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
+#define YY_FLEX_SUBMINOR_VERSION 37
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -106,7 +106,6 @@ typedef int flex_int32_t;
 typedef unsigned char flex_uint8_t; 
 typedef unsigned short int flex_uint16_t;
 typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
 
 /* Limits of integral types. */
 #ifndef INT8_MIN
@@ -137,6 +136,8 @@ typedef unsigned int flex_uint32_t;
 #define UINT32_MAX             (4294967295U)
 #endif
 
+#endif /* ! C99 */
+
 #endif /* ! FLEXINT_H */
 
 /* %endif */
@@ -223,8 +224,13 @@ typedef unsigned int flex_uint32_t;
 typedef struct grecs_meta1__buffer_state *YY_BUFFER_STATE;
 #endif
 
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t grecs_meta1__size_t;
+#endif
+
 /* %if-not-reentrant */
-extern int grecs_meta1_leng;
+extern grecs_meta1__size_t grecs_meta1_leng;
 /* %endif */
 
 /* %if-c-only */
@@ -255,11 +261,6 @@ extern FILE *grecs_meta1_in, *grecs_meta1_out;
 
 #define unput(c) grecs_meta1_unput( c, (grecs_meta1_text_ptr)  )
 
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t grecs_meta1__size_t;
-#endif
-
 #ifndef YY_STRUCT_YY_BUFFER_STATE
 #define YY_STRUCT_YY_BUFFER_STATE
 struct grecs_meta1__buffer_state
@@ -282,7 +283,7 @@ struct grecs_meta1__buffer_state
 	/* Number of characters read into grecs_meta1__ch_buf, not including EOB
 	 * characters.
 	 */
-	int grecs_meta1__n_chars;
+	grecs_meta1__size_t grecs_meta1__n_chars;
 
 	/* Whether we "own" the buffer - i.e., we know we created it,
 	 * and can realloc() it to grow it, and should free() it to
@@ -366,8 +367,8 @@ static YY_BUFFER_STATE * grecs_meta1__buffer_stack = 0; /**< Stack as an array.
 
 /* grecs_meta1__hold_char holds the character lost when grecs_meta1_text is formed. */
 static char grecs_meta1__hold_char;
-static int grecs_meta1__n_chars;		/* number of characters read into grecs_meta1__ch_buf */
-int grecs_meta1_leng;
+static grecs_meta1__size_t grecs_meta1__n_chars;		/* number of characters read into grecs_meta1__ch_buf */
+grecs_meta1__size_t grecs_meta1_leng;
 
 /* Points to current character in buffer. */
 static char *grecs_meta1__c_buf_p = (char *) 0;
@@ -398,7 +399,7 @@ static void grecs_meta1__init_buffer (YY_BUFFER_STATE b,FILE *file  );
 
 YY_BUFFER_STATE grecs_meta1__scan_buffer (char *base,grecs_meta1__size_t size  );
 YY_BUFFER_STATE grecs_meta1__scan_string (grecs_meta1_const char *grecs_meta1__str  );
-YY_BUFFER_STATE grecs_meta1__scan_bytes (grecs_meta1_const char *bytes,int len  );
+YY_BUFFER_STATE grecs_meta1__scan_bytes (grecs_meta1_const char *bytes,grecs_meta1__size_t len  );
 
 /* %endif */
 
@@ -629,7 +630,7 @@ static void meta1_line_add_unescape_hex(const char *text, size_t len);
  		grecs_meta1_lloc.end = grecs_current_locus_point;			\
    	} while (0);
 
-#line 633 "meta1-lex.c"
+#line 634 "meta1-lex.c"
 
 #define INITIAL 0
 #define COMMENT 1
@@ -683,7 +684,7 @@ FILE *grecs_meta1_get_out (void );
 
 void grecs_meta1_set_out  (FILE * out_str  );
 
-int grecs_meta1_get_leng (void );
+grecs_meta1__size_t grecs_meta1_get_leng (void );
 
 char *grecs_meta1_get_text (void );
 
@@ -749,7 +750,7 @@ static int input (void );
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO fwrite( grecs_meta1_text, grecs_meta1_leng, 1, grecs_meta1_out )
+#define ECHO do { if (fwrite( grecs_meta1_text, grecs_meta1_leng, 1, grecs_meta1_out )) {} } while (0)
 /* %endif */
 /* %if-c++-only C++ definition */
 /* %endif */
@@ -764,7 +765,7 @@ static int input (void );
 	if ( YY_CURRENT_BUFFER_LVALUE->grecs_meta1__is_interactive ) \
 		{ \
 		int c = '*'; \
-		int n; \
+		size_t n; \
 		for ( n = 0; n < max_size && \
 			     (c = getc( grecs_meta1_in )) != EOF && c != '\n'; ++n ) \
 			buf[n] = (char) c; \
@@ -874,7 +875,7 @@ YY_DECL
 #line 48 "meta1-lex.l"
 
          /* C-style comments */
-#line 878 "meta1-lex.c"
+#line 879 "meta1-lex.c"
 
 	if ( !(grecs_meta1__init) )
 		{
@@ -1136,7 +1137,7 @@ YY_RULE_SETUP
 #line 107 "meta1-lex.l"
 ECHO;
 	YY_BREAK
-#line 1140 "meta1-lex.c"
+#line 1141 "meta1-lex.c"
 case YY_STATE_EOF(INITIAL):
 case YY_STATE_EOF(COMMENT):
 case YY_STATE_EOF(STR):
@@ -1337,21 +1338,21 @@ static int grecs_meta1__get_next_buffer (void)
 
 	else
 		{
-			int num_to_read =
+			grecs_meta1__size_t num_to_read =
 			YY_CURRENT_BUFFER_LVALUE->grecs_meta1__buf_size - number_to_move - 1;
 
 		while ( num_to_read <= 0 )
 			{ /* Not enough room in the buffer - grow it. */
 
 			/* just a shorter name for the current buffer */
-			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
 
 			int grecs_meta1__c_buf_p_offset =
 				(int) ((grecs_meta1__c_buf_p) - b->grecs_meta1__ch_buf);
 
 			if ( b->grecs_meta1__is_our_buffer )
 				{
-				int new_size = b->grecs_meta1__buf_size * 2;
+				grecs_meta1__size_t new_size = b->grecs_meta1__buf_size * 2;
 
 				if ( new_size <= 0 )
 					b->grecs_meta1__buf_size += b->grecs_meta1__buf_size / 8;
@@ -1382,7 +1383,7 @@ static int grecs_meta1__get_next_buffer (void)
 
 		/* Read in more data. */
 		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->grecs_meta1__ch_buf[number_to_move]),
-			(grecs_meta1__n_chars), (size_t) num_to_read );
+			(grecs_meta1__n_chars), num_to_read );
 
 		YY_CURRENT_BUFFER_LVALUE->grecs_meta1__n_chars = (grecs_meta1__n_chars);
 		}
@@ -1490,7 +1491,7 @@ static int grecs_meta1__get_next_buffer (void)
 	grecs_meta1__current_state = grecs_meta1__nxt[grecs_meta1__base[grecs_meta1__current_state] + (unsigned int) grecs_meta1__c];
 	grecs_meta1__is_jam = (grecs_meta1__current_state == 53);
 
-	return grecs_meta1__is_jam ? 0 : grecs_meta1__current_state;
+		return grecs_meta1__is_jam ? 0 : grecs_meta1__current_state;
 }
 
 /* %if-c-only */
@@ -1525,7 +1526,7 @@ static int grecs_meta1__get_next_buffer (void)
 
 		else
 			{ /* need more input */
-			int offset = (grecs_meta1__c_buf_p) - (grecs_meta1_text_ptr);
+			grecs_meta1__size_t offset = (grecs_meta1__c_buf_p) - (grecs_meta1_text_ptr);
 			++(grecs_meta1__c_buf_p);
 
 			switch ( grecs_meta1__get_next_buffer(  ) )
@@ -1709,17 +1710,6 @@ static void grecs_meta1__load_buffer_state  (void)
 	grecs_meta1_free((void *) b  );
 }
 
-/* %if-c-only */
-
-#ifndef __cplusplus
-extern int isatty (int );
-#endif /* __cplusplus */
-    
-/* %endif */
-
-/* %if-c++-only */
-/* %endif */
-
 /* Initializes or reinitializes a buffer.
  * This function is sometimes called more than once on the same buffer,
  * such as during a grecs_meta1_restart() or at EOF.
@@ -1862,7 +1852,7 @@ static void grecs_meta1_ensure_buffer_stack (void)
 /* %if-c++-only */
 /* %endif */
 {
-	int num_to_alloc;
+	grecs_meta1__size_t num_to_alloc;
     
 	if (!(grecs_meta1__buffer_stack)) {
 
@@ -1960,12 +1950,12 @@ YY_BUFFER_STATE grecs_meta1__scan_string (grecs_meta1_const char * grecs_meta1_s
 /* %if-c-only */
 /** Setup the input buffer state to scan the given bytes. The next call to grecs_meta1_lex() will
  * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param grecs_meta1_bytes the byte buffer to scan
+ * @param _grecs_meta1_bytes_len the number of bytes in the buffer pointed to by @a bytes.
  * 
  * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE grecs_meta1__scan_bytes  (grecs_meta1_const char * grecs_meta1_bytes, int  _grecs_meta1_bytes_len )
+YY_BUFFER_STATE grecs_meta1__scan_bytes  (grecs_meta1_const char * grecs_meta1_bytes, grecs_meta1__size_t  _grecs_meta1_bytes_len )
 {
 	YY_BUFFER_STATE b;
 	char *buf;
@@ -2061,7 +2051,7 @@ FILE *grecs_meta1_get_out  (void)
 /** Get the length of the current token.
  * 
  */
-int grecs_meta1_get_leng  (void)
+grecs_meta1__size_t grecs_meta1_get_leng  (void)
 {
         return grecs_meta1_leng;
 }
diff --git a/grecs/src/parser.c b/grecs/src/parser.c
index 1ad43c1..ed99a7a 100644
--- a/grecs/src/parser.c
+++ b/grecs/src/parser.c
@@ -26,7 +26,7 @@ int grecs_error_count = 0;
 int grecs_default_port = 0;
 
 int grecs_trace_flags = 0;
-int grecs_adjust_string_locations = 0;
+int grecs_parser_options = 0;
 
 #ifndef GRECS_DEFAULT_PARSER
 # define GRECS_DEFAULT_PARSER grecs_grecs_parser
diff --git a/grecs/src/sockaddr.c b/grecs/src/sockaddr.c
index 8cd790d..83f2450 100644
--- a/grecs/src/sockaddr.c
+++ b/grecs/src/sockaddr.c
@@ -1,5 +1,5 @@
 /* grecs - Gray's Extensible Configuration System
-   Copyright (C) 2007-2016 Sergey Poznyakoff
+   Copyright (C) 2007-2017 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
@@ -19,6 +19,7 @@
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
+#include <stddef.h>
 #include <string.h>
 #include <ctype.h>
 #include <sys/types.h>
@@ -36,6 +37,7 @@ grecs_sockaddr_new(size_t s)
 {
 	struct grecs_sockaddr *sp = grecs_malloc(sizeof(*sp));
 	sp->next = NULL;
+	sp->str = NULL;
 	sp->sa = grecs_zalloc(s);
 	sp->len = s;
 	return sp;
@@ -47,6 +49,7 @@ grecs_sockaddr_free(struct grecs_sockaddr *p)
 	while (p) {
 		struct grecs_sockaddr *next = p->next;
 		free(p->sa);
+		free(p->str);
 		free(p);
 		p = next;
 	}
@@ -279,3 +282,62 @@ grecs_str_to_sockaddr(struct grecs_sockaddr **sap,
 	
 	return parse_inet(sap, AF_UNSPEC, arg, arg, gh, locus);
 }
+
+#define S_UN_NAME(sa, salen) \
+	((salen < offsetof(struct sockaddr_un,sun_path)) ?      \
+	 "" : (sa)->sun_path)
+
+static int
+sockaddr_str(struct sockaddr *sa, socklen_t salen, char **pbuf, size_t *psz)
+{
+	int rc;
+	
+	switch (sa->sa_family) {
+	case AF_INET:
+	case AF_INET6: {
+		char host[NI_MAXHOST];
+		char srv[NI_MAXSERV];
+		if (getnameinfo(sa, salen,
+				host, sizeof(host), srv, sizeof(srv),
+				NI_NUMERICHOST|NI_NUMERICSERV) == 0)
+			rc = grecs_asprintf(pbuf, psz, "%s://%s:%s",
+					    sa->sa_family == AF_INET ?
+					    "inet" : "inet6",
+					    host, srv);
+		else
+			rc = grecs_asprintf(pbuf, psz,
+					    "%s://[getnameinfo failed]",
+					    sa->sa_family == AF_INET ?
+					    "inet" : "inet6");
+		break;
+	}
+	case AF_UNIX: {
+		struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
+		if (S_UN_NAME(s_un, salen)[0] == 0)
+			rc = grecs_asprintf(pbuf, psz,
+					    "unix://[anonymous socket]");
+		else
+			rc = grecs_asprintf(pbuf, psz, "unix://%s",
+					    s_un->sun_path);
+		break;
+	}
+
+	default:
+		rc = grecs_asprintf(pbuf, psz, "family:%d", sa->sa_family);
+	}
+	return rc;
+}
+
+char const *
+grecs_sockaddr_str(struct grecs_sockaddr *sa)
+{
+	if (!sa->str) {
+		size_t sz = 0;
+		if (sockaddr_str(sa->sa, sa->len, &sa->str, &sz)) {
+			//FIXME
+			abort();
+		}
+	}
+	return sa->str;
+}
+
diff --git a/grecs/src/symtab.c b/grecs/src/symtab.c
index 540ea0f..3647a81 100644
--- a/grecs/src/symtab.c
+++ b/grecs/src/symtab.c
@@ -33,16 +33,36 @@ static unsigned int hash_size[] = {
 /* |max_rehash| keeps the number of entries in |hash_size| table. */
 static unsigned int max_rehash = sizeof(hash_size) / sizeof(hash_size[0]);
 
+enum symtab_defer_type {
+	defer_add,
+	defer_del
+};
+
 struct grecs_symtab {
 	int flags;
-	unsigned int hash_num;  /* Index to hash_size table */
-	size_t elsize;          /* Size of an element */
-	struct grecs_syment **tab;
-	unsigned (*hash_fun)(void *, unsigned long hash_num);
+	unsigned int hash_num;     /* Index to hash_size table */
+	size_t elsize;             /* Size of an element */
+	size_t elcount;            /* Number of elements in use */
+	struct grecs_syment **tab; /* Table of element pointers */	
+
+	/* Functions that can be overridden when creating the symtab: */
+	unsigned (*hash_fun)(void *, unsigned long);
 	int (*cmp_fun)(const void *, const void *);
 	int (*copy_fun)(void *, void *);
-	void *(*syment_alloc_fun)(size_t size);
+	void *(*syment_alloc_fun)(size_t);
 	void (*syment_free_fun) (void *);
+
+	/* Support for deferred operations.  When an insertion or deletion
+	   is requested while the symtab is being iterated over, this operation
+	   is deferred until the iteration is finished.  */
+
+	/* Iteration level.  Gets increased upon entry to grecs_symtab_foreach,
+	   and decreased right before leaving it. */
+	unsigned int itr_level;
+	/* Two deferment lists keep track of the deferred additions and
+	   removals:
+	*/
+	grecs_list_ptr_t defer_list[2];
 };
 
 static void
@@ -72,7 +92,17 @@ syment_alloc(struct grecs_symtab *st, void *key)
 	}
 	return ent;
 }
-
+
+static void
+symtab_defer_op(struct grecs_symtab *st, enum symtab_defer_type type,
+		struct grecs_syment *ent)
+{
+	if (!st->defer_list[type]) {
+		st->defer_list[type] = grecs_list_create();
+		st->defer_list[type]->cmp = st->cmp_fun;
+	}
+	grecs_list_append(st->defer_list[type], ent);
+}
 
 unsigned
 grecs_hash_string(const char *name, unsigned long hashsize)
@@ -101,8 +131,8 @@ grecs_hash_string_ci(const char *name, unsigned long hashsize)
 static unsigned
 def_hash(void *data, unsigned long hashsize)
 {
-  struct grecs_syment *sym = data;
-  return grecs_hash_string(sym->name, hashsize);
+	struct grecs_syment *sym = data;
+	return grecs_hash_string(sym->name, hashsize);
 }
 
 static int
@@ -218,6 +248,11 @@ grecs_symtab_remove(struct grecs_symtab *st, void *elt)
 	unsigned int pos, i, j, r;
 	struct grecs_syment *entry;
 	
+	if (st->itr_level) {
+		if (grecs_list_remove(st->defer_list[defer_add], elt) == 0)
+			return 0;
+	}
+	
 	pos = st->hash_fun(elt, hash_size[st->hash_num]);
 	for (i = pos; (entry = st->tab[i]);) {
 		if (st->cmp_fun(entry, elt) == 0)
@@ -231,7 +266,14 @@ grecs_symtab_remove(struct grecs_symtab *st, void *elt)
 	if (!entry)
 		return ENOENT;
 
+	if (st->itr_level) {
+		symtab_defer_op(st, defer_del, entry);
+		//FIXME: mark the entry as deleted
+		return 0;
+	}
+	
 	syment_free(st, entry);
+	st->elcount--;
 
 	for (;;) {
 		st->tab[i] = NULL;
@@ -312,10 +354,20 @@ grecs_symtab_lookup_or_install(struct grecs_symtab *st, void *key,
 				errno = ENOMEM;
 				return NULL;
 			}
-			st->tab[i] = ent;
+			if (st->itr_level) {
+				symtab_defer_op(st, defer_add, ent);
+			} else {
+				st->tab[i] = ent;
+				st->elcount++;
+			}
 			return ent;
 		} else
 			return st->tab[i];
+	} else if (rc == ENOENT && st->itr_level) {
+		void *ptr = grecs_list_locate(st->defer_list[defer_add], key);
+		if (ptr)
+			return ptr;
+		rc = ENOENT;
 	}
 	errno = rc;
 	return NULL;
@@ -337,6 +389,7 @@ grecs_symtab_clear(struct grecs_symtab *st)
 			st->tab[i] = NULL;
 		}
 	}
+	st->elcount = 0;	
 }
 
 struct grecs_symtab *
@@ -350,6 +403,7 @@ grecs_symtab_create(size_t elsize,
 	if (st) {
 		memset(st, 0, sizeof(*st));
 		st->elsize = elsize;
+		st->elcount = 0;
 		st->hash_fun = hash_fun ? hash_fun : def_hash;
 		st->cmp_fun = cmp_fun ? cmp_fun : def_cmp;
 		st->copy_fun = copy_fun ? copy_fun : def_copy;
@@ -381,39 +435,54 @@ grecs_symtab_free(struct grecs_symtab *st)
 {
 	if (st) {
 		grecs_symtab_clear(st);
+		grecs_list_free(st->defer_list[defer_add]);
+		grecs_list_free(st->defer_list[defer_del]);
 		free(st->tab);
 		free(st);
 	}
 }
 
 size_t
-grecs_symtab_count_entries(struct grecs_symtab *st)
+grecs_symtab_count(struct grecs_symtab *st)
 {
-	unsigned i;
-	size_t count = 0;
-	
-	for (i = 0; i < hash_size[st->hash_num]; i++)
-		if (st->tab[i])
-			count++;
-	return count;
+	return st->elcount;
 }
 
 int
-grecs_symtab_enumerate(struct grecs_symtab *st, grecs_symtab_enumerator_t fun,
-		       void *data)
+grecs_symtab_foreach(struct grecs_symtab *st, grecs_symtab_enumerator_t fun,
+		     void *data)
 {
 	unsigned i;
-
+	struct grecs_syment *ep;
+	
 	if (!st)
 		return 0;
+
+	++st->itr_level;
+
 	for (i = 0; i < hash_size[st->hash_num]; i++) {
-		struct grecs_syment *ep = st->tab[i];
-		if (ep) {
+		ep = st->tab[i];
+		if (ep && !grecs_list_locate(st->defer_list[defer_del], ep)) {
 			int rc = fun(ep, data);
 			if (rc)
 				return rc;
 		}
 	}
+
+	if (--st->itr_level == 0) {
+		while ((ep = grecs_list_pop(st->defer_list[defer_del])) != NULL)
+			grecs_symtab_remove(st, ep);
+		
+		while ((ep = grecs_list_pop(st->defer_list[defer_add])) != NULL) {
+			int install = 1;
+			if (grecs_symtab_get_index(&i, st, ep,
+						   &install) == 0) {
+				st->tab[i] = ep;
+				st->elcount++;
+			}
+		}
+	}
+	
 	return 0;
 }
 
diff --git a/grecs/src/tree.c b/grecs/src/tree.c
index 5826abf..2afe899 100644
--- a/grecs/src/tree.c
+++ b/grecs/src/tree.c
@@ -62,6 +62,19 @@ grecs_value_free(struct grecs_value *val)
 	grecs_free(val);
 }
 
+const char *
+grecs_value_type_string(int t)
+{
+	static const char *types[] = {
+		[GRECS_TYPE_STRING] = N_("string"),
+		[GRECS_TYPE_LIST]   = N_("list"),
+		[GRECS_TYPE_ARRAY]  = N_("one or more arguments")
+	};
+	if (t >= 0 && t < sizeof(types) / sizeof(types[0]))
+		return types[t];
+	return N_("unrecognized type; please report");
+}
+
 struct grecs_node *
 grecs_node_create(enum grecs_node_type type, grecs_locus_t *loc)
 {
@@ -128,9 +141,9 @@ grecs_node_unlink(struct grecs_node *node)
 		return 1;
 	if (node->next)
 		node->next->prev = node->prev;
+	node->up = node->prev = node->next = NULL;
 	return 0;
 }
-
 
 static void
 listel_dispose(void *el)
@@ -286,14 +299,32 @@ static struct grecs_keyword fake = {
 };
 
 static struct grecs_keyword *
-find_keyword(struct grecs_keyword *cursect, const char *ident)
+find_keyword(struct grecs_keyword *cursect, grecs_node_t *node)
 {
-	struct grecs_keyword *kwp;
-  
 	if (cursect && cursect->kwd && cursect != &fake) {
-		for (kwp = cursect->kwd; kwp->ident; kwp++)
-			if (strcmp(kwp->ident, ident) == 0)
-				return kwp;
+		struct grecs_keyword *found = NULL, *kwp;
+		char const *msg;
+
+		for (kwp = cursect->kwd; kwp->ident; kwp++) {
+			if (strcmp(kwp->ident, node->ident) == 0) {
+				found = kwp;
+				if (kwp->callback
+				    || (node->down
+				         ? kwp->type == grecs_type_section
+					: kwp->type != grecs_type_section))
+					return kwp;
+			}
+		}
+		if (found) {
+			if (found->type == grecs_type_section) {
+				msg = N_("section keyword used as a scalar");
+			} else {
+				msg = N_("scalar keyword used as a section");
+			}
+		} else {
+			msg = N_("unknown keyword");
+		}
+		grecs_error(&node->idloc, 0, "%s", gettext(msg));
 	} else {
 		return &fake;
 	}
@@ -915,21 +946,17 @@ nodeproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data)
 	
 	switch (op) {
 	case grecs_tree_recurse_set:
-		kwp = find_keyword(clos->cursect, node->ident);
-		if (!kwp) {
-			grecs_error(&node->idloc, 0, _("Unknown keyword"));
+		kwp = find_keyword(clos->cursect, node);
+		if (!kwp)
 			return grecs_tree_recurse_skip;
-		}
 		grecs_process_ident(kwp, node->v.value, CURRENT_BASE(clos),
 				    &node->idloc);
 		break;
 		
 	case grecs_tree_recurse_pre:
-		kwp = find_keyword(clos->cursect, node->ident);
-		if (!kwp) {
-			grecs_error(&node->locus, 0, _("Unknown keyword"));
+		kwp = find_keyword(clos->cursect, node);
+		if (!kwp)
 			return grecs_tree_recurse_skip;
-		}
 		stmt_begin(clos, kwp, node);
 		break;
 		
@@ -1090,7 +1117,10 @@ node_merge_block(struct grecs_node *to_node, struct grecs_node *from_node,
 		if (!sp->next)
 			break;
 	}
+
 	sp->next = to_node->down;
+	to_node->down->prev = sp;
+	
 	to_node->down = from_node->down;
 	from_node->down = NULL;
 }
@@ -1133,13 +1163,9 @@ reduceproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data)
 	} else {
 		struct grecs_keyword *kwp = NULL;
 		if (clos->cursect) {
-			kwp = find_keyword(clos->cursect, node->ident);
-			if (!kwp) {
-				grecs_error(&node->locus, 0,
-					    _("%s: unknown keyword"),
-					    node->ident);
+			kwp = find_keyword(clos->cursect, node);
+			if (!kwp)
 				return grecs_tree_recurse_skip;
-			}
 			if (kwp->flags & GRECS_INAC)
 				return grecs_tree_recurse_skip;
 			if (!(kwp->flags & GRECS_MULT) &&
diff --git a/grecs/tests/Makefile.am b/grecs/tests/Makefile.am
index 9bf28da..a8ca2d3 100644
--- a/grecs/tests/Makefile.am
+++ b/grecs/tests/Makefile.am
@@ -1,5 +1,5 @@
 # This file is part of grecs - Gray's Extensible Configuration System
-# Copyright (C) 2007-2016 Sergey Poznyakoff
+# Copyright (C) 2007-2019 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
@@ -121,9 +121,10 @@ TESTSUITE_AT = \
  set.at\
  sort00.at\
  sort01.at\
+ stradj.at\
+ strcat.at\
  testsuite.at\
  vercmp.at\
- wordsplit.at\
  @GRECS_DISTCK_AT@
 
 TESTSUITE = $(srcdir)/testsuite
@@ -137,10 +138,10 @@ $(TESTSUITE): package.m4 $(TESTSUITE_AT)
 atconfig: $(top_builddir)/config.status
 	cd $(top_builddir) && ./config.status tests/$@
 
-clean-local:
+clean-local: clean-wordsplit
 	test ! -f $(TESTSUITE) || $(SHELL) $(TESTSUITE) --clean
 
-check-local: atconfig atlocal $(TESTSUITE) $(noinst_PROGRAMS)
+check-local: check-wordsplit atconfig atlocal $(TESTSUITE) $(noinst_PROGRAMS)
 	$(SHELL) $(TESTSUITE)
 
 # Run the test suite on the *installed* tree.
@@ -153,15 +154,58 @@ noinst_PROGRAMS = \
  gcfenum\
  gcfpeek\
  gcfset\
- gcfver\
- wsp
+ gcfver
 
 if GRECS_COND_JSON
   noinst_PROGRAMS += json
 endif
 
-LDADD = @GRECS_LDADD@ $(LIBINTL)
+LDADD = @GRECS_LDADD@ $(LIBINTL) @GRECS_HOST_PROJECT_LDADD@
 AM_CPPFLAGS = @GRECS_INCLUDES@ @GRECS_HOST_PROJECT_INCLUDES@
 
+# Wordsplit testsuite
+WSTEST = $(srcdir)/wstest
+EXTRA_DIST += wstest wspackage.m4 wordsplit-version.h
+$(WSTEST): $(top_srcdir)/@GRECS_SUBDIR@/wordsplit/wordsplit.at $(srcdir)/wspackage.m4
+	$(AM_V_GEN)$(AUTOTEST) -I $(srcdir) \
+                  wspackage.m4 \
+                  $(top_srcdir)/@GRECS_SUBDIR@/wordsplit/wordsplit.at \
+	          -o $(WSTEST).tmp
+	$(AM_V_at)mv $(WSTEST).tmp $(WSTEST)
+
+$(srcdir)/wspackage.m4: $(top_srcdir)/configure.ac $(top_srcdir)/@GRECS_SUBDIR@/am/grecs.m4
+	$(AM_V_GEN){\
+	    if test -e $(top_srcdir)/@GRECS_SUBDIR@/wordsplit/.git; then \
+	        wsversion=$$(cd $(top_srcdir)/@GRECS_SUBDIR@/wordsplit; git describe); \
+	    else \
+                wsversion="unknown"; \
+	    fi;\
+            echo 'm4_define([AT_PACKAGE_NAME],      [wordsplit])'; \
+	    echo 'm4_define([AT_PACKAGE_TARNAME],   [wordsplit])'; \
+	    echo "m4_define([AT_PACKAGE_VERSION],   [$$wsversion])"; \
+	    echo 'm4_define([AT_PACKAGE_STRING],    [AT_PACKAGE_TARNAME AT_PACKAGE_VERSION])'; \
+	    echo 'm4_define([AT_PACKAGE_BUGREPORT], [@PACKAGE_BUGREPORT@])'; \
+        } > $(srcdir)/wspackage.m4
+
+$(srcdir)/wordsplit-version.h: $(srcdir)/wspackage.m4
+	$(AM_V_GEN){ echo "m4_divert(-1)";\
+          echo "m4_changequote([,])";\
+          echo "m4_changecom([//])";\
+	  echo "m4_include($(srcdir)/wspackage.m4)";\
+	  echo 'm4_divert(0)#define WORDSPLIT_VERSION "AT_PACKAGE_VERSION"'; } | \
+	 $(M4) -P - > $(srcdir)/wordsplit-version.h
+
+noinst_PROGRAMS += wsp
+wsp_SOURCES = 
+nodist_wsp_SOURCES = wsp.c
+wsp.o: $(srcdir)/wordsplit-version.h
+VPATH += $(top_srcdir)/@GRECS_SUBDIR@/wordsplit
+
+clean-wordsplit:
+	test ! -f $(WSTEST) || $(SHELL) $(WSTEST) --clean
+
+check-wordsplit: atconfig atlocal $(WSTEST) $(noinst_PROGRAMS)
+	$(SHELL) $(WSTEST)
+
 
 
diff --git a/grecs/tests/Makefile.in b/grecs/tests/Makefile.in
index d94e641..0744f42 100644
--- a/grecs/tests/Makefile.in
+++ b/grecs/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,7 @@
 @SET_MAKE@
 
 # This file is part of grecs - Gray's Extensible Configuration System
-# Copyright (C) 2007-2016 Sergey Poznyakoff
+# Copyright (C) 2007-2019 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
@@ -30,8 +30,17 @@
 # You should have received a copy of the GNU General Public License
 # along with Grecs.  If not, see <http://www.gnu.org/licenses/>.
 
-VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -100,12 +109,10 @@ host_triplet = @host@
 @GRECS_COND_GIT_PARSER_TRUE@am__append_4 = ENABLE_GIT_PARSER 
 @GRECS_COND_JSON_TRUE@am__append_5 = ENABLE_JSON
 noinst_PROGRAMS = distck$(EXEEXT) gcffmt$(EXEEXT) gcfenum$(EXEEXT) \
-	gcfpeek$(EXEEXT) gcfset$(EXEEXT) gcfver$(EXEEXT) wsp$(EXEEXT) \
-	$(am__EXEEXT_1)
+	gcfpeek$(EXEEXT) gcfset$(EXEEXT) gcfver$(EXEEXT) \
+	$(am__EXEEXT_1) wsp$(EXEEXT)
 @GRECS_COND_JSON_TRUE@am__append_6 = json
 subdir = grecs/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(srcdir)/atlocal.in $(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/am/gettext.m4 $(top_srcdir)/am/iconv.m4 \
@@ -116,6 +123,7 @@ am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES = atlocal
@@ -151,8 +159,9 @@ json_SOURCES = json.c
 json_OBJECTS = json.$(OBJEXT)
 json_LDADD = $(LDADD)
 json_DEPENDENCIES = $(am__DEPENDENCIES_1)
-wsp_SOURCES = wsp.c
-wsp_OBJECTS = wsp.$(OBJEXT)
+am_wsp_OBJECTS =
+nodist_wsp_OBJECTS = wsp.$(OBJEXT)
+wsp_OBJECTS = $(am_wsp_OBJECTS) $(nodist_wsp_OBJECTS)
 wsp_LDADD = $(LDADD)
 wsp_DEPENDENCIES = $(am__DEPENDENCIES_1)
 AM_V_P = $(am__v_P_@AM_V@)
@@ -184,9 +193,9 @@ am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
 SOURCES = distck.c gcfenum.c gcffmt.c gcfpeek.c gcfset.c gcfver.c \
-	json.c wsp.c
+	json.c $(wsp_SOURCES) $(nodist_wsp_SOURCES)
 DIST_SOURCES = distck.c gcfenum.c gcffmt.c gcfpeek.c gcfset.c gcfver.c \
-	json.c wsp.c
+	json.c $(wsp_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -211,7 +220,10 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/atlocal.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+VPATH = @srcdir@ $(top_srcdir)/@GRECS_SUBDIR@/wordsplit
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
@@ -242,7 +254,9 @@ GRECS_CHANGELOG = @GRECS_CHANGELOG@
 GRECS_DISTCK_AT = @GRECS_DISTCK_AT@
 GRECS_DISTDOC = @GRECS_DISTDOC@
 GRECS_DOCDIR = @GRECS_DOCDIR@
+GRECS_EXTRA_DIST = @GRECS_EXTRA_DIST@
 GRECS_HOST_PROJECT_INCLUDES = @GRECS_HOST_PROJECT_INCLUDES@
+GRECS_HOST_PROJECT_LDADD = @GRECS_HOST_PROJECT_LDADD@
 GRECS_INCLUDES = @GRECS_INCLUDES@
 GRECS_INCLUDE_DIR = @GRECS_INCLUDE_DIR@
 GRECS_LDADD = @GRECS_LDADD@
@@ -351,20 +365,9 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-EXTRA_DIST = \
- $(TESTSUITE_AT)\
- testsuite\
- package.m4\
- gcf1.conf\
- bind.conf\
- bind.keys\
- bind.int.conf\
- bind.ext.conf\
- bind.dlz\
- dhcpd.conf\
- meta1.conf\
- git.conf
-
+EXTRA_DIST = $(TESTSUITE_AT) testsuite package.m4 gcf1.conf bind.conf \
+	bind.keys bind.int.conf bind.ext.conf bind.dlz dhcpd.conf \
+	meta1.conf git.conf wstest wspackage.m4 wordsplit-version.h
 DISTCLEANFILES = atconfig $(check_SCRIPTS)
 MAINTAINERCLEANFILES = Makefile.in $(TESTSUITE)
 PARSER_DEFS = $(am__append_1) $(am__append_2) $(am__append_3) \
@@ -415,16 +418,22 @@ TESTSUITE_AT = \
  set.at\
  sort00.at\
  sort01.at\
+ stradj.at\
+ strcat.at\
  testsuite.at\
  vercmp.at\
- wordsplit.at\
  @GRECS_DISTCK_AT@
 
 TESTSUITE = $(srcdir)/testsuite
 M4 = m4
 AUTOTEST = $(AUTOM4TE) --language=autotest
-LDADD = @GRECS_LDADD@ $(LIBINTL)
+LDADD = @GRECS_LDADD@ $(LIBINTL) @GRECS_HOST_PROJECT_LDADD@
 AM_CPPFLAGS = @GRECS_INCLUDES@ @GRECS_HOST_PROJECT_INCLUDES@
+
+# Wordsplit testsuite
+WSTEST = $(srcdir)/wstest
+wsp_SOURCES = 
+nodist_wsp_SOURCES = wsp.c
 all: all-am
 
 .SUFFIXES:
@@ -441,7 +450,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits grecs/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnits grecs/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -730,6 +738,8 @@ uninstall-am:
 	mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 $(srcdir)/package.m4: $(top_srcdir)/configure.ac $(top_srcdir)/@GRECS_SUBDIR@/am/grecs.m4
 	$(AM_V_GEN){                                      \
@@ -751,11 +761,46 @@ $(TESTSUITE): package.m4 $(TESTSUITE_AT)
 atconfig: $(top_builddir)/config.status
 	cd $(top_builddir) && ./config.status tests/$@
 
-clean-local:
+clean-local: clean-wordsplit
 	test ! -f $(TESTSUITE) || $(SHELL) $(TESTSUITE) --clean
 
-check-local: atconfig atlocal $(TESTSUITE) $(noinst_PROGRAMS)
+check-local: check-wordsplit atconfig atlocal $(TESTSUITE) $(noinst_PROGRAMS)
 	$(SHELL) $(TESTSUITE)
+$(WSTEST): $(top_srcdir)/@GRECS_SUBDIR@/wordsplit/wordsplit.at $(srcdir)/wspackage.m4
+	$(AM_V_GEN)$(AUTOTEST) -I $(srcdir) \
+                  wspackage.m4 \
+                  $(top_srcdir)/@GRECS_SUBDIR@/wordsplit/wordsplit.at \
+	          -o $(WSTEST).tmp
+	$(AM_V_at)mv $(WSTEST).tmp $(WSTEST)
+
+$(srcdir)/wspackage.m4: $(top_srcdir)/configure.ac $(top_srcdir)/@GRECS_SUBDIR@/am/grecs.m4
+	$(AM_V_GEN){\
+	    if test -e $(top_srcdir)/@GRECS_SUBDIR@/wordsplit/.git; then \
+	        wsversion=$$(cd $(top_srcdir)/@GRECS_SUBDIR@/wordsplit; git describe); \
+	    else \
+                wsversion="unknown"; \
+	    fi;\
+            echo 'm4_define([AT_PACKAGE_NAME],      [wordsplit])'; \
+	    echo 'm4_define([AT_PACKAGE_TARNAME],   [wordsplit])'; \
+	    echo "m4_define([AT_PACKAGE_VERSION],   [$$wsversion])"; \
+	    echo 'm4_define([AT_PACKAGE_STRING],    [AT_PACKAGE_TARNAME AT_PACKAGE_VERSION])'; \
+	    echo 'm4_define([AT_PACKAGE_BUGREPORT], [@PACKAGE_BUGREPORT@])'; \
+        } > $(srcdir)/wspackage.m4
+
+$(srcdir)/wordsplit-version.h: $(srcdir)/wspackage.m4
+	$(AM_V_GEN){ echo "m4_divert(-1)";\
+          echo "m4_changequote([,])";\
+          echo "m4_changecom([//])";\
+	  echo "m4_include($(srcdir)/wspackage.m4)";\
+	  echo 'm4_divert(0)#define WORDSPLIT_VERSION "AT_PACKAGE_VERSION"'; } | \
+	 $(M4) -P - > $(srcdir)/wordsplit-version.h
+wsp.o: $(srcdir)/wordsplit-version.h
+
+clean-wordsplit:
+	test ! -f $(WSTEST) || $(SHELL) $(WSTEST) --clean
+
+check-wordsplit: atconfig atlocal $(WSTEST) $(noinst_PROGRAMS)
+	$(SHELL) $(WSTEST)
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/grecs/tests/gcffmt.c b/grecs/tests/gcffmt.c
index 8e378f9..170f788 100644
--- a/grecs/tests/gcffmt.c
+++ b/grecs/tests/gcffmt.c
@@ -94,7 +94,8 @@ main(int argc, char **argv)
 	int flags = GRECS_NODE_FLAG_DEFAULT;
 	int reduce = 0;
 	int sort = 0;
-	
+
+	grecs_parser_options = 0;
 	while (--argc) {
 		char *arg = *++argv;
 		if (strcmp(arg, "-locus") == 0)
@@ -128,6 +129,10 @@ main(int argc, char **argv)
 			grecs_gram_trace(1);
 		else if (strcmp(arg, "-X") == 0)
 			grecs_lex_trace(1);
+		else if (strcmp(arg, "-strcat") == 0)
+			grecs_parser_options |= GRECS_OPTION_QUOTED_STRING_CONCAT;
+		else if (strcmp(arg, "-stradj") == 0)
+			grecs_parser_options |= GRECS_OPTION_ADJUST_STRING_LOCATIONS;
 		else if (arg[0] == '-')
 			usage(progname, stderr, 1);
 		else {
diff --git a/grecs/tests/gcfpeek.c b/grecs/tests/gcfpeek.c
index 8e71c62..3dbd12b 100644
--- a/grecs/tests/gcfpeek.c
+++ b/grecs/tests/gcfpeek.c
@@ -74,6 +74,10 @@ main(int argc, char **argv)
 				usage(progname, stderr, 1);
 		} else if (strncmp(arg, "-root=", 6) == 0)
 			root_path = arg + 6;
+		else if (strcmp(arg, "-strcat") == 0)
+			grecs_parser_options |= GRECS_OPTION_QUOTED_STRING_CONCAT;
+		else if (strcmp(arg, "-stradj") == 0)
+			grecs_parser_options |= GRECS_OPTION_ADJUST_STRING_LOCATIONS;		
 		else if (strcmp(arg, "-h") == 0)
 			usage(progname, stdout, 0);
 		else if (arg[0] == '-')
diff --git a/grecs/tests/locus02.at b/grecs/tests/locus02.at
index d88cba6..4587be0 100644
--- a/grecs/tests/locus02.at
+++ b/grecs/tests/locus02.at
@@ -23,9 +23,11 @@ string "concatenated"
        " strings";
 ])
 
-AT_CHECK([gcfpeek -nopath -locus test.cf .string],
+AT_CHECK([gcfpeek -nopath -locus -strcat test.cf .string
+gcfpeek -nopath -locus -strcat -stradj test.cf .string],
 [0],
 [test.cf:2.8-4.17: "concatenated quoted strings"
+test.cf:2.9-4.16: "concatenated quoted strings"
 ])
 
 AT_CLEANUP
diff --git a/grecs/tests/package.m4 b/grecs/tests/package.m4
index a099285..f9a45d3 100644
--- a/grecs/tests/package.m4
+++ b/grecs/tests/package.m4
@@ -1,7 +1,7 @@
 # Signature of the current package.
 m4_define([AT_PACKAGE_NAME],      [GNU Direvent])
 m4_define([AT_PACKAGE_TARNAME],   [direvent])
-m4_define([AT_PACKAGE_VERSION],   [5.1])
-m4_define([AT_PACKAGE_STRING],    [GNU Direvent 5.1])
+m4_define([AT_PACKAGE_VERSION],   [5.2])
+m4_define([AT_PACKAGE_STRING],    [GNU Direvent 5.2])
 m4_define([AT_PACKAGE_BUGREPORT], [bug-direvent@gnu.org.ua])
 m4_define([GRECS_DISTCK_AT],      [])
diff --git a/grecs/tests/set.at b/grecs/tests/set.at
index 7daad18..c1cb0b0 100644
--- a/grecs/tests/set.at
+++ b/grecs/tests/set.at
@@ -32,7 +32,7 @@ Program bar:
 scalar = 25
 logging: 0/local2/baz/0
 ],
-[:25.1-8: Unknown keyword
+[:25.1-8: unknown keyword
 ])
 
-AT_CLEANUP
\ No newline at end of file
+AT_CLEANUP
diff --git a/grecs/tests/stradj.at b/grecs/tests/stradj.at
new file mode 100644
index 0000000..186078a
--- /dev/null
+++ b/grecs/tests/stradj.at
@@ -0,0 +1,39 @@
+# This file is part of grecs  -*- Autotest -*-
+# Copyright (C) 2016 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, 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/>.
+
+AT_SETUP([String location adjustment])
+AT_KEYWORDS([format option stradj])
+
+AT_DATA([input.conf],
+[ident name;
+option "string";
+])
+
+AT_CHECK([echo "Default"
+gcffmt -nopath -locus input.conf
+echo "Adjustment"
+gcffmt -nopath -locus -stradj input.conf
+],
+[0],
+[Default
+input.conf:1.7-10: "name"
+input.conf:2.8-15: "string"
+Adjustment
+input.conf:1.7-10: "name"
+input.conf:2.9-14: "string"
+])
+
+AT_CLEANUP
diff --git a/grecs/tests/strcat.at b/grecs/tests/strcat.at
new file mode 100644
index 0000000..b5f703a
--- /dev/null
+++ b/grecs/tests/strcat.at
@@ -0,0 +1,31 @@
+# This file is part of grecs  -*- Autotest -*-
+# Copyright (C) 2016 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, 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/>.
+
+AT_SETUP([String concatenation])
+AT_KEYWORDS([format option strcat concat])
+
+AT_DATA([input.conf],
+[option id "a" " string";
+])
+
+AT_CHECK([gcffmt input.conf
+gcffmt -strcat input.conf],
+[0],
+[.option: "id" "a" " string"
+.option: "id" "a string"
+])
+
+AT_CLEANUP
diff --git a/grecs/tests/testsuite b/grecs/tests/testsuite
index a9871a0..9448852 100755
--- a/grecs/tests/testsuite
+++ b/grecs/tests/testsuite
@@ -588,109 +588,44 @@ at_tested=''
 # As many question marks as there are digits in the last test group number.
 # Used to normalize the test group numbers so that `ls' lists them in
 # numerical order.
-at_format='???'
+at_format='??'
 # Description of all the test groups.
-at_help_all="1;wordsplit.at:58;simple input;wordsplit wsp wordsplit000 wsp000 wsp-simple;
-2;wordsplit.at:66;quoted space;wordsplit wsp wordsplit001 wsp000 wsp-quoted;
-3;wordsplit.at:72;tab character;wordsplit wsp wordsplit002 wsp000 wsp-tab;
-4;wordsplit.at:80;octal and hex escapes;wordsplit wsp wordsplit003 wsp000 wsp-escape wsp-escape000;
-5;wordsplit.at:86;octal and hex escapes 2;wordsplit wsp wordsplit004 wsp000 wsp-escape wsp-escape001;
-6;wordsplit.at:94;escape representation;wordsplit wsp wordsplit005 wsp000 wsp-escape wsp-escape002;
-7;wordsplit.at:105;append;wordsplit wsp wordsplit006 wsp000 wsp-append;
-8;wordsplit.at:127;dooffs;wordsplit wsp wordsplit007 wsp000 wsp-doofs;
-9;wordsplit.at:139;variable substitutions: single var;wordsplit wsp wordsplit008 wsp000 wsp-var wsp-var000;
-10;wordsplit.at:149;variable substitutions: concatenated vars;wordsplit wsp wordsplit009 wsp000 wsp-var wsp-var001;
-11;wordsplit.at:160;variable substitutions: field splitting;wordsplit wsp wordsplit010 wsp000 wsp-var wsp-var002;
-12;wordsplit.at:171;variable substitutions: double-quoted variable;wordsplit wsp wordsplit011 wsp000 wsp-var wsp-var003;
-13;wordsplit.at:181;variable substitutions: single-quoted variable;wordsplit wsp wordsplit012 wsp000 wsp-var wsp-var004;
-14;wordsplit.at:191;undefined variables 1;wordsplit wsp wordsplit013 wsp000 wsp-var wsp-var005;
-15;wordsplit.at:201;undefined variables 2;wordsplit wsp wordsplit014 wsp000 wsp-var wsp-var006;
-16;wordsplit.at:212;warn about undefined variables;wordsplit wsp wordsplit015 wsp000 wsp-var wsp-var007;
-17;wordsplit.at:220;bail out on undefined variables;wordsplit wsp wordsplit016 wsp000 wsp-var wsp-var008;
-18;wordsplit.at:227;disable variable expansion;wordsplit wsp wordsplit017 wsp000 wsp-var wsp-var009;
-19;wordsplit.at:235;K/V environment;wordsplit wsp wordsplit018 wsp000 wsp-var wsp-var010 wsp-env-kv wsp-env_kv;
-20;wordsplit.at:245;nosplit with expansion;wordsplit wsp wordsplit019 wsp000 wsp-var wsp-var011 wsp-var-nosplit;
-21;wordsplit.at:253;nosplit without expansion;wordsplit wsp wordsplit020 wsp000 wsp-var wsp-var012;
-22;wordsplit.at:261;default value (defined);wordsplit wsp wordsplit021 wsp000 wsp-var wsp-var013;
-23;wordsplit.at:269;default value;wordsplit wsp wordsplit022 wsp000 wsp-var wsp-var014;
-24;wordsplit.at:275;default value (defined);wordsplit wsp wordsplit023 wsp000 wsp-var wsp-var015;
-25;wordsplit.at:283;default value (:- null);wordsplit wsp wordsplit024 wsp000 wsp-var wsp-var016;
-26;wordsplit.at:291;default value (- null);wordsplit wsp wordsplit025 wsp000 wsp-var wsp-var017;
-27;wordsplit.at:298;default value (- null, unset);wordsplit wsp wordsplit026 wsp000 wsp-var wsp-var018;
-28;wordsplit.at:304;assign default values;wordsplit wsp wordsplit027 wsp000 wsp-var wsp-var019;
-29;wordsplit.at:313;default error message (var defined);wordsplit wsp wordsplit028 wsp000 wsp-var wsp-var020;
-30;wordsplit.at:323;default error message;wordsplit wsp wordsplit029 wsp000 wsp-var wsp-var021;
-31;wordsplit.at:330;custom error message (defined);wordsplit wsp wordsplit030 wsp000 wsp-var wsp-var022 wsp-custom-err wsp-custom-err00;
-32;wordsplit.at:340;custom error message;wordsplit wsp wordsplit031 wsp000 wsp-var wsp-var023 wsp-custom-err wsp-custom-err01;
-33;wordsplit.at:349;alternate value (defined);wordsplit wsp wordsplit032 wsp000 wsp-var wsp-var024 wsp-alt wsp-alt00;
-34;wordsplit.at:359;alternate value;wordsplit wsp wordsplit033 wsp000 wsp-var wsp-var025 wsp-alt wsp-alt01;
-35;wordsplit.at:368;getvar;wordsplit wsp wordsplit034 wsp000 wsp-var wsp-var026 wsp-getvar;
-36;wordsplit.at:381;getvar and env;wordsplit wsp wordsplit035 wsp000 wsp-var wsp-var027 wsp-getvar;
-37;wordsplit.at:396;getvar, alternate value;wordsplit wsp wordsplit036 wsp000 wsp-var wsp-var028 wsp-getvar;
-38;wordsplit.at:406;ignore quotes;wordsplit wsp wordsplit037 wsp000 wsp-ignore-quotes;
-39;wordsplit.at:415;custom delimiters (squeeze);wordsplit wsp wordsplit038 wsp000 wsp-delim wsp-delim000;
-40;wordsplit.at:426;custom delimiters (no squeeze);wordsplit wsp wordsplit039 wsp000 wsp-delim wsp-delim001;
-41;wordsplit.at:438;custom, with returned delimiters;wordsplit wsp wordsplit040 wsp000 wsp-delim wsp-delim002;
-42;wordsplit.at:453;custom, with returned & squeezed delimiters;wordsplit wsp wordsplit041 wsp000 wsp-delim wsp-delim003;
-43;wordsplit.at:471;sed expressions;wordsplit wsp wordsplit042 wsp000 wsp-sed wsp-sed000;
-44;wordsplit.at:481;C escapes on;wordsplit wsp wordsplit043 wsp000 wcp-c-escape;
-45;wordsplit.at:490;C escapes off;wordsplit wsp wordsplit044 wsp000 wcp-c-escape-off;
-46;wordsplit.at:499;ws elimination;wordsplit wsp wordsplit045 wsp000 wsp-ws-elim;
-47;wordsplit.at:508;ws elimination + return delim;wordsplit wsp wordsplit046 wsp000 wsp-ws-elim-ret;
-48;wordsplit.at:521;empty quotes;wordsplit wsp wordsplit047 wsp000 wsp-empty-quotes;
-49;wordsplit.at:527;delimiter following empty quotes;wordsplit wsp wordsplit048 wsp000;
-50;wordsplit.at:536;suppress ws trimming within quotes;wordsplit wsp wordsplit049 wsp000;
-51;wordsplit.at:548;unescape;wordsplit wsp wordsplit050 wsp000 wsp-unescape wsp-unescape-simple;
-52;wordsplit.at:558;unescape: word/quote;wordsplit wsp wordsplit051 wsp000 wsp-unescape wsp-unescape-word;
-53;wordsplit.at:571;dquote;wordsplit wsp wordsplit052 wsp000;
-54;wordsplit.at:580;squote;wordsplit wsp wordsplit053 wsp000;
-55;wordsplit.at:591;incremental;wordsplit wsp wordsplit054 wsp000 wsp-incr wsp-incr000;
-56;wordsplit.at:606;incremental append;wordsplit wsp wordsplit055 wsp000 wsp-incr wsp-incr001;
-57;wordsplit.at:624;incremental ws;wordsplit wsp wordsplit056 wsp000 wsp-incr wsp-incr002;
-58;wordsplit.at:643;simple command substitution;wordsplit wsp wsp-cmd wsp-cmd-1;
-59;wordsplit.at:662;quoted command substitution;wordsplit wsp wsp-cmd wsp-cmd-2;
-60;wordsplit.at:680;coalesced command substitution;wordsplit wsp wsp-cmd wsp-cmd-3;
-61;wordsplit.at:697;quoted coalesced command substitution;wordsplit wsp wsp-cmd wsp-cmd-4;
-62;wordsplit.at:713;variable and command substitution;wordsplit wsp wsp-var wsp-var24 wsp-cmd wsp-cmd-5;
-63;wordsplit.at:732;variable expansion and command substitution in quotes;wordsplit wsp wsp-var wsp-var25 wsp-cmd wsp-cmd-6;
-64;wordsplit.at:748;pathname expansion;wordsplit wsp wsp-path wsp-path-1;
-65;wordsplit.at:769;pathname expansion: no match;wordsplit wsp wsp-path wsp-path-2;
-66;wordsplit.at:788;pathname expansion: nullglob;wordsplit wsp wsp-path wsp-path-3;
-67;wordsplit.at:806;pathname expansion: failglob;wordsplit wsp wsp-path wsp-path-4;
-68;format00.at:17;Default format;format format00;
-69;format01.at:17;Locus;format format01;
-70;format02.at:17;Custom delimiter;format format02;
-71;enum.at:17;Enumerate nodes;enum;
-72;peek00.at:17;Peek;peek peek00;
-73;peek01.at:17;Nested nodes;peek peek01;
-74;peek02.at:17;Block nodes;peek peek02;
-75;peek03.at:17;Nested blocks;peek peek03;
-76;glob00.at:17;Leading wildcard;peek peek04 glob glob00;
-77;glob01.at:17;Trailing wildcard;peek peek05 glob glob01;
-78;glob02.at:17;Intermediate wildcard;peek peek05 glob glob02;
-79;glob03.at:17;Multiple wildcards;peek peek06 glob glob03;
-80;glob04.at:17;Subtree - asterisk;peek peek07 glob glob04;
-81;glob05.at:17;Subtree - percent;peek peek08 glob glob05;
-82;reduce00.at:17;Simple statement;reduce reduce00;
-83;reduce01.at:17;Block statement;reduce reduce01;
-84;reduce02.at:17;Nested block statement;reduce reduce02;
-85;reduce03.at:17;Table driven reduction;reduce reduce03;
-86;sort00.at:17;Sort;sort sort00;
-87;sort01.at:17;Stable sort;sort sort01;
-88;incl00.at:17;Include path;include incl00;
-89;incl01.at:17;Recursive inclusion;include incl01;
-90;incl02.at:17;Include once;include incl02;
-91;incl03.at:17;Wildcard inclusion;include incl03;
-92;join.at:17;Join;join;
-93;cfhelp.at:17;Help;help;
-94;set.at:17;Set values;set;
-95;vercmp.at:17;Version comparator;vercmp;
-96;grecs00.at:17;C comments in GRECS-style parser;parser grecs grecs00;
-97;empty.at:17;Empty input file;parser empty;
-98;locus00.at:17;Scalar value;locus scalar locus00;
-99;locus01.at:17;Multiline strings;locus multiline locus01;
-100;locus02.at:17;Adjacent quoted strings;locus adjacent locus02;
-101;path-locus.at:17;Path;locus path;
+at_help_all="1;format00.at:17;Default format;format format00;
+2;format01.at:17;Locus;format format01;
+3;format02.at:17;Custom delimiter;format format02;
+4;stradj.at:17;String location adjustment;format option stradj;
+5;strcat.at:17;String concatenation;format option strcat concat;
+6;enum.at:17;Enumerate nodes;enum;
+7;peek00.at:17;Peek;peek peek00;
+8;peek01.at:17;Nested nodes;peek peek01;
+9;peek02.at:17;Block nodes;peek peek02;
+10;peek03.at:17;Nested blocks;peek peek03;
+11;glob00.at:17;Leading wildcard;peek peek04 glob glob00;
+12;glob01.at:17;Trailing wildcard;peek peek05 glob glob01;
+13;glob02.at:17;Intermediate wildcard;peek peek05 glob glob02;
+14;glob03.at:17;Multiple wildcards;peek peek06 glob glob03;
+15;glob04.at:17;Subtree - asterisk;peek peek07 glob glob04;
+16;glob05.at:17;Subtree - percent;peek peek08 glob glob05;
+17;reduce00.at:17;Simple statement;reduce reduce00;
+18;reduce01.at:17;Block statement;reduce reduce01;
+19;reduce02.at:17;Nested block statement;reduce reduce02;
+20;reduce03.at:17;Table driven reduction;reduce reduce03;
+21;sort00.at:17;Sort;sort sort00;
+22;sort01.at:17;Stable sort;sort sort01;
+23;incl00.at:17;Include path;include incl00;
+24;incl01.at:17;Recursive inclusion;include incl01;
+25;incl02.at:17;Include once;include incl02;
+26;incl03.at:17;Wildcard inclusion;include incl03;
+27;join.at:17;Join;join;
+28;cfhelp.at:17;Help;help;
+29;set.at:17;Set values;set;
+30;vercmp.at:17;Version comparator;vercmp;
+31;grecs00.at:17;C comments in GRECS-style parser;parser grecs grecs00;
+32;empty.at:17;Empty input file;parser empty;
+33;locus00.at:17;Scalar value;locus scalar locus00;
+34;locus01.at:17;Multiline strings;locus multiline locus01;
+35;locus02.at:17;Adjacent quoted strings;locus adjacent locus02;
+36;path-locus.at:17;Path;locus path;
 "
 # List of the all the test groups.
 at_groups_all=`$as_echo "$at_help_all" | sed 's/;.*//'`
@@ -704,7 +639,7 @@ at_fn_validate_ranges ()
   for at_grp
   do
     eval at_value=\$$at_grp
-    if test $at_value -lt 1 || test $at_value -gt 101; then
+    if test $at_value -lt 1 || test $at_value -gt 36; then
       $as_echo "invalid test group: $at_value" >&2
       exit 1
     fi
@@ -1003,7 +938,7 @@ fi
 # List of tests.
 if $at_list_p; then
   cat <<_ATEOF || at_write_fail=1
-GNU Direvent 5.1 test suite test groups:
+GNU Direvent 5.2 test suite test groups:
 
  NUM: FILE-NAME:LINE     TEST-GROUP-NAME
       KEYWORDS
@@ -1044,7 +979,7 @@ _ATEOF
   exit $at_write_fail
 fi
 if $at_version_p; then
-  $as_echo "$as_me (GNU Direvent 5.1)" &&
+  $as_echo "$as_me (GNU Direvent 5.2)" &&
   cat <<\_ATEOF || at_write_fail=1
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1061,35 +996,35 @@ case $at_groups in #(
   * ) at_print_banners=false ;;
 esac
 # Text for banner N, set to a single space once printed.
-# Banner 1. wordsplit.at:17
+# Banner 1. testsuite.at:50
 # Category starts at test group 1.
-at_banner_text_1="Wordsplit"
-# Banner 2. testsuite.at:52
-# Category starts at test group 68.
-at_banner_text_2="Formats"
-# Banner 3. testsuite.at:57
-# Category starts at test group 71.
+at_banner_text_1="Formats"
+# Banner 2. testsuite.at:55
+# Category starts at test group 4.
+at_banner_text_2="Options"
+# Banner 3. testsuite.at:59
+# Category starts at test group 6.
 at_banner_text_3="Enumeration"
-# Banner 4. testsuite.at:60
-# Category starts at test group 72.
+# Banner 4. testsuite.at:62
+# Category starts at test group 7.
 at_banner_text_4="Peek a node"
-# Banner 5. testsuite.at:66
-# Category starts at test group 76.
+# Banner 5. testsuite.at:68
+# Category starts at test group 11.
 at_banner_text_5="Globbing"
-# Banner 6. testsuite.at:74
-# Category starts at test group 82.
+# Banner 6. testsuite.at:76
+# Category starts at test group 17.
 at_banner_text_6="Reduce"
-# Banner 7. testsuite.at:80
-# Category starts at test group 86.
+# Banner 7. testsuite.at:82
+# Category starts at test group 21.
 at_banner_text_7="Sort"
-# Banner 8. testsuite.at:84
-# Category starts at test group 88.
+# Banner 8. testsuite.at:86
+# Category starts at test group 23.
 at_banner_text_8="Include"
-# Banner 9. testsuite.at:114
-# Category starts at test group 92.
+# Banner 9. testsuite.at:116
+# Category starts at test group 27.
 at_banner_text_9="Other operatios"
-# Banner 10. testsuite.at:122
-# Category starts at test group 98.
+# Banner 10. testsuite.at:124
+# Category starts at test group 33.
 at_banner_text_10="Locations"
 
 # Take any -C into account.
@@ -1251,11 +1186,11 @@ exec 5>>"$at_suite_log"
 
 # Banners and logs.
 $as_echo "## ---------------------------- ##
-## GNU Direvent 5.1 test suite. ##
+## GNU Direvent 5.2 test suite. ##
 ## ---------------------------- ##"
 {
   $as_echo "## ---------------------------- ##
-## GNU Direvent 5.1 test suite. ##
+## GNU Direvent 5.2 test suite. ##
 ## ---------------------------- ##"
   echo
 
@@ -2099,7 +2034,7 @@ _ASBOX
   $as_echo "Please send $at_msg and all information you think might help:
 
    To: <bug-direvent@gnu.org.ua>
-   Subject: [GNU Direvent 5.1] $as_me: $at_fail_list${at_fail_list:+ failed${at_xpass_list:+, }}$at_xpass_list${at_xpass_list:+ passed unexpectedly}
+   Subject: [GNU Direvent 5.2] $as_me: $at_fail_list${at_fail_list:+ failed${at_xpass_list:+, }}$at_xpass_list${at_xpass_list:+ passed unexpectedly}
 
 You may investigate any problem if you feel able to do so, in which
 case the test suite provides a good starting point.  Its output may
@@ -2114,2813 +2049,14 @@ exit 0
 ## Actual tests. ##
 ## ------------- ##
 #AT_START_1
-at_fn_group_banner 1 'wordsplit.at:58' \
-  "simple input" "                                   " 1
+at_fn_group_banner 1 'format00.at:17' \
+  "Default format" "                                 " 1
 at_xfail=no
 (
   $as_echo "1. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:58:
- wsp  <<'EOT'
-1 2 3
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:58"
-( $at_check_trace;
- wsp  <<'EOT'
-1 2 3
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: 1
-1: 2
-2: 3
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:58"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_1
-#AT_START_2
-at_fn_group_banner 2 'wordsplit.at:66' \
-  "quoted space" "                                   " 1
-at_xfail=no
-(
-  $as_echo "2. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:66:
- wsp  <<'EOT'
-quoted\\ space
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:66"
-( $at_check_trace;
- wsp  <<'EOT'
-quoted\ space
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: \"quoted space\"
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:66"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_2
-#AT_START_3
-at_fn_group_banner 3 'wordsplit.at:72' \
-  "tab character" "                                  " 1
-at_xfail=no
-(
-  $as_echo "3. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:72:
- wsp  <<'EOT'
-a \"tab	character\"
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:72"
-( $at_check_trace;
- wsp  <<'EOT'
-a "tab	character"
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 2
-0: a
-1: tab\\tcharacter
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:72"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_3
-#AT_START_4
-at_fn_group_banner 4 'wordsplit.at:80' \
-  "octal and hex escapes" "                          " 1
-at_xfail=no
-(
-  $as_echo "4. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:80:
- wsp  <<'EOT'
-\\157\\143\\164\\141\\154\\40and\\x20\\x68\\x65\\x78
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:80"
-( $at_check_trace;
- wsp  <<'EOT'
-\157\143\164\141\154\40and\x20\x68\x65\x78
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: \"octal and hex\"
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:80"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_4
-#AT_START_5
-at_fn_group_banner 5 'wordsplit.at:86' \
-  "octal and hex escapes 2" "                        " 1
-at_xfail=no
-(
-  $as_echo "5. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:86:
- wsp  <<'EOT'
-\\157\\143\\164\\141\\154\\40 and \\x20\\x68\\x65\\x78
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:86"
-( $at_check_trace;
- wsp  <<'EOT'
-\157\143\164\141\154\40 and \x20\x68\x65\x78
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: \"octal \"
-1: and
-2: \" hex\"
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:86"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_5
-#AT_START_6
-at_fn_group_banner 6 'wordsplit.at:94' \
-  "escape representation" "                          " 1
-at_xfail=no
-(
-  $as_echo "6. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:94:
- wsp  <<'EOT'
-A\\x3-\\48\\39
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:94"
-( $at_check_trace;
- wsp  <<'EOT'
-A\x3-\48\39
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: A\\003-\\0048\\0039
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:94"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_6
-#AT_START_7
-at_fn_group_banner 7 'wordsplit.at:105' \
-  "append" "                                         " 1
-at_xfail=no
-(
-  $as_echo "7. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:105:
- wsp append <<'EOT'
-jeden dwa trzy
-cztery
-piec szesc
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:105"
-( $at_check_trace;
- wsp append <<'EOT'
-jeden dwa trzy
-cztery
-piec szesc
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: jeden
-1: dwa
-2: trzy
-NF: 4
-0: jeden
-1: dwa
-2: trzy
-3: cztery
-NF: 6
-0: jeden
-1: dwa
-2: trzy
-3: cztery
-4: piec
-5: szesc
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:105"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_7
-#AT_START_8
-at_fn_group_banner 8 'wordsplit.at:127' \
-  "dooffs" "                                         " 1
-at_xfail=no
-(
-  $as_echo "8. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:127:
- wsp dooffs 3 jeden dwa trzy <<'EOT'
-cztery piec
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:127"
-( $at_check_trace;
- wsp dooffs 3 jeden dwa trzy <<'EOT'
-cztery piec
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 2 (3)
-(0): jeden
-(1): dwa
-(2): trzy
-3: cztery
-4: piec
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:127"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_8
-#AT_START_9
-at_fn_group_banner 9 'wordsplit.at:139' \
-  "variable substitutions: single var" "             " 1
-at_xfail=no
-(
-  $as_echo "9. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:139:
-FOO=bar wsp  <<'EOT'
-a \$FOO test
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:139"
-( $at_check_trace;
-FOO=bar wsp  <<'EOT'
-a $FOO test
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: a
-1: bar
-2: test
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:139"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_9
-#AT_START_10
-at_fn_group_banner 10 'wordsplit.at:149' \
-  "variable substitutions: concatenated vars" "      " 1
-at_xfail=no
-(
-  $as_echo "10. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:149:
-FOO=str BAR=ing wsp  <<'EOT'
-a \$FOO\${BAR}ent test
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:149"
-( $at_check_trace;
-FOO=str BAR=ing wsp  <<'EOT'
-a $FOO${BAR}ent test
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: a
-1: stringent
-2: test
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:149"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_10
-#AT_START_11
-at_fn_group_banner 11 'wordsplit.at:160' \
-  "variable substitutions: field splitting" "        " 1
-at_xfail=no
-(
-  $as_echo "11. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:160:
-FOO=\"variable substitution\" wsp  <<'EOT'
-a \$FOO test
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:160"
-( $at_check_trace;
-FOO="variable substitution" wsp  <<'EOT'
-a $FOO test
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 4
-0: a
-1: variable
-2: substitution
-3: test
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:160"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_11
-#AT_START_12
-at_fn_group_banner 12 'wordsplit.at:171' \
-  "variable substitutions: double-quoted variable" " " 1
-at_xfail=no
-(
-  $as_echo "12. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:171:
-FOO=\"variable substitution\" wsp  <<'EOT'
-a \"\$FOO\" test
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:171"
-( $at_check_trace;
-FOO="variable substitution" wsp  <<'EOT'
-a "$FOO" test
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: a
-1: \"variable substitution\"
-2: test
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:171"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_12
-#AT_START_13
-at_fn_group_banner 13 'wordsplit.at:181' \
-  "variable substitutions: single-quoted variable" " " 1
-at_xfail=no
-(
-  $as_echo "13. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:181:
-FOO=\"variable substitution\" wsp  <<'EOT'
-a '\$FOO' test
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:181"
-( $at_check_trace;
-FOO="variable substitution" wsp  <<'EOT'
-a '$FOO' test
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: a
-1: \$FOO
-2: test
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:181"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_13
-#AT_START_14
-at_fn_group_banner 14 'wordsplit.at:191' \
-  "undefined variables 1" "                          " 1
-at_xfail=no
-(
-  $as_echo "14. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:191:
-unset FOO; wsp  <<'EOT'
-a \$FOO test a\${FOO}b
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:191"
-( $at_check_trace;
-unset FOO; wsp  <<'EOT'
-a $FOO test a${FOO}b
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: a
-1: test
-2: ab
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:191"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_14
-#AT_START_15
-at_fn_group_banner 15 'wordsplit.at:201' \
-  "undefined variables 2" "                          " 1
-at_xfail=no
-(
-  $as_echo "15. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:201:
-unset FOO; wsp keepundef <<'EOT'
-a \$FOO test a\${FOO}b
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:201"
-( $at_check_trace;
-unset FOO; wsp keepundef <<'EOT'
-a $FOO test a${FOO}b
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 4
-0: a
-1: \$FOO
-2: test
-3: a\${FOO}b
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:201"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_15
-#AT_START_16
-at_fn_group_banner 16 'wordsplit.at:212' \
-  "warn about undefined variables" "                 " 1
-at_xfail=no
-(
-  $as_echo "16. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:212:
-unset FOO; wsp warnundef <<'EOT'
-\$FOO
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:212"
-( $at_check_trace;
-unset FOO; wsp warnundef <<'EOT'
-$FOO
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-echo >>"$at_stderr"; $as_echo "warning: undefined variable \`FOO'
-" | \
-  $at_diff - "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 0
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:212"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_16
-#AT_START_17
-at_fn_group_banner 17 'wordsplit.at:220' \
-  "bail out on undefined variables" "                " 1
-at_xfail=no
-(
-  $as_echo "17. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:220:
-unset FOO; wsp undef <<'EOT'
-\$FOO
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:220"
-( $at_check_trace;
-unset FOO; wsp undef <<'EOT'
-$FOO
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-echo >>"$at_stderr"; $as_echo "undefined variable
-" | \
-  $at_diff - "$at_stderr" || at_failed=:
-at_fn_diff_devnull "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:220"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_17
-#AT_START_18
-at_fn_group_banner 18 'wordsplit.at:227' \
-  "disable variable expansion" "                     " 1
-at_xfail=no
-(
-  $as_echo "18. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:227:
-FOO=bar wsp novar <<'EOT'
-\$FOO
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:227"
-( $at_check_trace;
-FOO=bar wsp novar <<'EOT'
-$FOO
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: \$FOO
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:227"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_18
-#AT_START_19
-at_fn_group_banner 19 'wordsplit.at:235' \
-  "K/V environment" "                                " 1
-at_xfail=no
-(
-  $as_echo "19. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:235:
-FOO=bar BAZ=qux wsp env_kv <<'EOT'
-\$FOO a\$BAZ
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:235"
-( $at_check_trace;
-FOO=bar BAZ=qux wsp env_kv <<'EOT'
-$FOO a$BAZ
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 2
-0: bar
-1: aqux
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:235"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_19
-#AT_START_20
-at_fn_group_banner 20 'wordsplit.at:245' \
-  "nosplit with expansion" "                         " 1
-at_xfail=no
-(
-  $as_echo "20. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:245:
-FOO=\"variable expansion\" wsp nosplit <<'EOT'
-a \$FOO test
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:245"
-( $at_check_trace;
-FOO="variable expansion" wsp nosplit <<'EOT'
-a $FOO test
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: \"a variable expansion test\\n\"
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:245"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_20
-#AT_START_21
-at_fn_group_banner 21 'wordsplit.at:253' \
-  "nosplit without expansion" "                      " 1
-at_xfail=no
-(
-  $as_echo "21. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:253:
-FOO=\"variable expansion\" wsp nosplit novar <<'EOT'
-a \$FOO test
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:253"
-( $at_check_trace;
-FOO="variable expansion" wsp nosplit novar <<'EOT'
-a $FOO test
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: \"a \$FOO test\\n\"
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:253"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_21
-#AT_START_22
-at_fn_group_banner 22 'wordsplit.at:261' \
-  "default value (defined)" "                        " 1
-at_xfail=no
-(
-  $as_echo "22. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:261:
-FOO=qux wsp  <<'EOT'
-\${FOO:-bar}
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:261"
-( $at_check_trace;
-FOO=qux wsp  <<'EOT'
-${FOO:-bar}
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: qux
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:261"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_22
-#AT_START_23
-at_fn_group_banner 23 'wordsplit.at:269' \
-  "default value" "                                  " 1
-at_xfail=no
-(
-  $as_echo "23. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:269:
- wsp  <<'EOT'
-\${FOO:-bar}
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:269"
-( $at_check_trace;
- wsp  <<'EOT'
-${FOO:-bar}
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: bar
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:269"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_23
-#AT_START_24
-at_fn_group_banner 24 'wordsplit.at:275' \
-  "default value (defined)" "                        " 1
-at_xfail=no
-(
-  $as_echo "24. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:275:
-FOO=qux wsp  <<'EOT'
-\${FOO:-bar}
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:275"
-( $at_check_trace;
-FOO=qux wsp  <<'EOT'
-${FOO:-bar}
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: qux
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:275"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_24
-#AT_START_25
-at_fn_group_banner 25 'wordsplit.at:283' \
-  "default value (:- null)" "                        " 1
-at_xfail=no
-(
-  $as_echo "25. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:283:
-FOO= wsp  <<'EOT'
-\${FOO:-bar}
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:283"
-( $at_check_trace;
-FOO= wsp  <<'EOT'
-${FOO:-bar}
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: bar
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:283"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_25
-#AT_START_26
-at_fn_group_banner 26 'wordsplit.at:291' \
-  "default value (- null)" "                         " 1
-at_xfail=no
-(
-  $as_echo "26. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:291:
-FOO= wsp  <<'EOT'
-\${FOO-bar}
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:291"
-( $at_check_trace;
-FOO= wsp  <<'EOT'
-${FOO-bar}
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 0
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:291"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_26
-#AT_START_27
-at_fn_group_banner 27 'wordsplit.at:298' \
-  "default value (- null, unset)" "                  " 1
-at_xfail=no
-(
-  $as_echo "27. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:298:
- wsp  <<'EOT'
-\${FOO-bar}
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:298"
-( $at_check_trace;
- wsp  <<'EOT'
-${FOO-bar}
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: bar
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:298"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_27
-#AT_START_28
-at_fn_group_banner 28 'wordsplit.at:304' \
-  "assign default values" "                          " 1
-at_xfail=no
-(
-  $as_echo "28. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:304:
- wsp  <<'EOT'
-\${FOO=bar}
-\$FOO
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:304"
-( $at_check_trace;
- wsp  <<'EOT'
-${FOO=bar}
-$FOO
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: bar
-NF: 1
-0: bar
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:304"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_28
-#AT_START_29
-at_fn_group_banner 29 'wordsplit.at:313' \
-  "default error message (var defined)" "            " 1
-at_xfail=no
-(
-  $as_echo "29. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:313:
-FOO=bar wsp  <<'EOT'
-a \${FOO:?} test
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:313"
-( $at_check_trace;
-FOO=bar wsp  <<'EOT'
-a ${FOO:?} test
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: a
-1: bar
-2: test
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:313"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_29
-#AT_START_30
-at_fn_group_banner 30 'wordsplit.at:323' \
-  "default error message" "                          " 1
-at_xfail=no
-(
-  $as_echo "30. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:323:
- wsp  <<'EOT'
-\${FOO:?}
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:323"
-( $at_check_trace;
- wsp  <<'EOT'
-${FOO:?}
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-echo >>"$at_stderr"; $as_echo "FOO: variable null or not set
-" | \
-  $at_diff - "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 0
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:323"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_30
-#AT_START_31
-at_fn_group_banner 31 'wordsplit.at:330' \
-  "custom error message (defined)" "                 " 1
-at_xfail=no
-(
-  $as_echo "31. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:330:
-FOO=bar wsp  <<'EOT'
-a \${FOO:?please define it} test
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:330"
-( $at_check_trace;
-FOO=bar wsp  <<'EOT'
-a ${FOO:?please define it} test
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: a
-1: bar
-2: test
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:330"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_31
-#AT_START_32
-at_fn_group_banner 32 'wordsplit.at:340' \
-  "custom error message" "                           " 1
-at_xfail=no
-(
-  $as_echo "32. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:340:
- wsp  <<'EOT'
-a \${FOO:?please define it} test
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:340"
-( $at_check_trace;
- wsp  <<'EOT'
-a ${FOO:?please define it} test
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-echo >>"$at_stderr"; $as_echo "FOO: please define it
-" | \
-  $at_diff - "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 2
-0: a
-1: test
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:340"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_32
-#AT_START_33
-at_fn_group_banner 33 'wordsplit.at:349' \
-  "alternate value (defined)" "                      " 1
-at_xfail=no
-(
-  $as_echo "33. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:349:
-FOO=bar wsp  <<'EOT'
-a \${FOO:+isset} test
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:349"
-( $at_check_trace;
-FOO=bar wsp  <<'EOT'
-a ${FOO:+isset} test
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: a
-1: isset
-2: test
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:349"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_33
-#AT_START_34
-at_fn_group_banner 34 'wordsplit.at:359' \
-  "alternate value" "                                " 1
-at_xfail=no
-(
-  $as_echo "34. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:359:
-unset FOO; wsp  <<'EOT'
-a \${FOO:+isset} test
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:359"
-( $at_check_trace;
-unset FOO; wsp  <<'EOT'
-a ${FOO:+isset} test
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 2
-0: a
-1: test
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:359"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_34
-#AT_START_35
-at_fn_group_banner 35 'wordsplit.at:368' \
-  "getvar" "                                         " 1
-at_xfail=no
-(
-  $as_echo "35. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:368: unset foo; unset x
- wsp foo=bar x=quux <<'EOT'
-begin \$foo \$x end
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:368"
-( $at_check_trace; unset foo; unset x
- wsp foo=bar x=quux <<'EOT'
-begin $foo $x end
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 4
-0: begin
-1: bar
-2: quux
-3: end
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:368"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_35
-#AT_START_36
-at_fn_group_banner 36 'wordsplit.at:381' \
-  "getvar and env" "                                 " 1
-at_xfail=no
-(
-  $as_echo "36. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:381: unset foo; unset x
-TVAR=12 y=zwar wsp foo=bar x=quux y=xur <<'EOT'
-begin \$foo \$TVAR \$x \$y end
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:381"
-( $at_check_trace; unset foo; unset x
-TVAR=12 y=zwar wsp foo=bar x=quux y=xur <<'EOT'
-begin $foo $TVAR $x $y end
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 6
-0: begin
-1: bar
-2: 12
-3: quux
-4: zwar
-5: end
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:381"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_36
-#AT_START_37
-at_fn_group_banner 37 'wordsplit.at:396' \
-  "getvar, alternate value" "                        " 1
-at_xfail=no
-(
-  $as_echo "37. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:396:
- wsp foo=bar <<'EOT'
-a \${foo:+isset}
-EOT
-"
-at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:396"
-( $at_check_trace;
- wsp foo=bar <<'EOT'
-a ${foo:+isset}
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 2
-0: a
-1: isset
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:396"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_37
-#AT_START_38
-at_fn_group_banner 38 'wordsplit.at:406' \
-  "ignore quotes" "                                  " 1
-at_xfail=no
-(
-  $as_echo "38. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:406:
- wsp -quote <<'EOT'
-\"a text\"
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:406"
-( $at_check_trace;
- wsp -quote <<'EOT'
-"a text"
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 2
-0: \"\\\"a\"
-1: \"text\\\"\"
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:406"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_38
-#AT_START_39
-at_fn_group_banner 39 'wordsplit.at:415' \
-  "custom delimiters (squeeze)" "                    " 1
-at_xfail=no
-(
-  $as_echo "39. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:415:
- wsp delim : -ws trimnl <<'EOT'
-semicolon: separated::list: of :words
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:415"
-( $at_check_trace;
- wsp delim : -ws trimnl <<'EOT'
-semicolon: separated::list: of :words
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 5
-0: semicolon
-1: \" separated\"
-2: list
-3: \" of \"
-4: words
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:415"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_39
-#AT_START_40
-at_fn_group_banner 40 'wordsplit.at:426' \
-  "custom delimiters (no squeeze)" "                 " 1
-at_xfail=no
-(
-  $as_echo "40. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:426:
- wsp delim : -ws -squeeze_delims trimnl <<'EOT'
-semicolon: separated::list: of :words
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:426"
-( $at_check_trace;
- wsp delim : -ws -squeeze_delims trimnl <<'EOT'
-semicolon: separated::list: of :words
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 6
-0: semicolon
-1: \" separated\"
-2: \"\"
-3: list
-4: \" of \"
-5: words
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:426"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_40
-#AT_START_41
-at_fn_group_banner 41 'wordsplit.at:438' \
-  "custom, with returned delimiters" "               " 1
-at_xfail=no
-(
-  $as_echo "41. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:438:
- wsp delim : -ws trimnl return_delims <<'EOT'
-semicolon: separated::list: of :words
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:438"
-( $at_check_trace;
- wsp delim : -ws trimnl return_delims <<'EOT'
-semicolon: separated::list: of :words
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 9
-0: semicolon
-1: :
-2: \" separated\"
-3: :
-4: list
-5: :
-6: \" of \"
-7: :
-8: words
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:438"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_41
-#AT_START_42
-at_fn_group_banner 42 'wordsplit.at:453' \
-  "custom, with returned & squeezed delimiters" "    " 1
-at_xfail=no
-(
-  $as_echo "42. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:453:
- wsp delim : -ws trimnl return_delims -squeeze_delims <<'EOT'
-semicolon: separated::list: of :words
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:453"
-( $at_check_trace;
- wsp delim : -ws trimnl return_delims -squeeze_delims <<'EOT'
-semicolon: separated::list: of :words
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 10
-0: semicolon
-1: :
-2: \" separated\"
-3: :
-4: :
-5: list
-6: :
-7: \" of \"
-8: :
-9: words
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:453"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_42
-#AT_START_43
-at_fn_group_banner 43 'wordsplit.at:471' \
-  "sed expressions" "                                " 1
-at_xfail=no
-(
-  $as_echo "43. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:471:
- wsp sed <<'EOT'
-arg1 s/foo/bar/g;s/bar baz/quz quux/ arg2
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:471"
-( $at_check_trace;
- wsp sed <<'EOT'
-arg1 s/foo/bar/g;s/bar baz/quz quux/ arg2
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: arg1
-1: \"s/foo/bar/g;s/bar baz/quz quux/\"
-2: arg2
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:471"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_43
-#AT_START_44
-at_fn_group_banner 44 'wordsplit.at:481' \
-  "C escapes on" "                                   " 1
-at_xfail=no
-(
-  $as_echo "44. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:481:
- wsp cescapes <<'EOT'
-a\\ttab form\\ffeed and new\\nline
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:481"
-( $at_check_trace;
- wsp cescapes <<'EOT'
-a\ttab form\ffeed and new\nline
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 4
-0: a\\ttab
-1: form\\ffeed
-2: and
-3: new\\nline
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:481"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_44
-#AT_START_45
-at_fn_group_banner 45 'wordsplit.at:490' \
-  "C escapes off" "                                  " 1
-at_xfail=no
-(
-  $as_echo "45. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:490:
- wsp -cescapes <<'EOT'
-a\\ttab form\\ffeed and new\\nline
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:490"
-( $at_check_trace;
- wsp -cescapes <<'EOT'
-a\ttab form\ffeed and new\nline
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 4
-0: attab
-1: formffeed
-2: and
-3: newnline
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:490"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_45
-#AT_START_46
-at_fn_group_banner 46 'wordsplit.at:499' \
-  "ws elimination" "                                 " 1
-at_xfail=no
-(
-  $as_echo "46. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:499:
- wsp delim ' ()' ws return_delims <<'EOT'
-( list  items  )
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:499"
-( $at_check_trace;
- wsp delim ' ()' ws return_delims <<'EOT'
-( list  items  )
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 4
-0: (
-1: list
-2: items
-3: )
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:499"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_46
-#AT_START_47
-at_fn_group_banner 47 'wordsplit.at:508' \
-  "ws elimination + return delim" "                  " 1
-at_xfail=no
-(
-  $as_echo "47. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:508:
- wsp -default novar nocmd delim \":,\" return_delims ws dquote <<'EOT'
-\"foo\" : \"bar\", \"quux\" : \"baaz\"
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:508"
-( $at_check_trace;
- wsp -default novar nocmd delim ":," return_delims ws dquote <<'EOT'
-"foo" : "bar", "quux" : "baaz"
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 7
-0: foo
-1: :
-2: bar
-3: ,
-4: quux
-5: :
-6: baaz
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:508"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_47
-#AT_START_48
-at_fn_group_banner 48 'wordsplit.at:521' \
-  "empty quotes" "                                   " 1
-at_xfail=no
-(
-  $as_echo "48. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:521:
- wsp delim : ws return_delims <<'EOT'
-t=\"\"
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:521"
-( $at_check_trace;
- wsp delim : ws return_delims <<'EOT'
-t=""
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: t=
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:521"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_48
-#AT_START_49
-at_fn_group_banner 49 'wordsplit.at:527' \
-  "delimiter following empty quotes" "               " 1
-at_xfail=no
-(
-  $as_echo "49. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:527:
- wsp delim : ws return_delims <<'EOT'
-t=\"\":r
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:527"
-( $at_check_trace;
- wsp delim : ws return_delims <<'EOT'
-t="":r
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: t=
-1: :
-2: r
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:527"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_49
-#AT_START_50
-at_fn_group_banner 50 'wordsplit.at:536' \
-  "suppress ws trimming within quotes" "             " 1
-at_xfail=no
-(
-  $as_echo "50. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:536:
- wsp default delim , ws return_delims <<'EOT'
-nocomponent,nonewline, formatfield=\"In message %{text}, \"
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:536"
-( $at_check_trace;
- wsp default delim , ws return_delims <<'EOT'
-nocomponent,nonewline, formatfield="In message %{text}, "
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 5
-0: nocomponent
-1: ,
-2: nonewline
-3: ,
-4: \"formatfield=In message %{text}, \"
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:536"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_50
-#AT_START_51
-at_fn_group_banner 51 'wordsplit.at:548' \
-  "unescape" "                                       " 1
-at_xfail=no
-(
-  $as_echo "51. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:548:
- wsp -default novar nocmd quote escape ':+:\\\\\"\"' <<'EOT'
-\\Seen \"quote \\\"\" \"bs \\\\\"
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:548"
-( $at_check_trace;
- wsp -default novar nocmd quote escape ':+:\\""' <<'EOT'
-\Seen "quote \"" "bs \\"
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: \\\\Seen
-1: \"quote \\\"\"
-2: \"bs \\\\\"
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:548"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_51
-#AT_START_52
-at_fn_group_banner 52 'wordsplit.at:558' \
-  "unescape: word/quote" "                           " 1
-at_xfail=no
-(
-  $as_echo "52. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:558:
- wsp -default novar nocmd quote escape-word '\\\\\"\"' escape-quote ':+0x:\\\\\"\"' <<'EOT'
-\\Seen \"quote \\\"\" \"bs \\\\\" \"3\\x31 \\101\" 3\\x31 \\101
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:558"
-( $at_check_trace;
- wsp -default novar nocmd quote escape-word '\\""' escape-quote ':+0x:\\""' <<'EOT'
-\Seen "quote \"" "bs \\" "3\x31 \101" 3\x31 \101
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 6
-0: Seen
-1: \"quote \\\"\"
-2: \"bs \\\\\"
-3: \"31 A\"
-4: 3x31
-5: 101
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:558"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_52
-#AT_START_53
-at_fn_group_banner 53 'wordsplit.at:571' \
-  "dquote" "                                         " 1
-at_xfail=no
-(
-  $as_echo "53. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:571:
- wsp -default novar nocmd dquote <<'EOT'
-a \"quoted example\" isn't it
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:571"
-( $at_check_trace;
- wsp -default novar nocmd dquote <<'EOT'
-a "quoted example" isn't it
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 4
-0: a
-1: \"quoted example\"
-2: isn't
-3: it
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:571"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_53
-#AT_START_54
-at_fn_group_banner 54 'wordsplit.at:580' \
-  "squote" "                                         " 1
-at_xfail=no
-(
-  $as_echo "54. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:580:
- wsp -default novar nocmd squote <<'EOT'
-a 'quoted example' isn\"t it
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:580"
-( $at_check_trace;
- wsp -default novar nocmd squote <<'EOT'
-a 'quoted example' isn"t it
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 4
-0: a
-1: \"quoted example\"
-2: \"isn\\\"t\"
-3: it
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:580"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_54
-#AT_START_55
-at_fn_group_banner 55 'wordsplit.at:591' \
-  "incremental" "                                    " 1
-at_xfail=no
-(
-  $as_echo "55. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:591:
- wsp incremental <<'EOT'
-incremental \"input test\" line
-
-
-
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:591"
-( $at_check_trace;
- wsp incremental <<'EOT'
-incremental "input test" line
-
-
-
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-echo >>"$at_stderr"; $as_echo "input exhausted
-" | \
-  $at_diff - "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: incremental
-NF: 1
-0: \"input test\"
-NF: 1
-0: line
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:591"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_55
-#AT_START_56
-at_fn_group_banner 56 'wordsplit.at:606' \
-  "incremental append" "                             " 1
-at_xfail=no
-(
-  $as_echo "56. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:606:
- wsp incremental append <<'EOT'
-incremental \"input test\" line
-
-
-
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:606"
-( $at_check_trace;
- wsp incremental append <<'EOT'
-incremental "input test" line
-
-
-
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-echo >>"$at_stderr"; $as_echo "input exhausted
-" | \
-  $at_diff - "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: incremental
-NF: 2
-0: incremental
-1: \"input test\"
-NF: 3
-0: incremental
-1: \"input test\"
-2: line
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:606"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_56
-#AT_START_57
-at_fn_group_banner 57 'wordsplit.at:624' \
-  "incremental ws" "                                 " 1
-at_xfail=no
-(
-  $as_echo "57. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:624:
- wsp return_delims -squeeze_delims incremental ws <<'EOT'
-a   list  test
-
-
-
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:624"
-( $at_check_trace;
- wsp return_delims -squeeze_delims incremental ws <<'EOT'
-a   list  test
-
-
-
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-echo >>"$at_stderr"; $as_echo "input exhausted
-" | \
-  $at_diff - "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: a
-NF: 1
-0: list
-NF: 1
-0: test
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:624"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_57
-#AT_START_58
-at_fn_group_banner 58 'wordsplit.at:643' \
-  "simple command substitution" "                    " 1
-at_xfail=no
-(
-  $as_echo "58. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:645:
-mkdir dir
-> dir/file
-
-wsp -nocmd <<'EOT'
-begin \$(find dir) end
-EOT
-"
-at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:645"
-( $at_check_trace;
-mkdir dir
-> dir/file
-
-wsp -nocmd <<'EOT'
-begin $(find dir) end
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 4
-0: begin
-1: dir
-2: dir/file
-3: end
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:645"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_58
-#AT_START_59
-at_fn_group_banner 59 'wordsplit.at:662' \
-  "quoted command substitution" "                    " 1
-at_xfail=no
-(
-  $as_echo "59. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:664:
-mkdir dir
-> dir/file
-
-wsp -nocmd <<'EOT'
-begin \"\$(find dir)\" end
-EOT
-"
-at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:664"
-( $at_check_trace;
-mkdir dir
-> dir/file
-
-wsp -nocmd <<'EOT'
-begin "$(find dir)" end
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: begin
-1: \"dir dir/file\"
-2: end
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:664"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_59
-#AT_START_60
-at_fn_group_banner 60 'wordsplit.at:680' \
-  "coalesced command substitution" "                 " 1
-at_xfail=no
-(
-  $as_echo "60. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:682:
-mkdir dir
-> dir/file
-
-wsp -nocmd <<'EOT'
-begin(\$(find dir))end
-EOT
-"
-at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:682"
-( $at_check_trace;
-mkdir dir
-> dir/file
-
-wsp -nocmd <<'EOT'
-begin($(find dir))end
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 2
-0: begin(dir
-1: dir/file)end
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:682"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_60
-#AT_START_61
-at_fn_group_banner 61 'wordsplit.at:697' \
-  "quoted coalesced command substitution" "          " 1
-at_xfail=no
-(
-  $as_echo "61. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:699:
-mkdir dir
-> dir/file
-
-wsp -nocmd <<'EOT'
-\"begin(\$(find dir))end\"
-EOT
-"
-at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:699"
-( $at_check_trace;
-mkdir dir
-> dir/file
-
-wsp -nocmd <<'EOT'
-"begin($(find dir))end"
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: \"begin(dir dir/file)end\"
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:699"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_61
-#AT_START_62
-at_fn_group_banner 62 'wordsplit.at:713' \
-  "variable and command substitution" "              " 1
-at_xfail=no
-(
-  $as_echo "62. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:715:
-mkdir dir
-> dir/file
-
-DIR=dir wsp -nocmd -novar<<'EOT'
-begin \$(find \$DIR) end
-EOT
-"
-at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:715"
-( $at_check_trace;
-mkdir dir
-> dir/file
-
-DIR=dir wsp -nocmd -novar<<'EOT'
-begin $(find $DIR) end
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 4
-0: begin
-1: dir
-2: dir/file
-3: end
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:715"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_62
-#AT_START_63
-at_fn_group_banner 63 'wordsplit.at:732' \
-  "variable expansion and command substitution in quotes" "" 1
-at_xfail=no
-(
-  $as_echo "63. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:734:
-mkdir dir
-> dir/file
-
-DIR=dir wsp -nocmd -novar<<'EOT'
-\"begin(\$(find \$DIR))end\"
-EOT
-"
-at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:734"
-( $at_check_trace;
-mkdir dir
-> dir/file
-
-DIR=dir wsp -nocmd -novar<<'EOT'
-"begin($(find $DIR))end"
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 1
-0: \"begin(dir dir/file)end\"
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:734"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_63
-#AT_START_64
-at_fn_group_banner 64 'wordsplit.at:748' \
-  "pathname expansion" "                             " 1
-at_xfail=no
-(
-  $as_echo "64. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:750:
-mkdir dir
-> dir/1.c
-> dir/2.c
-> dir/3.b
-
-wsp pathexpand<<'EOT'
-begin dir/*.c end
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:750"
-( $at_check_trace;
-mkdir dir
-> dir/1.c
-> dir/2.c
-> dir/3.b
-
-wsp pathexpand<<'EOT'
-begin dir/*.c end
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 4
-0: begin
-1: dir/1.c
-2: dir/2.c
-3: end
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:750"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_64
-#AT_START_65
-at_fn_group_banner 65 'wordsplit.at:769' \
-  "pathname expansion: no match" "                   " 1
-at_xfail=no
-(
-  $as_echo "65. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:771:
-mkdir dir
-> dir/1.c
-> dir/2.b
-
-wsp pathexpand<<'EOT'
-begin dir/*.d end
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:771"
-( $at_check_trace;
-mkdir dir
-> dir/1.c
-> dir/2.b
-
-wsp pathexpand<<'EOT'
-begin dir/*.d end
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 3
-0: begin
-1: dir/*.d
-2: end
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:771"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_65
-#AT_START_66
-at_fn_group_banner 66 'wordsplit.at:788' \
-  "pathname expansion: nullglob" "                   " 1
-at_xfail=no
-(
-  $as_echo "66. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:790:
-mkdir dir
-> dir/1.c
-> dir/2.b
-
-wsp pathexpand nullglob<<'EOT'
-begin dir/*.d end
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:790"
-( $at_check_trace;
-mkdir dir
-> dir/1.c
-> dir/2.b
-
-wsp pathexpand nullglob<<'EOT'
-begin dir/*.d end
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-at_fn_diff_devnull "$at_stderr" || at_failed=:
-echo >>"$at_stdout"; $as_echo "NF: 2
-0: begin
-1: end
-" | \
-  $at_diff - "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:790"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_66
-#AT_START_67
-at_fn_group_banner 67 'wordsplit.at:806' \
-  "pathname expansion: failglob" "                   " 1
-at_xfail=no
-(
-  $as_echo "67. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
-{ set +x
-$as_echo "$at_srcdir/wordsplit.at:808:
-mkdir dir
-> dir/1.c
-> dir/2.b
-
-wsp pathexpand failglob<<'EOT'
-begin dir/*.d end
-EOT
-"
-at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:808"
-( $at_check_trace;
-mkdir dir
-> dir/1.c
-> dir/2.b
-
-wsp pathexpand failglob<<'EOT'
-begin dir/*.d end
-EOT
-
-) >>"$at_stdout" 2>>"$at_stderr" 5>&-
-at_status=$? at_failed=false
-$at_check_filter
-echo >>"$at_stderr"; $as_echo "no files match pattern dir/*.d
-" | \
-  $at_diff - "$at_stderr" || at_failed=:
-at_fn_diff_devnull "$at_stdout" || at_failed=:
-at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:808"
-$at_failed && at_fn_log_failure
-$at_traceon; }
-
-  set +x
-  $at_times_p && times >"$at_times_file"
-) 5>&1 2>&1 7>&- | eval $at_tee_pipe
-read at_status <"$at_status_file"
-#AT_STOP_67
-#AT_START_68
-at_fn_group_banner 68 'format00.at:17' \
-  "Default format" "                                 " 2
-at_xfail=no
-(
-  $as_echo "68. $at_setup_line: testing $at_desc ..."
-  $at_traceon
-
-
 
 { set +x
 $as_echo "$at_srcdir/format00.at:20: gcffmt \$abs_srcdir/gcf1.conf"
@@ -4955,13 +2091,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_68
-#AT_START_69
-at_fn_group_banner 69 'format01.at:17' \
-  "Locus" "                                          " 2
+#AT_STOP_1
+#AT_START_2
+at_fn_group_banner 2 'format01.at:17' \
+  "Locus" "                                          " 1
 at_xfail=no
 (
-  $as_echo "69. $at_setup_line: testing $at_desc ..."
+  $as_echo "2. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -4999,13 +2135,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_69
-#AT_START_70
-at_fn_group_banner 70 'format02.at:17' \
-  "Custom delimiter" "                               " 2
+#AT_STOP_2
+#AT_START_3
+at_fn_group_banner 3 'format02.at:17' \
+  "Custom delimiter" "                               " 1
 at_xfail=no
 (
-  $as_echo "70. $at_setup_line: testing $at_desc ..."
+  $as_echo "3. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5043,13 +2179,102 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_70
-#AT_START_71
-at_fn_group_banner 71 'enum.at:17' \
+#AT_STOP_3
+#AT_START_4
+at_fn_group_banner 4 'stradj.at:17' \
+  "String location adjustment" "                     " 2
+at_xfail=no
+(
+  $as_echo "4. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+cat >input.conf <<'_ATEOF'
+ident name;
+option "string";
+_ATEOF
+
+
+{ set +x
+$as_echo "$at_srcdir/stradj.at:25: echo \"Default\"
+gcffmt -nopath -locus input.conf
+echo \"Adjustment\"
+gcffmt -nopath -locus -stradj input.conf
+"
+at_fn_check_prepare_notrace 'an embedded newline' "stradj.at:25"
+( $at_check_trace; echo "Default"
+gcffmt -nopath -locus input.conf
+echo "Adjustment"
+gcffmt -nopath -locus -stradj input.conf
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "Default
+input.conf:1.7-10: \"name\"
+input.conf:2.8-15: \"string\"
+Adjustment
+input.conf:1.7-10: \"name\"
+input.conf:2.9-14: \"string\"
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/stradj.at:25"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_4
+#AT_START_5
+at_fn_group_banner 5 'strcat.at:17' \
+  "String concatenation" "                           " 2
+at_xfail=no
+(
+  $as_echo "5. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+cat >input.conf <<'_ATEOF'
+option id "a" " string";
+_ATEOF
+
+
+{ set +x
+$as_echo "$at_srcdir/strcat.at:24: gcffmt input.conf
+gcffmt -strcat input.conf"
+at_fn_check_prepare_notrace 'an embedded newline' "strcat.at:24"
+( $at_check_trace; gcffmt input.conf
+gcffmt -strcat input.conf
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo ".option: \"id\" \"a\" \" string\"
+.option: \"id\" \"a string\"
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/strcat.at:24"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_5
+#AT_START_6
+at_fn_group_banner 6 'enum.at:17' \
   "Enumerate nodes" "                                " 3
 at_xfail=no
 (
-  $as_echo "71. $at_setup_line: testing $at_desc ..."
+  $as_echo "6. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5093,13 +2318,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_71
-#AT_START_72
-at_fn_group_banner 72 'peek00.at:17' \
+#AT_STOP_6
+#AT_START_7
+at_fn_group_banner 7 'peek00.at:17' \
   "Peek" "                                           " 4
 at_xfail=no
 (
-  $as_echo "72. $at_setup_line: testing $at_desc ..."
+  $as_echo "7. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5124,13 +2349,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_72
-#AT_START_73
-at_fn_group_banner 73 'peek01.at:17' \
+#AT_STOP_7
+#AT_START_8
+at_fn_group_banner 8 'peek01.at:17' \
   "Nested nodes" "                                   " 4
 at_xfail=no
 (
-  $as_echo "73. $at_setup_line: testing $at_desc ..."
+  $as_echo "8. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5171,13 +2396,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_73
-#AT_START_74
-at_fn_group_banner 74 'peek02.at:17' \
+#AT_STOP_8
+#AT_START_9
+at_fn_group_banner 9 'peek02.at:17' \
   "Block nodes" "                                    " 4
 at_xfail=no
 (
-  $as_echo "74. $at_setup_line: testing $at_desc ..."
+  $as_echo "9. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5203,13 +2428,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_74
-#AT_START_75
-at_fn_group_banner 75 'peek03.at:17' \
+#AT_STOP_9
+#AT_START_10
+at_fn_group_banner 10 'peek03.at:17' \
   "Nested blocks" "                                  " 4
 at_xfail=no
 (
-  $as_echo "75. $at_setup_line: testing $at_desc ..."
+  $as_echo "10. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5253,13 +2478,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_75
-#AT_START_76
-at_fn_group_banner 76 'glob00.at:17' \
+#AT_STOP_10
+#AT_START_11
+at_fn_group_banner 11 'glob00.at:17' \
   "Leading wildcard" "                               " 5
 at_xfail=no
 (
-  $as_echo "76. $at_setup_line: testing $at_desc ..."
+  $as_echo "11. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5286,13 +2511,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_76
-#AT_START_77
-at_fn_group_banner 77 'glob01.at:17' \
+#AT_STOP_11
+#AT_START_12
+at_fn_group_banner 12 'glob01.at:17' \
   "Trailing wildcard" "                              " 5
 at_xfail=no
 (
-  $as_echo "77. $at_setup_line: testing $at_desc ..."
+  $as_echo "12. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5319,13 +2544,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_77
-#AT_START_78
-at_fn_group_banner 78 'glob02.at:17' \
+#AT_STOP_12
+#AT_START_13
+at_fn_group_banner 13 'glob02.at:17' \
   "Intermediate wildcard" "                          " 5
 at_xfail=no
 (
-  $as_echo "78. $at_setup_line: testing $at_desc ..."
+  $as_echo "13. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5350,13 +2575,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_78
-#AT_START_79
-at_fn_group_banner 79 'glob03.at:17' \
+#AT_STOP_13
+#AT_START_14
+at_fn_group_banner 14 'glob03.at:17' \
   "Multiple wildcards" "                             " 5
 at_xfail=no
 (
-  $as_echo "79. $at_setup_line: testing $at_desc ..."
+  $as_echo "14. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5411,13 +2636,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_79
-#AT_START_80
-at_fn_group_banner 80 'glob04.at:17' \
+#AT_STOP_14
+#AT_START_15
+at_fn_group_banner 15 'glob04.at:17' \
   "Subtree - asterisk" "                             " 5
 at_xfail=no
 (
-  $as_echo "80. $at_setup_line: testing $at_desc ..."
+  $as_echo "15. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5461,13 +2686,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_80
-#AT_START_81
-at_fn_group_banner 81 'glob05.at:17' \
+#AT_STOP_15
+#AT_START_16
+at_fn_group_banner 16 'glob05.at:17' \
   "Subtree - percent" "                              " 5
 at_xfail=no
 (
-  $as_echo "81. $at_setup_line: testing $at_desc ..."
+  $as_echo "16. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5511,13 +2736,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_81
-#AT_START_82
-at_fn_group_banner 82 'reduce00.at:17' \
+#AT_STOP_16
+#AT_START_17
+at_fn_group_banner 17 'reduce00.at:17' \
   "Simple statement" "                               " 6
 at_xfail=no
 (
-  $as_echo "82. $at_setup_line: testing $at_desc ..."
+  $as_echo "17. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5548,13 +2773,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_82
-#AT_START_83
-at_fn_group_banner 83 'reduce01.at:17' \
+#AT_STOP_17
+#AT_START_18
+at_fn_group_banner 18 'reduce01.at:17' \
   "Block statement" "                                " 6
 at_xfail=no
 (
-  $as_echo "83. $at_setup_line: testing $at_desc ..."
+  $as_echo "18. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5598,13 +2823,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_83
-#AT_START_84
-at_fn_group_banner 84 'reduce02.at:17' \
+#AT_STOP_18
+#AT_START_19
+at_fn_group_banner 19 'reduce02.at:17' \
   "Nested block statement" "                         " 6
 at_xfail=no
 (
-  $as_echo "84. $at_setup_line: testing $at_desc ..."
+  $as_echo "19. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5659,13 +2884,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_84
-#AT_START_85
-at_fn_group_banner 85 'reduce03.at:17' \
+#AT_STOP_19
+#AT_START_20
+at_fn_group_banner 20 'reduce03.at:17' \
   "Table driven reduction" "                         " 6
 at_xfail=no
 (
-  $as_echo "85. $at_setup_line: testing $at_desc ..."
+  $as_echo "20. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5710,13 +2935,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_85
-#AT_START_86
-at_fn_group_banner 86 'sort00.at:17' \
+#AT_STOP_20
+#AT_START_21
+at_fn_group_banner 21 'sort00.at:17' \
   "Sort" "                                           " 7
 at_xfail=no
 (
-  $as_echo "86. $at_setup_line: testing $at_desc ..."
+  $as_echo "21. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5774,13 +2999,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_86
-#AT_START_87
-at_fn_group_banner 87 'sort01.at:17' \
+#AT_STOP_21
+#AT_START_22
+at_fn_group_banner 22 'sort01.at:17' \
   "Stable sort" "                                    " 7
 at_xfail=no
 (
-  $as_echo "87. $at_setup_line: testing $at_desc ..."
+  $as_echo "22. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5818,13 +3043,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_87
-#AT_START_88
-at_fn_group_banner 88 'incl00.at:17' \
+#AT_STOP_22
+#AT_START_23
+at_fn_group_banner 23 'incl00.at:17' \
   "Include path" "                                   " 8
 at_xfail=no
 (
-  $as_echo "88. $at_setup_line: testing $at_desc ..."
+  $as_echo "23. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5883,13 +3108,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_88
-#AT_START_89
-at_fn_group_banner 89 'incl01.at:17' \
+#AT_STOP_23
+#AT_START_24
+at_fn_group_banner 24 'incl01.at:17' \
   "Recursive inclusion" "                            " 8
 at_xfail=no
 (
-  $as_echo "89. $at_setup_line: testing $at_desc ..."
+  $as_echo "24. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -5955,13 +3180,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_89
-#AT_START_90
-at_fn_group_banner 90 'incl02.at:17' \
+#AT_STOP_24
+#AT_START_25
+at_fn_group_banner 25 'incl02.at:17' \
   "Include once" "                                   " 8
 at_xfail=no
 (
-  $as_echo "90. $at_setup_line: testing $at_desc ..."
+  $as_echo "25. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -6043,13 +3268,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_90
-#AT_START_91
-at_fn_group_banner 91 'incl03.at:17' \
+#AT_STOP_25
+#AT_START_26
+at_fn_group_banner 26 'incl03.at:17' \
   "Wildcard inclusion" "                             " 8
 at_xfail=no
 (
-  $as_echo "91. $at_setup_line: testing $at_desc ..."
+  $as_echo "26. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -6126,13 +3351,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_91
-#AT_START_92
-at_fn_group_banner 92 'join.at:17' \
+#AT_STOP_26
+#AT_START_27
+at_fn_group_banner 27 'join.at:17' \
   "Join" "                                           " 9
 at_xfail=no
 (
-  $as_echo "92. $at_setup_line: testing $at_desc ..."
+  $as_echo "27. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -6184,13 +3409,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_92
-#AT_START_93
-at_fn_group_banner 93 'cfhelp.at:17' \
+#AT_STOP_27
+#AT_START_28
+at_fn_group_banner 28 'cfhelp.at:17' \
   "Help" "                                           " 9
 at_xfail=no
 (
-  $as_echo "93. $at_setup_line: testing $at_desc ..."
+  $as_echo "28. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -6266,13 +3491,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_93
-#AT_START_94
-at_fn_group_banner 94 'set.at:17' \
+#AT_STOP_28
+#AT_START_29
+at_fn_group_banner 29 'set.at:17' \
   "Set values" "                                     " 9
 at_xfail=no
 (
-  $as_echo "94. $at_setup_line: testing $at_desc ..."
+  $as_echo "29. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -6286,7 +3511,7 @@ sed 's|^.*/gcf1.conf||' err >&2
 ) >>"$at_stdout" 2>>"$at_stderr" 5>&-
 at_status=$? at_failed=false
 $at_check_filter
-echo >>"$at_stderr"; $as_echo ":25.1-8: Unknown keyword
+echo >>"$at_stderr"; $as_echo ":25.1-8: unknown keyword
 " | \
   $at_diff - "$at_stderr" || at_failed=:
 echo >>"$at_stdout"; $as_echo "Global settings:
@@ -6311,13 +3536,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_94
-#AT_START_95
-at_fn_group_banner 95 'vercmp.at:17' \
+#AT_STOP_29
+#AT_START_30
+at_fn_group_banner 30 'vercmp.at:17' \
   "Version comparator" "                             " 9
 at_xfail=no
 (
-  $as_echo "95. $at_setup_line: testing $at_desc ..."
+  $as_echo "30. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -6522,13 +3747,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_95
-#AT_START_96
-at_fn_group_banner 96 'grecs00.at:17' \
+#AT_STOP_30
+#AT_START_31
+at_fn_group_banner 31 'grecs00.at:17' \
   "C comments in GRECS-style parser" "               " 9
 at_xfail=no
 (
-  $as_echo "96. $at_setup_line: testing $at_desc ..."
+  $as_echo "31. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -6575,13 +3800,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_96
-#AT_START_97
-at_fn_group_banner 97 'empty.at:17' \
+#AT_STOP_31
+#AT_START_32
+at_fn_group_banner 32 'empty.at:17' \
   "Empty input file" "                               " 9
 at_xfail=no
 (
-  $as_echo "97. $at_setup_line: testing $at_desc ..."
+  $as_echo "32. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -6633,13 +3858,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_97
-#AT_START_98
-at_fn_group_banner 98 'locus00.at:17' \
+#AT_STOP_32
+#AT_START_33
+at_fn_group_banner 33 'locus00.at:17' \
   "Scalar value" "                                   " 10
 at_xfail=no
 (
-  $as_echo "98. $at_setup_line: testing $at_desc ..."
+  $as_echo "33. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -6670,13 +3895,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_98
-#AT_START_99
-at_fn_group_banner 99 'locus01.at:17' \
+#AT_STOP_33
+#AT_START_34
+at_fn_group_banner 34 'locus01.at:17' \
   "Multiline strings" "                              " 10
 at_xfail=no
 (
-  $as_echo "99. $at_setup_line: testing $at_desc ..."
+  $as_echo "34. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -6711,13 +3936,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_99
-#AT_START_100
-at_fn_group_banner 100 'locus02.at:17' \
+#AT_STOP_34
+#AT_START_35
+at_fn_group_banner 35 'locus02.at:17' \
   "Adjacent quoted strings" "                        " 10
 at_xfail=no
 (
-  $as_echo "100. $at_setup_line: testing $at_desc ..."
+  $as_echo "35. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -6731,14 +3956,17 @@ _ATEOF
 
 
 { set +x
-$as_echo "$at_srcdir/locus02.at:26: gcfpeek -nopath -locus test.cf .string"
-at_fn_check_prepare_trace "locus02.at:26"
-( $at_check_trace; gcfpeek -nopath -locus test.cf .string
+$as_echo "$at_srcdir/locus02.at:26: gcfpeek -nopath -locus -strcat test.cf .string
+gcfpeek -nopath -locus -strcat -stradj test.cf .string"
+at_fn_check_prepare_notrace 'an embedded newline' "locus02.at:26"
+( $at_check_trace; gcfpeek -nopath -locus -strcat test.cf .string
+gcfpeek -nopath -locus -strcat -stradj test.cf .string
 ) >>"$at_stdout" 2>>"$at_stderr" 5>&-
 at_status=$? at_failed=false
 $at_check_filter
 at_fn_diff_devnull "$at_stderr" || at_failed=:
 echo >>"$at_stdout"; $as_echo "test.cf:2.8-4.17: \"concatenated quoted strings\"
+test.cf:2.9-4.16: \"concatenated quoted strings\"
 " | \
   $at_diff - "$at_stdout" || at_failed=:
 at_fn_check_status 0 $at_status "$at_srcdir/locus02.at:26"
@@ -6750,13 +3978,13 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_100
-#AT_START_101
-at_fn_group_banner 101 'path-locus.at:17' \
+#AT_STOP_35
+#AT_START_36
+at_fn_group_banner 36 'path-locus.at:17' \
   "Path" "                                           " 10
 at_xfail=no
 (
-  $as_echo "101. $at_setup_line: testing $at_desc ..."
+  $as_echo "36. $at_setup_line: testing $at_desc ..."
   $at_traceon
 
 
@@ -6871,4 +4099,4 @@ $at_traceon; }
   $at_times_p && times >"$at_times_file"
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
-#AT_STOP_101
+#AT_STOP_36
diff --git a/grecs/tests/testsuite.at b/grecs/tests/testsuite.at
index ec94ff0..ee9ebb8 100644
--- a/grecs/tests/testsuite.at
+++ b/grecs/tests/testsuite.at
@@ -47,13 +47,15 @@ dnl # Begin tests
 AT_INIT
 m4_if(GRECS_DISTCK_AT,,,[m4_include(GRECS_DISTCK_AT)])
 
-m4_include([wordsplit.at])
-
 AT_BANNER([Formats])
 m4_include([format00.at])
 m4_include([format01.at])
 m4_include([format02.at])
 
+AT_BANNER([Options])
+m4_include([stradj.at])
+m4_include([strcat.at])
+
 AT_BANNER([Enumeration])
 m4_include([enum.at])
 
diff --git a/grecs/tests/wordsplit-version.h b/grecs/tests/wordsplit-version.h
new file mode 100644
index 0000000..48d8a9d
--- /dev/null
+++ b/grecs/tests/wordsplit-version.h
@@ -0,0 +1 @@
+#define WORDSPLIT_VERSION "v1.0-6-gd36275f"
diff --git a/grecs/tests/wsp.c b/grecs/tests/wsp.c
deleted file mode 100644
index e8eb9c6..0000000
--- a/grecs/tests/wsp.c
+++ /dev/null
@@ -1,626 +0,0 @@
-/* grecs - Gray's Extensible Configuration System
-   Copyright (C) 2014-2016 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 <errno.h>
-#include "grecs.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 },
-  { "pathexpand", WRDSF_PATHEXPAND },
-  { NULL, 0 }
-};
-
-struct kwd opt_keytab[] = {
-  { "nullglob", WRDSO_NULLGLOB },
-  { "failglob", WRDSO_FAILGLOB },
-  { "dotglob",  WRDSO_DOTGLOB },
-  { 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] [VAR=VALUE...]\n", progname);
-  printf ("options are:\n");
-  printf (" [-]trimnl\n");
-  printf (" [-]plaintext\n");
-  printf (" -env\n");
-  printf (" env sys|none|null\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", string_keytab[i].name);
-      printf (" %s ARG\n", string_keytab[i].name);
-    }
-  printf (" escape-word ARG\n");
-  printf (" escape-quote ARG\n");
-  putchar ('\n');
-  for (i = 0; opt_keytab[i].name; i++)
-    {
-      printf (" [-]%s\n", opt_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, &quote);
-
-  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 * 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;
-}
-
-static int
-wsp_getvar (char **ret, const char *vptr, size_t vlen, void *data)
-{
-  char **base = data;
-  int i;
-
-  for (i = 0; base[i]; i++)
-    {
-      size_t l = strcspn (base[i], "=");
-      if (l == vlen && memcmp (base[i], vptr, vlen) == 0)
-	{
-	  char *p = strdup (base[i] + vlen + 1);
-	  if (p == NULL)
-	    return WRDSE_NOSPACE;
-	  *ret = p;
-	  return WRDSE_OK;
-	}
-    }
-  return WRDSE_UNDEF;
-}
-
-static int
-wsp_runcmd (char **ret, const char *str, size_t len, char **argv, void *closure)
-{
-  FILE *fp;
-  char *cmd;
-  int c, lastc;
-  char *buffer = NULL;
-  size_t bufsize = 0;
-  size_t buflen = 0;
-  
-  cmd = malloc (len + 1);
-  if (!cmd)
-    return WRDSE_NOSPACE;
-  memcpy (cmd, str, len);
-  cmd[len] = 0;
-
-  fp = popen(cmd, "r");
-  if (!fp)
-    {
-      size_t size = 0;
-      ret = NULL;
-      if (grecs_asprintf (ret, &size, "can't run %s: %s",
-			  cmd, strerror (errno)))
-	return WRDSE_NOSPACE;
-      else
-	return WRDSE_USERERR;
-    }
-
-  while ((c = fgetc (fp)) != EOF)
-    {
-      lastc = c;
-      if (c == '\n')
-	c = ' ';
-      if (buflen == bufsize)
-	{
-	  char *p;
-	  
-	  if (bufsize == 0)
-	    bufsize = 80;
-	  else
-	    bufsize *= 2;
-	  p = realloc (buffer, bufsize);
-	  if (!p)
-	    {
-	      free (buffer);
-	      free (cmd);
-	      return WRDSE_NOSPACE;
-	    }
-	  buffer = p;
-	}
-      buffer[buflen++] = c;
-    }
-
-  if (buffer)
-    {
-      if (lastc == '\n')
-	--buflen;
-      buffer[buflen] = 0;
-    }
-  
-  pclose (fp);
-  free (cmd);
-
-  *ret = buffer;
-  return WRDSE_OK;
-}
-
-enum env_type
-  {
-    env_none,
-    env_null,
-    env_sys
-  };
-
-struct kwd env_keytab[] = {
-  { "none",   env_none },
-  { "null",   env_null },
-  { "sys",    env_sys },
-  { NULL }
-};
-
-static void
-set_escape_string (wordsplit_t *ws, int *wsflags, int q, const char *str)
-{
-  if (*str == ':')
-    {
-      while (*++str != ':')
-	{
-	  int f;
-	  switch (*str)
-	    {
-	    case '+':
-	      f = WRDSO_BSKEEP;
-	      break;
-
-	    case '0':
-	      f = WRDSO_OESC;
-	      break;
-
-	    case 'x':
-	      f = WRDSO_XESC;
-	      break;
-
-	    default:
-	      fprintf (stderr, "%s: invalid escape flag near %s\n",
-		       progname, str);
-	      abort ();
-	    }
-	  WRDSO_ESC_SET (ws, q, f);
-	}
-      *wsflags |= WRDSF_OPTIONS;
-      ++str;
-    }
-  ws->ws_escape[q] = str;
-}
-
-int
-main (int argc, char **argv)
-{
-  char buf[1024], *ptr, *saved_ptr;
-  int i, offarg = 0;
-  int trimnl_option = 0;
-  int plaintext_option = 0;
-  int wsflags = (WRDSF_DEFFLAGS & ~WRDSF_NOVAR) |
-                 WRDSF_ENOMEMABRT |
-                 WRDSF_SHOWERR;
-  wordsplit_t ws;
-  int next_call = 0;
-  char *fenvbase[128];
-  size_t fenvidx = 0;
-  size_t fenvmax = sizeof (fenvbase) / sizeof (fenvbase[0]);
-  int use_env = env_sys;
-  
-  progname = argv[0];
-
-  ws.ws_options = 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 (strcmp (opt, "env") == 0)
-	{
-	  if (negate)
-	    use_env = env_none;
-	  else
-	    {
-	      i++;
-	      if (i == argc)
-		{
-		  fprintf (stderr, "%s: missing argument for env\n",
-			   progname);
-		  exit (1);
-		}
-
-	      if (kwxlat (env_keytab, argv[i], &use_env))
-		{
-		  fprintf (stderr, "%s: invalid argument for env\n",
-			   progname);
-		  exit (1);
-		}
-	    }
-	  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:
-		  set_escape_string (&ws, &wsflags, 0, argv[i]);
-		  set_escape_string (&ws, &wsflags, 1, argv[i]);
-		  break;
-		}
-	      
-	      wsflags |= flag;
-	    }
-	  continue;
-	}
-
-      if (strcmp (opt, "escape-word") == 0
-	  || strcmp (opt, "escape-quote") == 0)
-	{
-	  int q = opt[7] == 'q';
-	  
-	  i++;
-	  if (i == argc)
-	    {
-	      fprintf (stderr, "%s: missing argument for %s\n",
-		       progname, opt);
-	      exit (1);
-	    }
-	  if (!(wsflags & WRDSF_ESCAPE))
-	    {
-	      wsflags |= WRDSF_ESCAPE;
-	      ws.ws_escape[!q] = NULL;
-	    }
-	  set_escape_string (&ws, &wsflags, q, argv[i]);
-	  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;
-	}
-
-      if (kwxlat (opt_keytab, opt, &flag) == 0)
-	{
-	  wsflags |= WRDSF_OPTIONS;
-	  if (negate)
-	    ws.ws_options &= ~flag;
-	  else
-	    ws.ws_options |= flag;
-	  continue;
-	}
-      
-      if (strchr (opt, '='))
-	{
-	  assert (fenvidx < fenvmax - 1);
-	  fenvbase[fenvidx++] = opt;
-	  continue;
-	}
-      
-      fprintf (stderr, "%s: unrecognized argument: %s\n",
-	       progname, opt);
-      exit (1);
-    }
-
-  if (fenvidx)
-    {
-      fenvbase[fenvidx] = NULL;
-      wsflags |= WRDSF_GETVAR | WRDSF_CLOSURE;
-      ws.ws_getvar = wsp_getvar;
-      ws.ws_closure = fenvbase;
-    }
-
-  switch (use_env)
-    {
-    case env_null:
-      wsflags |= WRDSF_ENV;
-      ws.ws_env = NULL;
-      break;
-
-    case env_none:
-      break;
-
-    case env_sys:
-      wsflags |= WRDSF_ENV;
-      if (wsflags & WRDSF_ENV_KV)
-	ws.ws_env = (const char **) make_env_kv ();
-      else
-	ws.ws_env = (const char **) environ;
-      break;
-    }
-  
-  if (!(wsflags & WRDSF_NOCMD))
-    ws.ws_command = wsp_runcmd;
-  
-  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 (saved_ptr);
-	    }
-	  else
-	    next_call = 1;
-	  if (ptr)
-	    {
-	      ptr = saved_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 | (ws.ws_flags & WRDSF_ENV);
-      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;
-}
diff --git a/grecs/tests/wspackage.m4 b/grecs/tests/wspackage.m4
new file mode 100644
index 0000000..8f55c3e
--- /dev/null
+++ b/grecs/tests/wspackage.m4
@@ -0,0 +1,5 @@
+m4_define([AT_PACKAGE_NAME],      [wordsplit])
+m4_define([AT_PACKAGE_TARNAME],   [wordsplit])
+m4_define([AT_PACKAGE_VERSION],   [v1.0-6-gd36275f])
+m4_define([AT_PACKAGE_STRING],    [AT_PACKAGE_TARNAME AT_PACKAGE_VERSION])
+m4_define([AT_PACKAGE_BUGREPORT], [bug-direvent@gnu.org.ua])
diff --git a/grecs/tests/wstest b/grecs/tests/wstest
new file mode 100755
index 0000000..0ffa16c
--- /dev/null
+++ b/grecs/tests/wstest
@@ -0,0 +1,5540 @@
+#! /bin/sh
+# Generated from ../../grecs/wordsplit/wordsplit.at by GNU Autoconf 2.69.
+#
+# Copyright (C) 2009-2012 Free Software Foundation, Inc.
+#
+# This test suite is free software; the Free Software Foundation gives
+# unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# How were we run?
+at_cli_args="$@"
+
+
+# Not all shells have the 'times' builtin; the subshell is needed to make
+# sure we discard the 'times: not found' message from the shell.
+at_times_p=false
+(times) >/dev/null 2>&1 && at_times_p=:
+
+# CLI Arguments to pass to the debugging scripts.
+at_debug_args=
+# -e sets to true
+at_errexit_p=false
+# Shall we be verbose?  ':' means no, empty means yes.
+at_verbose=:
+at_quiet=
+# Running several jobs in parallel, 0 means as many as test groups.
+at_jobs=1
+at_traceon=:
+at_trace_echo=:
+at_check_filter_trace=:
+
+# Shall we keep the debug scripts?  Must be `:' when the suite is
+# run by a debug script, so that the script doesn't remove itself.
+at_debug_p=false
+# Display help message?
+at_help_p=false
+# Display the version message?
+at_version_p=false
+# List test groups?
+at_list_p=false
+# --clean
+at_clean=false
+# Test groups to run
+at_groups=
+# Whether to rerun failed tests.
+at_recheck=
+# Whether a write failure occurred
+at_write_fail=0
+
+# The directory we run the suite in.  Default to . if no -C option.
+at_dir=`pwd`
+# An absolute reference to this testsuite script.
+case $as_myself in
+  [\\/]* | ?:[\\/]* ) at_myself=$as_myself ;;
+  * ) at_myself=$at_dir/$as_myself ;;
+esac
+# Whether -C is in effect.
+at_change_dir=false
+
+# Whether to enable colored test results.
+at_color=no
+# List of the tested programs.
+at_tested='wsp'
+# As many question marks as there are digits in the last test group number.
+# Used to normalize the test group numbers so that `ls' lists them in
+# numerical order.
+at_format='??'
+# Description of all the test groups.
+at_help_all="1;wordsplit.at:59;simple input;wordsplit wsp wordsplit000 wsp000 wsp-simple;
+2;wordsplit.at:68;quoted space;wordsplit wsp wordsplit001 wsp000 wsp-quoted;
+3;wordsplit.at:75;tab character;wordsplit wsp wordsplit002 wsp000 wsp-tab;
+4;wordsplit.at:84;octal and hex escapes;wordsplit wsp wordsplit003 wsp000 wsp-escape wsp-escape000;
+5;wordsplit.at:91;octal and hex escapes 2;wordsplit wsp wordsplit004 wsp000 wsp-escape wsp-escape001;
+6;wordsplit.at:100;escape representation;wordsplit wsp wordsplit005 wsp000 wsp-escape wsp-escape002;
+7;wordsplit.at:112;append;wordsplit wsp wordsplit006 wsp000 wsp-append;
+8;wordsplit.at:137;dooffs;wordsplit wsp wordsplit007 wsp000 wsp-doofs;
+9;wordsplit.at:150;variable substitutions: single var;wordsplit wsp wordsplit008 wsp000 wsp-var wsp-var000;
+10;wordsplit.at:161;variable substitutions: concatenated vars;wordsplit wsp wordsplit009 wsp000 wsp-var wsp-var001;
+11;wordsplit.at:173;variable substitutions: field splitting;wordsplit wsp wordsplit010 wsp000 wsp-var wsp-var002;
+12;wordsplit.at:185;variable substitutions: double-quoted variable;wordsplit wsp wordsplit011 wsp000 wsp-var wsp-var003;
+13;wordsplit.at:196;variable substitutions: single-quoted variable;wordsplit wsp wordsplit012 wsp000 wsp-var wsp-var004;
+14;wordsplit.at:207;undefined variables 1;wordsplit wsp wordsplit013 wsp000 wsp-var wsp-var005;
+15;wordsplit.at:218;undefined variables 2;wordsplit wsp wordsplit014 wsp000 wsp-var wsp-var006;
+16;wordsplit.at:230;warn about undefined variables;wordsplit wsp wordsplit015 wsp000 wsp-var wsp-var007;
+17;wordsplit.at:239;bail out on undefined variables;wordsplit wsp wordsplit016 wsp000 wsp-var wsp-var008;
+18;wordsplit.at:246;disable variable expansion;wordsplit wsp wordsplit017 wsp000 wsp-var wsp-var009;
+19;wordsplit.at:255;K/V environment;wordsplit wsp wordsplit018 wsp000 wsp-var wsp-var010 wsp-env-kv wsp-env_kv;
+20;wordsplit.at:266;nosplit with variable expansion;wordsplit wsp wordsplit019 wsp000 wsp-var wsp-var011 wsp-var-nosplit;
+21;wordsplit.at:275;nosplit without variable expansion;wordsplit wsp wordsplit020 wsp000 wsp-var wsp-var012;
+22;wordsplit.at:284;nosplit: empty expansion;wordsplit wsp wordsplit021 wsp000 wsp-var wsp-var013;
+23;wordsplit.at:293;default value;wordsplit wsp wordsplit022 wsp000 wsp-var wsp-var014;
+24;wordsplit.at:300;default value (defined);wordsplit wsp wordsplit023 wsp000 wsp-var wsp-var015;
+25;wordsplit.at:309;default value (:- null);wordsplit wsp wordsplit024 wsp000 wsp-var wsp-var016;
+26;wordsplit.at:318;default value (- null);wordsplit wsp wordsplit025 wsp000 wsp-var wsp-var017;
+27;wordsplit.at:326;default value (- null, unset);wordsplit wsp wordsplit026 wsp000 wsp-var wsp-var018;
+28;wordsplit.at:333;assign default values;wordsplit wsp wordsplit027 wsp000 wsp-var wsp-var019;
+29;wordsplit.at:344;default error message (var defined);wordsplit wsp wordsplit028 wsp000 wsp-var wsp-var020;
+30;wordsplit.at:355;default error message;wordsplit wsp wordsplit029 wsp000 wsp-var wsp-var021;
+31;wordsplit.at:363;custom error message (defined);wordsplit wsp wordsplit030 wsp000 wsp-var wsp-var022 wsp-custom-err wsp-custom-err00;
+32;wordsplit.at:374;custom error message;wordsplit wsp wordsplit031 wsp000 wsp-var wsp-var023 wsp-custom-err wsp-custom-err01;
+33;wordsplit.at:384;alternate value (defined);wordsplit wsp wordsplit032 wsp000 wsp-var wsp-var024 wsp-alt wsp-alt00;
+34;wordsplit.at:395;alternate value;wordsplit wsp wordsplit033 wsp000 wsp-var wsp-var025 wsp-alt wsp-alt01;
+35;wordsplit.at:405;getvar;wordsplit wsp wordsplit034 wsp000 wsp-var wsp-var026 wsp-getvar;
+36;wordsplit.at:419;getvar and env;wordsplit wsp wordsplit035 wsp000 wsp-var wsp-var027 wsp-getvar;
+37;wordsplit.at:435;getvar, alternate value;wordsplit wsp wordsplit036 wsp000 wsp-var wsp-var028 wsp-getvar;
+38;wordsplit.at:446;ignore quotes;wordsplit wsp wordsplit037 wsp000 wsp-ignore-quotes;
+39;wordsplit.at:456;custom delimiters (squeeze);wordsplit wsp wordsplit038 wsp000 wsp-delim wsp-delim000;
+40;wordsplit.at:468;custom delimiters (no squeeze);wordsplit wsp wordsplit039 wsp000 wsp-delim wsp-delim001;
+41;wordsplit.at:481;custom, with returned delimiters;wordsplit wsp wordsplit040 wsp000 wsp-delim wsp-delim002;
+42;wordsplit.at:497;custom, with returned & squeezed delimiters;wordsplit wsp wordsplit041 wsp000 wsp-delim wsp-delim003;
+43;wordsplit.at:516;sed expressions;wordsplit wsp wordsplit042 wsp000 wsp-sed wsp-sed000;
+44;wordsplit.at:527;C escapes on;wordsplit wsp wordsplit043 wsp000 wcp-c-escape;
+45;wordsplit.at:537;C escapes off;wordsplit wsp wordsplit044 wsp000 wcp-c-escape-off;
+46;wordsplit.at:547;ws elimination;wordsplit wsp wordsplit045 wsp000 wsp-ws-elim;
+47;wordsplit.at:557;ws elimination + return delim;wordsplit wsp wordsplit046 wsp000 wsp-ws-elim-ret;
+48;wordsplit.at:571;empty quotes;wordsplit wsp wordsplit047 wsp000 wsp-empty-quotes;
+49;wordsplit.at:578;delimiter following empty quotes;wordsplit wsp wordsplit048 wsp000;
+50;wordsplit.at:588;suppress ws trimming within quotes;wordsplit wsp wordsplit049 wsp000;
+51;wordsplit.at:601;unescape;wordsplit wsp wordsplit050 wsp000 wsp-unescape wsp-unescape-simple;
+52;wordsplit.at:612;unescape: word/quote;wordsplit wsp wordsplit051 wsp000 wsp-unescape wsp-unescape-word;
+53;wordsplit.at:626;dquote;wordsplit wsp wordsplit052 wsp000;
+54;wordsplit.at:636;squote;wordsplit wsp wordsplit053 wsp000;
+55;wordsplit.at:648;incremental;wordsplit wsp wordsplit054 wsp000 wsp-incr wsp-incr000;
+56;wordsplit.at:666;incremental append;wordsplit wsp wordsplit055 wsp000 wsp-incr wsp-incr001;
+57;wordsplit.at:687;incremental ws;wordsplit wsp wordsplit056 wsp000 wsp-incr wsp-incr002;
+58;wordsplit.at:706;incremental nosplit;wordsplit wsp wordsplit057 wsp000 wsp-incr wsp-incr003;
+59;wordsplit.at:716;simple command substitution;wordsplit wsp wordsplit058 wsp000 wsp-incr wsp-incr004;
+60;wordsplit.at:726;quoted command substitution;wordsplit wsp wordsplit059 wsp000 wsp-incr wsp-incr005;
+61;wordsplit.at:735;coalesced command substitution;wordsplit wsp wordsplit060 wsp000 wsp-incr wsp-incr006;
+62;wordsplit.at:743;quoted coalesced command substitution;wordsplit wsp wordsplit061 wsp000 wsp-incr wsp-incr007;
+63;wordsplit.at:750;variable and command substitution;wordsplit wsp wordsplit062 wsp000 wsp-incr wsp-incr008;
+64;wordsplit.at:761;variable expansion and command substitution in quotes;wordsplit wsp wordsplit063 wsp000 wsp-incr wsp-incr009;
+65;wordsplit.at:768;nested commands;wordsplit wsp wordsplit064 wsp000 wsp-incr wsp-incr010;
+66;wordsplit.at:779;pathname expansion;wordsplit wsp wsp-path wsp-path-1;
+67;wordsplit.at:801;pathname expansion: no match;wordsplit wsp wsp-path wsp-path-2;
+68;wordsplit.at:821;pathname expansion: nullglob;wordsplit wsp wsp-path wsp-path-3;
+69;wordsplit.at:840;pathname expansion: failglob;wordsplit wsp wsp-path wsp-path-4;
+70;wordsplit.at:857;append;wordsplit wsp wordsplit065 wsp000 wsp-incr wsp-incr011;
+71;wordsplit.at:869;append + dooffs + env;wordsplit wsp wordsplit066 wsp000 wsp-incr wsp-incr012;
+72;wordsplit.at:886;maxwords;wordsplit wsp wordsplit067 wsp000 wsp-incr wsp-incr013;
+73;wordsplit.at:896;maxwords return_delims;wordsplit wsp wordsplit068 wsp000 wsp-incr wsp-incr014;
+74;wordsplit.at:911;maxwords return_delims -squeeze_delims;wordsplit wsp wordsplit069 wsp000 wsp-incr wsp-incr015;
+75;wordsplit.at:926;maxwords incremental;wordsplit wsp wordsplit070 wsp000 wsp-incr wsp-incr016;
+76;wordsplit.at:945;variable nosplit;wordsplit wsp wordsplit071 wsp000 wsp-incr wsp-incr017;
+77;wordsplit.at:954;command nosplit;wordsplit wsp wordsplit072 wsp000 wsp-incr wsp-incr018;
+78;wordsplit.at:963;positional parameters;wordsplit wsp wordsplit073 wsp000 wsp-incr wsp-incr019;
+79;wordsplit.at:976;\$* and \$@;wordsplit wsp wordsplit074 wsp000 wsp-incr wsp-incr020;
+80;wordsplit.at:1001;\$* and \$@ in nosplit mode;wordsplit wsp wordsplit075 wsp000 wsp-incr wsp-incr021;
+81;wordsplit.at:1013;\$* and \$@ in nosplit mode with delimiter;wordsplit wsp wordsplit076 wsp000 wsp-incr wsp-incr022;
+"
+# List of the all the test groups.
+at_groups_all=`$as_echo "$at_help_all" | sed 's/;.*//'`
+
+# at_fn_validate_ranges NAME...
+# -----------------------------
+# Validate and normalize the test group number contained in each variable
+# NAME. Leading zeroes are treated as decimal.
+at_fn_validate_ranges ()
+{
+  for at_grp
+  do
+    eval at_value=\$$at_grp
+    if test $at_value -lt 1 || test $at_value -gt 81; then
+      $as_echo "invalid test group: $at_value" >&2
+      exit 1
+    fi
+    case $at_value in
+      0*) # We want to treat leading 0 as decimal, like expr and test, but
+	  # AS_VAR_ARITH treats it as octal if it uses $(( )).
+	  # With XSI shells, ${at_value#${at_value%%[1-9]*}} avoids the
+	  # expr fork, but it is not worth the effort to determine if the
+	  # shell supports XSI when the user can just avoid leading 0.
+	  eval $at_grp='`expr $at_value + 0`' ;;
+    esac
+  done
+}
+
+at_prev=
+for at_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$at_prev"; then
+    at_option=$at_prev=$at_option
+    at_prev=
+  fi
+
+  case $at_option in
+  *=?*) at_optarg=`expr "X$at_option" : '[^=]*=\(.*\)'` ;;
+  *)    at_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $at_option in
+    --help | -h )
+	at_help_p=:
+	;;
+
+    --list | -l )
+	at_list_p=:
+	;;
+
+    --version | -V )
+	at_version_p=:
+	;;
+
+    --clean | -c )
+	at_clean=:
+	;;
+
+    --color )
+	at_color=always
+	;;
+    --color=* )
+	case $at_optarg in
+	no | never | none) at_color=never ;;
+	auto | tty | if-tty) at_color=auto ;;
+	always | yes | force) at_color=always ;;
+	*) at_optname=`echo " $at_option" | sed 's/^ //; s/=.*//'`
+	   as_fn_error $? "unrecognized argument to $at_optname: $at_optarg" ;;
+	esac
+	;;
+
+    --debug | -d )
+	at_debug_p=:
+	;;
+
+    --errexit | -e )
+	at_debug_p=:
+	at_errexit_p=:
+	;;
+
+    --verbose | -v )
+	at_verbose=; at_quiet=:
+	;;
+
+    --trace | -x )
+	at_traceon='set -x'
+	at_trace_echo=echo
+	at_check_filter_trace=at_fn_filter_trace
+	;;
+
+    [0-9] | [0-9][0-9] | [0-9][0-9][0-9] | [0-9][0-9][0-9][0-9])
+	at_fn_validate_ranges at_option
+	as_fn_append at_groups "$at_option$as_nl"
+	;;
+
+    # Ranges
+    [0-9]- | [0-9][0-9]- | [0-9][0-9][0-9]- | [0-9][0-9][0-9][0-9]-)
+	at_range_start=`echo $at_option |tr -d X-`
+	at_fn_validate_ranges at_range_start
+	at_range=`$as_echo "$at_groups_all" | \
+	  sed -ne '/^'$at_range_start'$/,$p'`
+	as_fn_append at_groups "$at_range$as_nl"
+	;;
+
+    -[0-9] | -[0-9][0-9] | -[0-9][0-9][0-9] | -[0-9][0-9][0-9][0-9])
+	at_range_end=`echo $at_option |tr -d X-`
+	at_fn_validate_ranges at_range_end
+	at_range=`$as_echo "$at_groups_all" | \
+	  sed -ne '1,/^'$at_range_end'$/p'`
+	as_fn_append at_groups "$at_range$as_nl"
+	;;
+
+    [0-9]-[0-9] | [0-9]-[0-9][0-9] | [0-9]-[0-9][0-9][0-9] | \
+    [0-9]-[0-9][0-9][0-9][0-9] | [0-9][0-9]-[0-9][0-9] | \
+    [0-9][0-9]-[0-9][0-9][0-9] | [0-9][0-9]-[0-9][0-9][0-9][0-9] | \
+    [0-9][0-9][0-9]-[0-9][0-9][0-9] | \
+    [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9] | \
+    [0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9] )
+	at_range_start=`expr $at_option : '\(.*\)-'`
+	at_range_end=`expr $at_option : '.*-\(.*\)'`
+	if test $at_range_start -gt $at_range_end; then
+	  at_tmp=$at_range_end
+	  at_range_end=$at_range_start
+	  at_range_start=$at_tmp
+	fi
+	at_fn_validate_ranges at_range_start at_range_end
+	at_range=`$as_echo "$at_groups_all" | \
+	  sed -ne '/^'$at_range_start'$/,/^'$at_range_end'$/p'`
+	as_fn_append at_groups "$at_range$as_nl"
+	;;
+
+    # Directory selection.
+    --directory | -C )
+	at_prev=--directory
+	;;
+    --directory=* )
+	at_change_dir=:
+	at_dir=$at_optarg
+	if test x- = "x$at_dir" ; then
+	  at_dir=./-
+	fi
+	;;
+
+    # Parallel execution.
+    --jobs | -j )
+	at_jobs=0
+	;;
+    --jobs=* | -j[0-9]* )
+	if test -n "$at_optarg"; then
+	  at_jobs=$at_optarg
+	else
+	  at_jobs=`expr X$at_option : 'X-j\(.*\)'`
+	fi
+	case $at_jobs in *[!0-9]*)
+	  at_optname=`echo " $at_option" | sed 's/^ //; s/[0-9=].*//'`
+	  as_fn_error $? "non-numeric argument to $at_optname: $at_jobs" ;;
+	esac
+	;;
+
+    # Keywords.
+    --keywords | -k )
+	at_prev=--keywords
+	;;
+    --keywords=* )
+	at_groups_selected=$at_help_all
+	at_save_IFS=$IFS
+	IFS=,
+	set X $at_optarg
+	shift
+	IFS=$at_save_IFS
+	for at_keyword
+	do
+	  at_invert=
+	  case $at_keyword in
+	  '!'*)
+	    at_invert="-v"
+	    at_keyword=`expr "X$at_keyword" : 'X!\(.*\)'`
+	    ;;
+	  esac
+	  # It is on purpose that we match the test group titles too.
+	  at_groups_selected=`$as_echo "$at_groups_selected" |
+	      grep -i $at_invert "^[1-9][^;]*;.*[; ]$at_keyword[ ;]"`
+	done
+	# Smash the keywords.
+	at_groups_selected=`$as_echo "$at_groups_selected" | sed 's/;.*//'`
+	as_fn_append at_groups "$at_groups_selected$as_nl"
+	;;
+    --recheck)
+	at_recheck=:
+	;;
+
+    *=*)
+	at_envvar=`expr "x$at_option" : 'x\([^=]*\)='`
+	# Reject names that are not valid shell variable names.
+	case $at_envvar in
+	  '' | [0-9]* | *[!_$as_cr_alnum]* )
+	    as_fn_error $? "invalid variable name: \`$at_envvar'" ;;
+	esac
+	at_value=`$as_echo "$at_optarg" | sed "s/'/'\\\\\\\\''/g"`
+	# Export now, but save eval for later and for debug scripts.
+	export $at_envvar
+	as_fn_append at_debug_args " $at_envvar='$at_value'"
+	;;
+
+     *) $as_echo "$as_me: invalid option: $at_option" >&2
+	$as_echo "Try \`$0 --help' for more information." >&2
+	exit 1
+	;;
+  esac
+done
+
+# Verify our last option didn't require an argument
+if test -n "$at_prev"; then :
+  as_fn_error $? "\`$at_prev' requires an argument"
+fi
+
+# The file containing the suite.
+at_suite_log=$at_dir/$as_me.log
+
+# Selected test groups.
+if test -z "$at_groups$at_recheck"; then
+  at_groups=$at_groups_all
+else
+  if test -n "$at_recheck" && test -r "$at_suite_log"; then
+    at_oldfails=`sed -n '
+      /^Failed tests:$/,/^Skipped tests:$/{
+	s/^[ ]*\([1-9][0-9]*\):.*/\1/p
+      }
+      /^Unexpected passes:$/,/^## Detailed failed tests/{
+	s/^[ ]*\([1-9][0-9]*\):.*/\1/p
+      }
+      /^## Detailed failed tests/q
+      ' "$at_suite_log"`
+    as_fn_append at_groups "$at_oldfails$as_nl"
+  fi
+  # Sort the tests, removing duplicates.
+  at_groups=`$as_echo "$at_groups" | sort -nu | sed '/^$/d'`
+fi
+
+if test x"$at_color" = xalways \
+   || { test x"$at_color" = xauto && test -t 1; }; then
+  at_red=`printf '\033[0;31m'`
+  at_grn=`printf '\033[0;32m'`
+  at_lgn=`printf '\033[1;32m'`
+  at_blu=`printf '\033[1;34m'`
+  at_std=`printf '\033[m'`
+else
+  at_red= at_grn= at_lgn= at_blu= at_std=
+fi
+
+# Help message.
+if $at_help_p; then
+  cat <<_ATEOF || at_write_fail=1
+Usage: $0 [OPTION]... [VARIABLE=VALUE]... [TESTS]
+
+Run all the tests, or the selected TESTS, given by numeric ranges, and
+save a detailed log file.  Upon failure, create debugging scripts.
+
+Do not change environment variables directly.  Instead, set them via
+command line arguments.  Set \`AUTOTEST_PATH' to select the executables
+to exercise.  Each relative directory is expanded as build and source
+directories relative to the top level of this distribution.
+E.g., from within the build directory /tmp/foo-1.0, invoking this:
+
+  $ $0 AUTOTEST_PATH=bin
+
+is equivalent to the following, assuming the source directory is /src/foo-1.0:
+
+  PATH=/tmp/foo-1.0/bin:/src/foo-1.0/bin:\$PATH $0
+_ATEOF
+cat <<_ATEOF || at_write_fail=1
+
+Operation modes:
+  -h, --help     print the help message, then exit
+  -V, --version  print version number, then exit
+  -c, --clean    remove all the files this test suite might create and exit
+  -l, --list     describes all the tests, or the selected TESTS
+_ATEOF
+cat <<_ATEOF || at_write_fail=1
+
+Execution tuning:
+  -C, --directory=DIR
+                 change to directory DIR before starting
+      --color[=never|auto|always]
+                 enable colored test results on terminal, or always
+  -j, --jobs[=N]
+                 Allow N jobs at once; infinite jobs with no arg (default 1)
+  -k, --keywords=KEYWORDS
+                 select the tests matching all the comma-separated KEYWORDS
+                 multiple \`-k' accumulate; prefixed \`!' negates a KEYWORD
+      --recheck  select all tests that failed or passed unexpectedly last time
+  -e, --errexit  abort as soon as a test fails; implies --debug
+  -v, --verbose  force more detailed output
+                 default for debugging scripts
+  -d, --debug    inhibit clean up and top-level logging
+                 default for debugging scripts
+  -x, --trace    enable tests shell tracing
+_ATEOF
+cat <<_ATEOF || at_write_fail=1
+
+Report bugs to <bug-direvent@gnu.org.ua>.
+_ATEOF
+  exit $at_write_fail
+fi
+
+# List of tests.
+if $at_list_p; then
+  cat <<_ATEOF || at_write_fail=1
+wordsplit v1.0-6-gd36275f test suite test groups:
+
+ NUM: FILE-NAME:LINE     TEST-GROUP-NAME
+      KEYWORDS
+
+_ATEOF
+  # Pass an empty line as separator between selected groups and help.
+  $as_echo "$at_groups$as_nl$as_nl$at_help_all" |
+    awk 'NF == 1 && FS != ";" {
+	   selected[$ 1] = 1
+	   next
+	 }
+	 /^$/ { FS = ";" }
+	 NF > 0 {
+	   if (selected[$ 1]) {
+	     printf " %3d: %-18s %s\n", $ 1, $ 2, $ 3
+	     if ($ 4) {
+	       lmax = 79
+	       indent = "     "
+	       line = indent
+	       len = length (line)
+	       n = split ($ 4, a, " ")
+	       for (i = 1; i <= n; i++) {
+		 l = length (a[i]) + 1
+		 if (i > 1 && len + l > lmax) {
+		   print line
+		   line = indent " " a[i]
+		   len = length (line)
+		 } else {
+		   line = line " " a[i]
+		   len += l
+		 }
+	       }
+	       if (n)
+		 print line
+	     }
+	   }
+	 }' || at_write_fail=1
+  exit $at_write_fail
+fi
+if $at_version_p; then
+  $as_echo "$as_me (wordsplit v1.0-6-gd36275f)" &&
+  cat <<\_ATEOF || at_write_fail=1
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This test suite is free software; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+_ATEOF
+  exit $at_write_fail
+fi
+
+# Should we print banners?  Yes if more than one test is run.
+case $at_groups in #(
+  *$as_nl* )
+      at_print_banners=: ;; #(
+  * ) at_print_banners=false ;;
+esac
+# Text for banner N, set to a single space once printed.
+
+# Take any -C into account.
+if $at_change_dir ; then
+  test x != "x$at_dir" && cd "$at_dir" \
+    || as_fn_error $? "unable to change directory"
+  at_dir=`pwd`
+fi
+
+# Load the config files for any default variable assignments.
+for at_file in atconfig atlocal
+do
+  test -r $at_file || continue
+  . ./$at_file || as_fn_error $? "invalid content: $at_file"
+done
+
+# Autoconf <=2.59b set at_top_builddir instead of at_top_build_prefix:
+: "${at_top_build_prefix=$at_top_builddir}"
+
+# Perform any assignments requested during argument parsing.
+eval "$at_debug_args"
+
+# atconfig delivers names relative to the directory the test suite is
+# in, but the groups themselves are run in testsuite-dir/group-dir.
+if test -n "$at_top_srcdir"; then
+  builddir=../..
+  for at_dir_var in srcdir top_srcdir top_build_prefix
+  do
+    eval at_val=\$at_$at_dir_var
+    case $at_val in
+      [\\/$]* | ?:[\\/]* ) at_prefix= ;;
+      *) at_prefix=../../ ;;
+    esac
+    eval "$at_dir_var=\$at_prefix\$at_val"
+  done
+fi
+
+## -------------------- ##
+## Directory structure. ##
+## -------------------- ##
+
+# This is the set of directories and files used by this script
+# (non-literals are capitalized):
+#
+# TESTSUITE         - the testsuite
+# TESTSUITE.log     - summarizes the complete testsuite run
+# TESTSUITE.dir/    - created during a run, remains after -d or failed test
+# + at-groups/      - during a run: status of all groups in run
+# | + NNN/          - during a run: meta-data about test group NNN
+# | | + check-line  - location (source file and line) of current AT_CHECK
+# | | + status      - exit status of current AT_CHECK
+# | | + stdout      - stdout of current AT_CHECK
+# | | + stder1      - stderr, including trace
+# | | + stderr      - stderr, with trace filtered out
+# | | + test-source - portion of testsuite that defines group
+# | | + times       - timestamps for computing duration
+# | | + pass        - created if group passed
+# | | + xpass       - created if group xpassed
+# | | + fail        - created if group failed
+# | | + xfail       - created if group xfailed
+# | | + skip        - created if group skipped
+# + at-stop         - during a run: end the run if this file exists
+# + at-source-lines - during a run: cache of TESTSUITE line numbers for extraction
+# + 0..NNN/         - created for each group NNN, remains after -d or failed test
+# | + TESTSUITE.log - summarizes the group results
+# | + ...           - files created during the group
+
+# The directory the whole suite works in.
+# Should be absolute to let the user `cd' at will.
+at_suite_dir=$at_dir/$as_me.dir
+# The file containing the suite ($at_dir might have changed since earlier).
+at_suite_log=$at_dir/$as_me.log
+# The directory containing helper files per test group.
+at_helper_dir=$at_suite_dir/at-groups
+# Stop file: if it exists, do not start new jobs.
+at_stop_file=$at_suite_dir/at-stop
+# The fifo used for the job dispatcher.
+at_job_fifo=$at_suite_dir/at-job-fifo
+
+if $at_clean; then
+  test -d "$at_suite_dir" &&
+    find "$at_suite_dir" -type d ! -perm -700 -exec chmod u+rwx \{\} \;
+  rm -f -r "$at_suite_dir" "$at_suite_log"
+  exit $?
+fi
+
+# Don't take risks: use only absolute directories in PATH.
+#
+# For stand-alone test suites (ie. atconfig was not found),
+# AUTOTEST_PATH is relative to `.'.
+#
+# For embedded test suites, AUTOTEST_PATH is relative to the top level
+# of the package.  Then expand it into build/src parts, since users
+# may create executables in both places.
+AUTOTEST_PATH=`$as_echo "$AUTOTEST_PATH" | sed "s|:|$PATH_SEPARATOR|g"`
+at_path=
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $AUTOTEST_PATH $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -n "$at_path" && as_fn_append at_path $PATH_SEPARATOR
+case $as_dir in
+  [\\/]* | ?:[\\/]* )
+    as_fn_append at_path "$as_dir"
+    ;;
+  * )
+    if test -z "$at_top_build_prefix"; then
+      # Stand-alone test suite.
+      as_fn_append at_path "$as_dir"
+    else
+      # Embedded test suite.
+      as_fn_append at_path "$at_top_build_prefix$as_dir$PATH_SEPARATOR"
+      as_fn_append at_path "$at_top_srcdir/$as_dir"
+    fi
+    ;;
+esac
+  done
+IFS=$as_save_IFS
+
+
+# Now build and simplify PATH.
+#
+# There might be directories that don't exist, but don't redirect
+# builtins' (eg., cd) stderr directly: Ultrix's sh hates that.
+at_new_path=
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $at_path
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -d "$as_dir" || continue
+case $as_dir in
+  [\\/]* | ?:[\\/]* ) ;;
+  * ) as_dir=`(cd "$as_dir" && pwd) 2>/dev/null` ;;
+esac
+case $PATH_SEPARATOR$at_new_path$PATH_SEPARATOR in
+  *$PATH_SEPARATOR$as_dir$PATH_SEPARATOR*) ;;
+  $PATH_SEPARATOR$PATH_SEPARATOR) at_new_path=$as_dir ;;
+  *) as_fn_append at_new_path "$PATH_SEPARATOR$as_dir" ;;
+esac
+  done
+IFS=$as_save_IFS
+
+PATH=$at_new_path
+export PATH
+
+# Setting up the FDs.
+
+
+
+# 5 is the log file.  Not to be overwritten if `-d'.
+if $at_debug_p; then
+  at_suite_log=/dev/null
+else
+  : >"$at_suite_log"
+fi
+exec 5>>"$at_suite_log"
+
+# Banners and logs.
+$as_echo "## ------------------------------------- ##
+## wordsplit v1.0-6-gd36275f test suite. ##
+## ------------------------------------- ##"
+{
+  $as_echo "## ------------------------------------- ##
+## wordsplit v1.0-6-gd36275f test suite. ##
+## ------------------------------------- ##"
+  echo
+
+  $as_echo "$as_me: command line was:"
+  $as_echo "  \$ $0 $at_cli_args"
+  echo
+
+  # If ChangeLog exists, list a few lines in case it might help determining
+  # the exact version.
+  if test -n "$at_top_srcdir" && test -f "$at_top_srcdir/ChangeLog"; then
+    $as_echo "## ---------- ##
+## ChangeLog. ##
+## ---------- ##"
+    echo
+    sed 's/^/| /;10q' "$at_top_srcdir/ChangeLog"
+    echo
+  fi
+
+  {
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+}
+  echo
+
+  # Contents of the config files.
+  for at_file in atconfig atlocal
+  do
+    test -r $at_file || continue
+    $as_echo "$as_me: $at_file:"
+    sed 's/^/| /' $at_file
+    echo
+  done
+} >&5
+
+
+## ------------------------- ##
+## Autotest shell functions. ##
+## ------------------------- ##
+
+# at_fn_banner NUMBER
+# -------------------
+# Output banner NUMBER, provided the testsuite is running multiple groups and
+# this particular banner has not yet been printed.
+at_fn_banner ()
+{
+  $at_print_banners || return 0
+  eval at_banner_text=\$at_banner_text_$1
+  test "x$at_banner_text" = "x " && return 0
+  eval "at_banner_text_$1=\" \""
+  if test -z "$at_banner_text"; then
+    $at_first || echo
+  else
+    $as_echo "$as_nl$at_banner_text$as_nl"
+  fi
+} # at_fn_banner
+
+# at_fn_check_prepare_notrace REASON LINE
+# ---------------------------------------
+# Perform AT_CHECK preparations for the command at LINE for an untraceable
+# command; REASON is the reason for disabling tracing.
+at_fn_check_prepare_notrace ()
+{
+  $at_trace_echo "Not enabling shell tracing (command contains $1)"
+  $as_echo "$2" >"$at_check_line_file"
+  at_check_trace=: at_check_filter=:
+  : >"$at_stdout"; : >"$at_stderr"
+}
+
+# at_fn_check_prepare_trace LINE
+# ------------------------------
+# Perform AT_CHECK preparations for the command at LINE for a traceable
+# command.
+at_fn_check_prepare_trace ()
+{
+  $as_echo "$1" >"$at_check_line_file"
+  at_check_trace=$at_traceon at_check_filter=$at_check_filter_trace
+  : >"$at_stdout"; : >"$at_stderr"
+}
+
+# at_fn_check_prepare_dynamic COMMAND LINE
+# ----------------------------------------
+# Decide if COMMAND at LINE is traceable at runtime, and call the appropriate
+# preparation function.
+at_fn_check_prepare_dynamic ()
+{
+  case $1 in
+    *$as_nl*)
+      at_fn_check_prepare_notrace 'an embedded newline' "$2" ;;
+    *)
+      at_fn_check_prepare_trace "$2" ;;
+  esac
+}
+
+# at_fn_filter_trace
+# ------------------
+# Remove the lines in the file "$at_stderr" generated by "set -x" and print
+# them to stderr.
+at_fn_filter_trace ()
+{
+  mv "$at_stderr" "$at_stder1"
+  grep '^ *+' "$at_stder1" >&2
+  grep -v '^ *+' "$at_stder1" >"$at_stderr"
+}
+
+# at_fn_log_failure FILE-LIST
+# ---------------------------
+# Copy the files in the list on stdout with a "> " prefix, and exit the shell
+# with a failure exit code.
+at_fn_log_failure ()
+{
+  for file
+    do $as_echo "$file:"; sed 's/^/> /' "$file"; done
+  echo 1 > "$at_status_file"
+  exit 1
+}
+
+# at_fn_check_skip EXIT-CODE LINE
+# -------------------------------
+# Check whether EXIT-CODE is a special exit code (77 or 99), and if so exit
+# the test group subshell with that same exit code. Use LINE in any report
+# about test failure.
+at_fn_check_skip ()
+{
+  case $1 in
+    99) echo 99 > "$at_status_file"; at_failed=:
+	$as_echo "$2: hard failure"; exit 99;;
+    77) echo 77 > "$at_status_file"; exit 77;;
+  esac
+}
+
+# at_fn_check_status EXPECTED EXIT-CODE LINE
+# ------------------------------------------
+# Check whether EXIT-CODE is the EXPECTED exit code, and if so do nothing.
+# Otherwise, if it is 77 or 99, exit the test group subshell with that same
+# exit code; if it is anything else print an error message referring to LINE,
+# and fail the test.
+at_fn_check_status ()
+{
+  case $2 in
+    $1 ) ;;
+    77) echo 77 > "$at_status_file"; exit 77;;
+    99) echo 99 > "$at_status_file"; at_failed=:
+	$as_echo "$3: hard failure"; exit 99;;
+    *) $as_echo "$3: exit code was $2, expected $1"
+      at_failed=:;;
+  esac
+}
+
+# at_fn_diff_devnull FILE
+# -----------------------
+# Emit a diff between /dev/null and FILE. Uses "test -s" to avoid useless diff
+# invocations.
+at_fn_diff_devnull ()
+{
+  test -s "$1" || return 0
+  $at_diff "$at_devnull" "$1"
+}
+
+# at_fn_test NUMBER
+# -----------------
+# Parse out test NUMBER from the tail of this file.
+at_fn_test ()
+{
+  eval at_sed=\$at_sed$1
+  sed "$at_sed" "$at_myself" > "$at_test_source"
+}
+
+# at_fn_create_debugging_script
+# -----------------------------
+# Create the debugging script $at_group_dir/run which will reproduce the
+# current test group.
+at_fn_create_debugging_script ()
+{
+  {
+    echo "#! /bin/sh" &&
+    echo 'test "${ZSH_VERSION+set}" = set && alias -g '\''${1+"$@"}'\''='\''"$@"'\''' &&
+    $as_echo "cd '$at_dir'" &&
+    $as_echo "exec \${CONFIG_SHELL-$SHELL} \"$at_myself\" -v -d $at_debug_args $at_group \${1+\"\$@\"}" &&
+    echo 'exit 1'
+  } >"$at_group_dir/run" &&
+  chmod +x "$at_group_dir/run"
+}
+
+## -------------------------------- ##
+## End of autotest shell functions. ##
+## -------------------------------- ##
+{
+  $as_echo "## ---------------- ##
+## Tested programs. ##
+## ---------------- ##"
+  echo
+} >&5
+
+# Report what programs are being tested.
+for at_program in : $at_tested
+do
+  test "$at_program" = : && continue
+  case $at_program in
+    [\\/]* | ?:[\\/]* ) $at_program_=$at_program ;;
+    * )
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -f "$as_dir/$at_program" && break
+  done
+IFS=$as_save_IFS
+
+    at_program_=$as_dir/$at_program ;;
+  esac
+  if test -f "$at_program_"; then
+    {
+      $as_echo "$at_srcdir/wordsplit.at:17: $at_program_ --version"
+      "$at_program_" --version </dev/null
+      echo
+    } >&5 2>&1
+  else
+    as_fn_error $? "cannot find $at_program" "$LINENO" 5
+  fi
+done
+
+{
+  $as_echo "## ------------------ ##
+## Running the tests. ##
+## ------------------ ##"
+} >&5
+
+at_start_date=`date`
+at_start_time=`date +%s 2>/dev/null`
+$as_echo "$as_me: starting at: $at_start_date" >&5
+
+# Create the master directory if it doesn't already exist.
+as_dir="$at_suite_dir"; as_fn_mkdir_p ||
+  as_fn_error $? "cannot create \`$at_suite_dir'" "$LINENO" 5
+
+# Can we diff with `/dev/null'?  DU 5.0 refuses.
+if diff /dev/null /dev/null >/dev/null 2>&1; then
+  at_devnull=/dev/null
+else
+  at_devnull=$at_suite_dir/devnull
+  >"$at_devnull"
+fi
+
+# Use `diff -u' when possible.
+if at_diff=`diff -u "$at_devnull" "$at_devnull" 2>&1` && test -z "$at_diff"
+then
+  at_diff='diff -u'
+else
+  at_diff=diff
+fi
+
+# Get the last needed group.
+for at_group in : $at_groups; do :; done
+
+# Extract the start and end lines of each test group at the tail
+# of this file
+awk '
+BEGIN { FS="" }
+/^#AT_START_/ {
+  start = NR
+}
+/^#AT_STOP_/ {
+  test = substr ($ 0, 10)
+  print "at_sed" test "=\"1," start "d;" (NR-1) "q\""
+  if (test == "'"$at_group"'") exit
+}' "$at_myself" > "$at_suite_dir/at-source-lines" &&
+. "$at_suite_dir/at-source-lines" ||
+  as_fn_error $? "cannot create test line number cache" "$LINENO" 5
+rm -f "$at_suite_dir/at-source-lines"
+
+# Set number of jobs for `-j'; avoid more jobs than test groups.
+set X $at_groups; shift; at_max_jobs=$#
+if test $at_max_jobs -eq 0; then
+  at_jobs=1
+fi
+if test $at_jobs -ne 1 &&
+   { test $at_jobs -eq 0 || test $at_jobs -gt $at_max_jobs; }; then
+  at_jobs=$at_max_jobs
+fi
+
+# If parallel mode, don't output banners, don't split summary lines.
+if test $at_jobs -ne 1; then
+  at_print_banners=false
+  at_quiet=:
+fi
+
+# Set up helper dirs.
+rm -rf "$at_helper_dir" &&
+mkdir "$at_helper_dir" &&
+cd "$at_helper_dir" &&
+{ test -z "$at_groups" || mkdir $at_groups; } ||
+as_fn_error $? "testsuite directory setup failed" "$LINENO" 5
+
+# Functions for running a test group.  We leave the actual
+# test group execution outside of a shell function in order
+# to avoid hitting zsh 4.x exit status bugs.
+
+# at_fn_group_prepare
+# -------------------
+# Prepare for running a test group.
+at_fn_group_prepare ()
+{
+  # The directory for additional per-group helper files.
+  at_job_dir=$at_helper_dir/$at_group
+  # The file containing the location of the last AT_CHECK.
+  at_check_line_file=$at_job_dir/check-line
+  # The file containing the exit status of the last command.
+  at_status_file=$at_job_dir/status
+  # The files containing the output of the tested commands.
+  at_stdout=$at_job_dir/stdout
+  at_stder1=$at_job_dir/stder1
+  at_stderr=$at_job_dir/stderr
+  # The file containing the code for a test group.
+  at_test_source=$at_job_dir/test-source
+  # The file containing dates.
+  at_times_file=$at_job_dir/times
+
+  # Be sure to come back to the top test directory.
+  cd "$at_suite_dir"
+
+  # Clearly separate the test groups when verbose.
+  $at_first || $at_verbose echo
+
+  at_group_normalized=$at_group
+
+  eval 'while :; do
+    case $at_group_normalized in #(
+    '"$at_format"'*) break;;
+    esac
+    at_group_normalized=0$at_group_normalized
+  done'
+
+
+  # Create a fresh directory for the next test group, and enter.
+  # If one already exists, the user may have invoked ./run from
+  # within that directory; we remove the contents, but not the
+  # directory itself, so that we aren't pulling the rug out from
+  # under the shell's notion of the current directory.
+  at_group_dir=$at_suite_dir/$at_group_normalized
+  at_group_log=$at_group_dir/$as_me.log
+  if test -d "$at_group_dir"; then
+  find "$at_group_dir" -type d ! -perm -700 -exec chmod u+rwx {} \;
+  rm -fr "$at_group_dir"/* "$at_group_dir"/.[!.] "$at_group_dir"/.??*
+fi ||
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: test directory for $at_group_normalized could not be cleaned" >&5
+$as_echo "$as_me: WARNING: test directory for $at_group_normalized could not be cleaned" >&2;}
+  # Be tolerant if the above `rm' was not able to remove the directory.
+  as_dir="$at_group_dir"; as_fn_mkdir_p
+
+  echo 0 > "$at_status_file"
+
+  # In verbose mode, append to the log file *and* show on
+  # the standard output; in quiet mode only write to the log.
+  if test -z "$at_verbose"; then
+    at_tee_pipe='tee -a "$at_group_log"'
+  else
+    at_tee_pipe='cat >> "$at_group_log"'
+  fi
+}
+
+# at_fn_group_banner ORDINAL LINE DESC PAD [BANNER]
+# -------------------------------------------------
+# Declare the test group ORDINAL, located at LINE with group description DESC,
+# and residing under BANNER. Use PAD to align the status column.
+at_fn_group_banner ()
+{
+  at_setup_line="$2"
+  test -n "$5" && at_fn_banner $5
+  at_desc="$3"
+  case $1 in
+    [0-9])      at_desc_line="  $1: ";;
+    [0-9][0-9]) at_desc_line=" $1: " ;;
+    *)          at_desc_line="$1: "  ;;
+  esac
+  as_fn_append at_desc_line "$3$4"
+  $at_quiet $as_echo_n "$at_desc_line"
+  echo "#                             -*- compilation -*-" >> "$at_group_log"
+}
+
+# at_fn_group_postprocess
+# -----------------------
+# Perform cleanup after running a test group.
+at_fn_group_postprocess ()
+{
+  # Be sure to come back to the suite directory, in particular
+  # since below we might `rm' the group directory we are in currently.
+  cd "$at_suite_dir"
+
+  if test ! -f "$at_check_line_file"; then
+    sed "s/^ */$as_me: WARNING: /" <<_ATEOF
+      A failure happened in a test group before any test could be
+      run. This means that test suite is improperly designed.  Please
+      report this failure to <bug-direvent@gnu.org.ua>.
+_ATEOF
+    $as_echo "$at_setup_line" >"$at_check_line_file"
+    at_status=99
+  fi
+  $at_verbose $as_echo_n "$at_group. $at_setup_line: "
+  $as_echo_n "$at_group. $at_setup_line: " >> "$at_group_log"
+  case $at_xfail:$at_status in
+    yes:0)
+	at_msg="UNEXPECTED PASS"
+	at_res=xpass
+	at_errexit=$at_errexit_p
+	at_color=$at_red
+	;;
+    no:0)
+	at_msg="ok"
+	at_res=pass
+	at_errexit=false
+	at_color=$at_grn
+	;;
+    *:77)
+	at_msg='skipped ('`cat "$at_check_line_file"`')'
+	at_res=skip
+	at_errexit=false
+	at_color=$at_blu
+	;;
+    no:* | *:99)
+	at_msg='FAILED ('`cat "$at_check_line_file"`')'
+	at_res=fail
+	at_errexit=$at_errexit_p
+	at_color=$at_red
+	;;
+    yes:*)
+	at_msg='expected failure ('`cat "$at_check_line_file"`')'
+	at_res=xfail
+	at_errexit=false
+	at_color=$at_lgn
+	;;
+  esac
+  echo "$at_res" > "$at_job_dir/$at_res"
+  # In parallel mode, output the summary line only afterwards.
+  if test $at_jobs -ne 1 && test -n "$at_verbose"; then
+    $as_echo "$at_desc_line $at_color$at_msg$at_std"
+  else
+    # Make sure there is a separator even with long titles.
+    $as_echo " $at_color$at_msg$at_std"
+  fi
+  at_log_msg="$at_group. $at_desc ($at_setup_line): $at_msg"
+  case $at_status in
+    0|77)
+      # $at_times_file is only available if the group succeeded.
+      # We're not including the group log, so the success message
+      # is written in the global log separately.  But we also
+      # write to the group log in case they're using -d.
+      if test -f "$at_times_file"; then
+	at_log_msg="$at_log_msg     ("`sed 1d "$at_times_file"`')'
+	rm -f "$at_times_file"
+      fi
+      $as_echo "$at_log_msg" >> "$at_group_log"
+      $as_echo "$at_log_msg" >&5
+
+      # Cleanup the group directory, unless the user wants the files
+      # or the success was unexpected.
+      if $at_debug_p || test $at_res = xpass; then
+	at_fn_create_debugging_script
+	if test $at_res = xpass && $at_errexit; then
+	  echo stop > "$at_stop_file"
+	fi
+      else
+	if test -d "$at_group_dir"; then
+	  find "$at_group_dir" -type d ! -perm -700 -exec chmod u+rwx \{\} \;
+	  rm -fr "$at_group_dir"
+	fi
+	rm -f "$at_test_source"
+      fi
+      ;;
+    *)
+      # Upon failure, include the log into the testsuite's global
+      # log.  The failure message is written in the group log.  It
+      # is later included in the global log.
+      $as_echo "$at_log_msg" >> "$at_group_log"
+
+      # Upon failure, keep the group directory for autopsy, and create
+      # the debugging script.  With -e, do not start any further tests.
+      at_fn_create_debugging_script
+      if $at_errexit; then
+	echo stop > "$at_stop_file"
+      fi
+      ;;
+  esac
+}
+
+
+## ------------ ##
+## Driver loop. ##
+## ------------ ##
+
+
+if (set -m && set +m && set +b) >/dev/null 2>&1; then
+  set +b
+  at_job_control_on='set -m' at_job_control_off='set +m' at_job_group=-
+else
+  at_job_control_on=: at_job_control_off=: at_job_group=
+fi
+
+for at_signal in 1 2 15; do
+  trap 'set +x; set +e
+	$at_job_control_off
+	at_signal='"$at_signal"'
+	echo stop > "$at_stop_file"
+	trap "" $at_signal
+	at_pgids=
+	for at_pgid in `jobs -p 2>/dev/null`; do
+	  at_pgids="$at_pgids $at_job_group$at_pgid"
+	done
+	test -z "$at_pgids" || kill -$at_signal $at_pgids 2>/dev/null
+	wait
+	if test "$at_jobs" -eq 1 || test -z "$at_verbose"; then
+	  echo >&2
+	fi
+	at_signame=`kill -l $at_signal 2>&1 || echo $at_signal`
+	set x $at_signame
+	test 0 -gt 2 && at_signame=$at_signal
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: caught signal $at_signame, bailing out" >&5
+$as_echo "$as_me: WARNING: caught signal $at_signame, bailing out" >&2;}
+	as_fn_arith 128 + $at_signal && exit_status=$as_val
+	as_fn_exit $exit_status' $at_signal
+done
+
+rm -f "$at_stop_file"
+at_first=:
+
+if test $at_jobs -ne 1 &&
+     rm -f "$at_job_fifo" &&
+     test -n "$at_job_group" &&
+     ( mkfifo "$at_job_fifo" && trap 'exit 1' PIPE STOP TSTP ) 2>/dev/null
+then
+  # FIFO job dispatcher.
+
+  trap 'at_pids=
+	for at_pid in `jobs -p`; do
+	  at_pids="$at_pids $at_job_group$at_pid"
+	done
+	if test -n "$at_pids"; then
+	  at_sig=TSTP
+	  test "${TMOUT+set}" = set && at_sig=STOP
+	  kill -$at_sig $at_pids 2>/dev/null
+	fi
+	kill -STOP $$
+	test -z "$at_pids" || kill -CONT $at_pids 2>/dev/null' TSTP
+
+  echo
+  # Turn jobs into a list of numbers, starting from 1.
+  at_joblist=`$as_echo "$at_groups" | sed -n 1,${at_jobs}p`
+
+  set X $at_joblist
+  shift
+  for at_group in $at_groups; do
+    $at_job_control_on 2>/dev/null
+    (
+      # Start one test group.
+      $at_job_control_off
+      if $at_first; then
+	exec 7>"$at_job_fifo"
+      else
+	exec 6<&-
+      fi
+      trap 'set +x; set +e
+	    trap "" PIPE
+	    echo stop > "$at_stop_file"
+	    echo >&7
+	    as_fn_exit 141' PIPE
+      at_fn_group_prepare
+      if cd "$at_group_dir" &&
+	 at_fn_test $at_group &&
+	 . "$at_test_source"
+      then :; else
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unable to parse test group: $at_group" >&5
+$as_echo "$as_me: WARNING: unable to parse test group: $at_group" >&2;}
+	at_failed=:
+      fi
+      at_fn_group_postprocess
+      echo >&7
+    ) &
+    $at_job_control_off
+    if $at_first; then
+      at_first=false
+      exec 6<"$at_job_fifo" 7>"$at_job_fifo"
+    fi
+    shift # Consume one token.
+    if test $# -gt 0; then :; else
+      read at_token <&6 || break
+      set x $*
+    fi
+    test -f "$at_stop_file" && break
+  done
+  exec 7>&-
+  # Read back the remaining ($at_jobs - 1) tokens.
+  set X $at_joblist
+  shift
+  if test $# -gt 0; then
+    shift
+    for at_job
+    do
+      read at_token
+    done <&6
+  fi
+  exec 6<&-
+  wait
+else
+  # Run serially, avoid forks and other potential surprises.
+  for at_group in $at_groups; do
+    at_fn_group_prepare
+    if cd "$at_group_dir" &&
+       at_fn_test $at_group &&
+       . "$at_test_source"; then :; else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unable to parse test group: $at_group" >&5
+$as_echo "$as_me: WARNING: unable to parse test group: $at_group" >&2;}
+      at_failed=:
+    fi
+    at_fn_group_postprocess
+    test -f "$at_stop_file" && break
+    at_first=false
+  done
+fi
+
+# Wrap up the test suite with summary statistics.
+cd "$at_helper_dir"
+
+# Use ?..???? when the list must remain sorted, the faster * otherwise.
+at_pass_list=`for f in */pass; do echo $f; done | sed '/\*/d; s,/pass,,'`
+at_skip_list=`for f in */skip; do echo $f; done | sed '/\*/d; s,/skip,,'`
+at_xfail_list=`for f in */xfail; do echo $f; done | sed '/\*/d; s,/xfail,,'`
+at_xpass_list=`for f in ?/xpass ??/xpass ???/xpass ????/xpass; do
+		 echo $f; done | sed '/?/d; s,/xpass,,'`
+at_fail_list=`for f in ?/fail ??/fail ???/fail ????/fail; do
+		echo $f; done | sed '/?/d; s,/fail,,'`
+
+set X $at_pass_list $at_xpass_list $at_xfail_list $at_fail_list $at_skip_list
+shift; at_group_count=$#
+set X $at_xpass_list; shift; at_xpass_count=$#; at_xpass_list=$*
+set X $at_xfail_list; shift; at_xfail_count=$#
+set X $at_fail_list; shift; at_fail_count=$#; at_fail_list=$*
+set X $at_skip_list; shift; at_skip_count=$#
+
+as_fn_arith $at_group_count - $at_skip_count && at_run_count=$as_val
+as_fn_arith $at_xpass_count + $at_fail_count && at_unexpected_count=$as_val
+as_fn_arith $at_xfail_count + $at_fail_count && at_total_fail_count=$as_val
+
+# Back to the top directory.
+cd "$at_dir"
+rm -rf "$at_helper_dir"
+
+# Compute the duration of the suite.
+at_stop_date=`date`
+at_stop_time=`date +%s 2>/dev/null`
+$as_echo "$as_me: ending at: $at_stop_date" >&5
+case $at_start_time,$at_stop_time in
+  [0-9]*,[0-9]*)
+    as_fn_arith $at_stop_time - $at_start_time && at_duration_s=$as_val
+    as_fn_arith $at_duration_s / 60 && at_duration_m=$as_val
+    as_fn_arith $at_duration_m / 60 && at_duration_h=$as_val
+    as_fn_arith $at_duration_s % 60 && at_duration_s=$as_val
+    as_fn_arith $at_duration_m % 60 && at_duration_m=$as_val
+    at_duration="${at_duration_h}h ${at_duration_m}m ${at_duration_s}s"
+    $as_echo "$as_me: test suite duration: $at_duration" >&5
+    ;;
+esac
+
+echo
+$as_echo "## ------------- ##
+## Test results. ##
+## ------------- ##"
+echo
+{
+  echo
+  $as_echo "## ------------- ##
+## Test results. ##
+## ------------- ##"
+  echo
+} >&5
+
+if test $at_run_count = 1; then
+  at_result="1 test"
+  at_were=was
+else
+  at_result="$at_run_count tests"
+  at_were=were
+fi
+if $at_errexit_p && test $at_unexpected_count != 0; then
+  if test $at_xpass_count = 1; then
+    at_result="$at_result $at_were run, one passed"
+  else
+    at_result="$at_result $at_were run, one failed"
+  fi
+  at_result="$at_result unexpectedly and inhibited subsequent tests."
+  at_color=$at_red
+else
+  # Don't you just love exponential explosion of the number of cases?
+  at_color=$at_red
+  case $at_xpass_count:$at_fail_count:$at_xfail_count in
+    # So far, so good.
+    0:0:0) at_result="$at_result $at_were successful." at_color=$at_grn ;;
+    0:0:*) at_result="$at_result behaved as expected." at_color=$at_lgn ;;
+
+    # Some unexpected failures
+    0:*:0) at_result="$at_result $at_were run,
+$at_fail_count failed unexpectedly." ;;
+
+    # Some failures, both expected and unexpected
+    0:*:1) at_result="$at_result $at_were run,
+$at_total_fail_count failed ($at_xfail_count expected failure)." ;;
+    0:*:*) at_result="$at_result $at_were run,
+$at_total_fail_count failed ($at_xfail_count expected failures)." ;;
+
+    # No unexpected failures, but some xpasses
+    *:0:*) at_result="$at_result $at_were run,
+$at_xpass_count passed unexpectedly." ;;
+
+    # No expected failures, but failures and xpasses
+    *:1:0) at_result="$at_result $at_were run,
+$at_unexpected_count did not behave as expected ($at_fail_count unexpected failure)." ;;
+    *:*:0) at_result="$at_result $at_were run,
+$at_unexpected_count did not behave as expected ($at_fail_count unexpected failures)." ;;
+
+    # All of them.
+    *:*:1) at_result="$at_result $at_were run,
+$at_xpass_count passed unexpectedly,
+$at_total_fail_count failed ($at_xfail_count expected failure)." ;;
+    *:*:*) at_result="$at_result $at_were run,
+$at_xpass_count passed unexpectedly,
+$at_total_fail_count failed ($at_xfail_count expected failures)." ;;
+  esac
+
+  if test $at_skip_count = 0 && test $at_run_count -gt 1; then
+    at_result="All $at_result"
+  fi
+fi
+
+# Now put skips in the mix.
+case $at_skip_count in
+  0) ;;
+  1) at_result="$at_result
+1 test was skipped." ;;
+  *) at_result="$at_result
+$at_skip_count tests were skipped." ;;
+esac
+
+if test $at_unexpected_count = 0; then
+  echo "$at_color$at_result$at_std"
+  echo "$at_result" >&5
+else
+  echo "${at_color}ERROR: $at_result$at_std" >&2
+  echo "ERROR: $at_result" >&5
+  {
+    echo
+    $as_echo "## ------------------------ ##
+## Summary of the failures. ##
+## ------------------------ ##"
+
+    # Summary of failed and skipped tests.
+    if test $at_fail_count != 0; then
+      echo "Failed tests:"
+      $SHELL "$at_myself" $at_fail_list --list
+      echo
+    fi
+    if test $at_skip_count != 0; then
+      echo "Skipped tests:"
+      $SHELL "$at_myself" $at_skip_list --list
+      echo
+    fi
+    if test $at_xpass_count != 0; then
+      echo "Unexpected passes:"
+      $SHELL "$at_myself" $at_xpass_list --list
+      echo
+    fi
+    if test $at_fail_count != 0; then
+      $as_echo "## ---------------------- ##
+## Detailed failed tests. ##
+## ---------------------- ##"
+      echo
+      for at_group in $at_fail_list
+      do
+	at_group_normalized=$at_group
+
+  eval 'while :; do
+    case $at_group_normalized in #(
+    '"$at_format"'*) break;;
+    esac
+    at_group_normalized=0$at_group_normalized
+  done'
+
+	cat "$at_suite_dir/$at_group_normalized/$as_me.log"
+	echo
+      done
+      echo
+    fi
+    if test -n "$at_top_srcdir"; then
+      sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## ${at_top_build_prefix}config.log ##
+_ASBOX
+      sed 's/^/| /' ${at_top_build_prefix}config.log
+      echo
+    fi
+  } >&5
+
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## $as_me.log was created. ##
+_ASBOX
+
+  echo
+  if $at_debug_p; then
+    at_msg='per-test log files'
+  else
+    at_msg="\`${at_testdir+${at_testdir}/}$as_me.log'"
+  fi
+  $as_echo "Please send $at_msg and all information you think might help:
+
+   To: <bug-direvent@gnu.org.ua>
+   Subject: [wordsplit v1.0-6-gd36275f] $as_me: $at_fail_list${at_fail_list:+ failed${at_xpass_list:+, }}$at_xpass_list${at_xpass_list:+ passed unexpectedly}
+
+You may investigate any problem if you feel able to do so, in which
+case the test suite provides a good starting point.  Its output may
+be found below \`${at_testdir+${at_testdir}/}$as_me.dir'.
+"
+  exit 1
+fi
+
+exit 0
+
+## ------------- ##
+## Actual tests. ##
+## ------------- ##
+#AT_START_1
+at_fn_group_banner 1 'wordsplit.at:59' \
+  "simple input" "                                   "
+at_xfail=no
+(
+  $as_echo "1. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:59:
+ wsp  <<'EOT'
+1 2 3
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:59"
+( $at_check_trace;
+ wsp  <<'EOT'
+1 2 3
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: 1
+1: 2
+2: 3
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_1
+#AT_START_2
+at_fn_group_banner 2 'wordsplit.at:68' \
+  "quoted space" "                                   "
+at_xfail=no
+(
+  $as_echo "2. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:68:
+ wsp  <<'EOT'
+quoted\\ space
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:68"
+( $at_check_trace;
+ wsp  <<'EOT'
+quoted\ space
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: \"quoted space\"
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:68"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_2
+#AT_START_3
+at_fn_group_banner 3 'wordsplit.at:75' \
+  "tab character" "                                  "
+at_xfail=no
+(
+  $as_echo "3. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:75:
+ wsp  <<'EOT'
+a \"tab	character\"
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:75"
+( $at_check_trace;
+ wsp  <<'EOT'
+a "tab	character"
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 2
+0: a
+1: tab\\tcharacter
+TOTAL: 2
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:75"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_3
+#AT_START_4
+at_fn_group_banner 4 'wordsplit.at:84' \
+  "octal and hex escapes" "                          "
+at_xfail=no
+(
+  $as_echo "4. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:84:
+ wsp  <<'EOT'
+\\157\\143\\164\\141\\154\\40and\\x20\\x68\\x65\\x78
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:84"
+( $at_check_trace;
+ wsp  <<'EOT'
+\157\143\164\141\154\40and\x20\x68\x65\x78
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: \"octal and hex\"
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:84"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_4
+#AT_START_5
+at_fn_group_banner 5 'wordsplit.at:91' \
+  "octal and hex escapes 2" "                        "
+at_xfail=no
+(
+  $as_echo "5. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:91:
+ wsp  <<'EOT'
+\\157\\143\\164\\141\\154\\40 and \\x20\\x68\\x65\\x78
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:91"
+( $at_check_trace;
+ wsp  <<'EOT'
+\157\143\164\141\154\40 and \x20\x68\x65\x78
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: \"octal \"
+1: and
+2: \" hex\"
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:91"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_5
+#AT_START_6
+at_fn_group_banner 6 'wordsplit.at:100' \
+  "escape representation" "                          "
+at_xfail=no
+(
+  $as_echo "6. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:100:
+ wsp  <<'EOT'
+A\\x3-\\48\\39
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:100"
+( $at_check_trace;
+ wsp  <<'EOT'
+A\x3-\48\39
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: A\\003-\\0048\\0039
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:100"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_6
+#AT_START_7
+at_fn_group_banner 7 'wordsplit.at:112' \
+  "append" "                                         "
+at_xfail=no
+(
+  $as_echo "7. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:112:
+ wsp -append <<'EOT'
+jeden dwa trzy
+cztery
+piec szesc
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:112"
+( $at_check_trace;
+ wsp -append <<'EOT'
+jeden dwa trzy
+cztery
+piec szesc
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: jeden
+1: dwa
+2: trzy
+TOTAL: 3
+NF: 4
+0: jeden
+1: dwa
+2: trzy
+3: cztery
+TOTAL: 1
+NF: 6
+0: jeden
+1: dwa
+2: trzy
+3: cztery
+4: piec
+5: szesc
+TOTAL: 2
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:112"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_7
+#AT_START_8
+at_fn_group_banner 8 'wordsplit.at:137' \
+  "dooffs" "                                         "
+at_xfail=no
+(
+  $as_echo "8. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:137:
+ wsp -dooffs jeden dwa trzy <<'EOT'
+cztery piec
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:137"
+( $at_check_trace;
+ wsp -dooffs jeden dwa trzy <<'EOT'
+cztery piec
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 2 (3)
+(0): jeden
+(1): dwa
+(2): trzy
+3: cztery
+4: piec
+TOTAL: 2
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:137"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_8
+#AT_START_9
+at_fn_group_banner 9 'wordsplit.at:150' \
+  "variable substitutions: single var" "             "
+at_xfail=no
+(
+  $as_echo "9. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:150:
+FOO=bar wsp  <<'EOT'
+a \$FOO test
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:150"
+( $at_check_trace;
+FOO=bar wsp  <<'EOT'
+a $FOO test
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: a
+1: bar
+2: test
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:150"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_9
+#AT_START_10
+at_fn_group_banner 10 'wordsplit.at:161' \
+  "variable substitutions: concatenated vars" "      "
+at_xfail=no
+(
+  $as_echo "10. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:161:
+FOO=str BAR=ing wsp  <<'EOT'
+a \$FOO\${BAR}ent test
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:161"
+( $at_check_trace;
+FOO=str BAR=ing wsp  <<'EOT'
+a $FOO${BAR}ent test
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: a
+1: stringent
+2: test
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:161"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_10
+#AT_START_11
+at_fn_group_banner 11 'wordsplit.at:173' \
+  "variable substitutions: field splitting" "        "
+at_xfail=no
+(
+  $as_echo "11. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:173:
+FOO=\"variable substitution\" wsp  <<'EOT'
+a \$FOO test
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:173"
+( $at_check_trace;
+FOO="variable substitution" wsp  <<'EOT'
+a $FOO test
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 4
+0: a
+1: variable
+2: substitution
+3: test
+TOTAL: 4
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:173"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_11
+#AT_START_12
+at_fn_group_banner 12 'wordsplit.at:185' \
+  "variable substitutions: double-quoted variable" " "
+at_xfail=no
+(
+  $as_echo "12. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:185:
+FOO=\"variable substitution\" wsp  <<'EOT'
+a \"\$FOO\" test
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:185"
+( $at_check_trace;
+FOO="variable substitution" wsp  <<'EOT'
+a "$FOO" test
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: a
+1: \"variable substitution\"
+2: test
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:185"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_12
+#AT_START_13
+at_fn_group_banner 13 'wordsplit.at:196' \
+  "variable substitutions: single-quoted variable" " "
+at_xfail=no
+(
+  $as_echo "13. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:196:
+FOO=\"variable substitution\" wsp  <<'EOT'
+a '\$FOO' test
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:196"
+( $at_check_trace;
+FOO="variable substitution" wsp  <<'EOT'
+a '$FOO' test
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: a
+1: \$FOO
+2: test
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:196"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_13
+#AT_START_14
+at_fn_group_banner 14 'wordsplit.at:207' \
+  "undefined variables 1" "                          "
+at_xfail=no
+(
+  $as_echo "14. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:207:
+unset FOO; wsp  <<'EOT'
+a \$FOO test a\${FOO}b
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:207"
+( $at_check_trace;
+unset FOO; wsp  <<'EOT'
+a $FOO test a${FOO}b
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: a
+1: test
+2: ab
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:207"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_14
+#AT_START_15
+at_fn_group_banner 15 'wordsplit.at:218' \
+  "undefined variables 2" "                          "
+at_xfail=no
+(
+  $as_echo "15. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:218:
+unset FOO; wsp -keepundef <<'EOT'
+a \$FOO test a\${FOO}b
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:218"
+( $at_check_trace;
+unset FOO; wsp -keepundef <<'EOT'
+a $FOO test a${FOO}b
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 4
+0: a
+1: \$FOO
+2: test
+3: a\${FOO}b
+TOTAL: 4
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:218"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_15
+#AT_START_16
+at_fn_group_banner 16 'wordsplit.at:230' \
+  "warn about undefined variables" "                 "
+at_xfail=no
+(
+  $as_echo "16. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:230:
+unset FOO; wsp -warnundef <<'EOT'
+\$FOO
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:230"
+( $at_check_trace;
+unset FOO; wsp -warnundef <<'EOT'
+$FOO
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; $as_echo "warning: undefined variable \`FOO'
+" | \
+  $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 0
+TOTAL: 0
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:230"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_16
+#AT_START_17
+at_fn_group_banner 17 'wordsplit.at:239' \
+  "bail out on undefined variables" "                "
+at_xfail=no
+(
+  $as_echo "17. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:239:
+unset FOO; wsp -undef <<'EOT'
+\$FOO
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:239"
+( $at_check_trace;
+unset FOO; wsp -undef <<'EOT'
+$FOO
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; $as_echo "undefined variable: FOO
+" | \
+  $at_diff - "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:239"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_17
+#AT_START_18
+at_fn_group_banner 18 'wordsplit.at:246' \
+  "disable variable expansion" "                     "
+at_xfail=no
+(
+  $as_echo "18. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:246:
+FOO=bar wsp -novar <<'EOT'
+\$FOO
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:246"
+( $at_check_trace;
+FOO=bar wsp -novar <<'EOT'
+$FOO
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: \$FOO
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:246"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_18
+#AT_START_19
+at_fn_group_banner 19 'wordsplit.at:255' \
+  "K/V environment" "                                "
+at_xfail=no
+(
+  $as_echo "19. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:255:
+FOO=bar BAZ=qux wsp -env_kv <<'EOT'
+\$FOO a\$BAZ
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:255"
+( $at_check_trace;
+FOO=bar BAZ=qux wsp -env_kv <<'EOT'
+$FOO a$BAZ
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 2
+0: bar
+1: aqux
+TOTAL: 2
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:255"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_19
+#AT_START_20
+at_fn_group_banner 20 'wordsplit.at:266' \
+  "nosplit with variable expansion" "                "
+at_xfail=no
+(
+  $as_echo "20. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:266:
+FOO=\"variable expansion\" wsp -nosplit <<'EOT'
+a \$FOO test
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:266"
+( $at_check_trace;
+FOO="variable expansion" wsp -nosplit <<'EOT'
+a $FOO test
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: \"a variable expansion test\\n\"
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:266"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_20
+#AT_START_21
+at_fn_group_banner 21 'wordsplit.at:275' \
+  "nosplit without variable expansion" "             "
+at_xfail=no
+(
+  $as_echo "21. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:275:
+FOO=\"variable expansion\" wsp -nosplit -novar <<'EOT'
+a \$FOO test
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:275"
+( $at_check_trace;
+FOO="variable expansion" wsp -nosplit -novar <<'EOT'
+a $FOO test
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: \"a \$FOO test\\n\"
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:275"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_21
+#AT_START_22
+at_fn_group_banner 22 'wordsplit.at:284' \
+  "nosplit: empty expansion" "                       "
+at_xfail=no
+(
+  $as_echo "22. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:284:
+FOO=\"\" wsp -nosplit -trimnl <<'EOT'
+\$FOO
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:284"
+( $at_check_trace;
+FOO="" wsp -nosplit -trimnl <<'EOT'
+$FOO
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: \"\"
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:284"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_22
+#AT_START_23
+at_fn_group_banner 23 'wordsplit.at:293' \
+  "default value" "                                  "
+at_xfail=no
+(
+  $as_echo "23. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:293:
+ wsp  <<'EOT'
+\${FOO:-bar}
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:293"
+( $at_check_trace;
+ wsp  <<'EOT'
+${FOO:-bar}
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: bar
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:293"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_23
+#AT_START_24
+at_fn_group_banner 24 'wordsplit.at:300' \
+  "default value (defined)" "                        "
+at_xfail=no
+(
+  $as_echo "24. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:300:
+FOO=qux wsp  <<'EOT'
+\${FOO:-bar}
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:300"
+( $at_check_trace;
+FOO=qux wsp  <<'EOT'
+${FOO:-bar}
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: qux
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:300"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_24
+#AT_START_25
+at_fn_group_banner 25 'wordsplit.at:309' \
+  "default value (:- null)" "                        "
+at_xfail=no
+(
+  $as_echo "25. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:309:
+FOO= wsp  <<'EOT'
+\${FOO:-bar}
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:309"
+( $at_check_trace;
+FOO= wsp  <<'EOT'
+${FOO:-bar}
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: bar
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:309"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_25
+#AT_START_26
+at_fn_group_banner 26 'wordsplit.at:318' \
+  "default value (- null)" "                         "
+at_xfail=no
+(
+  $as_echo "26. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:318:
+FOO= wsp  <<'EOT'
+\${FOO-bar}
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:318"
+( $at_check_trace;
+FOO= wsp  <<'EOT'
+${FOO-bar}
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 0
+TOTAL: 0
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:318"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_26
+#AT_START_27
+at_fn_group_banner 27 'wordsplit.at:326' \
+  "default value (- null, unset)" "                  "
+at_xfail=no
+(
+  $as_echo "27. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:326:
+ wsp  <<'EOT'
+\${FOO-bar}
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:326"
+( $at_check_trace;
+ wsp  <<'EOT'
+${FOO-bar}
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: bar
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:326"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_27
+#AT_START_28
+at_fn_group_banner 28 'wordsplit.at:333' \
+  "assign default values" "                          "
+at_xfail=no
+(
+  $as_echo "28. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:333:
+ wsp  <<'EOT'
+\${FOO=bar}
+\$FOO
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:333"
+( $at_check_trace;
+ wsp  <<'EOT'
+${FOO=bar}
+$FOO
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: bar
+TOTAL: 1
+NF: 1
+0: bar
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:333"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_28
+#AT_START_29
+at_fn_group_banner 29 'wordsplit.at:344' \
+  "default error message (var defined)" "            "
+at_xfail=no
+(
+  $as_echo "29. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:344:
+FOO=bar wsp  <<'EOT'
+a \${FOO:?} test
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:344"
+( $at_check_trace;
+FOO=bar wsp  <<'EOT'
+a ${FOO:?} test
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: a
+1: bar
+2: test
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:344"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_29
+#AT_START_30
+at_fn_group_banner 30 'wordsplit.at:355' \
+  "default error message" "                          "
+at_xfail=no
+(
+  $as_echo "30. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:355:
+ wsp  <<'EOT'
+\${FOO:?}
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:355"
+( $at_check_trace;
+ wsp  <<'EOT'
+${FOO:?}
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; $as_echo "FOO: variable null or not set
+" | \
+  $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 0
+TOTAL: 0
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:355"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_30
+#AT_START_31
+at_fn_group_banner 31 'wordsplit.at:363' \
+  "custom error message (defined)" "                 "
+at_xfail=no
+(
+  $as_echo "31. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:363:
+FOO=bar wsp  <<'EOT'
+a \${FOO:?please define it} test
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:363"
+( $at_check_trace;
+FOO=bar wsp  <<'EOT'
+a ${FOO:?please define it} test
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: a
+1: bar
+2: test
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:363"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_31
+#AT_START_32
+at_fn_group_banner 32 'wordsplit.at:374' \
+  "custom error message" "                           "
+at_xfail=no
+(
+  $as_echo "32. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:374:
+ wsp  <<'EOT'
+a \${FOO:?please define it} test
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:374"
+( $at_check_trace;
+ wsp  <<'EOT'
+a ${FOO:?please define it} test
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; $as_echo "FOO: please define it
+" | \
+  $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 2
+0: a
+1: test
+TOTAL: 2
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:374"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_32
+#AT_START_33
+at_fn_group_banner 33 'wordsplit.at:384' \
+  "alternate value (defined)" "                      "
+at_xfail=no
+(
+  $as_echo "33. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:384:
+FOO=bar wsp  <<'EOT'
+a \${FOO:+isset} test
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:384"
+( $at_check_trace;
+FOO=bar wsp  <<'EOT'
+a ${FOO:+isset} test
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: a
+1: isset
+2: test
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:384"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_33
+#AT_START_34
+at_fn_group_banner 34 'wordsplit.at:395' \
+  "alternate value" "                                "
+at_xfail=no
+(
+  $as_echo "34. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:395:
+unset FOO; wsp  <<'EOT'
+a \${FOO:+isset} test
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:395"
+( $at_check_trace;
+unset FOO; wsp  <<'EOT'
+a ${FOO:+isset} test
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 2
+0: a
+1: test
+TOTAL: 2
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:395"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_34
+#AT_START_35
+at_fn_group_banner 35 'wordsplit.at:405' \
+  "getvar" "                                         "
+at_xfail=no
+(
+  $as_echo "35. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:405: unset foo; unset x
+ wsp foo=bar x=quux <<'EOT'
+begin \$foo \$x end
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:405"
+( $at_check_trace; unset foo; unset x
+ wsp foo=bar x=quux <<'EOT'
+begin $foo $x end
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 4
+0: begin
+1: bar
+2: quux
+3: end
+TOTAL: 4
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:405"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_35
+#AT_START_36
+at_fn_group_banner 36 'wordsplit.at:419' \
+  "getvar and env" "                                 "
+at_xfail=no
+(
+  $as_echo "36. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:419: unset foo; unset x
+TVAR=12 y=zwar wsp foo=bar x=quux y=xur <<'EOT'
+begin \$foo \$TVAR \$x \$y end
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:419"
+( $at_check_trace; unset foo; unset x
+TVAR=12 y=zwar wsp foo=bar x=quux y=xur <<'EOT'
+begin $foo $TVAR $x $y end
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 6
+0: begin
+1: bar
+2: 12
+3: quux
+4: zwar
+5: end
+TOTAL: 6
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:419"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_36
+#AT_START_37
+at_fn_group_banner 37 'wordsplit.at:435' \
+  "getvar, alternate value" "                        "
+at_xfail=no
+(
+  $as_echo "37. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:435:
+ wsp foo=bar <<'EOT'
+a \${foo:+isset}
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:435"
+( $at_check_trace;
+ wsp foo=bar <<'EOT'
+a ${foo:+isset}
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 2
+0: a
+1: isset
+TOTAL: 2
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:435"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_37
+#AT_START_38
+at_fn_group_banner 38 'wordsplit.at:446' \
+  "ignore quotes" "                                  "
+at_xfail=no
+(
+  $as_echo "38. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:446:
+ wsp -noquote <<'EOT'
+\"a text\"
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:446"
+( $at_check_trace;
+ wsp -noquote <<'EOT'
+"a text"
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 2
+0: \"\\\"a\"
+1: \"text\\\"\"
+TOTAL: 2
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:446"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_38
+#AT_START_39
+at_fn_group_banner 39 'wordsplit.at:456' \
+  "custom delimiters (squeeze)" "                    "
+at_xfail=no
+(
+  $as_echo "39. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:456:
+ wsp -delim : -nows -trimnl <<'EOT'
+semicolon: separated::list: of :words
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:456"
+( $at_check_trace;
+ wsp -delim : -nows -trimnl <<'EOT'
+semicolon: separated::list: of :words
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 5
+0: semicolon
+1: \" separated\"
+2: list
+3: \" of \"
+4: words
+TOTAL: 5
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:456"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_39
+#AT_START_40
+at_fn_group_banner 40 'wordsplit.at:468' \
+  "custom delimiters (no squeeze)" "                 "
+at_xfail=no
+(
+  $as_echo "40. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:468:
+ wsp -delim : -nows -nosqueeze_delims -trimnl <<'EOT'
+semicolon: separated::list: of :words
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:468"
+( $at_check_trace;
+ wsp -delim : -nows -nosqueeze_delims -trimnl <<'EOT'
+semicolon: separated::list: of :words
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 6
+0: semicolon
+1: \" separated\"
+2: \"\"
+3: list
+4: \" of \"
+5: words
+TOTAL: 6
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:468"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_40
+#AT_START_41
+at_fn_group_banner 41 'wordsplit.at:481' \
+  "custom, with returned delimiters" "               "
+at_xfail=no
+(
+  $as_echo "41. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:481:
+ wsp -delim : -nows -trimnl -return_delims <<'EOT'
+semicolon: separated::list: of :words
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:481"
+( $at_check_trace;
+ wsp -delim : -nows -trimnl -return_delims <<'EOT'
+semicolon: separated::list: of :words
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 9
+0: semicolon
+1: :
+2: \" separated\"
+3: :
+4: list
+5: :
+6: \" of \"
+7: :
+8: words
+TOTAL: 9
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:481"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_41
+#AT_START_42
+at_fn_group_banner 42 'wordsplit.at:497' \
+  "custom, with returned & squeezed delimiters" "    "
+at_xfail=no
+(
+  $as_echo "42. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:497:
+ wsp -delim : -nows -trimnl -return_delims -nosqueeze_delims <<'EOT'
+semicolon: separated::list: of :words
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:497"
+( $at_check_trace;
+ wsp -delim : -nows -trimnl -return_delims -nosqueeze_delims <<'EOT'
+semicolon: separated::list: of :words
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 10
+0: semicolon
+1: :
+2: \" separated\"
+3: :
+4: :
+5: list
+6: :
+7: \" of \"
+8: :
+9: words
+TOTAL: 10
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:497"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_42
+#AT_START_43
+at_fn_group_banner 43 'wordsplit.at:516' \
+  "sed expressions" "                                "
+at_xfail=no
+(
+  $as_echo "43. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:516:
+ wsp -sed <<'EOT'
+arg1 s/foo/bar/g;s/bar baz/quz quux/ arg2
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:516"
+( $at_check_trace;
+ wsp -sed <<'EOT'
+arg1 s/foo/bar/g;s/bar baz/quz quux/ arg2
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: arg1
+1: \"s/foo/bar/g;s/bar baz/quz quux/\"
+2: arg2
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:516"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_43
+#AT_START_44
+at_fn_group_banner 44 'wordsplit.at:527' \
+  "C escapes on" "                                   "
+at_xfail=no
+(
+  $as_echo "44. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:527:
+ wsp -cescapes <<'EOT'
+a\\ttab form\\ffeed and new\\nline
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:527"
+( $at_check_trace;
+ wsp -cescapes <<'EOT'
+a\ttab form\ffeed and new\nline
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 4
+0: a\\ttab
+1: form\\ffeed
+2: and
+3: new\\nline
+TOTAL: 4
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:527"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_44
+#AT_START_45
+at_fn_group_banner 45 'wordsplit.at:537' \
+  "C escapes off" "                                  "
+at_xfail=no
+(
+  $as_echo "45. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:537:
+ wsp -nocescapes <<'EOT'
+a\\ttab form\\ffeed and new\\nline
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:537"
+( $at_check_trace;
+ wsp -nocescapes <<'EOT'
+a\ttab form\ffeed and new\nline
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 4
+0: attab
+1: formffeed
+2: and
+3: newnline
+TOTAL: 4
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:537"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_45
+#AT_START_46
+at_fn_group_banner 46 'wordsplit.at:547' \
+  "ws elimination" "                                 "
+at_xfail=no
+(
+  $as_echo "46. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:547:
+ wsp -delim ' ()' -ws -return_delims <<'EOT'
+( list  items  )
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:547"
+( $at_check_trace;
+ wsp -delim ' ()' -ws -return_delims <<'EOT'
+( list  items  )
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 4
+0: (
+1: list
+2: items
+3: )
+TOTAL: 4
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:547"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_46
+#AT_START_47
+at_fn_group_banner 47 'wordsplit.at:557' \
+  "ws elimination + return delim" "                  "
+at_xfail=no
+(
+  $as_echo "47. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:557:
+ wsp -nodefault -novar -nocmd -delim \":,\" -return_delims -ws -dquote <<'EOT'
+\"foo\" : \"bar\", \"quux\" : \"baaz\"
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:557"
+( $at_check_trace;
+ wsp -nodefault -novar -nocmd -delim ":," -return_delims -ws -dquote <<'EOT'
+"foo" : "bar", "quux" : "baaz"
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 7
+0: foo
+1: :
+2: bar
+3: ,
+4: quux
+5: :
+6: baaz
+TOTAL: 7
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:557"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_47
+#AT_START_48
+at_fn_group_banner 48 'wordsplit.at:571' \
+  "empty quotes" "                                   "
+at_xfail=no
+(
+  $as_echo "48. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:571:
+ wsp -delim : -ws -return_delims <<'EOT'
+t=\"\"
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:571"
+( $at_check_trace;
+ wsp -delim : -ws -return_delims <<'EOT'
+t=""
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: t=
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:571"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_48
+#AT_START_49
+at_fn_group_banner 49 'wordsplit.at:578' \
+  "delimiter following empty quotes" "               "
+at_xfail=no
+(
+  $as_echo "49. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:578:
+ wsp -delim : -ws -return_delims <<'EOT'
+t=\"\":r
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:578"
+( $at_check_trace;
+ wsp -delim : -ws -return_delims <<'EOT'
+t="":r
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: t=
+1: :
+2: r
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:578"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_49
+#AT_START_50
+at_fn_group_banner 50 'wordsplit.at:588' \
+  "suppress ws trimming within quotes" "             "
+at_xfail=no
+(
+  $as_echo "50. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:588:
+ wsp -default -delim , -ws -return_delims <<'EOT'
+nocomponent,nonewline, formatfield=\"In message %{text}, \"
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:588"
+( $at_check_trace;
+ wsp -default -delim , -ws -return_delims <<'EOT'
+nocomponent,nonewline, formatfield="In message %{text}, "
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 5
+0: nocomponent
+1: ,
+2: nonewline
+3: ,
+4: \"formatfield=In message %{text}, \"
+TOTAL: 5
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:588"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_50
+#AT_START_51
+at_fn_group_banner 51 'wordsplit.at:601' \
+  "unescape" "                                       "
+at_xfail=no
+(
+  $as_echo "51. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:601:
+ wsp -nodefault -novar -nocmd -quote -escape ':+:\\\\\"\"' <<'EOT'
+\\Seen \"quote \\\"\" \"bs \\\\\"
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:601"
+( $at_check_trace;
+ wsp -nodefault -novar -nocmd -quote -escape ':+:\\""' <<'EOT'
+\Seen "quote \"" "bs \\"
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: \\\\Seen
+1: \"quote \\\"\"
+2: \"bs \\\\\"
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:601"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_51
+#AT_START_52
+at_fn_group_banner 52 'wordsplit.at:612' \
+  "unescape: word/quote" "                           "
+at_xfail=no
+(
+  $as_echo "52. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:612:
+ wsp -nodefault -novar -nocmd -quote -escape-word '\\\\\"\"' -escape-quote ':+0x:\\\\\"\"' <<'EOT'
+\\Seen \"quote \\\"\" \"bs \\\\\" \"3\\x31 \\101\" 3\\x31 \\101
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:612"
+( $at_check_trace;
+ wsp -nodefault -novar -nocmd -quote -escape-word '\\""' -escape-quote ':+0x:\\""' <<'EOT'
+\Seen "quote \"" "bs \\" "3\x31 \101" 3\x31 \101
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 6
+0: Seen
+1: \"quote \\\"\"
+2: \"bs \\\\\"
+3: \"31 A\"
+4: 3x31
+5: 101
+TOTAL: 6
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:612"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_52
+#AT_START_53
+at_fn_group_banner 53 'wordsplit.at:626' \
+  "dquote" "                                         "
+at_xfail=no
+(
+  $as_echo "53. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:626:
+ wsp -nodefault -novar -nocmd -dquote <<'EOT'
+a \"quoted example\" isn't it
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:626"
+( $at_check_trace;
+ wsp -nodefault -novar -nocmd -dquote <<'EOT'
+a "quoted example" isn't it
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 4
+0: a
+1: \"quoted example\"
+2: isn't
+3: it
+TOTAL: 4
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:626"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_53
+#AT_START_54
+at_fn_group_banner 54 'wordsplit.at:636' \
+  "squote" "                                         "
+at_xfail=no
+(
+  $as_echo "54. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:636:
+ wsp -nodefault -novar -nocmd -squote <<'EOT'
+a 'quoted example' isn\"t it
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:636"
+( $at_check_trace;
+ wsp -nodefault -novar -nocmd -squote <<'EOT'
+a 'quoted example' isn"t it
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 4
+0: a
+1: \"quoted example\"
+2: \"isn\\\"t\"
+3: it
+TOTAL: 4
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:636"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_54
+#AT_START_55
+at_fn_group_banner 55 'wordsplit.at:648' \
+  "incremental" "                                    "
+at_xfail=no
+(
+  $as_echo "55. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:648:
+ wsp -incremental <<'EOT'
+incremental \"input test\" line
+
+
+
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:648"
+( $at_check_trace;
+ wsp -incremental <<'EOT'
+incremental "input test" line
+
+
+
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; $as_echo "input exhausted
+" | \
+  $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: incremental
+TOTAL: 1
+NF: 1
+0: \"input test\"
+TOTAL: 2
+NF: 1
+0: line
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:648"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_55
+#AT_START_56
+at_fn_group_banner 56 'wordsplit.at:666' \
+  "incremental append" "                             "
+at_xfail=no
+(
+  $as_echo "56. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:666:
+ wsp -incremental -append <<'EOT'
+incremental \"input test\" line
+
+
+
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:666"
+( $at_check_trace;
+ wsp -incremental -append <<'EOT'
+incremental "input test" line
+
+
+
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; $as_echo "input exhausted
+" | \
+  $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: incremental
+TOTAL: 1
+NF: 2
+0: incremental
+1: \"input test\"
+TOTAL: 2
+NF: 3
+0: incremental
+1: \"input test\"
+2: line
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:666"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_56
+#AT_START_57
+at_fn_group_banner 57 'wordsplit.at:687' \
+  "incremental ws" "                                 "
+at_xfail=no
+(
+  $as_echo "57. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:687:
+ wsp -return_delims -nosqueeze_delims -incremental -ws <<'EOT'
+a   list  test
+
+
+
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:687"
+( $at_check_trace;
+ wsp -return_delims -nosqueeze_delims -incremental -ws <<'EOT'
+a   list  test
+
+
+
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; $as_echo "input exhausted
+" | \
+  $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: a
+TOTAL: 1
+NF: 1
+0: list
+TOTAL: 2
+NF: 1
+0: test
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:687"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_57
+#AT_START_58
+at_fn_group_banner 58 'wordsplit.at:706' \
+  "incremental nosplit" "                            "
+at_xfail=no
+(
+  $as_echo "58. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:706:
+ wsp -incremental -nosplit <<'EOT'
+incremental \"input test\" line
+
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:706"
+( $at_check_trace;
+ wsp -incremental -nosplit <<'EOT'
+incremental "input test" line
+
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; $as_echo "input exhausted
+" | \
+  $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: \"incremental input test line\"
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:706"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_58
+#AT_START_59
+at_fn_group_banner 59 'wordsplit.at:716' \
+  "simple command substitution" "                    "
+at_xfail=no
+(
+  $as_echo "59. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:716:
+ wsp -cmd <<'EOT'
+begin \$(words a b) end
+EOT
+"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:716"
+( $at_check_trace;
+ wsp -cmd <<'EOT'
+begin $(words a b) end
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 4
+0: begin
+1: a
+2: b
+3: end
+TOTAL: 4
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:716"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_59
+#AT_START_60
+at_fn_group_banner 60 'wordsplit.at:726' \
+  "quoted command substitution" "                    "
+at_xfail=no
+(
+  $as_echo "60. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:726:
+ wsp -cmd <<'EOT'
+begin \"\$(words a b)\" end
+EOT
+"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:726"
+( $at_check_trace;
+ wsp -cmd <<'EOT'
+begin "$(words a b)" end
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: begin
+1: \"a b\"
+2: end
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:726"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_60
+#AT_START_61
+at_fn_group_banner 61 'wordsplit.at:735' \
+  "coalesced command substitution" "                 "
+at_xfail=no
+(
+  $as_echo "61. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:735:
+ wsp -cmd <<'EOT'
+begin(\$(words a b))end
+EOT
+"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:735"
+( $at_check_trace;
+ wsp -cmd <<'EOT'
+begin($(words a b))end
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 2
+0: begin(a
+1: b)end
+TOTAL: 2
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:735"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_61
+#AT_START_62
+at_fn_group_banner 62 'wordsplit.at:743' \
+  "quoted coalesced command substitution" "          "
+at_xfail=no
+(
+  $as_echo "62. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:743:
+ wsp -cmd <<'EOT'
+\"begin(\$(words a b))end\"
+EOT
+"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:743"
+( $at_check_trace;
+ wsp -cmd <<'EOT'
+"begin($(words a b))end"
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: \"begin(a b)end\"
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:743"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_62
+#AT_START_63
+at_fn_group_banner 63 'wordsplit.at:750' \
+  "variable and command substitution" "              "
+at_xfail=no
+(
+  $as_echo "63. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:750:
+X=a Y=b wsp -cmd -var <<'EOT'
+begin \$X \$(words \$X \$Y) end
+EOT
+"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:750"
+( $at_check_trace;
+X=a Y=b wsp -cmd -var <<'EOT'
+begin $X $(words $X $Y) end
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 5
+0: begin
+1: a
+2: a
+3: b
+4: end
+TOTAL: 5
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:750"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_63
+#AT_START_64
+at_fn_group_banner 64 'wordsplit.at:761' \
+  "variable expansion and command substitution in quotes" ""
+at_xfail=no
+(
+  $as_echo "64. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:761:
+X=a Y=b BEGIN=begin wsp -cmd -var <<'EOT'
+\"\${BEGIN}(\$(words \$X \$Y))end\"
+EOT
+"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:761"
+( $at_check_trace;
+X=a Y=b BEGIN=begin wsp -cmd -var <<'EOT'
+"${BEGIN}($(words $X $Y))end"
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: \"begin(a b)end\"
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:761"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_64
+#AT_START_65
+at_fn_group_banner 65 'wordsplit.at:768' \
+  "nested commands" "                                "
+at_xfail=no
+(
+  $as_echo "65. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:768:
+SUFFIX=put wsp -cmd -var <<'EOT'
+\$(words output \$(words in\$SUFFIX text) end)
+EOT
+"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:768"
+( $at_check_trace;
+SUFFIX=put wsp -cmd -var <<'EOT'
+$(words output $(words in$SUFFIX text) end)
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 4
+0: output
+1: input
+2: text
+3: end
+TOTAL: 4
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:768"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_65
+#AT_START_66
+at_fn_group_banner 66 'wordsplit.at:779' \
+  "pathname expansion" "                             "
+at_xfail=no
+(
+  $as_echo "66. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:781:
+mkdir dir
+> dir/1.c
+> dir/2.c
+> dir/3.b
+
+wsp -pathexpand<<'EOT'
+begin dir/*.c end
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:781"
+( $at_check_trace;
+mkdir dir
+> dir/1.c
+> dir/2.c
+> dir/3.b
+
+wsp -pathexpand<<'EOT'
+begin dir/*.c end
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 4
+0: begin
+1: dir/1.c
+2: dir/2.c
+3: end
+TOTAL: 4
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:781"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_66
+#AT_START_67
+at_fn_group_banner 67 'wordsplit.at:801' \
+  "pathname expansion: no match" "                   "
+at_xfail=no
+(
+  $as_echo "67. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:803:
+mkdir dir
+> dir/1.c
+> dir/2.b
+
+wsp -pathexpand<<'EOT'
+begin dir/*.d end
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:803"
+( $at_check_trace;
+mkdir dir
+> dir/1.c
+> dir/2.b
+
+wsp -pathexpand<<'EOT'
+begin dir/*.d end
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: begin
+1: dir/*.d
+2: end
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:803"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_67
+#AT_START_68
+at_fn_group_banner 68 'wordsplit.at:821' \
+  "pathname expansion: nullglob" "                   "
+at_xfail=no
+(
+  $as_echo "68. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:823:
+mkdir dir
+> dir/1.c
+> dir/2.b
+
+wsp -pathexpand -nullglob<<'EOT'
+begin dir/*.d end
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:823"
+( $at_check_trace;
+mkdir dir
+> dir/1.c
+> dir/2.b
+
+wsp -pathexpand -nullglob<<'EOT'
+begin dir/*.d end
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 2
+0: begin
+1: end
+TOTAL: 2
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:823"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_68
+#AT_START_69
+at_fn_group_banner 69 'wordsplit.at:840' \
+  "pathname expansion: failglob" "                   "
+at_xfail=no
+(
+  $as_echo "69. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:842:
+mkdir dir
+> dir/1.c
+> dir/2.b
+
+wsp -pathexpand -failglob<<'EOT'
+begin dir/*.d end
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:842"
+( $at_check_trace;
+mkdir dir
+> dir/1.c
+> dir/2.b
+
+wsp -pathexpand -failglob<<'EOT'
+begin dir/*.d end
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; $as_echo "no files match pattern dir/*.d
+" | \
+  $at_diff - "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:842"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_69
+#AT_START_70
+at_fn_group_banner 70 'wordsplit.at:857' \
+  "append" "                                         "
+at_xfail=no
+(
+  $as_echo "70. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:857:
+ wsp -append-args extra arguments follow <<'EOT'
+some words and
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:857"
+( $at_check_trace;
+ wsp -append-args extra arguments follow <<'EOT'
+some words and
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 6
+0: some
+1: words
+2: and
+3: extra
+4: arguments
+5: follow
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:857"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_70
+#AT_START_71
+at_fn_group_banner 71 'wordsplit.at:869' \
+  "append + dooffs + env" "                          "
+at_xfail=no
+(
+  $as_echo "71. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:869:
+ wsp -env none -dooffs preface words -- V=2 -append-args extra arguments follow <<'EOT'
+some words and var=\$V
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:869"
+( $at_check_trace;
+ wsp -env none -dooffs preface words -- V=2 -append-args extra arguments follow <<'EOT'
+some words and var=$V
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 7 (2)
+(0): preface
+(1): words
+2: some
+3: words
+4: and
+5: var=2
+6: extra
+7: arguments
+8: follow
+TOTAL: 4
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:869"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_71
+#AT_START_72
+at_fn_group_banner 72 'wordsplit.at:886' \
+  "maxwords" "                                       "
+at_xfail=no
+(
+  $as_echo "72. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:886:
+ wsp -trimnl -maxwords 3 <<'EOT'
+ws_maxwords  limits the   number of returned words
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:886"
+( $at_check_trace;
+ wsp -trimnl -maxwords 3 <<'EOT'
+ws_maxwords  limits the   number of returned words
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: ws_maxwords
+1: limits
+2: \"the   number of returned words\"
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:886"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_72
+#AT_START_73
+at_fn_group_banner 73 'wordsplit.at:896' \
+  "maxwords return_delims" "                         "
+at_xfail=no
+(
+  $as_echo "73. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:896:
+ wsp -trimnl -maxwords 8 -return_delims -delim :- <<'EOT'
+foo:::bar-:baz-quux:ux:zu
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:896"
+( $at_check_trace;
+ wsp -trimnl -maxwords 8 -return_delims -delim :- <<'EOT'
+foo:::bar-:baz-quux:ux:zu
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 8
+0: foo
+1: :
+2: bar
+3: -
+4: :
+5: baz
+6: -
+7: quux:ux:zu
+TOTAL: 8
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:896"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_73
+#AT_START_74
+at_fn_group_banner 74 'wordsplit.at:911' \
+  "maxwords return_delims -squeeze_delims" "         "
+at_xfail=no
+(
+  $as_echo "74. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:911:
+ wsp -trimnl -maxwords 8 -return_delims -nosqueeze_delims -delim :- <<'EOT'
+foo:::bar-:baz:qux-
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:911"
+( $at_check_trace;
+ wsp -trimnl -maxwords 8 -return_delims -nosqueeze_delims -delim :- <<'EOT'
+foo:::bar-:baz:qux-
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 8
+0: foo
+1: :
+2: :
+3: :
+4: bar
+5: -
+6: :
+7: baz:qux-
+TOTAL: 8
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:911"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_74
+#AT_START_75
+at_fn_group_banner 75 'wordsplit.at:926' \
+  "maxwords incremental" "                           "
+at_xfail=no
+(
+  $as_echo "75. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:926:
+ wsp -trimnl -maxwords 3 -incremental <<'EOT'
+foo  bar	baz qux  uz
+
+
+
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:926"
+( $at_check_trace;
+ wsp -trimnl -maxwords 3 -incremental <<'EOT'
+foo  bar	baz qux  uz
+
+
+
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; $as_echo "input exhausted
+" | \
+  $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: foo
+TOTAL: 1
+NF: 1
+0: bar
+TOTAL: 2
+NF: 1
+0: \"baz qux  uz\"
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:926"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_75
+#AT_START_76
+at_fn_group_banner 76 'wordsplit.at:945' \
+  "variable nosplit" "                               "
+at_xfail=no
+(
+  $as_echo "76. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:945:
+ wsp -novar -novarsplit <<'EOT'
+begin \${VAR:- a b} end
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:945"
+( $at_check_trace;
+ wsp -novar -novarsplit <<'EOT'
+begin ${VAR:- a b} end
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: begin
+1: \"\${VAR:- a b}\"
+2: end
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:945"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_76
+#AT_START_77
+at_fn_group_banner 77 'wordsplit.at:954' \
+  "command nosplit" "                                "
+at_xfail=no
+(
+  $as_echo "77. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:954:
+ wsp -nocmd -nocmdsplit <<'EOT'
+begin \$(words a b) end
+EOT
+"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "wordsplit.at:954"
+( $at_check_trace;
+ wsp -nocmd -nocmdsplit <<'EOT'
+begin $(words a b) end
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: begin
+1: \"\$(words a b)\"
+2: end
+TOTAL: 3
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:954"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_77
+#AT_START_78
+at_fn_group_banner 78 'wordsplit.at:963' \
+  "positional parameters" "                          "
+at_xfail=no
+(
+  $as_echo "78. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:963:
+ wsp one two three four five six seven eight nine ten eleven twelve <<'EOT'
+\$0 \$5 \${10}
+\$#
+EOT
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "wordsplit.at:963"
+( $at_check_trace;
+ wsp one two three four five six seven eight nine ten eleven twelve <<'EOT'
+$0 $5 ${10}
+$#
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 3
+0: one
+1: six
+2: eleven
+TOTAL: 3
+NF: 1
+0: 12
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:963"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_78
+#AT_START_79
+at_fn_group_banner 79 'wordsplit.at:976' \
+  "\$* and \$@" "                                      "
+at_xfail=no
+(
+  $as_echo "79. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:976:
+ wsp 'one two' three 'four five' <<'EOT'
+\$*
+\$@
+\"\$*\"
+\"\$@\"
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:976"
+( $at_check_trace;
+ wsp 'one two' three 'four five' <<'EOT'
+$*
+$@
+"$*"
+"$@"
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 5
+0: one
+1: two
+2: three
+3: four
+4: five
+TOTAL: 5
+NF: 3
+0: \"one two\"
+1: three
+2: \"four five\"
+TOTAL: 3
+NF: 1
+0: \"one two three four five\"
+TOTAL: 1
+NF: 1
+0: \"one two three four five\"
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:976"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_79
+#AT_START_80
+at_fn_group_banner 80 'wordsplit.at:1001' \
+  "\$* and \$@ in nosplit mode" "                      "
+at_xfail=no
+(
+  $as_echo "80. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:1001:
+ wsp -trimnl -nosplit 'one two' three 'four five' <<'EOT'
+\$*
+\$@
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:1001"
+( $at_check_trace;
+ wsp -trimnl -nosplit 'one two' three 'four five' <<'EOT'
+$*
+$@
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: \"one two three four five\"
+TOTAL: 1
+NF: 1
+0: \"one two three four five\"
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:1001"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_80
+#AT_START_81
+at_fn_group_banner 81 'wordsplit.at:1013' \
+  "\$* and \$@ in nosplit mode with delimiter" "       "
+at_xfail=no
+(
+  $as_echo "81. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+{ set +x
+$as_echo "$at_srcdir/wordsplit.at:1013:
+ wsp -trimnl -nosplit -delim : 'one two' three 'four five' <<'EOT'
+\$*
+\$@
+EOT
+"
+at_fn_check_prepare_notrace 'an embedded newline' "wordsplit.at:1013"
+( $at_check_trace;
+ wsp -trimnl -nosplit -delim : 'one two' three 'four five' <<'EOT'
+$*
+$@
+EOT
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "NF: 1
+0: \"one two:three:four five\"
+TOTAL: 1
+NF: 1
+0: \"one two:three:four five\"
+TOTAL: 1
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/wordsplit.at:1013"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_81
diff --git a/grecs/tests/wordsplit.at b/grecs/wordsplit/wordsplit.at
similarity index 60%
rename from grecs/tests/wordsplit.at
rename to grecs/wordsplit/wordsplit.at
index 895a392..52a4a75 100644
--- a/grecs/tests/wordsplit.at
+++ b/grecs/wordsplit/wordsplit.at
@@ -1,20 +1,21 @@
-# This file is part of grecs  -*- Autotest -*-
-# Copyright (C) 2014-2016 Sergey Poznyakoff
+# Test suite for wordsplit -*- Autotest -*-
+# Copyright (C) 2014-2019 Sergey Poznyakoff
 #
-# Grecs is free software; you can redistribute it and/or modify
+# Wordsplit 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, or (at your option)
 # any later version.
 #
-# Grecs is distributed in the hope that it will be useful,
+# Wordsplit 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/>.
+# along with wordsplit.  If not, see <http://www.gnu.org/licenses/>.
 
-AT_BANNER(Wordsplit)
+AT_INIT
+AT_TESTED(wsp)
 
 m4_pushdef([wspnum],[0])
 m4_pushdef([wspid])
@@ -61,12 +62,14 @@ TESTWSP([simple input],[wsp-simple],[],
 0: 1
 1: 2
 2: 3
+TOTAL: 3
 ])
 
 TESTWSP([quoted space],[wsp-quoted],[],
 [quoted\ space],
 [NF: 1
 0: "quoted space"
+TOTAL: 1
 ])
 
 TESTWSP([tab character],[wsp-tab],[],
@@ -74,6 +77,7 @@ TESTWSP([tab character],[wsp-tab],[],
 [NF: 2
 0: a
 1: tab\tcharacter
+TOTAL: 2
 ])
 
 WSPGROUP(wsp-escape)
@@ -81,6 +85,7 @@ TESTWSP([octal and hex escapes],[],[],
 [\157\143\164\141\154\40and\x20\x68\x65\x78],
 [NF: 1
 0: "octal and hex"
+TOTAL: 1
 ])
 
 TESTWSP([octal and hex escapes 2],[],[],
@@ -89,12 +94,14 @@ TESTWSP([octal and hex escapes 2],[],[],
 0: "octal "
 1: and
 2: " hex"
+TOTAL: 3
 ])
 
 TESTWSP([escape representation],[],[],
 [A\x3-\48\39],
 [NF: 1
 0: A\003-\0048\0039
+TOTAL: 1
 ])
 
 WSPGROUP()
@@ -102,7 +109,7 @@ WSPGROUP()
 dnl ------------------------------------------------------------
 dnl Test worsplit-specific behavior
 dnl ------------------------------------------------------------
-TESTWSP([append],[wsp-append],[append],
+TESTWSP([append],[wsp-append],[-append],
 [jeden dwa trzy
 cztery
 piec szesc],
@@ -110,11 +117,13 @@ piec szesc],
 0: jeden
 1: dwa
 2: trzy
+TOTAL: 3
 NF: 4
 0: jeden
 1: dwa
 2: trzy
 3: cztery
+TOTAL: 1
 NF: 6
 0: jeden
 1: dwa
@@ -122,9 +131,10 @@ NF: 6
 3: cztery
 4: piec
 5: szesc
+TOTAL: 2
 ])
 
-TESTWSP([dooffs],[wsp-doofs ],[dooffs 3 jeden dwa trzy],
+TESTWSP([dooffs],[wsp-doofs ],[-dooffs jeden dwa trzy],
 [cztery piec],
 [NF: 2 (3)
 (0): jeden
@@ -132,6 +142,7 @@ TESTWSP([dooffs],[wsp-doofs ],[dooffs 3 jeden dwa trzy],
 (2): trzy
 3: cztery
 4: piec
+TOTAL: 2
 ])
 
 WSPGROUP(wsp-var)
@@ -142,6 +153,7 @@ TESTWSP([variable substitutions: single var],[],[],
 0: a
 1: bar
 2: test
+TOTAL: 3
 ],
 [],
 [FOO=bar])
@@ -153,6 +165,7 @@ TESTWSP([variable substitutions: concatenated vars],[],
 0: a
 1: stringent
 2: test
+TOTAL: 3
 ],
 [],
 [FOO=str BAR=ing])
@@ -164,6 +177,7 @@ TESTWSP([variable substitutions: field splitting],[],[],
 1: variable
 2: substitution
 3: test
+TOTAL: 4
 ],
 [],
 [FOO="variable substitution"])
@@ -174,6 +188,7 @@ TESTWSP([variable substitutions: double-quoted variable],[],[],
 0: a
 1: "variable substitution"
 2: test
+TOTAL: 3
 ],
 [],
 [FOO="variable substitution"])
@@ -184,6 +199,7 @@ TESTWSP([variable substitutions: single-quoted variable],[],[],
 0: a
 1: $FOO
 2: test
+TOTAL: 3
 ],
 [],
 [FOO="variable substitution"])
@@ -194,88 +210,98 @@ TESTWSP([undefined variables 1],[],[],
 0: a
 1: test
 2: ab
+TOTAL: 3
 ],
 [],
 [unset FOO;])
 
-TESTWSP([undefined variables 2],[],[keepundef],
+TESTWSP([undefined variables 2],[],[-keepundef],
 [a $FOO test a${FOO}b],
 [NF: 4
 0: a
 1: $FOO
 2: test
 3: a${FOO}b
+TOTAL: 4
 ],
 [],
 [unset FOO;])
 
-TESTWSP([warn about undefined variables],[],[warnundef],
+TESTWSP([warn about undefined variables],[],[-warnundef],
 [$FOO],
 [NF: 0
+TOTAL: 0
 ],
 [warning: undefined variable `FOO'
 ],
 [unset FOO;])
 
-TESTWSP([bail out on undefined variables],[],[undef],
+TESTWSP([bail out on undefined variables],[],[-undef],
 [$FOO],
 [],
-[undefined variable
+[undefined variable: FOO
 ],
 [unset FOO;])
 
-TESTWSP([disable variable expansion],[],[novar],
+TESTWSP([disable variable expansion],[],[-novar],
 [$FOO],
 [NF: 1
 0: $FOO
+TOTAL: 1
 ],
 [],
 [FOO=bar])
 
 TESTWSP([K/V environment],[wsp-env-kv wsp-env_kv],
-[env_kv],
+[-env_kv],
 [$FOO a$BAZ],
 [NF: 2
 0: bar
 1: aqux
+TOTAL: 2
 ],
 [],
 [FOO=bar BAZ=qux])
 
-TESTWSP([nosplit with expansion],[wsp-var-nosplit],[nosplit],
+TESTWSP([nosplit with variable expansion],[wsp-var-nosplit],[-nosplit],
 [a $FOO test],
 [NF: 1
 0: "a variable expansion test\n"
+TOTAL: 1
 ],
 [],
 [FOO="variable expansion"])
 
-TESTWSP([nosplit without expansion],[],[nosplit novar],
+TESTWSP([nosplit without variable expansion],[],[-nosplit -novar],
 [a $FOO test],
 [NF: 1
 0: "a $FOO test\n"
+TOTAL: 1
 ],
 [],
 [FOO="variable expansion"])
 
-TESTWSP([default value (defined)],[],[],
-[${FOO:-bar}],
+TESTWSP([nosplit: empty expansion],[],[-nosplit -trimnl],
+[$FOO],
 [NF: 1
-0: qux
+0: ""
+TOTAL: 1
 ],
 [],
-[FOO=qux])
+[FOO=""])
 
 TESTWSP([default value],[],[],
 [${FOO:-bar}],
 [NF: 1
 0: bar
+TOTAL: 1
 ])
 
 TESTWSP([default value (defined)],[],[],
 [${FOO:-bar}],
 [NF: 1
 0: qux
+TOTAL: 1
 ],
 [],
 [FOO=qux])
@@ -284,6 +310,7 @@ TESTWSP([default value (:- null)],[],[],
 [${FOO:-bar}],
 [NF: 1
 0: bar
+TOTAL: 1
 ],
 [],
 [FOO=])
@@ -291,6 +318,7 @@ TESTWSP([default value (:- null)],[],[],
 TESTWSP([default value (- null)],[],[],
 [${FOO-bar}],
 [NF: 0
+TOTAL: 0
 ],
 [],
 [FOO=])
@@ -299,6 +327,7 @@ TESTWSP([default value (- null, unset)],[],[],
 [${FOO-bar}],
 [NF: 1
 0: bar
+TOTAL: 1
 ])
 
 TESTWSP([assign default values],[],[],
@@ -306,8 +335,10 @@ TESTWSP([assign default values],[],[],
 $FOO],
 [NF: 1
 0: bar
+TOTAL: 1
 NF: 1
 0: bar
+TOTAL: 1
 ])
 
 TESTWSP([default error message (var defined)],[],[],
@@ -316,6 +347,7 @@ TESTWSP([default error message (var defined)],[],[],
 0: a
 1: bar
 2: test
+TOTAL: 3
 ],
 [],
 [FOO=bar])
@@ -323,6 +355,7 @@ TESTWSP([default error message (var defined)],[],[],
 TESTWSP([default error message],[],[],
 [${FOO:?}],
 [NF: 0
+TOTAL: 0
 ],
 [FOO: variable null or not set
 ])
@@ -333,6 +366,7 @@ TESTWSP([custom error message (defined)],[wsp-custom-err wsp-custom-err00],[],
 0: a
 1: bar
 2: test
+TOTAL: 3
 ],
 [],
 [FOO=bar])
@@ -342,6 +376,7 @@ TESTWSP([custom error message],[wsp-custom-err wsp-custom-err01],[],
 [NF: 2
 0: a
 1: test
+TOTAL: 2
 ],
 [FOO: please define it
 ])
@@ -352,6 +387,7 @@ TESTWSP([alternate value (defined)],[wsp-alt wsp-alt00],[],
 0: a
 1: isset
 2: test
+TOTAL: 3
 ],
 [],
 [FOO=bar])
@@ -361,6 +397,7 @@ TESTWSP([alternate value],[wsp-alt wsp-alt01],[],
 [NF: 2
 0: a
 1: test
+TOTAL: 2
 ],
 [],
 [unset FOO;])
@@ -373,6 +410,7 @@ TESTWSP([getvar],[wsp-getvar],
 1: bar
 2: quux
 3: end
+TOTAL: 4
 ],
 [],
 [],
@@ -388,6 +426,7 @@ TESTWSP([getvar and env],[wsp-getvar],
 3: quux
 4: zwar
 5: end
+TOTAL: 6
 ],
 [],
 [TVAR=12 y=zwar],
@@ -399,21 +438,23 @@ TESTWSP([getvar, alternate value],[wsp-getvar],
 [NF: 2
 0: a
 1: isset
+TOTAL: 2
 ])
 
 WSPGROUP()
 
-TESTWSP([ignore quotes],[wsp-ignore-quotes ],[-quote],
+TESTWSP([ignore quotes],[wsp-ignore-quotes ],[-noquote],
 ["a text"],
 [NF: 2
 0: "\"a"
 1: "text\""
+TOTAL: 2
 ])
 
 WSPGROUP(wsp-delim)
 
 TESTWSP([custom delimiters (squeeze)],[],
-[delim : -ws trimnl],
+[-delim : -nows -trimnl],
 [semicolon: separated::list: of :words],
 [NF: 5
 0: semicolon
@@ -421,10 +462,11 @@ TESTWSP([custom delimiters (squeeze)],[],
 2: list
 3: " of "
 4: words
+TOTAL: 5
 ])
 
 TESTWSP([custom delimiters (no squeeze)],[],
-[delim : -ws -squeeze_delims trimnl],
+[-delim : -nows -nosqueeze_delims -trimnl],
 [semicolon: separated::list: of :words],
 [NF: 6
 0: semicolon
@@ -433,10 +475,11 @@ TESTWSP([custom delimiters (no squeeze)],[],
 3: list
 4: " of "
 5: words
+TOTAL: 6
 ])
 
 TESTWSP([custom, with returned delimiters],[],
-[delim : -ws trimnl return_delims],
+[-delim : -nows -trimnl -return_delims],
 [semicolon: separated::list: of :words],
 [NF: 9
 0: semicolon
@@ -448,10 +491,11 @@ TESTWSP([custom, with returned delimiters],[],
 6: " of "
 7: :
 8: words
+TOTAL: 9
 ])
 
 TESTWSP([custom, with returned & squeezed delimiters],[],
-[delim : -ws trimnl return_delims -squeeze_delims],
+[-delim : -nows -trimnl -return_delims -nosqueeze_delims],
 [semicolon: separated::list: of :words],
 [NF: 10
 0: semicolon
@@ -464,49 +508,54 @@ TESTWSP([custom, with returned & squeezed delimiters],[],
 7: " of "
 8: :
 9: words
+TOTAL: 10
 ])
 
 WSPGROUP(wsp-sed)
 
-TESTWSP([sed expressions],[],[sed],
+TESTWSP([sed expressions],[],[-sed],
 [arg1 s/foo/bar/g;s/bar baz/quz quux/ arg2],
 [NF: 3
 0: arg1
 1: "s/foo/bar/g;s/bar baz/quz quux/"
 2: arg2
+TOTAL: 3
 ])
 
 WSPGROUP()
 
-TESTWSP([C escapes on],[wcp-c-escape],[cescapes],
+TESTWSP([C escapes on],[wcp-c-escape],[-cescapes],
 [a\ttab form\ffeed and new\nline],
 [NF: 4
 0: a\ttab
 1: form\ffeed
 2: and
 3: new\nline
+TOTAL: 4
 ])
 
-TESTWSP([C escapes off],[wcp-c-escape-off],[-cescapes],
+TESTWSP([C escapes off],[wcp-c-escape-off],[-nocescapes],
 [a\ttab form\ffeed and new\nline],
 [NF: 4
 0: attab
 1: formffeed
 2: and
 3: newnline
+TOTAL: 4
 ])
 
-TESTWSP([ws elimination],[wsp-ws-elim],[delim ' ()' ws return_delims],
+TESTWSP([ws elimination],[wsp-ws-elim],[-delim ' ()' -ws -return_delims],
 [( list  items  )],
 [NF: 4
 0: (
 1: list
 2: items
 3: )
+TOTAL: 4
 ])
 
 TESTWSP([ws elimination + return delim],[wsp-ws-elim-ret],
-[-default novar nocmd delim ":," return_delims ws dquote],
+[-nodefault -novar -nocmd -delim ":," -return_delims -ws -dquote],
 ["foo" : "bar", "quux" : "baaz" ],
 [NF: 7
 0: foo
@@ -516,26 +565,29 @@ TESTWSP([ws elimination + return delim],[wsp-ws-elim-ret],
 4: quux
 5: :
 6: baaz
+TOTAL: 7
 ])
 
-TESTWSP([empty quotes],[wsp-empty-quotes],[delim : ws return_delims],
+TESTWSP([empty quotes],[wsp-empty-quotes],[-delim : -ws -return_delims],
 [t=""],
 [NF: 1
 0: t=
+TOTAL: 1
 ])
 
 TESTWSP([delimiter following empty quotes],
-[],[delim : ws return_delims],
+[],[-delim : -ws -return_delims],
 [t="":r],
 [NF: 3
 0: t=
 1: :
 2: r
+TOTAL: 3
 ])
 
 TESTWSP([suppress ws trimming within quotes],
 [],
-[default delim , ws return_delims],
+[-default -delim , -ws -return_delims],
 [nocomponent,nonewline, formatfield="In message %{text}, "],
 [NF: 5
 0: nocomponent
@@ -543,21 +595,23 @@ TESTWSP([suppress ws trimming within quotes],
 2: nonewline
 3: ,
 4: "formatfield=In message %{text}, "
+TOTAL: 5
 ])
 
 TESTWSP([unescape],
 [wsp-unescape wsp-unescape-simple],
-[-default novar nocmd quote escape ':+:\\""'],
+[-nodefault -novar -nocmd -quote -escape ':+:\\""'],
 [\Seen "quote \"" "bs \\"],
 [NF: 3
 0: \\Seen
 1: "quote \""
 2: "bs \\"
+TOTAL: 3
 ])
 
 TESTWSP([unescape: word/quote],
 [wsp-unescape wsp-unescape-word],
-[-default novar nocmd quote escape-word '\\""' escape-quote ':+0x:\\""'],
+[-nodefault -novar -nocmd -quote -escape-word '\\""' -escape-quote ':+0x:\\""'],
 [\Seen "quote \"" "bs \\" "3\x31 \101" 3\x31 \101],
 [NF: 6
 0: Seen
@@ -566,185 +620,162 @@ TESTWSP([unescape: word/quote],
 3: "31 A"
 4: 3x31
 5: 101
+TOTAL: 6
 ])
 
-TESTWSP([dquote],[],[-default novar nocmd dquote],
+TESTWSP([dquote],[],[-nodefault -novar -nocmd -dquote],
 [a "quoted example" isn't it],
 [NF: 4
 0: a
 1: "quoted example"
 2: isn't
 3: it
+TOTAL: 4
 ])
 
-TESTWSP([squote],[],[-default novar nocmd squote],
+TESTWSP([squote],[],[-nodefault -novar -nocmd -squote],
 [a 'quoted example' isn"t it],
 [NF: 4
 0: a
 1: "quoted example"
 2: "isn\"t"
 3: it
+TOTAL: 4
 ])
 
 WSPGROUP(wsp-incr)
 
-TESTWSP([incremental],[],[incremental],
+TESTWSP([incremental],[],[-incremental],
 [incremental "input test" line
 
 
 ],
 [NF: 1
 0: incremental
+TOTAL: 1
 NF: 1
 0: "input test"
+TOTAL: 2
 NF: 1
 0: line
+TOTAL: 3
 ],
 [input exhausted
 ])
 
-TESTWSP([incremental append],[],[incremental append],
+TESTWSP([incremental append],[],[-incremental -append],
 [incremental "input test" line
 
 
 ],
 [NF: 1
 0: incremental
+TOTAL: 1
 NF: 2
 0: incremental
 1: "input test"
+TOTAL: 2
 NF: 3
 0: incremental
 1: "input test"
 2: line
+TOTAL: 3
 ],
 [input exhausted
 ])
 
 TESTWSP([incremental ws],
-[],[return_delims -squeeze_delims incremental ws],
+[],[-return_delims -nosqueeze_delims -incremental -ws],
 [a   list  test
 
 
 ],
 [NF: 1
 0: a
+TOTAL: 1
 NF: 1
 0: list
+TOTAL: 2
 NF: 1
 0: test
+TOTAL: 3
 ],
 [input exhausted
 ])
 
-
-dnl Something that doesn't fit into TESTWSP
-
-AT_SETUP([simple command substitution])
-AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-1])
-AT_CHECK([
-mkdir dir
-> dir/file
-
-wsp -nocmd <<'EOT'
-begin $(find dir) end
-EOT
+TESTWSP([incremental nosplit],[],[-incremental -nosplit],
+[incremental "input test" line
 ],
-[0],
+[NF: 1
+0: "incremental input test line"
+TOTAL: 1
+],
+[input exhausted
+])
+
+TESTWSP([simple command substitution],[],[-cmd],
+[begin $(words a b) end],
 [NF: 4
 0: begin
-1: dir
-2: dir/file
+1: a
+2: b
 3: end
+TOTAL: 4
 ])
-AT_CLEANUP
-
-AT_SETUP([quoted command substitution])
-AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-2])
-AT_CHECK([
-mkdir dir
-> dir/file
 
-wsp -nocmd <<'EOT'
-begin "$(find dir)" end
-EOT
-],
-[0],
+TESTWSP([quoted command substitution],[],[-cmd],
+[begin "$(words a b)" end],
 [NF: 3
 0: begin
-1: "dir dir/file"
+1: "a b"
 2: end
+TOTAL: 3
 ])
-AT_CLEANUP
 
-AT_SETUP([coalesced command substitution])
-AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-3])
-AT_CHECK([
-mkdir dir
-> dir/file
-
-wsp -nocmd <<'EOT'
-begin($(find dir))end
-EOT
-],
-[0],
+TESTWSP([coalesced command substitution],[],[-cmd],
+[begin($(words a b))end],
 [NF: 2
-0: begin(dir
-1: dir/file)end
+0: begin(a
+1: b)end
+TOTAL: 2
 ])
-AT_CLEANUP
-
-AT_SETUP([quoted coalesced command substitution])
-AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-4])
-AT_CHECK([
-mkdir dir
-> dir/file
 
-wsp -nocmd <<'EOT'
-"begin($(find dir))end"
-EOT
-],
-[0],
+TESTWSP([quoted coalesced command substitution],[],[-cmd],
+["begin($(words a b))end"],
 [NF: 1
-0: "begin(dir dir/file)end"
+0: "begin(a b)end"
+TOTAL: 1
 ])
-AT_CLEANUP
-
-AT_SETUP([variable and command substitution])
-AT_KEYWORDS([wordsplit wsp wsp-var wsp-var24 wsp-cmd wsp-cmd-5])
-AT_CHECK([
-mkdir dir
-> dir/file
 
-DIR=dir wsp -nocmd -novar<<'EOT'
-begin $(find $DIR) end
-EOT
-],
-[0],
-[NF: 4
+TESTWSP([variable and command substitution],[],[-cmd -var],
+[begin $X $(words $X $Y) end],
+[NF: 5
 0: begin
-1: dir
-2: dir/file
-3: end
-])
-AT_CLEANUP
-
-AT_SETUP([variable expansion and command substitution in quotes])
-AT_KEYWORDS([wordsplit wsp wsp-var wsp-var25 wsp-cmd wsp-cmd-6])
-AT_CHECK([
-mkdir dir
-> dir/file
-
-DIR=dir wsp -nocmd -novar<<'EOT'
-"begin($(find $DIR))end"
-EOT
-],
-[0],
+1: a
+2: a
+3: b
+4: end
+TOTAL: 5
+],[],[X=a Y=b])
+
+TESTWSP([variable expansion and command substitution in quotes],[],[-cmd -var],
+["${BEGIN}($(words $X $Y))end"],
 [NF: 1
-0: "begin(dir dir/file)end"
-])
-AT_CLEANUP
+0: "begin(a b)end"
+TOTAL: 1
+],[],[X=a Y=b BEGIN=begin])
 
+TESTWSP([nested commands],[],[-cmd -var],
+[$(words output $(words in$SUFFIX text) end)],
+[NF: 4
+0: output
+1: input 
+2: text
+3: end
+TOTAL: 4
+],[],[SUFFIX=put])
+
+dnl Something that doesn't fit into TESTWSP
 AT_SETUP([pathname expansion])
 AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-1])
 AT_CHECK([
@@ -753,7 +784,7 @@ mkdir dir
 > dir/2.c
 > dir/3.b
 
-wsp pathexpand<<'EOT'
+wsp -pathexpand<<'EOT'
 begin dir/*.c end
 EOT
 ],
@@ -763,6 +794,7 @@ EOT
 1: dir/1.c
 2: dir/2.c
 3: end
+TOTAL: 4
 ])
 AT_CLEANUP
 
@@ -773,7 +805,7 @@ mkdir dir
 > dir/1.c
 > dir/2.b
 
-wsp pathexpand<<'EOT'
+wsp -pathexpand<<'EOT'
 begin dir/*.d end
 EOT
 ],
@@ -782,6 +814,7 @@ EOT
 0: begin
 1: dir/*.d
 2: end
+TOTAL: 3
 ])
 AT_CLEANUP
 
@@ -792,7 +825,7 @@ mkdir dir
 > dir/1.c
 > dir/2.b
 
-wsp pathexpand nullglob<<'EOT'
+wsp -pathexpand -nullglob<<'EOT'
 begin dir/*.d end
 EOT
 ],
@@ -800,6 +833,7 @@ EOT
 [NF: 2
 0: begin
 1: end
+TOTAL: 2
 ])
 AT_CLEANUP
 
@@ -810,7 +844,7 @@ mkdir dir
 > dir/1.c
 > dir/2.b
 
-wsp pathexpand failglob<<'EOT'
+wsp -pathexpand -failglob<<'EOT'
 begin dir/*.d end
 EOT
 ],
@@ -820,6 +854,174 @@ EOT
 ])
 AT_CLEANUP
 
+TESTWSP([append],[],[-append-args extra arguments follow],
+[some words and],
+[NF: 6
+0: some
+1: words
+2: and
+3: extra
+4: arguments
+5: follow
+TOTAL: 3
+])
+
+TESTWSP([append + dooffs + env],[],
+[-env none -dooffs preface words -- V=2 -append-args extra arguments follow],
+[some words and var=$V],
+[NF: 7 (2)
+(0): preface
+(1): words
+2: some
+3: words
+4: and
+5: var=2
+6: extra
+7: arguments
+8: follow
+TOTAL: 4
+])
+
+# Maxwords
+TESTWSP([maxwords],[],
+[-trimnl -maxwords 3],
+[ws_maxwords  limits the   number of returned words],
+[NF: 3
+0: ws_maxwords
+1: limits
+2: "the   number of returned words"
+TOTAL: 3
+])
+
+TESTWSP([maxwords return_delims],[],
+[-trimnl -maxwords 8 -return_delims -delim :-],
+[foo:::bar-:baz-quux:ux:zu],
+[NF: 8
+0: foo
+1: :
+2: bar
+3: -
+4: :
+5: baz
+6: -
+7: quux:ux:zu
+TOTAL: 8
+])
+
+TESTWSP([maxwords return_delims -squeeze_delims],[],
+[-trimnl -maxwords 8 -return_delims -nosqueeze_delims -delim :-],
+[foo:::bar-:baz:qux-],
+[NF: 8
+0: foo
+1: :
+2: :
+3: :
+4: bar
+5: -
+6: :
+7: baz:qux-
+TOTAL: 8
+])
+
+TESTWSP([maxwords incremental],[],
+[-trimnl -maxwords 3 -incremental],
+[foo  bar	baz qux  uz
+
+
+],
+[NF: 1
+0: foo
+TOTAL: 1
+NF: 1
+0: bar
+TOTAL: 2
+NF: 1
+0: "baz qux  uz"
+TOTAL: 3
+],
+[input exhausted
+]))
+
+TESTWSP([variable nosplit],[],[-novar -novarsplit],
+[begin ${VAR:- a b} end],
+[NF: 3
+0: begin
+1: "${VAR:- a b}"
+2: end
+TOTAL: 3
+])
+
+TESTWSP([command nosplit],[],[-nocmd -nocmdsplit],
+[begin $(words a b) end],
+[NF: 3
+0: begin
+1: "$(words a b)"
+2: end
+TOTAL: 3
+])
+
+TESTWSP([positional parameters],[],[one two three four five six seven eight nine ten eleven twelve],
+[$0 $5 ${10}
+$#],
+[NF: 3
+0: one
+1: six
+2: eleven
+TOTAL: 3
+NF: 1
+0: 12
+TOTAL: 1
+])
+
+TESTWSP([$* and $@],[],['one two' three 'four five'],
+[$*
+$@
+"$*"
+"$@"],
+[NF: 5
+0: one
+1: two
+2: three
+3: four
+4: five
+TOTAL: 5
+NF: 3
+0: "one two"
+1: three
+2: "four five"
+TOTAL: 3
+NF: 1
+0: "one two three four five"
+TOTAL: 1
+NF: 1
+0: "one two three four five"
+TOTAL: 1
+])
+
+TESTWSP([$* and $@ in nosplit mode],[],
+[-trimnl -nosplit 'one two' three 'four five'],
+[$*
+$@],
+[NF: 1
+0: "one two three four five"
+TOTAL: 1
+NF: 1
+0: "one two three four five"
+TOTAL: 1
+])
+
+TESTWSP([$* and $@ in nosplit mode with delimiter],[],
+[-trimnl -nosplit -delim : 'one two' three 'four five'],
+[$*
+$@],
+[NF: 1
+0: "one two:three:four five"
+TOTAL: 1
+NF: 1
+0: "one two:three:four five"
+TOTAL: 1
+])
+
 m4_popdef([TESTWSP])
 m4_popdef([wspnum])
 m4_popdef([wspid])
diff --git a/grecs/src/wordsplit.c b/grecs/wordsplit/wordsplit.c
similarity index 68%
rename from grecs/src/wordsplit.c
rename to grecs/wordsplit/wordsplit.c
index e326c8c..d3ec9e1 100644
--- a/grecs/src/wordsplit.c
+++ b/grecs/wordsplit/wordsplit.c
@@ -1,5 +1,5 @@
 /* wordsplit - a word splitter
-   Copyright (C) 2009-2016 Sergey Poznyakoff
+   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
@@ -27,6 +27,7 @@
 #include <stdarg.h>
 #include <pwd.h>
 #include <glob.h>
+#include <limits.h>
 
 #if ENABLE_NLS
 # include <gettext.h>
@@ -52,17 +53,26 @@
 
 #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 to_num(c) \
+  (ISDIGIT(c) ? c - '0' : (ISXDIGIT(c) ? toupper(c) - 'A' + 10 : 255 ))
+
 #define ALLOC_INIT 128
 #define ALLOC_INCR 128
 
 static void
 _wsplt_alloc_die (struct wordsplit *wsp)
 {
-  wsp->ws_error (_("memory exhausted"));
+  wsp->ws_error ("%s", _("memory exhausted"));
   abort ();
 }
 
+static void _wsplt_error (const char *fmt, ...)
+   __attribute__ ((format (printf, 1, 2)));
+
 static void
 _wsplt_error (const char *fmt, ...)
 {
@@ -84,7 +94,7 @@ _wsplt_seterr (struct wordsplit *wsp, int ec)
     wordsplit_perror (wsp);
   return ec;
 }
-  
+
 static int
 _wsplt_nomem (struct wordsplit *wsp)
 {
@@ -100,15 +110,46 @@ _wsplt_nomem (struct wordsplit *wsp)
   return wsp->ws_errno;
 }
 
+static void
+_wsplt_store_errctx (struct wordsplit *wsp, char const *str, size_t len)
+{
+  free (wsp->ws_errctx);
+  wsp->ws_errctx = malloc (len + 1);
+  if (!wsp->ws_errctx)
+    {
+      wsp->ws_error ("%s",
+		     _("memory exhausted while trying to store error context"));
+    }
+  else
+    {
+      memcpy (wsp->ws_errctx, str, len);
+      wsp->ws_errctx[len] = 0;
+    }
+}
+
+static inline int
+_wsplt_setctxerr (struct wordsplit *wsp, int ec, char const *str, size_t len)
+{
+  _wsplt_store_errctx (wsp, str, len);
+  return _wsplt_seterr (wsp, ec);
+}
+
 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 flags, int finalize)
 {
+  int rc;
+
   wss->ws_delim = wsp->ws_delim;
   wss->ws_debug = wsp->ws_debug;
   wss->ws_error = wsp->ws_error;
@@ -132,21 +173,38 @@ _wsplt_subsplit (struct wordsplit *wsp, struct wordsplit *wss,
     }
 
   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));
-	    
-  return wordsplit_run (str, len, wss, flags, wsp->ws_lvl + 1);
+	 | 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)
 {
+  /* Clear user-defined error */
   if (wsp->ws_errno == WRDSE_USERERR)
     free (wsp->ws_usererr);
+  /* Copy error state */
   wsp->ws_errno = wss->ws_errno;
   if (wss->ws_errno == WRDSE_USERERR)
     {
@@ -154,6 +212,10 @@ _wsplt_seterr_sub (struct wordsplit *wsp, struct wordsplit *wss)
       wss->ws_errno = WRDSE_EOF;
       wss->ws_usererr = NULL;
     }
+  /* Copy error context */
+  free (wsp->ws_errctx);
+  wsp->ws_errctx = wss->ws_errctx;
+  wss->ws_errctx = NULL;
 }
 
 static void
@@ -173,11 +235,10 @@ wordsplit_init0 (struct wordsplit *wsp)
     }
 
   wsp->ws_errno = 0;
-  wsp->ws_head = wsp->ws_tail = NULL;
 }
 
 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)
@@ -228,6 +289,9 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
   if (!(wsp->ws_flags & WRDSF_DELIM))
     wsp->ws_delim = " \t\n";
 
+  wsp->ws_sep[0] = wsp->ws_delim[0];
+  wsp->ws_sep[1] = 0;
+
   if (!(wsp->ws_flags & WRDSF_COMMENT))
     wsp->ws_comment = NULL;
 
@@ -250,8 +314,8 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
 	{
 	  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;
+	  wsp->ws_options |= WRDSO_OESC_QUOTE | WRDSO_OESC_WORD
+			     | WRDSO_XESC_QUOTE | WRDSO_XESC_WORD;
 	}
       else
 	{
@@ -260,8 +324,23 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
 	  wsp->ws_options |= WRDSO_BSKEEP_QUOTE;
 	}
     }
-  
+
+  if (!(wsp->ws_options & WRDSO_PARAMV))
+    {
+      wsp->ws_paramv = NULL;
+      wsp->ws_paramc = 0;
+    }
+  wsp->ws_paramidx = wsp->ws_paramsiz = 0;
+  wsp->ws_parambuf = NULL;
+
   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;
+
+  wsp->ws_errctx = NULL;
 
   wordsplit_init0 (wsp);
 
@@ -308,7 +387,7 @@ alloc_space (struct wordsplit *wsp, size_t count)
 #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_CONST    0x80     /* with _WSNF_WORD: v.word is constant */
 #define _WSNF_EMPTYOK  0x0100	/* special flag indicating that
 				   wordsplit_add_segm must add the
 				   segment even if it is empty */
@@ -400,7 +479,7 @@ wsnode_new (struct wordsplit *wsp, struct wordsplit_node **pnode)
 static void
 wsnode_free (struct wordsplit_node *p)
 {
-  if (p->flags & _WSNF_WORD)
+  if ((p->flags & (_WSNF_WORD|_WSNF_CONST)) == _WSNF_WORD)
     free (p->v.word);
   free (p);
 }
@@ -441,6 +520,14 @@ wsnode_remove (struct wordsplit *wsp, struct wordsplit_node *node)
   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)
@@ -456,22 +543,24 @@ wsnode_insert (struct wordsplit *wsp, struct wordsplit_node *node,
 	wsnode_insert (wsp, node, anchor->prev, 0);
       else
 	{
+	  struct wordsplit_node *tail = wsnode_tail (node);
 	  node->prev = NULL;
-	  node->next = anchor;
-	  anchor->prev = node;
+	  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 = node;
+	p->prev = tail;
       else
-	wsp->ws_tail = node;
-      node->next = p;
+	wsp->ws_tail = tail;
+      tail->next = p;
       node->prev = anchor;
       anchor->next = node;
     }
@@ -538,6 +627,9 @@ coalesce_segment (struct wordsplit *wsp, struct wordsplit_node *node)
   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);
@@ -598,9 +690,7 @@ wsnode_quoteremoval (struct wordsplit *wsp)
       int unquote;
 
       if (wsp->ws_flags & WRDSF_QUOTE)
-	{
-	  unquote = !(p->flags & _WSNF_NOEXPAND);
-	}
+	unquote = !(p->flags & _WSNF_NOEXPAND);
       else
 	unquote = 0;
 
@@ -638,43 +728,223 @@ wsnode_coalesce (struct wordsplit *wsp)
   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 *p;
   size_t n;
+  int delim;
 
-  n = 0;
+  /* Postprocess delimiters. It would be rather simple, if it weren't for
+     the incremental operation.
 
-  for (p = wsp->ws_head; p; p = p->next)
-    n++;
+     Nodes of type _WSNF_DELIM get inserted to the node list if either
+     WRDSF_RETURN_DELIMS flag or WRDSO_MAXWORDS option is set.
+
+     The following cases should be distinguished:
+
+     1. If both WRDSF_SQUEEZE_DELIMS and WRDSF_RETURN_DELIMS are set, compress
+	any runs of similar delimiter nodes to a single node. The nodes are
+	'similar' if they point to the same delimiter character.
+
+	If WRDSO_MAXWORDS option is set, stop compressing when
+	ws_wordi + 1 == ws_maxwords, and coalesce the rest of nodes into
+	a single last node.
+
+     2. If WRDSO_MAXWORDS option is set, but WRDSF_RETURN_DELIMS is not,
+	remove any delimiter nodes. Stop operation when
+	ws_wordi + 1 == ws_maxwords, and coalesce the rest of nodes into
+	a single last node.
+
+     3. If incremental operation is in progress, restart the loop any time
+	a delimiter node is about to be returned, unless WRDSF_RETURN_DELIMS
+	is set.
+  */
+ again:
+  delim = 0;         /* Delimiter being processed (if any) */
+  n = 0;             /* Number of words processed so far */
+  p = wsp->ws_head;  /* Current node */
+
+  while (p)
+    {
+      struct wordsplit_node *next = p->next;
+      if (p->flags & _WSNF_DELIM)
+	{
+	  if (wsp->ws_flags & WRDSF_RETURN_DELIMS)
+	    {
+	      if (wsp->ws_flags & WRDSF_SQUEEZE_DELIMS)
+		{
+		  char const *s = wsnode_ptr (wsp, p);
+		  if (delim)
+		    {
+		      if (delim == *s)
+			{
+			  wsnode_remove (wsp, p);
+			  p = next;
+			  continue;
+			}
+		      else
+			{
+			  delim = 0;
+			  n++; /* Count this node; it will be returned */
+			}
+		    }
+		  else
+		    {
+		      delim = *s;
+		      p = next;
+		      continue;
+		    }
+		}
+	    }
+	  else if (wsp->ws_options & WRDSO_MAXWORDS)
+	    {
+	      wsnode_remove (wsp, p);
+	      p = next;
+	      continue;
+	    }
+	}
+      else
+	{
+	  if (delim)
+	    {
+	      /* Last node was a delimiter or a compressed run of delimiters;
+		 Count it, and clear the delimiter marker */
+	      n++;
+	      delim = 0;
+	    }
+	  if (wsp->ws_options & WRDSO_MAXWORDS)
+	    {
+	      if (wsp->ws_wordi + n + 1 == wsp->ws_maxwords)
+		break;
+	    }
+	}
+      n++;
+      if (wsp->ws_flags & WRDSF_INCREMENTAL)
+	p = NULL; /* Break the loop */
+      else
+	p = next;
+    }
+
+  if (p)
+    {
+      /* We're here if WRDSO_MAXWORDS is in effect and wsp->ws_maxwords
+	 words have already been collected. Reconstruct a single final
+	 node from the remaining nodes. */
+      if (wsnode_tail_coalesce (wsp, p))
+	return wsp->ws_errno;
+      n++;
+    }
+
+  if (n == 0)
+    {
+      /* The loop above have eliminated all nodes. */
+      if (wsp->ws_flags & WRDSF_INCREMENTAL)
+	{
+	  /* Restart the processing, if there's any input left. */
+	  if (wsp->ws_endp < wsp->ws_len)
+	    {
+	      int rc;
+	      if (wsp->ws_flags & WRDSF_SHOWDBG)
+		wsp->ws_debug (_("Restarting"));
+	      rc = wordsplit_process_list (wsp, skip_delim (wsp));
+	      if (rc)
+		return rc;
+	    }
+	  else
+	    {
+	      wsp->ws_errno = WRDSE_EOF;
+	      return WRDSE_EOF;
+	    }
+	  goto again;
+	}
+
+      if (wsp->ws_flags & WRDSF_NOSPLIT)
+	{
+	  if (wordsplit_add_segm (wsp, 0, 0, _WSNF_EMPTYOK))
+	    return wsp->ws_errno;
+	  n = 1;
+	}
+    }
 
   if (alloc_space (wsp, n + 1))
-    return 1;
+    return wsp->ws_errno;
 
-  for (p = wsp->ws_head; p; p = p->next)
+  while (wsp->ws_head)
     {
-      const char *str = wsnode_ptr (wsp, p);
-      size_t slen = wsnode_len (p);
+      const char *str = wsnode_ptr (wsp, wsp->ws_head);
+      size_t slen = wsnode_len (wsp->ws_head);
       char *newstr = malloc (slen + 1);
 
       /* Assign newstr first, even if it is NULL.  This way
-         wordsplit_free will work even if we return
-         nomem later. */
+	 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;
 
+      wsnode_remove (wsp, wsp->ws_head);
+
       wsp->ws_wordc++;
+      wsp->ws_wordi++;
 
+      if (wsp->ws_flags & WRDSF_INCREMENTAL)
+	break;
     }
   wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = NULL;
   return 0;
 }
 
+int
+wordsplit_append (wordsplit_t *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 wordsplit *wsp,
@@ -712,7 +982,7 @@ node_split_prefix (struct wordsplit *wsp,
 
 static int
 find_closing_paren (const char *str, size_t i, size_t len, size_t *poff,
-		    char *paren)
+		    char const *paren)
 {
   enum { st_init, st_squote, st_dquote } state = st_init;
   size_t level = 1;
@@ -740,7 +1010,7 @@ find_closing_paren (const char *str, size_t i, size_t len, size_t *poff,
 		  break;
 		}
 	      break;
-	      
+
 	    case '"':
 	      state = st_dquote;
 	      break;
@@ -767,15 +1037,13 @@ find_closing_paren (const char *str, size_t i, size_t len, size_t *poff,
   return 1;
 }
 
-static int
-wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len,
-		    char const **ret)
+static char const *
+wsplt_env_find (struct wordsplit *wsp, const char *name, size_t len)
 {
   size_t i;
 
-  if (!(wsp->ws_flags & WRDSF_ENV))
-    return WRDSE_UNDEF;
-
+  if (!wsp->ws_env)
+    return NULL;
   if (wsp->ws_flags & WRDSF_ENV_KV)
     {
       /* A key-value pair environment */
@@ -783,17 +1051,14 @@ wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len,
 	{
 	  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 WRDSE_OK;
-	    }
+	    return wsp->ws_env[i + 1];
 	  /* Skip the value.  Break the loop if it is NULL. */
 	  i++;
 	  if (wsp->ws_env[i] == NULL)
 	    break;
 	}
     }
-  else if (wsp->ws_env)
+  else 
     {
       /* Usual (A=B) environment. */
       for (i = 0; wsp->ws_env[i]; i++)
@@ -805,22 +1070,45 @@ wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len,
 	    if (name[j] != var[j])
 	      break;
 	  if (j == len && var[j] == '=')
-	    {
-	      *ret = var + j + 1;
-	      return WRDSE_OK;
-	    }
+	    return var + j + 1;
+	}
+    }
+  return NULL;
+}
+
+static int
+wsplt_env_lookup (struct wordsplit *wsp, const char *name, size_t len,
+		  char **ret)
+{
+  if (wsp->ws_flags & WRDSF_ENV)
+    {
+      char const *val = wsplt_env_find (wsp, name, len);
+      if (val)
+	{
+	  char *retval = strdup (val);
+	  if (!retval)
+	    return WRDSE_NOSPACE;
+	  *ret = retval;
+	  return WRDSE_OK;
 	}
     }
   return WRDSE_UNDEF;
 }
 
+static int
+wsplt_env_getvar (struct wordsplit *wsp, const char *name, size_t len,
+		  char **ret)
+{
+  return wsp->ws_getvar (ret, name, len, wsp->ws_closure);
+}
+
 static int
 wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
-		  char *value)
+		  char const *value)
 {
   int n = (wsp->ws_flags & WRDSF_ENV_KV) ? 2 : 1;
   char *v;
-  
+
   if (wsp->ws_envidx + n >= wsp->ws_envsiz)
     {
       size_t sz;
@@ -837,7 +1125,7 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
 		  for (; wsp->ws_env[i]; i++)
 		    ;
 		}
-	      
+
 	      sz = i + n + 1;
 
 	      newenv = calloc (sz, sizeof(newenv[0]));
@@ -851,12 +1139,12 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
 		    {
 		      for (; j > 1; j--)
 			free (newenv[j-1]);
-		      free (newenv[j-1]);
+		      free (newenv);
 		      return _wsplt_nomem (wsp);
 		    }
 		}
 	      newenv[j] = NULL;
-	      
+
 	      wsp->ws_envbuf = newenv;
 	      wsp->ws_envidx = i;
 	      wsp->ws_envsiz = sz;
@@ -876,16 +1164,20 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
 	}
       else
 	{
-	  wsp->ws_envsiz *= 2;
-	  newenv = realloc (wsp->ws_envbuf,
-			    wsp->ws_envsiz * sizeof (wsp->ws_envbuf[0]));
+	  size_t n = wsp->ws_envsiz;
+
+	  if ((size_t) -1 / 3 * 2 / sizeof (wsp->ws_envbuf[0]) <= n)
+	    return _wsplt_nomem (wsp);
+	  n += (n + 1) / 2;
+	  newenv = realloc (wsp->ws_envbuf, n * sizeof (wsp->ws_envbuf[0]));
 	  if (!newenv)
 	    return _wsplt_nomem (wsp);
 	  wsp->ws_envbuf = newenv;
+	  wsp->ws_envsiz = n;
 	  wsp->ws_env = (const char**) wsp->ws_envbuf;
 	}
     }
-  
+
   if (wsp->ws_flags & WRDSF_ENV_KV)
     {
       /* A key-value pair environment */
@@ -914,10 +1206,170 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
       strcpy(v + namelen, value);
       wsp->ws_env[wsp->ws_envidx++] = v;
     }
-  wsp->ws_env[wsp->ws_envidx++] = NULL;
+  wsp->ws_env[wsp->ws_envidx] = NULL;
   return WRDSE_OK;
 }
 
+static int
+wsplt_assign_param (struct wordsplit *wsp, int param_idx, char *value)
+{
+  char *v;
+
+  if (param_idx < 0)
+    return _wsplt_seterr (wsp, WRDSE_BADPARAM);
+  if (param_idx == wsp->ws_paramc)
+    {
+      char **parambuf;
+      if (!wsp->ws_parambuf)
+	{
+	  size_t i;
+
+	  parambuf = calloc ((size_t)param_idx + 1, sizeof (parambuf[0]));
+	  if (!parambuf)
+	    return _wsplt_nomem (wsp);
+
+	  for (i = 0; i < wsp->ws_paramc; i++)
+	    {
+	      parambuf[i] = strdup (wsp->ws_paramv[i]);
+	      if (!parambuf[i])
+		{
+		  for (; i > 1; i--)
+		    free (parambuf[i-1]);
+		  free (parambuf);
+		  return _wsplt_nomem (wsp);
+		}
+	    }
+
+	  wsp->ws_parambuf = parambuf;
+	  wsp->ws_paramidx = param_idx;
+	  wsp->ws_paramsiz = param_idx + 1;
+	}
+      else
+	{
+	  size_t n = wsp->ws_paramsiz;
+
+	  if ((size_t) -1 / 3 * 2 / sizeof (wsp->ws_parambuf[0]) <= n)
+	    return _wsplt_nomem (wsp);
+	  n += (n + 1) / 2;
+	  parambuf = realloc (wsp->ws_parambuf, n * sizeof (wsp->ws_parambuf[0]));
+	  if (!parambuf)
+	    return _wsplt_nomem (wsp);
+	  wsp->ws_parambuf = parambuf;
+	  wsp->ws_paramsiz = n;
+	  wsp->ws_parambuf[param_idx] = NULL;
+	}
+
+      wsp->ws_paramv = (const char**) wsp->ws_parambuf;
+      wsp->ws_paramc = param_idx + 1;
+    }
+  else if (param_idx > wsp->ws_paramc)
+    return _wsplt_seterr (wsp, WRDSE_BADPARAM);
+
+  v = strdup (value);
+  if (!v)
+    return _wsplt_nomem (wsp);
+
+  free (wsp->ws_parambuf[param_idx]);
+  wsp->ws_parambuf[param_idx] = v;
+  return WRDSE_OK;
+}
+
+/* Recover from what looked like a variable reference, but turned out
+   not to be one. STR points to first character after '$'. */
+static int
+expvar_recover (struct wordsplit *wsp, const char *str,
+		struct wordsplit_node **ptail, const char **pend, int flg)
+{
+  struct wordsplit_node *newnode;
+
+  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;
+}
+
+static int
+expand_paramv (struct wordsplit *wsp, struct wordsplit_node **ptail, int flg,
+	       int q)
+{
+  struct wordsplit ws;
+  int wsflags = WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_QUOTE
+	      | (WSP_RETURN_DELIMS (wsp) ? WRDSF_RETURN_DELIMS : 0)
+	      | (q ? WRDSF_NOSPLIT : 0);
+  size_t i;
+  struct wordsplit_node *tail = *ptail;
+
+  for (i = 0; i < wsp->ws_paramc; i++)
+    {
+      struct wordsplit_node *np;
+      int rc = _wsplt_subsplit (wsp, &ws,
+				wsp->ws_paramv[i], strlen (wsp->ws_paramv[i]),
+				wsflags, q);
+      if (rc)
+	{
+	  _wsplt_seterr_sub (wsp, &ws);
+	  wordsplit_free (&ws);
+	  return 1;
+	}
+
+      if (q)
+	{
+	  if (wsnode_new (wsp, &np))
+	    return 1;
+	  wsnode_insert (wsp, np, *ptail, 0);
+	  *ptail = np;
+	  np->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg;
+	  np->v.word = ws.ws_wordv[0];
+
+	  ws.ws_wordv[0] = NULL;
+	}
+      else
+	{
+	  for (np = ws.ws_head; np; np = np->next)
+	    np->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg;
+	  wsnode_insert (wsp, ws.ws_head, *ptail, 0);
+	  *ptail = ws.ws_tail;
+	  ws.ws_head = ws.ws_tail = NULL;
+	}
+
+      wsflags |= WRDSF_REUSE;
+    }
+  if (wsflags & WRDSF_REUSE)
+    wordsplit_free (&ws);
+
+  if (flg & _WSNF_QUOTE)
+    {
+      tail = tail->next;
+      /* Insert delimiters, mark nodes as joinable */
+      while (tail != *ptail)
+	{
+	  struct wordsplit_node *next = tail->next;
+	  struct wordsplit_node *newnode;
+
+	  tail->flags |= _WSNF_JOIN;
+
+	  if (wsnode_new (wsp, &newnode))
+	    return 1;
+	  newnode->flags = _WSNF_WORD | _WSNF_CONST | _WSNF_NOEXPAND | _WSNF_JOIN;
+	  newnode->v.word = wsp->ws_sep;
+
+	  wsnode_insert (wsp, newnode, tail, 0);
+	  tail = next;
+	}
+    }
+
+  return 0;
+}
+
 static int
 expvar (struct wordsplit *wsp, const char *str, size_t len,
 	struct wordsplit_node **ptail, const char **pend, int flg)
@@ -925,12 +1377,13 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
   size_t i = 0;
   const char *defstr = NULL;
   char *value;
-  const char *vptr;
   struct wordsplit_node *newnode;
   const char *start = str - 1;
   int rc;
   struct wordsplit ws;
-  
+  int is_param = 0;
+  long param_idx = 0;
+
   if (ISVARBEG (str[0]))
     {
       for (i = 1; i < len; i++)
@@ -938,16 +1391,52 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
 	  break;
       *pend = str + i - 1;
     }
-  else if (str[0] == '{')
+  else if ((wsp->ws_options & WRDSO_PARAMV) && ISDIGIT (str[0]))
+    {
+      i = 1;
+      *pend = str;
+      is_param = 1;
+      param_idx = to_num (str[0]);
+    }
+  else if ((wsp->ws_options & WRDSO_PARAMV) && str[0] == '#')
+    {
+      char b[16];
+      snprintf (b, sizeof(b), "%d", (int) wsp->ws_paramc);
+      value = strdup (b);
+      if (!value)
+	return _wsplt_nomem (wsp);
+      if (wsnode_new (wsp, &newnode))
+	return 1;
+      wsnode_insert (wsp, newnode, *ptail, 0);
+      *ptail = newnode;
+      newnode->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg;
+      newnode->v.word = value;
+      return 0;
+    }
+  else if ((wsp->ws_options & WRDSO_PARAMV) && str[0] == '*')
+    {
+      return expand_paramv (wsp, ptail, flg, 0);
+    }
+  else if ((wsp->ws_options & WRDSO_PARAMV) && str[0] == '@')
+    {
+      return expand_paramv (wsp, ptail, flg, 1);
+    }
+  else if (str[0] == '{'
+	   && (ISVARBEG (str[1])
+	       || (is_param = (((wsp->ws_options & WRDSO_PARAMV)
+				&& ISDIGIT (str[1]))
+			       || ((wsp->ws_options & WRDSO_PARAM_NEGIDX)
+				   && (str[1] == '-'
+				       && ISDIGIT (str[2]))))) != 0))
     {
       str++;
       len--;
-      for (i = 1; i < len; i++)
+      for (i = str[0] == '-' ? 1 : 0; 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, WRDSE_CBRACE);
@@ -963,32 +1452,42 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
 	  else if (strchr ("-+?=", str[i]))
 	    {
 	      size_t j;
-	      
+
 	      defstr = str + i;
 	      if (find_closing_paren (str, i, len, &j, "{}"))
 		return _wsplt_seterr (wsp, WRDSE_CBRACE);
 	      *pend = str + j;
 	      break;
 	    }
+	  else if (is_param)
+	    {
+	      if (ISDIGIT (str[i]))
+		{
+		  param_idx = param_idx * 10 + to_num (str[i]);
+		  if ((str[0] == '-' && -param_idx < INT_MIN)
+		      || param_idx > INT_MAX)
+		    return expvar_recover (wsp, str - 1, ptail, pend, flg);
+		}
+	      else
+		{
+		  return expvar_recover (wsp, str - 1, ptail, pend, flg);
+		}
+	    }
+	  else if (!ISVARCHR (str[i]))
+	    {
+	      return expvar_recover (wsp, str - 1, ptail, pend, flg);
+	    }
 	}
+
+      if (is_param && str[0] == '-')
+	param_idx = wsp->ws_paramc - param_idx;
+
       if (i == len)
 	return _wsplt_seterr (wsp, 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;
+      return expvar_recover (wsp, str, ptail, pend, flg);
     }
 
   /* Actually expand the variable */
@@ -1003,25 +1502,49 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
     }
   else
     {
-      rc = wordsplit_find_env (wsp, str, i, &vptr);
-      if (rc == WRDSE_OK)
+      if (is_param)
 	{
-	  value = strdup (vptr);
-	  if (!value)
-	    rc = WRDSE_NOSPACE;
+	  if (param_idx >= 0 && param_idx < wsp->ws_paramc)
+	    {
+	      value = strdup (wsp->ws_paramv[param_idx]);
+	      if (!value)
+		rc = WRDSE_NOSPACE;
+	      else
+		rc = WRDSE_OK;
+	    }
+	  else
+	    rc = WRDSE_UNDEF;
 	}
-      else if (wsp->ws_flags & WRDSF_GETVAR)
-	rc = wsp->ws_getvar (&value, str, i, wsp->ws_closure);
       else
-	rc = WRDSE_UNDEF;
+	{
+	  if (wsp->ws_flags & WRDSF_GETVAR)
+	    {
+	      if (wsp->ws_options & WRDSO_GETVARPREF)
+		{
+		  rc = wsplt_env_getvar (wsp, str, i, &value);
+		  if (rc == WRDSE_UNDEF)
+		    rc = wsplt_env_lookup (wsp, str, i, &value);
+		}
+	      else
+		{
+		  rc = wsplt_env_lookup (wsp, str, i, &value);
+		  if (rc == WRDSE_UNDEF)
+		    rc = wsplt_env_getvar (wsp, str, i, &value);
+		}
+	    }
+	  else
+	    rc = wsplt_env_lookup (wsp, str, i, &value);
+	}
 
-      if (rc == WRDSE_OK && value[0] == 0 && defstr && defstr[-1] == ':')
+      if (rc == WRDSE_OK
+	  && (!value || value[0] == 0)
+	  && defstr && defstr[-1] == ':')
 	{
 	  free (value);
 	  rc = WRDSE_UNDEF;
 	}
     }
-  
+
   switch (rc)
     {
     case WRDSE_OK:
@@ -1032,7 +1555,7 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
 	  rc = _wsplt_subsplit (wsp, &ws, defstr, size,
 				WRDSF_NOSPLIT | WRDSF_WS | WRDSF_QUOTE |
 				(wsp->ws_flags &
-				 (WRDSF_NOVAR | WRDSF_NOCMD)));
+				 (WRDSF_NOVAR | WRDSF_NOCMD)), 1);
 	  if (rc)
 	    return rc;
 	  free (value);
@@ -1041,7 +1564,7 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
 	  wordsplit_free (&ws);
 	}
       break;
-      
+
     case WRDSE_UNDEF:
       if (defstr)
 	{
@@ -1053,18 +1576,29 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
 	      rc = _wsplt_subsplit (wsp, &ws, defstr, size,
 				    WRDSF_NOSPLIT | WRDSF_WS | WRDSF_QUOTE |
 				    (wsp->ws_flags &
-				     (WRDSF_NOVAR | WRDSF_NOCMD)));
+				     (WRDSF_NOVAR | WRDSF_NOCMD)),
+				    1);
 	      if (rc)
 		return rc;
 
 	      value = ws.ws_wordv[0];
 	      ws.ws_wordv[0] = NULL;
 	      wordsplit_free (&ws);
-	      
+
 	      if (defstr[-1] == '=')
-		wsplt_assign_var (wsp, str, i, value);
+		{
+		  if (is_param)
+		    rc = wsplt_assign_param (wsp, param_idx, value);
+		  else
+		    rc = wsplt_assign_var (wsp, str, i, value);
+		}
+	      if (rc)
+		{
+		  free (value);
+		  return rc;
+		}
 	    }
-	  else 
+	  else
 	    {
 	      if (*defstr == '?')
 		{
@@ -1078,7 +1612,8 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
 					    WRDSF_NOSPLIT | WRDSF_WS |
 					    WRDSF_QUOTE |
 					    (wsp->ws_flags &
-					     (WRDSF_NOVAR | WRDSF_NOCMD)));
+					     (WRDSF_NOVAR | WRDSF_NOCMD)),
+					    1);
 		      if (rc == 0)
 			wsp->ws_error ("%.*s: %s",
 				       (int) i, str, ws.ws_wordv[0]);
@@ -1093,7 +1628,7 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
 	}
       else if (wsp->ws_flags & WRDSF_UNDEF)
 	{
-	  _wsplt_seterr (wsp, WRDSE_UNDEF);
+	  _wsplt_setctxerr (wsp, WRDSE_UNDEF, str, *pend - str + 1);
 	  return 1;
 	}
       else
@@ -1111,7 +1646,7 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
 	    }
 	}
       break;
-      
+
     case WRDSE_NOSPACE:
       return _wsplt_nomem (wsp);
 
@@ -1149,11 +1684,13 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
       else
 	{
 	  struct wordsplit ws;
-	  int i, rc;
-	  
+	  int rc;
+
 	  rc = _wsplt_subsplit (wsp, &ws, value, strlen (value),
 				WRDSF_NOVAR | WRDSF_NOCMD |
-				WRDSF_QUOTE);
+				WRDSF_QUOTE
+				| (WSP_RETURN_DELIMS (wsp) ? WRDSF_RETURN_DELIMS : 0) ,
+				0);
 	  free (value);
 	  if (rc)
 	    {
@@ -1161,19 +1698,9 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
 	      wordsplit_free (&ws);
 	      return 1;
 	    }
-	  for (i = 0; i < ws.ws_wordc; i++)
-	    {
-	      if (wsnode_new (wsp, &newnode))
-		return 1;
-	      wsnode_insert (wsp, newnode, *ptail, 0);
-	      *ptail = newnode;
-	      newnode->flags = _WSNF_WORD |
-		_WSNF_NOEXPAND |
-		(i + 1 < ws.ws_wordc ? (flg & ~_WSNF_JOIN) : flg);
-	      newnode->v.word = strdup (ws.ws_wordv[i]);
-	      if (!newnode->v.word)
-		return _wsplt_nomem (wsp);
-	    }
+	  wsnode_insert (wsp, ws.ws_head, *ptail, 0);
+	  *ptail = ws.ws_tail;
+	  ws.ws_head = ws.ws_tail = NULL;
 	  wordsplit_free (&ws);
 	}
     }
@@ -1206,7 +1733,7 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
 static int
 begin_var_p (int c)
 {
-  return c == '{' || ISVARBEG (c);
+  return memchr ("{#@*", c, 4) != NULL || ISVARBEG (c) || ISDIGIT (c);
 }
 
 static int
@@ -1263,7 +1790,7 @@ node_expand (struct wordsplit *wsp, struct wordsplit_node *node,
     }
   return 0;
 }
-  
+
 /* Remove NULL nodes from the list */
 static void
 wsnode_nullelim (struct wordsplit *wsp)
@@ -1292,7 +1819,7 @@ wordsplit_varexp (struct wordsplit *wsp)
   for (p = wsp->ws_head; p;)
     {
       struct wordsplit_node *next = p->next;
-      if (!(p->flags & _WSNF_NOEXPAND))
+      if (!(p->flags & (_WSNF_NOEXPAND|_WSNF_DELIM)))
 	if (node_expand (wsp, p, begin_var_p, expvar))
 	  return 1;
       p = next;
@@ -1316,7 +1843,8 @@ expcmd (struct wordsplit *wsp, const char *str, size_t len,
   size_t j;
   char *value;
   struct wordsplit_node *newnode;
-  
+  struct wordsplit ws;
+
   str++;
   len--;
 
@@ -1327,25 +1855,16 @@ expcmd (struct wordsplit *wsp, const char *str, size_t len,
     }
 
   *pend = str + j;
-  if (wsp->ws_options & WRDSO_ARGV)
+  rc = _wsplt_subsplit (wsp, &ws, str, j, WRDSF_WS | WRDSF_QUOTE, 1);
+  if (rc)
     {
-      struct wordsplit ws;
-
-      rc = _wsplt_subsplit (wsp, &ws, str, j,
-			    WRDSF_NOVAR | WRDSF_NOCMD |
-			    WRDSF_WS | WRDSF_QUOTE);
-      if (rc)
-	{
-	  _wsplt_seterr_sub (wsp, &ws);
-	  wordsplit_free (&ws);
-	  return 1;
-	}
-      rc = wsp->ws_command (&value, str, j, ws.ws_wordv, wsp->ws_closure);
+      _wsplt_seterr_sub (wsp, &ws);
       wordsplit_free (&ws);
+      return 1;
     }
-  else
-    rc = wsp->ws_command (&value, str, j, NULL, wsp->ws_closure);
-  
+  rc = wsp->ws_command (&value, str, j, ws.ws_wordv, wsp->ws_closure);
+  wordsplit_free (&ws);
+
   if (rc == WRDSE_NOSPACE)
     return _wsplt_nomem (wsp);
   else if (rc)
@@ -1384,11 +1903,13 @@ expcmd (struct wordsplit *wsp, const char *str, size_t len,
       else
 	{
 	  struct wordsplit ws;
-	  int i, rc;
+	  int rc;
 
 	  rc = _wsplt_subsplit (wsp, &ws, value, strlen (value),
-				WRDSF_NOVAR | WRDSF_NOCMD |
-				WRDSF_WS | WRDSF_QUOTE);
+				WRDSF_NOVAR | WRDSF_NOCMD
+				| WRDSF_WS | WRDSF_QUOTE
+				| (WSP_RETURN_DELIMS (wsp) ? WRDSF_RETURN_DELIMS : 0),
+				0);
 	  free (value);
 	  if (rc)
 	    {
@@ -1396,19 +1917,9 @@ expcmd (struct wordsplit *wsp, const char *str, size_t len,
 	      wordsplit_free (&ws);
 	      return 1;
 	    }
-	  for (i = 0; i < ws.ws_wordc; i++)
-	    {
-	      if (wsnode_new (wsp, &newnode))
-		return 1;
-	      wsnode_insert (wsp, newnode, *ptail, 0);
-	      *ptail = newnode;
-	      newnode->flags = _WSNF_WORD |
-		_WSNF_NOEXPAND |
-		(i + 1 < ws.ws_wordc ? (flg & ~_WSNF_JOIN) : flg);
-	      newnode->v.word = strdup (ws.ws_wordv[i]);
-	      if (!newnode->v.word)
-		return _wsplt_nomem (wsp);
-	    }
+	  wsnode_insert (wsp, ws.ws_head, *ptail, 0);
+	  *ptail = ws.ws_tail;
+	  ws.ws_head = ws.ws_tail = NULL;
 	  wordsplit_free (&ws);
 	}
     }
@@ -1461,13 +1972,13 @@ wordsplit_trimws (struct wordsplit *wsp)
 	    ;
 	  p->v.segm.beg = n;
 	}
-      
+
       while (p->next && (p->flags & _WSNF_JOIN))
 	p = p->next;
-      
+
       if (p->flags & _WSNF_QUOTE)
 	continue;
-      
+
       /* Trim trailing whitespace */
       for (n = p->v.segm.end;
 	   n > p->v.segm.beg && ISWS (wsp->ws_input[n - 1]); n--);
@@ -1486,7 +1997,7 @@ wordsplit_tildexpand (struct wordsplit *wsp)
   struct wordsplit_node *p;
   char *uname = NULL;
   size_t usize = 0;
-  
+
   for (p = wsp->ws_head; p; p = p->next)
     {
       const char *str;
@@ -1501,7 +2012,7 @@ wordsplit_tildexpand (struct wordsplit *wsp)
 	  size_t slen = wsnode_len (p);
 	  struct passwd *pw;
 	  char *newstr;
-	  
+
 	  for (i = 1; i < slen && str[i] != '/'; i++)
 	    ;
 	  if (i == slen)
@@ -1577,7 +2088,7 @@ wordsplit_pathexpand (struct wordsplit *wsp)
   if (wsp->ws_options & WRDSO_DOTGLOB)
     flags = GLOB_PERIOD;
 #endif
-  
+
   for (p = wsp->ws_head; p; p = next)
     {
       const char *str;
@@ -1595,7 +2106,7 @@ wordsplit_pathexpand (struct wordsplit *wsp)
 	  int i;
 	  glob_t g;
 	  struct wordsplit_node *prev;
-	  
+
 	  if (slen + 1 > patsize)
 	    {
 	      char *p = realloc (pattern, slen + 1);
@@ -1606,16 +2117,16 @@ wordsplit_pathexpand (struct wordsplit *wsp)
 	    }
 	  memcpy (pattern, str, slen);
 	  pattern[slen] = 0;
-      
+
 	  switch (glob (pattern, flags, NULL, &g))
 	    {
 	    case 0:
 	      break;
-	      
+
 	    case GLOB_NOSPACE:
 	      free (pattern);
 	      return _wsplt_nomem (wsp);
-	      
+
 	    case GLOB_NOMATCH:
 	      if (wsp->ws_options & WRDSO_NULLGLOB)
 		{
@@ -1637,10 +2148,10 @@ wordsplit_pathexpand (struct wordsplit *wsp)
 		    return _wsplt_seterr (wsp, WRDSE_USERERR);
 		}
 	      continue;
-	      
+
 	    default:
 	      free (pattern);
-	      return _wsplt_seterr (wsp, WRDSE_GLOBERR);
+	      return _wsplt_setctxerr (wsp, WRDSE_GLOBERR, pattern, slen);
 	    }
 
 	  prev = p;
@@ -1648,7 +2159,7 @@ wordsplit_pathexpand (struct wordsplit *wsp)
 	    {
 	      struct wordsplit_node *newnode;
 	      char *newstr;
-	      
+
 	      if (wsnode_new (wsp, &newnode))
 		return 1;
 	      newstr = strdup (g.gl_pathv[i]);
@@ -1702,33 +2213,24 @@ skip_sed_expr (const char *command, size_t i, size_t len)
   return i;
 }
 
-static size_t
-skip_delim (struct wordsplit *wsp)
+/* wsp->ws_endp points to a delimiter character. If RETURN_DELIMS
+   is true, return its value, otherwise return the index past it. */
+static inline size_t
+skip_delim_internal (struct wordsplit *wsp, int return_delims)
 {
-  size_t start = wsp->ws_endp;
-  if (wsp->ws_flags & WRDSF_SQUEEZE_DELIMS)
-    {
-      if ((wsp->ws_flags & WRDSF_RETURN_DELIMS) &&
-	  ISDELIM (wsp, wsp->ws_input[start]))
-	{
-	  int delim = wsp->ws_input[start];
-	  do
-	    start++;
-	  while (start < wsp->ws_len && delim == wsp->ws_input[start]);
-	}
-      else
-	{
-	  do
-	    start++;
-	  while (start < wsp->ws_len && ISDELIM (wsp, wsp->ws_input[start]));
-	}
-      start--;
-    }
+  return return_delims ? wsp->ws_endp : wsp->ws_endp + 1;
+}
 
-  if (!(wsp->ws_flags & WRDSF_RETURN_DELIMS))
-    start++;
+static inline size_t
+skip_delim (struct wordsplit *wsp)
+{
+  return skip_delim_internal (wsp, WSP_RETURN_DELIMS (wsp));
+}
 
-  return start;
+static inline size_t
+skip_delim_real (struct wordsplit *wsp)
+{
+  return skip_delim_internal (wsp, wsp->ws_flags & WRDSF_RETURN_DELIMS);
 }
 
 #define _WRDS_EOF   0
@@ -1736,7 +2238,7 @@ skip_delim (struct wordsplit *wsp)
 #define _WRDS_ERR   2
 
 static int
-scan_qstring (struct wordsplit *wsp, size_t start, size_t * end)
+scan_qstring (struct wordsplit *wsp, size_t start, size_t *end)
 {
   size_t j;
   const char *command = wsp->ws_input;
@@ -1765,13 +2267,14 @@ scan_qstring (struct wordsplit *wsp, size_t start, size_t * end)
 }
 
 static int
-scan_word (struct wordsplit *wsp, size_t start)
+scan_word (struct wordsplit *wsp, size_t start, int consume_all)
 {
   size_t len = wsp->ws_len;
   const char *command = wsp->ws_input;
   const char *comment = wsp->ws_comment;
   int join = 0;
   int flags = 0;
+  struct wordsplit_node *np = wsp->ws_tail;
 
   size_t i = start;
 
@@ -1789,7 +2292,7 @@ scan_word (struct wordsplit *wsp, size_t start)
       flags = _WSNF_SEXP;
       i = skip_sed_expr (command, i, len);
     }
-  else if (!ISDELIM (wsp, command[i]))
+  else if (consume_all || !ISDELIM (wsp, command[i]))
     {
       while (i < len)
 	{
@@ -1830,23 +2333,25 @@ scan_word (struct wordsplit *wsp, size_t start)
 
 	  if (command[i] == '$')
 	    {
-	      if (!(wsp->ws_flags & WRDSF_NOVAR)
+	      if ((!(wsp->ws_flags & WRDSF_NOVAR)
+		   || (wsp->ws_options & WRDSO_NOVARSPLIT))
 		  && command[i+1] == '{'
 		  && find_closing_paren (command, i + 2, len, &i, "{}") == 0)
 		continue;
-	      if (!(wsp->ws_flags & WRDSF_NOCMD)
+	      if ((!(wsp->ws_flags & WRDSF_NOCMD)
+		   || (wsp->ws_options & WRDSO_NOCMDSPLIT))
 		  && command[i+1] == '('
 		  && find_closing_paren (command, i + 2, len, &i, "()") == 0)
 		continue;
 	    }
 
-	  if (ISDELIM (wsp, command[i]))
+	  if (!consume_all && ISDELIM (wsp, command[i]))
 	    break;
 	  else
 	    i++;
 	}
     }
-  else if (wsp->ws_flags & WRDSF_RETURN_DELIMS)
+  else if (WSP_RETURN_DELIMS (wsp))
     {
       i++;
       flags |= _WSNF_DELIM;
@@ -1861,12 +2366,21 @@ scan_word (struct wordsplit *wsp, size_t start)
   wsp->ws_endp = i;
   if (wsp->ws_flags & WRDSF_INCREMENTAL)
     return _WRDS_EOF;
+
+  if (consume_all)
+    {
+      if (!np)
+	np = wsp->ws_head;
+      while (np)
+	{
+	  np->flags |= _WSNF_QUOTE;
+	  np = np->next;
+	}
+    }
+
   return _WRDS_OK;
 }
 
-#define to_num(c) \
-  (ISDIGIT(c) ? c - '0' : (ISXDIGIT(c) ? toupper(c) - 'A' + 10 : 255 ))
-
 static int
 xtonum (int *pval, const char *src, int base, int cnt)
 {
@@ -1913,7 +2427,7 @@ wordsplit_c_quoted_length (const char *str, int quote_hex, int *quote)
   return len;
 }
 
-int
+static int
 wsplt_unquote_char (const char *transtab, int c)
 {
   while (*transtab && transtab[1])
@@ -1925,7 +2439,7 @@ wsplt_unquote_char (const char *transtab, int c)
   return 0;
 }
 
-int
+static int
 wsplt_quote_char (const char *transtab, int c)
 {
   for (; *transtab && transtab[1]; transtab += 2)
@@ -2065,48 +2579,82 @@ wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex)
     }
 }
 
+
+/* This structure describes a single expansion phase */
 struct exptab
 {
-  char *descr;
-  int flag;
-  int opt;
-  int (*expansion) (struct wordsplit *wsp);
+  char const *descr; /* Textual description (for debugging) */
+  int flag;          /* WRDSF_ bit that controls this phase */
+  int opt;           /* Entry-specific options (see EXPOPT_ flags below */
+  int (*expansion) (struct wordsplit *wsp); /* expansion function */
 };
 
+/* The following options control expansions: */
+/* Normally the exptab entry is run if its flag bit is set in struct
+   wordsplit.  The EXPOPT_NEG option negates this test so that expansion
+   is performed if its associated flag bit is not set in struct wordsplit. */
 #define EXPOPT_NEG      0x01
-#define EXPOPT_COALESCE 0x02
+/* All bits in flag must be set in order for entry to match */
+#define EXPORT_ALLOF    0x02
+/* Coalesce the input list before running the expansion. */
+#define EXPOPT_COALESCE 0x04
 
 static struct exptab exptab[] = {
-  { N_("WS trimming"),          WRDSF_WS,         0, wordsplit_trimws },
-  { N_("tilde expansion"),      WRDSF_PATHEXPAND, 0, wordsplit_tildexpand },
+  { N_("WS trimming"),          WRDSF_WS,         0,
+    wordsplit_trimws },
+  { N_("command substitution"), WRDSF_NOCMD,      EXPOPT_NEG|EXPOPT_COALESCE,
+    wordsplit_cmdexp },
+  { N_("coalesce list"),        0,                EXPOPT_NEG|EXPOPT_COALESCE,
+    NULL },
+  { N_("tilde expansion"),      WRDSF_PATHEXPAND, 0,
+    wordsplit_tildexpand },
   { N_("variable expansion"),   WRDSF_NOVAR,      EXPOPT_NEG,
     wordsplit_varexp },
   { N_("quote removal"),        0,                EXPOPT_NEG,
     wsnode_quoteremoval },
-  { N_("command substitution"), WRDSF_NOCMD,      EXPOPT_NEG|EXPOPT_COALESCE,
-    wordsplit_cmdexp },
   { N_("coalesce list"),        0,                EXPOPT_NEG|EXPOPT_COALESCE,
     NULL },
-  { N_("path expansion"),       WRDSF_PATHEXPAND, 0, wordsplit_pathexpand },
+  { N_("path expansion"),       WRDSF_PATHEXPAND, 0,
+    wordsplit_pathexpand },
   { NULL }
 };
-    
+
+static inline int
+exptab_matches(struct exptab *p, struct wordsplit *wsp)
+{
+  int result;
+
+  result = (wsp->ws_flags & p->flag);
+  if (p->opt & EXPORT_ALLOF)
+    result = result == p->flag;
+  if (p->opt & EXPOPT_NEG)
+    result = !result;
+
+  return result;
+}
+
 static int
 wordsplit_process_list (struct wordsplit *wsp, size_t start)
 {
   struct exptab *p;
-  
-  if (wsp->ws_flags & WRDSF_NOSPLIT)
+
+  if (wsp->ws_flags & WRDSF_SHOWDBG)
+    wsp->ws_debug (_("(%02d) Input:%.*s;"),
+		   wsp->ws_lvl, (int) wsp->ws_len, wsp->ws_input);
+
+  if ((wsp->ws_flags & WRDSF_NOSPLIT)
+      || ((wsp->ws_options & WRDSO_MAXWORDS)
+	  && wsp->ws_wordi + 1 == wsp->ws_maxwords))
     {
-      /* Treat entire input as a quoted argument */
-      if (wordsplit_add_segm (wsp, start, wsp->ws_len, _WSNF_QUOTE))
+      /* Treat entire input as a single word */
+      if (scan_word (wsp, start, 1) == _WRDS_ERR)
 	return wsp->ws_errno;
     }
   else
     {
       int rc;
 
-      while ((rc = scan_word (wsp, start)) == _WRDS_OK)
+      while ((rc = scan_word (wsp, start, 0)) == _WRDS_OK)
 	start = skip_delim (wsp);
       /* Make sure tail element is not joinable */
       if (wsp->ws_tail)
@@ -2123,8 +2671,7 @@ wordsplit_process_list (struct wordsplit *wsp, size_t start)
 
   for (p = exptab; p->descr; p++)
     {
-      if ((p->opt & EXPOPT_NEG)
-	  ? !(wsp->ws_flags & p->flag) : (wsp->ws_flags & p->flag))
+      if (exptab_matches(p, wsp))
 	{
 	  if (p->opt & EXPOPT_COALESCE)
 	    {
@@ -2149,77 +2696,52 @@ wordsplit_process_list (struct wordsplit *wsp, size_t start)
 	    }
 	}
     }
+
   return wsp->ws_errno;
 }
 
 static int
 wordsplit_run (const char *command, size_t length, struct wordsplit *wsp,
-               int flags, int lvl)
+	       int flags, int lvl)
 {
   int rc;
   size_t start;
-  const char *cmdptr;
-  size_t cmdlen;
 
+  /* Initialize error context early */
+  wsp->ws_errctx = NULL;
   if (!command)
     {
       if (!(flags & WRDSF_INCREMENTAL))
-	return EINVAL;
+	return _wsplt_seterr (wsp, WRDSE_USAGE);
+
+      if (wsp->ws_head)
+	return wordsplit_finish (wsp);
 
-      start = skip_delim (wsp);
+      start = skip_delim_real (wsp);
       if (wsp->ws_endp == wsp->ws_len)
 	return _wsplt_seterr (wsp, WRDSE_NOINPUT);
 
-      cmdptr = wsp->ws_input + wsp->ws_endp;
-      cmdlen = wsp->ws_len - wsp->ws_endp;
       wsp->ws_flags |= WRDSF_REUSE;
       wordsplit_init0 (wsp);
     }
   else
     {
-      cmdptr = command;
-      cmdlen = length;
       start = 0;
-      rc = wordsplit_init (wsp, cmdptr, cmdlen, flags);
+      rc = wordsplit_init (wsp, command, length, flags);
       if (rc)
 	return rc;
       wsp->ws_lvl = lvl;
     }
 
-  if (wsp->ws_flags & WRDSF_SHOWDBG)
-    wsp->ws_debug (_("(%02d) Input:%.*s;"), wsp->ws_lvl, (int) cmdlen, cmdptr);
-
   rc = wordsplit_process_list (wsp, start);
-  if (rc == 0 && (flags & WRDSF_INCREMENTAL))
-    {
-      while (!wsp->ws_head && wsp->ws_endp < wsp->ws_len)
-	{
-	  start = skip_delim (wsp);
-	  if (wsp->ws_flags & WRDSF_SHOWDBG)
-	    {
-	      cmdptr = wsp->ws_input + wsp->ws_endp;
-	      cmdlen = wsp->ws_len - wsp->ws_endp;
-	      wsp->ws_debug (_("(%02d) Restart:%.*s;"),
-			     wsp->ws_lvl, (int) cmdlen, cmdptr);
-	    }
-	  rc = wordsplit_process_list (wsp, start);
-	  if (rc)
-	    break;
-	}
-    }
   if (rc)
-    {
-      wordsplit_free_nodes (wsp);
-      return rc;
-    }
-  wordsplit_finish (wsp);
-  wordsplit_free_nodes (wsp);
-  return wsp->ws_errno;
+    return rc;
+  return wordsplit_finish (wsp);
 }
 
 int
-wordsplit_len (const char *command, size_t length, struct wordsplit *wsp, 
-               int flags)
+wordsplit_len (const char *command, size_t length, struct wordsplit *wsp,
+	       int flags)
 {
   return wordsplit_run (command, length, wsp, flags, 0);
 }
@@ -2250,7 +2772,7 @@ wordsplit_free_words (struct wordsplit *ws)
 void
 wordsplit_free_envbuf (struct wordsplit *ws)
 {
-  if (ws->ws_flags & WRDSF_NOCMD)
+  if (!(ws->ws_flags & WRDSF_ENV))
     return;
   if (ws->ws_envbuf)
     {
@@ -2264,34 +2786,67 @@ wordsplit_free_envbuf (struct wordsplit *ws)
     }
 }
 
+void
+wordsplit_free_parambuf (struct wordsplit *ws)
+{
+  if (!(ws->ws_options & WRDSO_PARAMV))
+    return;
+  if (ws->ws_parambuf)
+    {
+      size_t i;
+
+      for (i = 0; ws->ws_parambuf[i]; i++)
+	free (ws->ws_parambuf[i]);
+      free (ws->ws_parambuf);
+      ws->ws_paramidx = ws->ws_paramsiz = 0;
+      ws->ws_parambuf = NULL;
+    }
+}
+
 void
 wordsplit_clearerr (struct wordsplit *ws)
 {
   if (ws->ws_errno == WRDSE_USERERR)
     free (ws->ws_usererr);
   ws->ws_usererr = NULL;
+
+  free (ws->ws_errctx);
+  ws->ws_errctx = NULL;
+
   ws->ws_errno = WRDSE_OK;
 }
 
 void
 wordsplit_free (struct wordsplit *ws)
 {
+  if (ws->ws_errno == WRDSE_USAGE)
+    /* Usage error: the structure is not properly initialized and there's
+       nothing to free. */
+    return;
+  wordsplit_clearerr (ws);
+  wordsplit_free_nodes (ws);
   wordsplit_free_words (ws);
   free (ws->ws_wordv);
   ws->ws_wordv = NULL;
   wordsplit_free_envbuf (ws);
+  wordsplit_free_parambuf (ws);
 }
 
-void
-wordsplit_getwords (struct wordsplit *ws, size_t *wordc, char ***wordv)
+int
+wordsplit_get_words (struct wordsplit *ws, size_t *wordc, char ***wordv)
 {
   char **p = realloc (ws->ws_wordv,
 		      (ws->ws_wordc + 1) * sizeof (ws->ws_wordv[0]));
-  *wordv = p ? p : ws->ws_wordv;
+  if (!p)
+    return -1;
+  *wordv = p;
   *wordc = ws->ws_wordc;
+
   ws->ws_wordv = NULL;
   ws->ws_wordc = 0;
   ws->ws_wordn = 0;
+
+  return 0;
 }
 
 const char *_wordsplit_errstr[] = {
@@ -2303,7 +2858,9 @@ const char *_wordsplit_errstr[] = {
   N_("undefined variable"),
   N_("input exhausted"),
   N_("unbalanced parenthesis"),
-  N_("globbing error")
+  N_("globbing error"),
+  N_("user-defined error"),
+  N_("invalid parameter number in assignment")
 };
 int _wordsplit_nerrs =
   sizeof (_wordsplit_errstr) / sizeof (_wordsplit_errstr[0]);
@@ -2330,7 +2887,9 @@ wordsplit_perror (struct wordsplit *wsp)
       break;
 
     default:
-      wsp->ws_error (wordsplit_strerror (wsp));
+      if (wsp->ws_errctx)
+	wsp->ws_error ("%s: %s", wordsplit_strerror (wsp), wsp->ws_errctx);
+      else
+	wsp->ws_error ("%s", wordsplit_strerror (wsp));
     }
 }
-
diff --git a/grecs/include/wordsplit.h b/grecs/wordsplit/wordsplit.h
similarity index 71%
rename from grecs/include/wordsplit.h
rename to grecs/wordsplit/wordsplit.h
index a7f6dd5..3451979 100644
--- a/grecs/include/wordsplit.h
+++ b/grecs/wordsplit/wordsplit.h
@@ -1,5 +1,5 @@
 /* wordsplit - a word splitter
-   Copyright (C) 2009-2016 Sergey Poznyakoff
+   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
@@ -26,45 +26,68 @@ typedef struct wordsplit wordsplit_t;
    provide return values when the function returns.  If neither mark is
    used, the member is internal and must not be used by the caller.
 
-   In the comments below, the
-   identifiers in parentheses indicate bits that must be set (or unset, if
-   starting with !) in the ws_flags to initialize or use the given member.
+   In the comments below, the identifiers in parentheses indicate bits that
+   must be set (or unset, if starting with !) in ws_flags (if starting with
+   WRDSF_) or ws_options (if starting with WRDSO_) to initialize or use the
+   given member.
+
    If not redefined explicitly, most of them are set to some reasonable
    default value upon entry to wordsplit(). */
-struct wordsplit            
+struct wordsplit
 {
   size_t ws_wordc;          /* [Output] Number of words in ws_wordv. */
   char **ws_wordv;          /* [Output] Array of parsed out words. */
   size_t ws_offs;           /* [Input] (WRDSF_DOOFFS) Number of initial
 			       elements in ws_wordv to fill with NULLs. */
-  size_t ws_wordn;          /* Number of elements ws_wordv can accomodate. */ 
+  size_t ws_wordn;          /* Number of elements ws_wordv can accomodate. */
   int ws_flags;             /* [Input] Flags passed to wordsplit. */
-  int ws_options;           /* [Input] (WRDSF_PATHEXPAND)
+  int ws_options;           /* [Input] (WRDSF_OPTIONS)
 			       Additional options. */
+  size_t ws_maxwords;       /* [Input] (WRDSO_MAXWORDS) Return at most that
+			       many words */
+  size_t ws_wordi;          /* [Output] (WRDSF_INCREMENTAL) Total number of
+			       words returned so far */
+
   const char *ws_delim;     /* [Input] (WRDSF_DELIM) Word delimiters. */
   const char *ws_comment;   /* [Input] (WRDSF_COMMENT) Comment characters. */
   const char *ws_escape[2]; /* [Input] (WRDSF_ESCAPE) Characters to be escaped
 			       with backslash. */
   void (*ws_alloc_die) (wordsplit_t *wsp);
-                            /* [Input] (WRDSF_ALLOC_DIE) Function called when
+			    /* [Input] (WRDSF_ALLOC_DIE) Function called when
 			       out of memory.  Must not return. */
   void (*ws_error) (const char *, ...)
-                   __attribute__ ((__format__ (__printf__, 1, 2)));
-                            /* [Input] (WRDSF_ERROR) Function used for error
+		   __attribute__ ((__format__ (__printf__, 1, 2)));
+			    /* [Input] (WRDSF_ERROR) Function used for error
 			       reporting */
   void (*ws_debug) (const char *, ...)
-                   __attribute__ ((__format__ (__printf__, 1, 2)));
-                            /* [Input] (WRDSF_DEBUG) Function used for debug
+		   __attribute__ ((__format__ (__printf__, 1, 2)));
+			    /* [Input] (WRDSF_DEBUG) Function used for debug
 			       output. */
   const char **ws_env;      /* [Input] (WRDSF_ENV, !WRDSF_NOVAR) Array of
 			       environment variables. */
 
-  char **ws_envbuf;
-  size_t ws_envidx;
-  size_t ws_envsiz;
-  
+	/* Temporary storage for environment variables. It is initialized
+	   upon first assignment which occurs during the parsing process
+	   (e.g. ${x:=2}). When this happens, all variables from ws_env are
+	   moved to ws_envbuf first, and the ws_envbuf address is assigned
+	   to ws_env. From this moment on, all variable expansions are served
+	   from ws_envbuf. */
+  char **ws_envbuf;         /* Storage for variables */
+  size_t ws_envidx;         /* Index of first free slot */
+  size_t ws_envsiz;         /* Size of the ws_envbuf array */
+
+  char const **ws_paramv;   /* [WRDSO_PARAMV] User-supplied positional
+			       parameters */
+  size_t ws_paramc;         /* Number of positional parameters */
+
+	/* Temporary storage for parameters. Works similarly to ws_enbuf.
+	 */
+  char **ws_parambuf;
+  size_t ws_paramidx;
+  size_t ws_paramsiz;
+
   int (*ws_getvar) (char **ret, const char *var, size_t len, void *clos);
-                            /* [Input] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up
+			    /* [Input] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up
 			       the name VAR (LEN bytes long) in the table of
 			       variables and if found returns in memory
 			       location pointed to by RET the value of that
@@ -73,22 +96,21 @@ struct wordsplit
 			       on error.  User-specific errors can be returned
 			       by storing the error diagnostic string in RET
 			       and returning WRDSE_USERERR.
-                               Whatever is stored in RET, it must be allocated
+			       Whatever is stored in RET, it must be allocated
 			       using malloc(3). */
   void *ws_closure;         /* [Input] (WRDSF_CLOSURE) Passed as the CLOS
 			       argument to ws_getvar and ws_command. */
   int (*ws_command) (char **ret, const char *cmd, size_t len, char **argv,
-                     void *clos);
-	                    /* [Input] (!WRDSF_NOCMD) Returns in the memory
+		     void *clos);
+			    /* [Input] (!WRDSF_NOCMD) Returns in the memory
 			       location pointed to by RET the expansion of
-			       the command CMD (LEN bytes nong).  If WRDSF_ARGV
-			       flag is set, ARGV contains CMD split out to
-			       words.  Otherwise ARGV is NULL.
+			       the command CMD (LEN bytes long).  On input,
+			       ARGV contains CMD split out to words.
 
 			       See ws_getvar for a discussion of possible
 			       return values. */
-	
-  const char *ws_input;     /* Input string (the S argument to wordsplit. */  
+
+  const char *ws_input;     /* Input string (the S argument to wordsplit). */
   size_t ws_len;            /* Length of ws_input. */
   size_t ws_endp;           /* Points past the last processed byte in
 			       ws_input. */
@@ -96,8 +118,13 @@ struct wordsplit
   char *ws_usererr;         /* Points to textual description of
 			       the error, if ws_errno is WRDSE_USERERR.  Must
 			       be allocated with malloc(3). */
+  char *ws_errctx;          /* Context in which the error occurred:
+			       For WRDSE_UNDEF - name of the undefined variable,
+			       For WRDSE_GLOBERR - pattern that caused error.
+			    */
   struct wordsplit_node *ws_head, *ws_tail;
-                            /* Doubly-linked list of parsed out nodes. */
+			    /* Doubly-linked list of parsed out nodes. */
+  char ws_sep[2];           /* Temporary storage used during splitting */
   int ws_lvl;               /* Invocation nesting level. */
 };
 
@@ -189,8 +216,8 @@ struct wordsplit
 #define WRDSO_FAILGLOB        0x00000002
 /* Allow a leading period to be matched by metacharacters. */
 #define WRDSO_DOTGLOB         0x00000004
-/* ws_command needs argv parameter */
-#define WRDSO_ARGV            0x00000008
+/* Prefer ws_getvar over lookup in ws_env, if both are supplied */
+#define WRDSO_GETVARPREF      0x00000008
 /* Keep backslash in unrecognized escape sequences in words */
 #define WRDSO_BSKEEP_WORD     0x00000010
 /* Handle octal escapes in words */
@@ -198,16 +225,32 @@ struct wordsplit
 /* Handle hex escapes in words */
 #define WRDSO_XESC_WORD       0x00000040
 
+/* ws_maxwords field is initialized */
+#define WRDSO_MAXWORDS        0x00000080
+
 /* Keep backslash in unrecognized escape sequences in quoted strings */
 #define WRDSO_BSKEEP_QUOTE    0x00000100
 /* Handle octal escapes in quoted strings */
 #define WRDSO_OESC_QUOTE      0x00000200
 /* Handle hex escapes in quoted strings */
 #define WRDSO_XESC_QUOTE      0x00000400
+/* Unused: 0x00000800 */
+/* Don't split variable references, even if they contain whitespace
+   (e.g. ${VAR:-foo bar}) */
+#define WRDSO_NOVARSPLIT     0x00001000
+/* Don't split commands, even containing whitespace, e.g.
+   $(echo foo bar) */
+#define WRDSO_NOCMDSPLIT     0x00002000
+
+/* Enable positional parameters */
+#define WRDSO_PARAMV         0x00004000
+/* Enable negative positional indices (${-1} is the last positional
+   parameter) */
+#define WRDSO_PARAM_NEGIDX   0x00008000
 
-#define WRDSO_BSKEEP          WRDSO_BSKEEP_WORD     
-#define WRDSO_OESC            WRDSO_OESC_WORD       
-#define WRDSO_XESC            WRDSO_XESC_WORD       
+#define WRDSO_BSKEEP          WRDSO_BSKEEP_WORD
+#define WRDSO_OESC            WRDSO_OESC_WORD
+#define WRDSO_XESC            WRDSO_XESC_WORD
 
 /* Indices into ws_escape */
 #define WRDSX_WORD  0
@@ -229,13 +272,26 @@ struct wordsplit
 #define WRDSE_PAREN      7
 #define WRDSE_GLOBERR    8
 #define WRDSE_USERERR    9
+#define WRDSE_BADPARAM  10
 
 int wordsplit (const char *s, wordsplit_t *ws, int flags);
 int wordsplit_len (const char *s, size_t len, wordsplit_t *ws, int flags);
 void wordsplit_free (wordsplit_t *ws);
 void wordsplit_free_words (wordsplit_t *ws);
 void wordsplit_free_envbuf (wordsplit_t *ws);
-void wordsplit_getwords (wordsplit_t *ws, size_t *wordc, char ***wordv);
+void wordsplit_free_parambuf (struct wordsplit *ws);
+int wordsplit_get_words (wordsplit_t *ws, size_t *wordc, char ***wordv);
+
+static inline void wordsplit_getwords (wordsplit_t *ws, size_t *wordc, char ***wordv)
+  __attribute__ ((deprecated));
+
+static inline void
+wordsplit_getwords (wordsplit_t *ws, size_t *wordc, char ***wordv)
+{
+  wordsplit_get_words (ws, wordc, wordv);
+}
+
+int wordsplit_append (wordsplit_t *wsp, int argc, char **argv);
 
 int wordsplit_c_unquote_char (int c);
 int wordsplit_c_quote_char (int c);
diff --git a/grecs/wordsplit/wsp.c b/grecs/wordsplit/wsp.c
new file mode 100644
index 0000000..6217d5e
--- /dev/null
+++ b/grecs/wordsplit/wsp.c
@@ -0,0 +1,771 @@
+/* wsp - test program for wordsplit
+   Copyright (C) 2014-2019 Sergey Poznyakoff
+
+   Wordsplit 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.
+
+   Wordsplit 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 wordsplit. 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 <errno.h>
+#include "wordsplit.h"
+#include "wordsplit-version.h"
+
+extern char **environ;
+
+char *progname;
+
+/* Global options */
+enum
+  {
+    TRIMNL_OPTION    = 0x01,   /* Remove trailing newline */
+    PLAINTEXT_OPTION = 0x02    /* Print intput verbatim (no escapes) */
+  };
+
+/* Environment types */
+enum env_type
+  {
+    env_none,                  /* No environment */
+    env_null,                  /* Null environment */
+    env_sys                    /* Use system environment */
+  };
+
+struct wsclosure
+{
+  int options;            /* Global options */
+  struct wordsplit ws;    /* The wordsplit structure */
+  int wsflags;            /* Wordsplit flags */
+  enum env_type env_type; /* Environment type */
+  int offarg;             /* Index of the first of the initial words in
+			     the argv array. The ws.ws_dooffs field gives
+			     the number of such variables. Forces the
+			     WRDSF_DOOFFS flag. */
+  char **fenvbase;        /* Environment for testing the ws_getenv function */
+  int fenvidx;            /* Number of variables in fenvbase */
+  int fenvmax;            /* Size of fenbase (entries) */
+  int append_start;       /* First argument to append (index in argv) */
+  int append_count;       /* Number of arguments to append */
+};
+
+/* Command line option types */
+enum
+  {
+    ws_no_argument,       /* Option requires no arguments */
+    ws_boolean,           /* Option is boolean (can be prefixed with -no) */
+    ws_required_argument, /* Option requires one argument */
+    ws_multiple_arguments /* Option takes multiple arguments, terminated with
+			     "--" or end of argument list */
+  };
+
+/* Structure describing a single command-line option */
+struct wsopt
+{
+  const char *name;    /* Option name */
+  int tok;             /* Corresponding flag */
+  int arg;             /* Option type (see the enum above) */
+  void (*setfn) (int tok, int neg, char *arg, struct wsclosure *wsc);
+                       /* Setter function */
+};
+
+/* Index of the next argument in the argv */
+static int wsoptind = -1;
+
+void
+print_version (void)
+{
+  printf ("wsp (wordsplit %s)\n", WORDSPLIT_VERSION);
+}
+
+/* Parse next argument from the command line. Return EOF on end of arguments
+   or when the "--" argument is seen. */
+static int
+getwsopt (int argc, char **argv, struct wsopt *wso, struct wsclosure *wsc)
+{
+  int negate = 0;
+  char *opt;
+
+  if (wsoptind == -1)
+    wsoptind = 1;
+  if (wsoptind == argc)
+    return EOF;
+
+  opt = argv[wsoptind++];
+  if (strcmp (opt, "--") == 0)
+    return EOF;
+  if (*opt != '-')
+    {
+      if (strchr (opt, '='))
+	{
+	  assert (wsc->fenvidx < wsc->fenvmax - 1);
+	  wsc->fenvbase[wsc->fenvidx++] = opt;
+	  return 0;
+	}
+      wsoptind--;
+      return EOF;
+    }
+
+  if (strcmp (opt, "--version") == 0)
+    {
+      print_version ();
+      exit (0);
+    }
+
+  opt++; /* skip past initial dash */
+  
+  if (strncmp (opt, "no-", 3) == 0)
+    {
+      negate = 1;
+      opt += 3;
+    }
+  else if (strncmp (opt, "no", 2) == 0)
+    {
+      negate = 1;
+      opt += 2;
+    }
+  
+  for (; wso->name; wso++)
+    {
+      if (wso->arg == ws_boolean && wso->name[0] == 'n' && wso->name[1] == 'o'
+	  && strcmp (wso->name + 2, opt) == 0)
+	{
+	  negate ^= 1;
+	  break;
+	}
+      if (strcmp (wso->name, opt) == 0)
+	break;
+    }
+
+  if (wso->name)
+    {
+      char *arg;
+      if (wso->arg == ws_multiple_arguments)
+	{
+	  while (1)
+	    {
+	      if (wsoptind == argc)
+		break;
+	      arg = argv[wsoptind++];
+	      if (strcmp (arg, "--") == 0)
+		break;
+	      wso->setfn (wso->tok, negate, arg, wsc);
+	    }
+	}
+      else
+	{
+	  if (wso->arg == ws_required_argument)
+	    {
+	      if (wsoptind == argc)
+		{
+		  fprintf (stderr, "%s: missing arguments for -%s\n",
+			   progname, opt);
+		  exit (1);
+		}
+	      arg = argv[wsoptind++];
+	    }
+	  wso->setfn (wso->tok, negate, arg, wsc);
+	}
+      return 0;
+    }
+
+  fprintf (stderr, "%s: unrecognized option: -%s\n",
+	   progname, opt);
+  fprintf (stderr, "%s: try %s -help for more detail\n",
+	   progname, progname);
+  exit (1);
+}
+
+/* Setter functions for various options */
+
+static void
+setfn_flag (int flag, int neg, char *arg, struct wsclosure *wsc)
+{
+  if (neg)
+    wsc->wsflags &= ~flag;
+  else
+    wsc->wsflags |= flag;
+}
+
+static void
+setfn_option (int flag, int neg, char *arg, struct wsclosure *wsc)
+{
+  wsc->wsflags |= WRDSF_OPTIONS;
+  if (neg)
+    wsc->ws.ws_options &= ~flag;
+  else
+    wsc->ws.ws_options |= flag;
+}
+
+static void
+setfn_delim (int flag, int neg, char *arg, struct wsclosure *wsc)
+{
+  wsc->wsflags |= flag;
+  wsc->ws.ws_delim = arg;
+}
+
+static void
+setfn_comment (int flag, int neg, char *arg, struct wsclosure *wsc)
+{
+  wsc->wsflags |= flag;
+  wsc->ws.ws_comment = arg;
+}
+
+static void
+set_escape_string (wordsplit_t *ws, int *wsflags, int q, const char *str)
+{
+  if (*str == ':')
+    {
+      while (*++str != ':')
+	{
+	  int f;
+	  switch (*str)
+	    {
+	    case '+':
+	      f = WRDSO_BSKEEP;
+	      break;
+
+	    case '0':
+	      f = WRDSO_OESC;
+	      break;
+
+	    case 'x':
+	      f = WRDSO_XESC;
+	      break;
+
+	    default:
+	      fprintf (stderr, "%s: invalid escape flag near %s\n",
+		       progname, str);
+	      abort ();
+	    }
+	  WRDSO_ESC_SET (ws, q, f);
+	}
+      *wsflags |= WRDSF_OPTIONS;
+      ++str;
+    }
+  ws->ws_escape[q] = str;
+}
+
+static void
+setfn_escape (int flag, int neg, char *arg, struct wsclosure *wsc)
+{
+  wsc->wsflags |= flag;
+  set_escape_string (&wsc->ws, &wsc->wsflags, 0, arg);
+  set_escape_string (&wsc->ws, &wsc->wsflags, 1, arg);
+}
+
+static void
+setfn_escape_qw (char *arg, int quote, struct wsclosure *wsc)
+{
+  if (!(wsc->wsflags & WRDSF_ESCAPE))
+    {
+      wsc->wsflags |= WRDSF_ESCAPE;
+      wsc->ws.ws_escape[!quote] = NULL;
+    }
+  set_escape_string (&wsc->ws, &wsc->wsflags, quote, arg);
+}
+
+static void
+setfn_escape_word (int flag, int neg, char *arg, struct wsclosure *wsc)
+{
+  setfn_escape_qw (arg, 0, wsc);
+}
+  
+static void
+setfn_escape_quote (int flag, int neg, char *arg, struct wsclosure *wsc)
+{
+  setfn_escape_qw (arg, 1, wsc);
+}
+
+static void
+setfn_maxwords (int flag, int neg, char *arg, struct wsclosure *wsc)
+{
+  char *p;
+
+  wsc->wsflags |= WRDSF_OPTIONS;
+  wsc->ws.ws_options |= WRDSO_MAXWORDS;
+
+  wsc->ws.ws_maxwords = strtoul (arg, &p, 10);
+  if (*p)
+    {
+      fprintf (stderr, "%s: invalid number: %s\n", progname, arg);
+      exit (1);
+    }
+}
+
+static void
+setfn_global (int flag, int neg, char *arg, struct wsclosure *wsc)
+{
+  if (neg)
+    wsc->options &= ~flag;
+  else
+    wsc->options |= flag;
+}
+
+static void
+setfn_env (int flag, int neg, char *arg, struct wsclosure *wsc)
+{
+  if (strcmp (arg, "none") == 0)
+    wsc->env_type = env_none;
+  else if (strcmp (arg, "null") == 0)
+    wsc->env_type = env_null;
+  else if (strcmp (arg, "sys") == 0)
+    wsc->env_type = env_sys;
+  else
+    {
+      fprintf (stderr, "%s: environment flag: %s\n", progname, arg);
+      exit (1);
+    }
+}
+
+static void
+setfn_dooffs (int flag, int neg, char *arg, struct wsclosure *wsc)
+{
+  if (!(wsc->wsflags & flag))
+    {
+      wsc->wsflags |= flag;
+      wsc->offarg = wsoptind - 1;
+      wsc->ws.ws_offs = 0;
+    }
+  wsc->ws.ws_offs++;
+}
+
+static void
+setfn_append (int flag, int neg, char *arg, struct wsclosure *wsc)
+{
+  if (wsc->append_count == 0)
+    wsc->append_start = wsoptind - 1;
+  wsc->append_count++;
+}
+
+static void help (void);
+
+static void
+setfn_help (int flag, int neg, char *arg, struct wsclosure *wsc)
+{
+  help ();
+  exit (0);
+}
+
+/* Available options: */
+struct wsopt opttab[] = {
+  /* Global options */
+  { "trimnl",         TRIMNL_OPTION,        ws_boolean, setfn_global },
+  { "plaintext",      PLAINTEXT_OPTION,     ws_boolean, setfn_global },
+  { "env",            0,          ws_required_argument, setfn_env },
+  
+  /* Wordsplit flags */
+  { "append",         WRDSF_APPEND,         ws_boolean, setfn_flag },
+  /*{ "reuse",  WRDSF_REUSE, ws_boolean, setfn_flag },*/
+  { "undef",          WRDSF_UNDEF,          ws_boolean, setfn_flag },
+  { "novar",          WRDSF_NOVAR,          ws_boolean, setfn_flag },
+  { "nocmd",          WRDSF_NOCMD,          ws_boolean, setfn_flag },
+  { "ws",             WRDSF_WS,             ws_boolean, setfn_flag },
+  { "quote",          WRDSF_QUOTE,          ws_boolean, setfn_flag },
+  { "squote",         WRDSF_SQUOTE,         ws_boolean, setfn_flag },
+  { "dquote",         WRDSF_DQUOTE,         ws_boolean, setfn_flag },
+  { "squeeze_delims", WRDSF_SQUEEZE_DELIMS, ws_boolean, setfn_flag },
+  { "return_delims",  WRDSF_RETURN_DELIMS,  ws_boolean, setfn_flag },
+  { "sed",            WRDSF_SED_EXPR,       ws_boolean, setfn_flag },
+  { "debug",          WRDSF_SHOWDBG,        ws_boolean, setfn_flag },
+  { "nosplit",        WRDSF_NOSPLIT,        ws_boolean, setfn_flag },
+  { "keepundef",      WRDSF_KEEPUNDEF,      ws_boolean, setfn_flag },
+  { "warnundef",      WRDSF_WARNUNDEF,      ws_boolean, setfn_flag },
+  { "cescapes",       WRDSF_CESCAPES,       ws_boolean, setfn_flag },
+  { "default",        WRDSF_DEFFLAGS,       ws_boolean, setfn_flag },
+  { "env_kv",         WRDSF_ENV_KV,         ws_boolean, setfn_flag },
+  { "incremental",    WRDSF_INCREMENTAL,    ws_boolean, setfn_flag },
+  { "pathexpand",     WRDSF_PATHEXPAND,     ws_boolean, setfn_flag },
+  { "default",        WRDSF_DEFFLAGS,       ws_boolean, setfn_flag },
+  /* Wordsplit options */
+  { "nullglob",       WRDSO_NULLGLOB,       ws_boolean, setfn_option },
+  { "failglob",       WRDSO_FAILGLOB,       ws_boolean, setfn_option },
+  { "dotglob",        WRDSO_DOTGLOB,        ws_boolean, setfn_option },
+  { "bskeep_words",   WRDSO_BSKEEP_WORD,    ws_boolean, setfn_option },
+  { "bskeep_quote",   WRDSO_BSKEEP_QUOTE,   ws_boolean, setfn_option },
+  { "bskeep",         WRDSO_BSKEEP_WORD|WRDSO_BSKEEP_QUOTE,
+                                            ws_boolean, setfn_option },
+  { "novarsplit",     WRDSO_NOVARSPLIT,     ws_boolean, setfn_option },
+  { "nocmdsplit",     WRDSO_NOCMDSPLIT,     ws_boolean, setfn_option },
+  { "maxwords",       WRDSO_MAXWORDS, ws_required_argument, setfn_maxwords },
+  /* String options */
+  { "delim",          WRDSF_DELIM,  ws_required_argument, setfn_delim },
+  { "comment",        WRDSF_COMMENT,ws_required_argument, setfn_comment },
+  { "escape",         WRDSF_ESCAPE, ws_required_argument, setfn_escape },
+  { "escape-word",    WRDSF_ESCAPE, ws_required_argument, setfn_escape_word },
+  { "escape-quote",   WRDSF_ESCAPE, ws_required_argument, setfn_escape_quote },
+
+  { "dooffs",         WRDSF_DOOFFS, ws_multiple_arguments, setfn_dooffs },  
+  { "append-args",    0,            ws_multiple_arguments, setfn_append },
+
+  { "help",           0,                   ws_no_argument, setfn_help },
+  
+  { NULL, 0 }
+};
+
+static void
+help (void)
+{
+  size_t i;
+  
+  printf ("usage: %s [options] [VAR=VALUE...] [-- EXTRA...]\n", progname);
+  printf ("options are:\n");
+  for (i = 0; opttab[i].name; i++)
+    {
+      printf (" -");
+      if (opttab[i].arg == ws_boolean)
+	printf ("[no]");
+      if (strncmp (opttab[i].name, "no", 2) == 0)
+	printf ("%s", opttab[i].name + 2);
+      else
+	printf ("%s", opttab[i].name);
+      switch (opttab[i].arg)
+	{
+	case ws_no_argument:
+	case ws_boolean:
+	  break;
+	case ws_required_argument:
+	  printf(" ARG");
+	  break;
+	case ws_multiple_arguments:
+	  printf(" ARGS... --");
+	}
+      putchar ('\n');
+    }
+  putchar ('\n');
+}
+
+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, &quote);
+
+  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 * 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;
+}
+
+static int
+wsp_getvar (char **ret, const char *vptr, size_t vlen, void *data)
+{
+  char **base = data;
+  int i;
+
+  for (i = 0; base[i]; i++)
+    {
+      size_t l = strcspn (base[i], "=");
+      if (l == vlen && memcmp (base[i], vptr, vlen) == 0)
+	{
+	  char *p = strdup (base[i] + vlen + 1);
+	  if (p == NULL)
+	    return WRDSE_NOSPACE;
+	  *ret = p;
+	  return WRDSE_OK;
+	}
+    }
+  return WRDSE_UNDEF;
+}
+
+static int
+cmd_quote (char **ret, const char *str, size_t len, char **argv)
+{
+  int alen;
+  for (alen = 0; alen < len && !(str[alen] == ' ' || str[alen] == '\t'); alen++)
+    ;
+  for (; alen < len && (str[alen] == ' ' || str[alen] == '\t'); alen++)
+    ;
+  len -= alen;
+  *ret = malloc (len + 1);
+  if (!*ret)
+    return WRDSE_NOSPACE;
+  memcpy (*ret, str + alen, len);
+  (*ret)[len] = 0;
+  return WRDSE_OK;
+}
+  
+static int
+cmd_words (char **ret, const char *str, size_t len, char **argv)
+{
+  char *p;
+  int i;
+  
+  p = malloc (len + 1);
+  if (!p)
+    return WRDSE_NOSPACE;
+  *ret = p;
+  for (i = 1; argv[i]; i++)
+    {
+      size_t s = strlen (argv[i]);
+      if (i > 1)
+	*p++ = ' ';
+      memcpy (p, argv[i], s);
+      p += s;
+    }
+  *p = 0;
+  return WRDSE_OK;
+}
+
+static int
+cmd_lines (char **ret, const char *str, size_t len, char **argv)
+{
+  char *p;
+  int i;
+  
+  p = malloc (len + 1);
+  if (!p)
+    return WRDSE_NOSPACE;
+  *ret = p;
+  for (i = 1; argv[i]; i++)
+    {
+      size_t s = strlen (argv[i]);
+      if (i > 1)
+	*p++ = '\n';
+      memcpy (p, argv[i], s);
+      p += s;
+    }
+  *p = 0;
+  return WRDSE_OK;
+}
+
+static struct command
+{
+  char const *name;
+  int (*cmd)(char **ret, const char *str, size_t len, char **argv);
+} comtab[] = {
+  { "quote", cmd_quote },
+  { "words", cmd_words },
+  { "lines", cmd_lines }
+};
+
+static int
+wsp_runcmd (char **ret, const char *str, size_t len, char **argv, void *closure)
+{
+  int i;
+  size_t s = 0;
+  char const msg[] = "unknown command: ";
+  
+  for (i = 0; ; i++)
+    {
+      if (i == sizeof (comtab) / sizeof (comtab[0]))
+	break;
+      if (strcmp (comtab[i].name, argv[0]) == 0)
+	return comtab[i].cmd (ret, str, len, argv);
+    }
+
+  *ret = malloc (sizeof (msg) + strlen (argv[0]));
+  if (!*ret)
+    return WRDSE_NOSPACE;
+  strcat (strcpy (*ret, msg), argv[0]);
+  return WRDSE_USERERR;
+}
+
+int
+main (int argc, char **argv)
+{
+  struct wsclosure wsc;
+  char *fenvbase[128];
+  char buf[1024], *ptr, *saved_ptr;
+  int next_call = 0;
+
+  wsc.options = 0;
+  wsc.wsflags = 0;
+  wsc.env_type = env_sys;
+  wsc.offarg = 0;
+  wsc.fenvbase = fenvbase;
+  wsc.fenvmax = sizeof (fenvbase) / sizeof (fenvbase[0]);
+  wsc.fenvidx = 0;
+  wsc.ws.ws_options = 0;
+  wsc.wsflags = (WRDSF_DEFFLAGS & ~WRDSF_NOVAR) |
+                 WRDSF_ENOMEMABRT |
+                 WRDSF_SHOWERR;
+  wsc.append_count = 0;
+  
+  progname = argv[0];
+  while (getwsopt (argc, argv, opttab, &wsc) != EOF)
+    ;
+
+  if (wsc.fenvidx > 0)
+    {
+      wsc.fenvbase[wsc.fenvidx] = NULL;
+      wsc.wsflags |= WRDSF_GETVAR | WRDSF_CLOSURE;
+      wsc.ws.ws_getvar = wsp_getvar;
+      wsc.ws.ws_closure = fenvbase;
+    }
+
+  if (wsoptind < argc)
+    {
+      wsc.ws.ws_paramc = argc - wsoptind;
+      wsc.ws.ws_paramv = (char const **) (argv + wsoptind);
+      wsc.ws.ws_options |= WRDSO_PARAMV|WRDSO_PARAM_NEGIDX;
+      wsc.wsflags |= WRDSF_OPTIONS;
+    }
+
+  switch (wsc.env_type)
+    {
+    case env_null:
+      wsc.wsflags |= WRDSF_ENV;
+      wsc.ws.ws_env = NULL;
+      break;
+
+    case env_none:
+      break;
+
+    case env_sys:
+      wsc.wsflags |= WRDSF_ENV;
+      if (wsc.wsflags & WRDSF_ENV_KV)
+	wsc.ws.ws_env = (const char **) make_env_kv ();
+      else
+	wsc.ws.ws_env = (const char **) environ;
+      break;
+    }
+  
+  if (!(wsc.wsflags & WRDSF_NOCMD))
+    wsc.ws.ws_command = wsp_runcmd;
+  
+  if (wsc.wsflags & WRDSF_INCREMENTAL)
+    wsc.options |= TRIMNL_OPTION;
+  
+  next_call = 0;
+  while ((ptr = fgets (buf, sizeof (buf), stdin)))
+    {
+      int rc;
+      size_t i;
+      
+      if (wsc.options & TRIMNL_OPTION)
+	{
+	  size_t len = strlen (ptr);
+	  if (len && ptr[len-1] == '\n')
+	    ptr[len-1] = 0;
+	}
+      
+      if (wsc.wsflags & WRDSF_INCREMENTAL)
+	{
+	  if (next_call)
+	    {
+	      if (*ptr == 0)
+		ptr = NULL;
+	      else
+		free (saved_ptr);
+	    }
+	  else
+	    next_call = 1;
+	  if (ptr)
+	    {
+	      ptr = saved_ptr = strdup (ptr);
+	      assert (ptr != NULL);
+	    }
+	}
+	
+      rc = wordsplit (ptr, &wsc.ws, wsc.wsflags);
+      if (rc)
+	{
+	  if (!(wsc.wsflags & WRDSF_SHOWERR))
+	    wordsplit_perror (&wsc.ws);
+	  continue;
+	}
+	  
+      if (wsc.offarg)
+	{
+	  size_t i;
+	  for (i = 0; i < wsc.ws.ws_offs; i++)
+	    wsc.ws.ws_wordv[i] = argv[wsc.offarg + i];
+	  wsc.offarg = 0;
+	}
+
+      if (wsc.append_count)
+	{
+	  rc = wordsplit_append (&wsc.ws, wsc.append_count,
+				 argv + wsc.append_start);
+	  if (rc)
+	    {
+	      if (!(wsc.wsflags & WRDSF_SHOWERR))
+		wordsplit_perror (&wsc.ws);
+	      continue;
+	    }
+	}
+      
+      wsc.wsflags |= WRDSF_REUSE;
+      printf ("NF: %lu", (unsigned long) wsc.ws.ws_wordc);
+      if (wsc.wsflags & WRDSF_DOOFFS)
+	printf (" (%lu)", (unsigned long) wsc.ws.ws_offs);
+      putchar ('\n');
+      for (i = 0; i < wsc.ws.ws_offs; i++)
+	{
+	  printf ("(%lu): ", (unsigned long) i);
+	  print_qword (wsc.ws.ws_wordv[i], wsc.options & PLAINTEXT_OPTION);
+	  putchar ('\n');
+	}
+      for (; i < wsc.ws.ws_offs + wsc.ws.ws_wordc; i++)
+	{
+	  printf ("%lu: ", (unsigned long) i);
+	  print_qword (wsc.ws.ws_wordv[i], wsc.options & PLAINTEXT_OPTION);
+	  putchar ('\n');
+	}
+      printf ("TOTAL: %lu\n", (unsigned long) wsc.ws.ws_wordi);
+    }
+  return 0;
+}
diff --git a/po/LINGUAS b/po/LINGUAS
index 76b769c..73367fb 100644
--- a/po/LINGUAS
+++ b/po/LINGUAS
@@ -1,11 +1,13 @@
 da
 de
 eo
+es
 fr
 hu
 nl
 pl
 pt_BR
 sr
+sv
 uk
 vi
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 393b83d..a203c98 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -4,7 +4,6 @@ src/cmdline.h
 src/config.c
 src/direvent.c
 src/environ.c
-src/hashtab.c
 src/progman.c
 src/watcher.c
 
@@ -14,4 +13,4 @@ grecs/src/path-parser.c
 grecs/src/preproc.c
 grecs/src/symtab.c
 grecs/src/tree.c
-grecs/src/wordsplit.c
+grecs/wordsplit/wordsplit.c
diff --git a/po/da.gmo b/po/da.gmo
index f66be15..f2859be 100644
Binary files a/po/da.gmo and b/po/da.gmo differ
diff --git a/po/da.po b/po/da.po
index 16d3cb0..850b54e 100644
--- a/po/da.po
+++ b/po/da.po
@@ -1,20 +1,24 @@
 # Danish translation libgsasl.
-# Copyright (C) 2015 Free Software Foundation, Inc.
+# Copyright (C) 2016 Free Software Foundation, Inc.
 # This file is distributed under the same license as the direvent package.
-# Joe Hansen <joedalton2@yahoo.dk>, 2015.
+# Joe Hansen <joedalton2@yahoo.dk>, 2015, 2016.
+#
+# statement -> erklæring (i programmering)
+# syslog er ikke oversat til systemlog
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: direvent-4.1.91\n"
+"Project-Id-Version: direvent-5.1\n"
 "Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
-"POT-Creation-Date: 2016-07-06 17:50+0300\n"
-"PO-Revision-Date: 2015-05-01 15:00+0000\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
+"PO-Revision-Date: 2016-11-03 16:00+0000\n"
 "Last-Translator: Joe Hansen <joedalton2@yahoo.dk>\n"
 "Language-Team: Danish <dansk@dansk-gruppen.dk>\n"
 "Language: da\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
 #: cmdline.opt:26
@@ -30,7 +34,7 @@ msgid ""
 "log everything with priority PRIO and higher to the stderr, as well as to "
 "the syslog"
 msgstr ""
-"log alt med prioritet PRIO og højere til standardfejl, samt til systemloggen"
+"log alt med prioritet PRIO og højere til standardfejl, samt til sysloggen"
 
 #: cmdline.opt:41
 msgid "NAME"
@@ -46,11 +50,11 @@ msgstr "bliv i forgrunden"
 
 #: cmdline.opt:53
 msgid "DIR"
-msgstr ""
+msgstr "MAPPE"
 
 #: cmdline.opt:53
 msgid "add include directory"
-msgstr ""
+msgstr "tilføj include-mappe"
 
 #: cmdline.opt:59
 msgid "PROG"
@@ -129,15 +133,18 @@ msgstr ""
 "Denne direvent bruger %s-grænsefladen.\n"
 "\n"
 
+# Hvis man linker til andre biblioteker når man kompilerer, skriver man
+# ofte "#include <stdio.h>", f.eks., og dette er nok søgestierne hvor
+# den kigger efter filer såsom stdio.h.
 #: cmdline.opt:102
 #, c-format
 msgid "Include search path:\n"
-msgstr ""
+msgstr "Søgesti for include:\n"
 
 #: cmdline.opt:105
 #, c-format
 msgid "No include search path.\n"
-msgstr ""
+msgstr "Ingen include-søgesti.\n"
 
 #: src/config.c:63
 #, c-format
@@ -151,7 +158,7 @@ msgstr "ukendt syslog-prioritet: %s"
 
 #: src/config.c:88
 msgid "unexpected block statement"
-msgstr "uventet blokudtryk"
+msgstr "uventet blokerklæring"
 
 #: src/config.c:97
 #, c-format
@@ -168,7 +175,7 @@ msgstr "forventede %s, men fandt %s"
 msgid "unknown syslog facility `%s'"
 msgstr "ukendt syslog-facilitet »%s«"
 
-#: src/config.c:133 src/config.c:706
+#: src/config.c:133 src/config.c:606
 msgid "name"
 msgstr "navn"
 
@@ -182,7 +189,7 @@ msgstr ""
 "authpriv, mail, cron, local0 til local7 (ikke forskel på små/store "
 "bogstaver), eller et facilitetnummer."
 
-#: src/config.c:139
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
 msgid "string"
 msgstr "streng"
 
@@ -196,181 +203,170 @@ msgstr "arg"
 
 #: src/config.c:143
 msgid "Prefix each message with its priority"
-msgstr "Lav præfiks for hver besked med deres prioritet"
+msgstr "Foranstil prioritet for hver besked"
 
-#: src/config.c:209
+#: src/config.c:191
 #, c-format
 msgid "%s: recursion depth does not match previous definition"
 msgstr "%s: rekursionsdybde matcher ikke foregående definition"
 
-#: src/config.c:247
+#: src/config.c:212
 msgid "no paths configured"
 msgstr "ingen stier er konfigureret"
 
-#: src/config.c:252
+#: src/config.c:217
 msgid "no command configured"
 msgstr "ingen kommando er konfigureret"
 
-#: src/config.c:264 grecs/src/tree.c:634
+#: src/config.c:229 grecs/src/tree.c:665
 msgid "invalid use of block statement"
-msgstr "ugyldig brug af blokudtryk"
+msgstr "ugyldig brug af blokerklæring"
 
-#: src/config.c:309
+#: src/config.c:274
 msgid "expected \"recursive\" or end of statement"
-msgstr "forventede »recursive« eller udtryksafslutning"
+msgstr "forventede »recursive« eller erklæringsafslutning"
 
-#: src/config.c:324
+#: src/config.c:289
 msgid "surplus argument"
 msgstr "overskydende argument"
 
-#: src/config.c:330 src/config.c:481
+#: src/config.c:295 src/config.c:446
 msgid "unexpected list"
 msgstr "uventet liste"
 
-#: src/config.c:361 src/config.c:376 src/config.c:391
+#: src/config.c:326 src/config.c:341 src/config.c:356
 msgid "unrecognized event code"
 msgstr "ukendt hændelseskode"
 
-#: src/config.c:473
+#: src/config.c:438
 msgid "surplus arguments"
 msgstr "overskydende argumenter"
 
-#: src/config.c:487
+#: src/config.c:452
 msgid "no such user"
 msgstr "ingen sådan bruger"
 
-#: src/config.c:494
+#: src/config.c:459
 msgid "no such group"
 msgstr "ingen sådan gruppe"
 
-#: src/config.c:535
-#, fuzzy
+#: src/config.c:501
 msgid "unrecognized option"
-msgstr "ukendt flag"
-
-#: src/config.c:613
-msgid "unterminated regexp"
-msgstr "uafsluttet regulært udtryk"
+msgstr "ukendt tilvalg"
 
-#: src/config.c:627
-#, c-format
-msgid "unrecognized flag: %c"
-msgstr "ukendt flag: %c"
-
-#: src/config.c:695
+#: src/config.c:595
 msgid "Pathname to watch"
 msgstr "Stinavn at overvåge"
 
-#: src/config.c:698
+#: src/config.c:598
 msgid "Events to watch for"
 msgstr "Hændelser at overvåge"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "regexp"
 msgstr "regulært udtryk"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "Files to watch for"
 msgstr "Filer at overvåge"
 
-#: src/config.c:704
+#: src/config.c:604
 msgid "Command to execute on event"
 msgstr "Kommando at køre ved hændelse"
 
-#: src/config.c:706
+#: src/config.c:606
 msgid "Run command as this user"
 msgstr "Kør kommando som denne bruger"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "seconds"
 msgstr "sekunder"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "Timeout for the command"
 msgstr "Tidsudløb for kommando"
 
-#: src/config.c:711
+#: src/config.c:611
 msgid "List of additional options"
-msgstr "Lister over yderligere tilvalg"
+msgstr "Liste over yderligere tilvalg"
 
-#: src/config.c:714
+#: src/config.c:614
 msgid "<arg: string> <arg: string>..."
-msgstr "<arg: streng> <arg: strenge>..."
+msgstr "<arg: streng> <arg: streng>..."
 
-#: src/config.c:715
+#: src/config.c:615
 msgid "Modify environment"
 msgstr "Ændr miljø"
 
-#: src/config.c:722
+#: src/config.c:622
 msgid "Run as this user"
 msgstr "Kør som denne bruger"
 
-#: src/config.c:724
+#: src/config.c:624
 msgid "Run in foreground"
 msgstr "Kør i forgrunden"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "file"
 msgstr "fil"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "Set pid file name"
 msgstr "Angiv pid-filnavn"
 
-#: src/config.c:728
+#: src/config.c:628
 msgid "Configure syslog logging"
 msgstr "Konfigurer syslog-logning"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "level"
 msgstr "niveau"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "Set debug level"
 msgstr "Angiv fejlsøgningsniveau"
 
-#: src/config.c:732
+#: src/config.c:632
 msgid "Configure event watcher"
 msgstr "Konfigurer hændelsesovervåger"
 
-#: src/config.c:743
+#: src/config.c:643
 msgid ""
 "Configuration file structure for direvent.\n"
 "For more information, use `info direvent configuration'."
 msgstr ""
 "Konfigurationsfilstruktur for direvent.\n"
-"For yderligere information, brug »info direvent configuration«."
+"Brug »info direvent configuration« for yderligere information."
 
-#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:86 src/watcher.c:182
-#: src/watcher.c:191
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
 msgid "not enough memory"
 msgstr "ikke nok hukommelse"
 
-#: src/direvent.c:272
+#: src/direvent.c:274
 #, c-format
 msgid "cannot open pidfile %s for writing: %s"
-msgstr "kan ikke åbne pid-filen %s for skrivning: %s"
+msgstr "kan ikke åbne pid-filen %s til skrivning: %s"
 
-#: src/direvent.c:300
+#: src/direvent.c:302
 #, c-format
 msgid "no user with UID %lu"
 msgstr "ingen bruger med UID: %lu"
 
-#: src/direvent.c:418
+#: src/direvent.c:420
 #, c-format
 msgid "cannot run `%s': fork failed: %s"
 msgstr "kan ikke køre »%s«: forgrening mislykkedes: %s"
 
-#: src/direvent.c:478
+#: src/direvent.c:480
 msgid "too many arguments"
 msgstr "for mange argumenter"
 
-#: src/direvent.c:520
+#: src/direvent.c:522
 #, c-format
 msgid "%s %s started"
 msgstr "%s %s startet"
 
-#: src/direvent.c:541
+#: src/direvent.c:546
 #, c-format
 msgid "%s %s stopped"
 msgstr "%s %s stoppet"
@@ -379,22 +375,10 @@ msgstr "%s %s stoppet"
 msgid "environment: "
 msgstr "miljø: "
 
-#: src/hashtab.c:140 grecs/src/symtab.c:206
-msgid "element not found in table"
-msgstr "element blev ikke fundet i tabel"
-
-#: src/hashtab.c:142 grecs/src/symtab.c:208
-msgid "symbol table is full"
-msgstr "symboltabel er fuld"
-
-#: src/hashtab.c:144
-msgid "out of memory"
-msgstr "ikke mere hukommelse"
-
 #: src/progman.c:142
 #, c-format
 msgid "process %lu exited successfully"
-msgstr "processen %lu afsluttedes med succes"
+msgstr "processen %lu blev udført"
 
 #: src/progman.c:145
 #, c-format
@@ -414,7 +398,7 @@ msgstr "processen %lu stoppede ved signalet %d"
 #: src/progman.c:163
 #, c-format
 msgid "process %lu dumped core"
-msgstr "processen %lu dumpet kerne"
+msgstr "processen %lu dumpede kerne"
 
 #: src/progman.c:167
 #, c-format
@@ -438,7 +422,7 @@ msgstr "planlægger alarm om %lu sekunder"
 #: src/progman.c:322
 #, c-format
 msgid "cannot start redirector for %s, pipe failed: %s"
-msgstr "kan ikke starte videresender for %s, datakanal mislykkedes: %s"
+msgstr "kan ikke starte videresender for %s; datakanal mislykkedes: %s"
 
 #: src/progman.c:354
 #, c-format
@@ -450,73 +434,123 @@ msgstr "kan ikke køre videresender »%s«: forgrening mislykkedes: %s"
 msgid "redirector for %s started, pid=%lu"
 msgstr "videresender for %s startet, pid=%lu"
 
-#: src/progman.c:454
+#: src/progman.c:455
 #, c-format
 msgid "starting %s, dir=%s, file=%s"
 msgstr "starter %s, mappe=%s, fil=%s"
 
-#: src/progman.c:482
+#: src/progman.c:484
 #, c-format
 msgid "cannot change to %s: %s"
 msgstr "kan ikke ændre til %s: %s"
 
-#: src/progman.c:510
+#: src/progman.c:512
 #, c-format
 msgid "%s running; dir=%s, file=%s, pid=%lu"
-msgstr "%s kørende; mapppe=%s fil=%s, pid=%lu"
+msgstr "%s kører; mappe=%s fil=%s, pid=%lu"
 
-#: src/progman.c:532
+#: src/progman.c:534
 #, c-format
 msgid "waiting for %s (%lu) to terminate"
 msgstr "venter på %s (%lu) for at afslutte"
 
-#: src/watcher.c:231
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr "fjerner overvåger %s"
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
 #, c-format
 msgid "creating watcher %s"
 msgstr "opretter overvåger %s"
 
-#: src/watcher.c:240
+#: src/watcher.c:281 src/watcher.c:296
 #, c-format
 msgid "cannot set watcher on %s: %s"
 msgstr "kan ikke angive overvåger på %s: %s"
 
-#: src/watcher.c:319
+#: src/watcher.c:377
 #, c-format
 msgid "cannot create watcher %s/%s: not enough memory"
 msgstr "kan ikke oprettet overvåger %s/%s: ikke nok hukommelse"
 
-#: src/watcher.c:326
+#: src/watcher.c:384
 #, c-format
 msgid "cannot create watcher %s/%s, stat failed: %s"
 msgstr "kan ikke oprette overvåger %s/%s, kørsel af stat mislykkedes: %s"
 
-#: src/watcher.c:355
+#: src/watcher.c:430
 #, c-format
 msgid "cannot open directory %s: %s"
 msgstr "kan ikke åbne mappen %s: %s"
 
-#: src/watcher.c:371
+#: src/watcher.c:447
 #, c-format
 msgid "cannot stat %s/%s: not enough memory"
 msgstr "kan ikke køre stat på %s/%s: ikke nok hukommelse"
 
-#: src/watcher.c:376
+#: src/watcher.c:452
 #, c-format
 msgid "cannot stat %s: %s"
-msgstr "Kan ikke køre stat på %s: %s"
+msgstr "kan ikke køre stat på %s: %s"
 
-#: src/watcher.c:412
+#: src/watcher.c:497
 msgid "no event handlers configured"
 msgstr "ingen hændelseshåndtering konfigureret"
 
-#: src/watcher.c:417
+#: src/watcher.c:502
 msgid "no event handlers installed"
 msgstr "ingen hændelseshåndteringer installeret"
 
-#: src/watcher.c:425
-#, c-format
-msgid "removing watcher %s"
-msgstr "fjerner overvåger %s"
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+#, fuzzy
+msgid "hostname"
+msgstr "navn"
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
+msgstr ""
 
 #: grecs/src/format.c:133
 msgid "Disabled;"
@@ -556,22 +590,25 @@ msgstr ""
 msgid "Report bugs to %s.\n"
 msgstr ""
 "Rapporter fejl til %s.\n"
-"Joe Hansen, 2015.\n"
 "\n"
+"Oversættelse:\n"
+"Joe Hansen, 2015-2016.\n"
+"\n"
+"Rapporter fejl i oversættelsen til Danskgruppen.\n"
 "Dansk-gruppen <dansk@dansk-gruppen.dk>\n"
 "Mere info: http://www.dansk-gruppen.dk\n"
 
 #: grecs/src/opthelp.c:205
 #, c-format
 msgid "%s home page: <%s>\n"
-msgstr "%s hjemmeside: <%s>\n"
+msgstr "Hjemmeside for %s: <%s>\n"
 
 #. TRANSLATORS: Translate "(C)" to the copyright symbol
 #. (C-in-a-circle), if this symbol is available in the user's
 #. locale.  Otherwise, do not translate "(C)"; leave it as-is.
 #: grecs/src/opthelp.c:457
 msgid "(C)"
-msgstr "(C)"
+msgstr "©"
 
 #: grecs/src/opthelp.c:466
 msgid ""
@@ -585,7 +622,7 @@ msgstr ""
 "html>.\n"
 "Dette er et frit program: du kan frit ændre og videredistribuere "
 "programmet.\n"
-"Der er ingen GARANTI, inden for lovens udstrækning.\n"
+"Der er INGEN GARANTI, inden for lovens udstrækning.\n"
 "\n"
 
 #: grecs/src/opthelp.c:483
@@ -649,22 +686,26 @@ msgstr "Kan ikke åbne »%s«"
 
 #: grecs/src/preproc.c:595
 msgid "Cannot parse include line"
-msgstr "Kan ikke fortolke inkluderingslinje"
+msgstr "Kan ikke fortolke include-linje"
 
 #: grecs/src/preproc.c:598
 msgid "invalid include statement"
-msgstr "ugyldigt inkluderingsudtryk"
+msgstr "ugyldigt include-erklæring"
 
 #: grecs/src/preproc.c:624
-#, fuzzy
 msgid "read error"
-msgstr "fortolkningsfejl"
+msgstr "læsefejl"
 
 #: grecs/src/preproc.c:632
 #, c-format
 msgid "%s: No such file or directory"
 msgstr "%s: Ingen sådan fil eller mappe"
 
+# præprocessoren/forbrænderen forbehandler C-kode før den kompileres.  Det som
+# præprocessoren/forbrænderen gør er modificere teksten når den møder kommandoer.
+# F.eks. #include <filnavn> betyder "indsæt indholdet af <filnavn> her
+# midt inde i koden", og man kan også definere at f.eks. ORD skal
+# erstattes med en eller anden tekst
 #: grecs/src/preproc.c:698
 #, c-format
 msgid "Unable to start external preprocessor `%s'"
@@ -675,185 +716,240 @@ msgstr "Kan ikke starte ekstern forbrænder »%s«"
 msgid "Cannot run `%s'"
 msgstr "Kan ikke køre »%s«"
 
-#: grecs/src/tree.c:329
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr "element blev ikke fundet i tabel"
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr "symboltabel er fuld"
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+#, fuzzy
+msgid "one or more arguments"
+msgstr "for mange argumenter"
+
+#: grecs/src/tree.c:75
+#, fuzzy
+msgid "unrecognized type; please report"
+msgstr "ukendt hændelseskode"
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+#, fuzzy
+msgid "unknown keyword"
+msgstr "Ukendt nøgleord"
+
+#: grecs/src/tree.c:360
 #, c-format
 msgid "%s: not a valid boolean value"
 msgstr "%s: ikke en gyldig boolesk værdi"
 
-#: grecs/src/tree.c:360
+#: grecs/src/tree.c:391
 #, c-format
 msgid "%s: UNIX socket name too long"
 msgstr "%s: UNIX-sokkelnavn er for langt"
 
-#: grecs/src/tree.c:389 grecs/src/tree.c:613
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
 #, c-format
 msgid "%s: not a valid IP address or hostname"
 msgstr "%s: ikke en gyldig IP-adresse eller værtsnavn"
 
-#: grecs/src/tree.c:413
+#: grecs/src/tree.c:444
 #, c-format
 msgid "%s: not a valid port number"
 msgstr "%s: ikke et gyldigt portnummer"
 
-#: grecs/src/tree.c:421
+#: grecs/src/tree.c:452
 msgid "missing port number"
 msgstr "mangler portnummer"
 
-#: grecs/src/tree.c:470
+#: grecs/src/tree.c:501
 msgid "numeric overflow"
 msgstr "numerisk overløb"
 
-#: grecs/src/tree.c:475
+#: grecs/src/tree.c:506
 msgid "value out of allowed range"
 msgstr "værdien er uden for det tilladte interval"
 
-#: grecs/src/tree.c:510 grecs/src/tree.c:540
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
 #, c-format
 msgid "not a number (stopped near `%s')"
-msgstr "ikke et nummer (stoppet nær »%s«)"
+msgstr "ikke et tal (stoppede nær »%s«)"
 
-#: grecs/src/tree.c:604
+#: grecs/src/tree.c:635
 #, c-format
 msgid "%s: not a valid IP address"
 msgstr "%s: ikke en gyldig IP-adresse"
 
-#: grecs/src/tree.c:743
+#: grecs/src/tree.c:774
 #, c-format
 msgid "too many arguments to `%s'; missing semicolon?"
 msgstr "for mange argumenter for »%s«; manglende semikolon?"
 
-#: grecs/src/tree.c:757 grecs/src/tree.c:805
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
 #, c-format
 msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
 msgstr "INTERN FEJL ved %s:%d: datatypen %d blev ikke håndteret"
 
-#: grecs/src/tree.c:772
+#: grecs/src/tree.c:803
 #, c-format
 msgid "%s: incompatible data type in list item #%d"
 msgstr "%s: datatypen i listepunktet #%d er ikke kompatibel"
 
-#: grecs/src/tree.c:792
+#: grecs/src/tree.c:823
 #, c-format
 msgid "incompatible data type for `%s'"
 msgstr "datatypen for »%s« er ikke kompatibel"
 
-#: grecs/src/tree.c:920 grecs/src/tree.c:930
-msgid "Unknown keyword"
-msgstr "Ukendt nøgleord"
-
-#: grecs/src/tree.c:1139
-#, c-format
-msgid "%s: unknown keyword"
-msgstr "%s: ukendt nøgleord"
-
-#: grecs/src/wordsplit.c:62 grecs/src/wordsplit.c:2300
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
 msgid "memory exhausted"
 msgstr "hukommelsen er opbrugt"
 
-#: grecs/src/wordsplit.c:1073
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:1607
 #, c-format
 msgid "%.*s: variable null or not set"
-msgstr ""
+msgstr "%.*s: variabel er null eller ikke angivet"
 
-#: grecs/src/wordsplit.c:1102
+#: grecs/wordsplit/wordsplit.c:1637
 #, c-format
 msgid "warning: undefined variable `%.*s'"
-msgstr "advarsel: ikke defineret variable »%.*s«"
+msgstr "advarsel: variabel er ikke defineret »%.*s«"
 
-#: grecs/src/wordsplit.c:1630
+#: grecs/wordsplit/wordsplit.c:2141
 #, c-format
 msgid "no files match pattern %s"
-msgstr ""
+msgstr "ingen filer matcher mønster %s"
 
-#: grecs/src/wordsplit.c:2080
+#: grecs/wordsplit/wordsplit.c:2603
 msgid "WS trimming"
-msgstr ""
+msgstr "WS-tilpasning"
 
-#: grecs/src/wordsplit.c:2081
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
+msgstr "kommandosubstitution"
+
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
+msgstr "sammensmelt liste"
+
+# expansion er her mere en evaluering eller udskrivning af noget
+# længere, f.eks. at konvertere ~brugernavn til /home/brugernavn.
+# Jeg ville sige tilde-erstatning, tilde-omskrivning eller lignende
+#: grecs/wordsplit/wordsplit.c:2609
 msgid "tilde expansion"
-msgstr ""
+msgstr "tilde-erstatning"
 
-#: grecs/src/wordsplit.c:2082
+#: grecs/wordsplit/wordsplit.c:2611
 msgid "variable expansion"
-msgstr ""
+msgstr "variabelerstatning"
 
-#: grecs/src/wordsplit.c:2084
+#: grecs/wordsplit/wordsplit.c:2613
 msgid "quote removal"
-msgstr ""
+msgstr "citatfjernelse"
 
-#: grecs/src/wordsplit.c:2086
-#, fuzzy
-msgid "command substitution"
-msgstr "kommandosubstitution er endnu ikke understøttet"
-
-#: grecs/src/wordsplit.c:2088
-msgid "coalesce list"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2090
+#: grecs/wordsplit/wordsplit.c:2617
 msgid "path expansion"
-msgstr ""
+msgstr "sti-erstatning"
 
-#: grecs/src/wordsplit.c:2120
-msgid "Initial list:"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2136
-#, fuzzy
-msgid "Coalesced list:"
-msgstr "uventet liste"
-
-#: grecs/src/wordsplit.c:2190
+#: grecs/wordsplit/wordsplit.c:2642
 #, c-format
 msgid "(%02d) Input:%.*s;"
-msgstr ""
+msgstr "(%02d) Inddata:%.*s;"
 
-#: grecs/src/wordsplit.c:2202
-#, c-format
-msgid "(%02d) Restart:%.*s;"
-msgstr ""
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
+msgstr "Startliste:"
+
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr "Sammensmeltet liste:"
 
-#: grecs/src/wordsplit.c:2298
+#: grecs/wordsplit/wordsplit.c:2853
 msgid "no error"
 msgstr "ingen fejl"
 
-#: grecs/src/wordsplit.c:2299
+#: grecs/wordsplit/wordsplit.c:2854
 msgid "missing closing quote"
 msgstr "mangler afsluttende citationstegn"
 
-#: grecs/src/wordsplit.c:2301
+#: grecs/wordsplit/wordsplit.c:2856
 msgid "invalid wordsplit usage"
 msgstr "ugyldig orddelingsbrug"
 
-#: grecs/src/wordsplit.c:2302
+#: grecs/wordsplit/wordsplit.c:2857
 msgid "unbalanced curly brace"
 msgstr "krøllet parentes er ikke lukket"
 
-#: grecs/src/wordsplit.c:2303
+#: grecs/wordsplit/wordsplit.c:2858
 msgid "undefined variable"
 msgstr "udefineret variabel"
 
-#: grecs/src/wordsplit.c:2304
+#: grecs/wordsplit/wordsplit.c:2859
 msgid "input exhausted"
 msgstr "inddata opbrugt"
 
-#: grecs/src/wordsplit.c:2305
+#: grecs/wordsplit/wordsplit.c:2860
 msgid "unbalanced parenthesis"
-msgstr ""
+msgstr "parentes uden modpart"
+
+# gerne glob-fejl
+# glob er når man siger "*.txt" og den laver stjernen om til en liste af
+# filer.  globbing er et "improviseret" verbum, som ikke virkelig
+# findes, så på dansk er det bedre bare at sige glob (alternativt
+# "globningsfejl", men det er nok ikke så pænt)
+#: grecs/wordsplit/wordsplit.c:2861
+msgid "globbing error"
+msgstr "glob-fejl"
 
-#: grecs/src/wordsplit.c:2306
+#: grecs/wordsplit/wordsplit.c:2862
 #, fuzzy
-msgid "globbing error"
-msgstr "ingen fejl"
+msgid "user-defined error"
+msgstr "læsefejl"
+
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
 
-#: grecs/src/wordsplit.c:2318
+#: grecs/wordsplit/wordsplit.c:2875
 msgid "unknown error"
 msgstr "ukendt fejl"
 
-#: grecs/src/wordsplit.c:2327
+#: grecs/wordsplit/wordsplit.c:2884
 #, c-format
 msgid "missing closing %c (start near #%lu)"
 msgstr "mangler afsluttende %c (start nær #%lu)"
 
-#~ msgid "INTERNAL ERROR at %s:%d"
-#~ msgstr "INTERN FEJL ved %s:%d"
+#~ msgid "unterminated regexp"
+#~ msgstr "uafsluttet regulært udtryk"
+
+#~ msgid "unrecognized flag: %c"
+#~ msgstr "ukendt flag: %c"
+
+#~ msgid "out of memory"
+#~ msgstr "ikke mere hukommelse"
+
+#~ msgid "%s: unknown keyword"
+#~ msgstr "%s: ukendt nøgleord"
+
+#~ msgid "(%02d) Restart:%.*s;"
+#~ msgstr "(%02d) Genstart:%.*s;"
diff --git a/po/de.gmo b/po/de.gmo
index a09467e..7d7ff3a 100644
Binary files a/po/de.gmo and b/po/de.gmo differ
diff --git a/po/de.po b/po/de.po
index 4c70fd2..d5fe7af 100644
--- a/po/de.po
+++ b/po/de.po
@@ -1,22 +1,23 @@
 # German translation of direvent.
 # Copyright (C) 2014 Free Software Foundation, Inc.
 # This file is distributed under the same license as the direvent package.
-# Mario Blättermann <mario.blaettermann@gmail.com>, 2014.
+# Mario Blättermann <mario.blaettermann@gmail.com>, 2014, 2016.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: direvent 4.1.91\n"
+"Project-Id-Version: direvent 5.1\n"
 "Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
-"POT-Creation-Date: 2016-07-06 17:50+0300\n"
-"PO-Revision-Date: 2014-09-11 20:07+0100\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
+"PO-Revision-Date: 2016-07-07 22:45+0200\n"
 "Last-Translator: Mario Blättermann <mario.blaettermann@gmail.com>\n"
 "Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
 "Language: de\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Poedit 1.5.4\n"
+"X-Generator: Poedit 1.8.7.1\n"
 
 #: cmdline.opt:26
 msgid "increase debug level"
@@ -48,11 +49,11 @@ msgstr "Im Vordergrund bleiben"
 
 #: cmdline.opt:53
 msgid "DIR"
-msgstr ""
+msgstr "VERZ"
 
 #: cmdline.opt:53
 msgid "add include directory"
-msgstr ""
+msgstr "Include-Verzeichnis hinzufügen"
 
 #: cmdline.opt:59
 msgid "PROG"
@@ -134,12 +135,12 @@ msgstr ""
 #: cmdline.opt:102
 #, c-format
 msgid "Include search path:\n"
-msgstr ""
+msgstr "Include-Suchpfad:\n"
 
 #: cmdline.opt:105
 #, c-format
 msgid "No include search path.\n"
-msgstr ""
+msgstr "Kein Include-Suchpfad.\n"
 
 #: src/config.c:63
 #, c-format
@@ -170,7 +171,7 @@ msgstr "%s erwartet, aber %s gefunden"
 msgid "unknown syslog facility `%s'"
 msgstr "Unbekannte Leistung des Sytemprotokolls: %s"
 
-#: src/config.c:133 src/config.c:706
+#: src/config.c:133 src/config.c:606
 msgid "name"
 msgstr "Name"
 
@@ -184,7 +185,7 @@ msgstr ""
 "user, daemon, auth, authpriv, mail, cron, local0, local7 (Groß-/"
 "Kleinschreibung spielt keine Rolle), oder eine Nummer einer Leistung."
 
-#: src/config.c:139
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
 msgid "string"
 msgstr "Zeichenkette"
 
@@ -200,142 +201,132 @@ msgstr "Arg"
 msgid "Prefix each message with its priority"
 msgstr "Jeder Meldung deren Priorität voranstellen"
 
-#: src/config.c:209
+#: src/config.c:191
 #, c-format
 msgid "%s: recursion depth does not match previous definition"
 msgstr "%s: Rekursionstiefe entspricht nicht der vorherigen Definition"
 
-#: src/config.c:247
+#: src/config.c:212
 msgid "no paths configured"
 msgstr "Keine Pfade eingerichtet"
 
-#: src/config.c:252
+#: src/config.c:217
 msgid "no command configured"
 msgstr "Kein Befehl eingerichtet"
 
-#: src/config.c:264 grecs/src/tree.c:634
+#: src/config.c:229 grecs/src/tree.c:665
 msgid "invalid use of block statement"
 msgstr "Ungültige Verwendung einer Block-Anweisung"
 
-#: src/config.c:309
+#: src/config.c:274
 msgid "expected \"recursive\" or end of statement"
 msgstr "»recursive« oder Ende der Anweisung erwartet"
 
-#: src/config.c:324
+#: src/config.c:289
 msgid "surplus argument"
 msgstr "Überzähliges Argument"
 
-#: src/config.c:330 src/config.c:481
+#: src/config.c:295 src/config.c:446
 msgid "unexpected list"
 msgstr "Unerwartete Liste"
 
-#: src/config.c:361 src/config.c:376 src/config.c:391
+#: src/config.c:326 src/config.c:341 src/config.c:356
 msgid "unrecognized event code"
 msgstr "Nicht erkannter Ereigniscode"
 
-#: src/config.c:473
+#: src/config.c:438
 msgid "surplus arguments"
 msgstr "Überzählige Argumente"
 
-#: src/config.c:487
+#: src/config.c:452
 msgid "no such user"
 msgstr "Kein solcher Benutzer"
 
-#: src/config.c:494
+#: src/config.c:459
 msgid "no such group"
 msgstr "Keine solche Gruppe"
 
-#: src/config.c:535
-#, fuzzy
+#: src/config.c:501
 msgid "unrecognized option"
-msgstr "Nicht erkannter Schalter"
-
-#: src/config.c:613
-msgid "unterminated regexp"
-msgstr "Nicht beendeter regulärer Ausdruck"
-
-#: src/config.c:627
-#, c-format
-msgid "unrecognized flag: %c"
-msgstr "Nicht erkannter Schalter: %c"
+msgstr "Nicht erkannte Option"
 
-#: src/config.c:695
+#: src/config.c:595
 msgid "Pathname to watch"
 msgstr "Zu überwachender Pfadname"
 
-#: src/config.c:698
+#: src/config.c:598
 msgid "Events to watch for"
 msgstr "Zu überwachende Ereignisse"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "regexp"
 msgstr "Reg. Ausdruck"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "Files to watch for"
 msgstr "Zu überwachende Dateien"
 
-#: src/config.c:704
+#: src/config.c:604
 msgid "Command to execute on event"
 msgstr "Bei Eintritt des Ereignisses auszuführender Befehl"
 
-#: src/config.c:706
+#: src/config.c:606
 msgid "Run command as this user"
 msgstr "Befehl als dieser Benutzer ausführen"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "seconds"
 msgstr "Sekunden"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "Timeout for the command"
 msgstr "Zeitüberschreitung für den Befehl"
 
-#: src/config.c:711
+#: src/config.c:611
 msgid "List of additional options"
 msgstr "Liste der zusätzlichen Optionen"
 
-#: src/config.c:714
+#: src/config.c:614
 msgid "<arg: string> <arg: string>..."
 msgstr "<Arg: Zeichenkette> <Arg: Zeichenkette> …"
 
-#: src/config.c:715
+#: src/config.c:615
 msgid "Modify environment"
 msgstr "Ausführungsumgebung ändern"
 
-#: src/config.c:722
+#: src/config.c:622
 msgid "Run as this user"
 msgstr "Als dieser Benutzer ausführen"
 
-#: src/config.c:724
+#: src/config.c:624
 msgid "Run in foreground"
 msgstr "Im Vordergrund ausführen"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "file"
 msgstr "Datei"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "Set pid file name"
 msgstr "Name der PID-Datei festlegen"
 
-#: src/config.c:728
+#: src/config.c:628
 msgid "Configure syslog logging"
 msgstr "Syslog-Protokollierung einrichten"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "level"
 msgstr "Stufe"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "Set debug level"
 msgstr "Debug-Stufe festlegen"
 
-#: src/config.c:732
+#: src/config.c:632
 msgid "Configure event watcher"
 msgstr "Ereignisüberwachung einrichten"
 
-#: src/config.c:743
+#: src/config.c:643
 msgid ""
 "Configuration file structure for direvent.\n"
 "For more information, use `info direvent configuration'."
@@ -343,36 +334,35 @@ msgstr ""
 "Struktur der Konfigurationsdatei für direvent.\n"
 "Weitere Informationen erhalten Sie mit »info direvent configuration«."
 
-#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:86 src/watcher.c:182
-#: src/watcher.c:191
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
 msgid "not enough memory"
 msgstr "Nicht genügend Speicher"
 
-#: src/direvent.c:272
+#: src/direvent.c:274
 #, c-format
 msgid "cannot open pidfile %s for writing: %s"
 msgstr "PID-Datei %s konnte nicht zum Schreiben geöffnet werden: %s"
 
-#: src/direvent.c:300
+#: src/direvent.c:302
 #, c-format
 msgid "no user with UID %lu"
 msgstr "Kein Benutzer mit UID %lu gefunden"
 
-#: src/direvent.c:418
+#: src/direvent.c:420
 #, c-format
 msgid "cannot run `%s': fork failed: %s"
 msgstr "»%s« kann nicht ausgeführt werden: fork() fehlgeschlagen: %s"
 
-#: src/direvent.c:478
+#: src/direvent.c:480
 msgid "too many arguments"
 msgstr "Zu viele Argumente"
 
-#: src/direvent.c:520
+#: src/direvent.c:522
 #, c-format
 msgid "%s %s started"
 msgstr "%s %s gestartet"
 
-#: src/direvent.c:541
+#: src/direvent.c:546
 #, c-format
 msgid "%s %s stopped"
 msgstr "%s %s gestoppt"
@@ -381,18 +371,6 @@ msgstr "%s %s gestoppt"
 msgid "environment: "
 msgstr "Umgebung:"
 
-#: src/hashtab.c:140 grecs/src/symtab.c:206
-msgid "element not found in table"
-msgstr "Element wurde in Tabelle nicht gefunden"
-
-#: src/hashtab.c:142 grecs/src/symtab.c:208
-msgid "symbol table is full"
-msgstr "Symboltabelle ist voll"
-
-#: src/hashtab.c:144
-msgid "out of memory"
-msgstr "Speicher erschöpft"
-
 #: src/progman.c:142
 #, c-format
 msgid "process %lu exited successfully"
@@ -455,75 +433,125 @@ msgstr ""
 msgid "redirector for %s started, pid=%lu"
 msgstr "Weiterleitung für %s gestartet, PID=%lu"
 
-#: src/progman.c:454
+#: src/progman.c:455
 #, c-format
 msgid "starting %s, dir=%s, file=%s"
 msgstr "%s wird gestartet, Verzeichnis=%s, Datei=%s"
 
-#: src/progman.c:482
+#: src/progman.c:484
 #, c-format
 msgid "cannot change to %s: %s"
 msgstr "Wechsel in %s nicht möglich: %s"
 
-#: src/progman.c:510
+#: src/progman.c:512
 #, c-format
 msgid "%s running; dir=%s, file=%s, pid=%lu"
 msgstr "%s läuft; Verz=%s, Datei=%s, PID=%lu"
 
-#: src/progman.c:532
+#: src/progman.c:534
 #, c-format
 msgid "waiting for %s (%lu) to terminate"
 msgstr "Es wird auf das Beenden von %s (%lu) gewartet"
 
-#: src/watcher.c:231
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr "Überwacher %s wird entfernt"
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
 #, c-format
 msgid "creating watcher %s"
 msgstr "Überwacher %s wird erstellt"
 
-#: src/watcher.c:240
+#: src/watcher.c:281 src/watcher.c:296
 #, c-format
 msgid "cannot set watcher on %s: %s"
 msgstr "Überwachung für %s konnte nicht eingerichtet werden: %s"
 
-#: src/watcher.c:319
+#: src/watcher.c:377
 #, c-format
 msgid "cannot create watcher %s/%s: not enough memory"
 msgstr "Überwacher %s/%s kann nicht erstellt werden: nicht genügend Speicher"
 
-#: src/watcher.c:326
+#: src/watcher.c:384
 #, c-format
 msgid "cannot create watcher %s/%s, stat failed: %s"
 msgstr ""
 "Überwachung für %s%s konnte nicht eingerichtet werden, »stat« "
 "fehlgeschlagen: %s"
 
-#: src/watcher.c:355
+#: src/watcher.c:430
 #, c-format
 msgid "cannot open directory %s: %s"
 msgstr "Verzeichnis %s kann nicht geöffnet werden: %s"
 
-#: src/watcher.c:371
+#: src/watcher.c:447
 #, c-format
 msgid "cannot stat %s/%s: not enough memory"
 msgstr "Aufruf von »stat« für %s/%s nicht möglich: nicht genügend Speicher"
 
-#: src/watcher.c:376
+#: src/watcher.c:452
 #, c-format
 msgid "cannot stat %s: %s"
 msgstr "Aufruf von »stat« für %s nicht möglich: %s"
 
-#: src/watcher.c:412
+#: src/watcher.c:497
 msgid "no event handlers configured"
 msgstr "Keine Ereignis-Handler eingerichtet"
 
-#: src/watcher.c:417
+#: src/watcher.c:502
 msgid "no event handlers installed"
 msgstr "Keine Ereignis-Handler installiert"
 
-#: src/watcher.c:425
-#, c-format
-msgid "removing watcher %s"
-msgstr "Überwacher %s wird entfernt"
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+#, fuzzy
+msgid "hostname"
+msgstr "Name"
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
+msgstr ""
 
 #: grecs/src/format.c:133
 msgid "Disabled;"
@@ -660,9 +688,8 @@ msgid "invalid include statement"
 msgstr "Ungültige Verwendung einer Include-Anweisung"
 
 #: grecs/src/preproc.c:624
-#, fuzzy
 msgid "read error"
-msgstr "Einlesefehler"
+msgstr "Lesefehler"
 
 #: grecs/src/preproc.c:632
 #, c-format
@@ -679,186 +706,236 @@ msgstr "Externes Vorverarbeitungsprogramm »%s« konnte nicht aufgerufen werden"
 msgid "Cannot run `%s'"
 msgstr "»%s« kann nicht ausgeführt werden"
 
-#: grecs/src/tree.c:329
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr "Element wurde in Tabelle nicht gefunden"
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr "Symboltabelle ist voll"
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+#, fuzzy
+msgid "one or more arguments"
+msgstr "Zu viele Argumente"
+
+#: grecs/src/tree.c:75
+#, fuzzy
+msgid "unrecognized type; please report"
+msgstr "Nicht erkannter Ereigniscode"
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+#, fuzzy
+msgid "unknown keyword"
+msgstr "Unbekanntes Schlüsselwort"
+
+#: grecs/src/tree.c:360
 #, c-format
 msgid "%s: not a valid boolean value"
 msgstr "%s: Kein gültiger boolescher Wert"
 
-#: grecs/src/tree.c:360
+#: grecs/src/tree.c:391
 #, c-format
 msgid "%s: UNIX socket name too long"
 msgstr "%s: UNIX-Name des Sockets ist zu lang"
 
-#: grecs/src/tree.c:389 grecs/src/tree.c:613
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
 #, c-format
 msgid "%s: not a valid IP address or hostname"
 msgstr "%s: Kein gültiger Hostname oder IP-Adresse"
 
-#: grecs/src/tree.c:413
+#: grecs/src/tree.c:444
 #, c-format
 msgid "%s: not a valid port number"
 msgstr "%s: Keine gültige Port-Nummer"
 
-#: grecs/src/tree.c:421
+#: grecs/src/tree.c:452
 msgid "missing port number"
 msgstr "Portnummer fehlt"
 
-#: grecs/src/tree.c:470
+#: grecs/src/tree.c:501
 msgid "numeric overflow"
 msgstr "Numerischer Überlauf"
 
-#: grecs/src/tree.c:475
+#: grecs/src/tree.c:506
 msgid "value out of allowed range"
 msgstr "Wert ist außerhalb des zulässigen Bereichs"
 
-#: grecs/src/tree.c:510 grecs/src/tree.c:540
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
 #, c-format
 msgid "not a number (stopped near `%s')"
 msgstr "Keine Zahl (gestoppt bei »%s«)"
 
-#: grecs/src/tree.c:604
+#: grecs/src/tree.c:635
 #, c-format
 msgid "%s: not a valid IP address"
 msgstr "%s: Keine gültige IP-Adresse"
 
-#: grecs/src/tree.c:743
+#: grecs/src/tree.c:774
 #, c-format
 msgid "too many arguments to `%s'; missing semicolon?"
 msgstr "Zu viele Argumente für »%s«; Semikolon fehlt?"
 
-#: grecs/src/tree.c:757 grecs/src/tree.c:805
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
 #, c-format
 msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
 msgstr "INTERNER FEHLER bei %s:%d: unbehandelter Datentyp %d"
 
-#: grecs/src/tree.c:772
+#: grecs/src/tree.c:803
 #, c-format
 msgid "%s: incompatible data type in list item #%d"
 msgstr "%s: inkompatibler Datentyp im Listeneintrag #%d"
 
-#: grecs/src/tree.c:792
+#: grecs/src/tree.c:823
 #, c-format
 msgid "incompatible data type for `%s'"
 msgstr "Inkompatibler Datentyp für »%s«"
 
-#: grecs/src/tree.c:920 grecs/src/tree.c:930
-msgid "Unknown keyword"
-msgstr "Unbekanntes Schlüsselwort"
-
-#: grecs/src/tree.c:1139
-#, c-format
-msgid "%s: unknown keyword"
-msgstr "%s: Unbekanntes Schlüsselwort"
-
-#: grecs/src/wordsplit.c:62 grecs/src/wordsplit.c:2300
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
 msgid "memory exhausted"
 msgstr "Speicher ausgeschöpft"
 
-#: grecs/src/wordsplit.c:1073
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:1607
 #, c-format
 msgid "%.*s: variable null or not set"
-msgstr ""
+msgstr "%.*s: Variable ist Null oder nicht gesetzt"
 
-#: grecs/src/wordsplit.c:1102
+#: grecs/wordsplit/wordsplit.c:1637
 #, c-format
 msgid "warning: undefined variable `%.*s'"
 msgstr "Warnung: Undefinierte Variable »%.*s«"
 
-#: grecs/src/wordsplit.c:1630
+#: grecs/wordsplit/wordsplit.c:2141
 #, c-format
 msgid "no files match pattern %s"
-msgstr ""
+msgstr "Keine Dateien, die dem Muster %s entsprechen"
 
-#: grecs/src/wordsplit.c:2080
+#: grecs/wordsplit/wordsplit.c:2603
 msgid "WS trimming"
-msgstr ""
+msgstr "Leerzeichenentfernung"
+
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
+msgstr "Befehlsersetzung"
 
-#: grecs/src/wordsplit.c:2081
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
+msgstr "Zusammenführungsliste"
+
+#: grecs/wordsplit/wordsplit.c:2609
 msgid "tilde expansion"
-msgstr ""
+msgstr "Tilde-Ersetzung"
 
-#: grecs/src/wordsplit.c:2082
+#: grecs/wordsplit/wordsplit.c:2611
 msgid "variable expansion"
-msgstr ""
+msgstr "Variablen-Ersetzung"
 
-#: grecs/src/wordsplit.c:2084
+#: grecs/wordsplit/wordsplit.c:2613
 msgid "quote removal"
-msgstr ""
+msgstr "Zitatzeichen-Entfernung"
 
-#: grecs/src/wordsplit.c:2086
-#, fuzzy
-msgid "command substitution"
-msgstr "Befehlsersetzung wird noch nicht unterstützt."
-
-#: grecs/src/wordsplit.c:2088
-msgid "coalesce list"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2090
+#: grecs/wordsplit/wordsplit.c:2617
 msgid "path expansion"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2120
-msgid "Initial list:"
-msgstr ""
+msgstr "Pfad-Ersetzung"
 
-#: grecs/src/wordsplit.c:2136
-#, fuzzy
-msgid "Coalesced list:"
-msgstr "Unerwartete Liste"
-
-#: grecs/src/wordsplit.c:2190
+#: grecs/wordsplit/wordsplit.c:2642
 #, c-format
 msgid "(%02d) Input:%.*s;"
-msgstr ""
+msgstr "(%02d) Eingabe:%.*s;"
 
-#: grecs/src/wordsplit.c:2202
-#, c-format
-msgid "(%02d) Restart:%.*s;"
-msgstr ""
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
+msgstr "Anfängliche Liste:"
+
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr "Zusammengeführte Liste:"
 
-#: grecs/src/wordsplit.c:2298
+#: grecs/wordsplit/wordsplit.c:2853
 msgid "no error"
 msgstr "Kein Fehler"
 
-#: grecs/src/wordsplit.c:2299
+#: grecs/wordsplit/wordsplit.c:2854
 msgid "missing closing quote"
 msgstr "schließendes Zitatzeichen fehlt"
 
-#: grecs/src/wordsplit.c:2301
+#: grecs/wordsplit/wordsplit.c:2856
 msgid "invalid wordsplit usage"
 msgstr "unzulässige Worttrennung"
 
-#: grecs/src/wordsplit.c:2302
+#: grecs/wordsplit/wordsplit.c:2857
 msgid "unbalanced curly brace"
 msgstr "Nicht geschlossene geschweifte Klammer"
 
-#: grecs/src/wordsplit.c:2303
+#: grecs/wordsplit/wordsplit.c:2858
 msgid "undefined variable"
 msgstr "nicht definierte Variable"
 
-#: grecs/src/wordsplit.c:2304
+#: grecs/wordsplit/wordsplit.c:2859
 msgid "input exhausted"
 msgstr "Eingabe ausgeschöpft"
 
-#: grecs/src/wordsplit.c:2305
+#: grecs/wordsplit/wordsplit.c:2860
 msgid "unbalanced parenthesis"
-msgstr ""
+msgstr "Unvollständiges Klammernpaar"
 
-#: grecs/src/wordsplit.c:2306
-#, fuzzy
+#: grecs/wordsplit/wordsplit.c:2861
 msgid "globbing error"
-msgstr "Kein Fehler"
+msgstr "Platzhalterfehler"
+
+#: grecs/wordsplit/wordsplit.c:2862
+#, fuzzy
+msgid "user-defined error"
+msgstr "Lesefehler"
 
-#: grecs/src/wordsplit.c:2318
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2875
 msgid "unknown error"
 msgstr "Unbekannter Fehler"
 
-#: grecs/src/wordsplit.c:2327
+#: grecs/wordsplit/wordsplit.c:2884
 #, c-format
 msgid "missing closing %c (start near #%lu)"
 msgstr "fehlendes schließendes %c (Beginn bei #%lu)"
 
+#~ msgid "unterminated regexp"
+#~ msgstr "Nicht beendeter regulärer Ausdruck"
+
+#~ msgid "unrecognized flag: %c"
+#~ msgstr "Nicht erkannter Schalter: %c"
+
+#~ msgid "out of memory"
+#~ msgstr "Speicher erschöpft"
+
+#~ msgid "%s: unknown keyword"
+#~ msgstr "%s: Unbekanntes Schlüsselwort"
+
+#~ msgid "(%02d) Restart:%.*s;"
+#~ msgstr "(%02d) Neustart:%.*s;"
+
 #~ msgid "INTERNAL ERROR at %s:%d"
 #~ msgstr "INTERNER FEHLER bei %s:%d"
 
diff --git a/po/direvent.pot b/po/direvent.pot
index bcba0cd..959112e 100644
--- a/po/direvent.pot
+++ b/po/direvent.pot
@@ -1,14 +1,14 @@
 # SOME DESCRIPTIVE TITLE.
 # Copyright (C) YEAR Sergey Poznyakoff
-# This file is distributed under the same license as the PACKAGE package.
+# This file is distributed under the same license as the direvent package.
 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 #
 #, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: direvent 5.1\n"
+"Project-Id-Version: direvent 5.2\n"
 "Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
-"POT-Creation-Date: 2016-07-06 17:50+0300\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -162,7 +162,7 @@ msgstr ""
 msgid "unknown syslog facility `%s'"
 msgstr ""
 
-#: src/config.c:133 src/config.c:706
+#: src/config.c:133 src/config.c:606
 msgid "name"
 msgstr ""
 
@@ -173,7 +173,7 @@ msgid ""
 "facility number."
 msgstr ""
 
-#: src/config.c:139
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
 msgid "string"
 msgstr ""
 
@@ -189,176 +189,166 @@ msgstr ""
 msgid "Prefix each message with its priority"
 msgstr ""
 
-#: src/config.c:209
+#: src/config.c:191
 #, c-format
 msgid "%s: recursion depth does not match previous definition"
 msgstr ""
 
-#: src/config.c:247
+#: src/config.c:212
 msgid "no paths configured"
 msgstr ""
 
-#: src/config.c:252
+#: src/config.c:217
 msgid "no command configured"
 msgstr ""
 
-#: src/config.c:264 grecs/src/tree.c:634
+#: src/config.c:229 grecs/src/tree.c:665
 msgid "invalid use of block statement"
 msgstr ""
 
-#: src/config.c:309
+#: src/config.c:274
 msgid "expected \"recursive\" or end of statement"
 msgstr ""
 
-#: src/config.c:324
+#: src/config.c:289
 msgid "surplus argument"
 msgstr ""
 
-#: src/config.c:330 src/config.c:481
+#: src/config.c:295 src/config.c:446
 msgid "unexpected list"
 msgstr ""
 
-#: src/config.c:361 src/config.c:376 src/config.c:391
+#: src/config.c:326 src/config.c:341 src/config.c:356
 msgid "unrecognized event code"
 msgstr ""
 
-#: src/config.c:473
+#: src/config.c:438
 msgid "surplus arguments"
 msgstr ""
 
-#: src/config.c:487
+#: src/config.c:452
 msgid "no such user"
 msgstr ""
 
-#: src/config.c:494
+#: src/config.c:459
 msgid "no such group"
 msgstr ""
 
-#: src/config.c:535
+#: src/config.c:501
 msgid "unrecognized option"
 msgstr ""
 
-#: src/config.c:613
-msgid "unterminated regexp"
-msgstr ""
-
-#: src/config.c:627
-#, c-format
-msgid "unrecognized flag: %c"
-msgstr ""
-
-#: src/config.c:695
+#: src/config.c:595
 msgid "Pathname to watch"
 msgstr ""
 
-#: src/config.c:698
+#: src/config.c:598
 msgid "Events to watch for"
 msgstr ""
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "regexp"
 msgstr ""
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "Files to watch for"
 msgstr ""
 
-#: src/config.c:704
+#: src/config.c:604
 msgid "Command to execute on event"
 msgstr ""
 
-#: src/config.c:706
+#: src/config.c:606
 msgid "Run command as this user"
 msgstr ""
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "seconds"
 msgstr ""
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "Timeout for the command"
 msgstr ""
 
-#: src/config.c:711
+#: src/config.c:611
 msgid "List of additional options"
 msgstr ""
 
-#: src/config.c:714
+#: src/config.c:614
 msgid "<arg: string> <arg: string>..."
 msgstr ""
 
-#: src/config.c:715
+#: src/config.c:615
 msgid "Modify environment"
 msgstr ""
 
-#: src/config.c:722
+#: src/config.c:622
 msgid "Run as this user"
 msgstr ""
 
-#: src/config.c:724
+#: src/config.c:624
 msgid "Run in foreground"
 msgstr ""
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "file"
 msgstr ""
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "Set pid file name"
 msgstr ""
 
-#: src/config.c:728
+#: src/config.c:628
 msgid "Configure syslog logging"
 msgstr ""
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "level"
 msgstr ""
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "Set debug level"
 msgstr ""
 
-#: src/config.c:732
+#: src/config.c:632
 msgid "Configure event watcher"
 msgstr ""
 
-#: src/config.c:743
+#: src/config.c:643
 msgid ""
 "Configuration file structure for direvent.\n"
 "For more information, use `info direvent configuration'."
 msgstr ""
 
-#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:86 src/watcher.c:182
-#: src/watcher.c:191
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
 msgid "not enough memory"
 msgstr ""
 
-#: src/direvent.c:272
+#: src/direvent.c:274
 #, c-format
 msgid "cannot open pidfile %s for writing: %s"
 msgstr ""
 
-#: src/direvent.c:300
+#: src/direvent.c:302
 #, c-format
 msgid "no user with UID %lu"
 msgstr ""
 
-#: src/direvent.c:418
+#: src/direvent.c:420
 #, c-format
 msgid "cannot run `%s': fork failed: %s"
 msgstr ""
 
-#: src/direvent.c:478
+#: src/direvent.c:480
 msgid "too many arguments"
 msgstr ""
 
-#: src/direvent.c:520
+#: src/direvent.c:522
 #, c-format
 msgid "%s %s started"
 msgstr ""
 
-#: src/direvent.c:541
+#: src/direvent.c:546
 #, c-format
 msgid "%s %s stopped"
 msgstr ""
@@ -367,18 +357,6 @@ msgstr ""
 msgid "environment: "
 msgstr ""
 
-#: src/hashtab.c:140 grecs/src/symtab.c:206
-msgid "element not found in table"
-msgstr ""
-
-#: src/hashtab.c:142 grecs/src/symtab.c:208
-msgid "symbol table is full"
-msgstr ""
-
-#: src/hashtab.c:144
-msgid "out of memory"
-msgstr ""
-
 #: src/progman.c:142
 #, c-format
 msgid "process %lu exited successfully"
@@ -438,72 +416,121 @@ msgstr ""
 msgid "redirector for %s started, pid=%lu"
 msgstr ""
 
-#: src/progman.c:454
+#: src/progman.c:455
 #, c-format
 msgid "starting %s, dir=%s, file=%s"
 msgstr ""
 
-#: src/progman.c:482
+#: src/progman.c:484
 #, c-format
 msgid "cannot change to %s: %s"
 msgstr ""
 
-#: src/progman.c:510
+#: src/progman.c:512
 #, c-format
 msgid "%s running; dir=%s, file=%s, pid=%lu"
 msgstr ""
 
-#: src/progman.c:532
+#: src/progman.c:534
 #, c-format
 msgid "waiting for %s (%lu) to terminate"
 msgstr ""
 
-#: src/watcher.c:231
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr ""
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
 #, c-format
 msgid "creating watcher %s"
 msgstr ""
 
-#: src/watcher.c:240
+#: src/watcher.c:281 src/watcher.c:296
 #, c-format
 msgid "cannot set watcher on %s: %s"
 msgstr ""
 
-#: src/watcher.c:319
+#: src/watcher.c:377
 #, c-format
 msgid "cannot create watcher %s/%s: not enough memory"
 msgstr ""
 
-#: src/watcher.c:326
+#: src/watcher.c:384
 #, c-format
 msgid "cannot create watcher %s/%s, stat failed: %s"
 msgstr ""
 
-#: src/watcher.c:355
+#: src/watcher.c:430
 #, c-format
 msgid "cannot open directory %s: %s"
 msgstr ""
 
-#: src/watcher.c:371
+#: src/watcher.c:447
 #, c-format
 msgid "cannot stat %s/%s: not enough memory"
 msgstr ""
 
-#: src/watcher.c:376
+#: src/watcher.c:452
 #, c-format
 msgid "cannot stat %s: %s"
 msgstr ""
 
-#: src/watcher.c:412
+#: src/watcher.c:497
 msgid "no event handlers configured"
 msgstr ""
 
-#: src/watcher.c:417
+#: src/watcher.c:502
 msgid "no event handlers installed"
 msgstr ""
 
-#: src/watcher.c:425
-#, c-format
-msgid "removing watcher %s"
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+msgid "hostname"
+msgstr ""
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
 msgstr ""
 
 #: grecs/src/format.c:133
@@ -649,179 +676,213 @@ msgstr ""
 msgid "Cannot run `%s'"
 msgstr ""
 
-#: grecs/src/tree.c:329
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr ""
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr ""
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+msgid "one or more arguments"
+msgstr ""
+
+#: grecs/src/tree.c:75
+msgid "unrecognized type; please report"
+msgstr ""
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+msgid "unknown keyword"
+msgstr ""
+
+#: grecs/src/tree.c:360
 #, c-format
 msgid "%s: not a valid boolean value"
 msgstr ""
 
-#: grecs/src/tree.c:360
+#: grecs/src/tree.c:391
 #, c-format
 msgid "%s: UNIX socket name too long"
 msgstr ""
 
-#: grecs/src/tree.c:389 grecs/src/tree.c:613
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
 #, c-format
 msgid "%s: not a valid IP address or hostname"
 msgstr ""
 
-#: grecs/src/tree.c:413
+#: grecs/src/tree.c:444
 #, c-format
 msgid "%s: not a valid port number"
 msgstr ""
 
-#: grecs/src/tree.c:421
+#: grecs/src/tree.c:452
 msgid "missing port number"
 msgstr ""
 
-#: grecs/src/tree.c:470
+#: grecs/src/tree.c:501
 msgid "numeric overflow"
 msgstr ""
 
-#: grecs/src/tree.c:475
+#: grecs/src/tree.c:506
 msgid "value out of allowed range"
 msgstr ""
 
-#: grecs/src/tree.c:510 grecs/src/tree.c:540
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
 #, c-format
 msgid "not a number (stopped near `%s')"
 msgstr ""
 
-#: grecs/src/tree.c:604
+#: grecs/src/tree.c:635
 #, c-format
 msgid "%s: not a valid IP address"
 msgstr ""
 
-#: grecs/src/tree.c:743
+#: grecs/src/tree.c:774
 #, c-format
 msgid "too many arguments to `%s'; missing semicolon?"
 msgstr ""
 
-#: grecs/src/tree.c:757 grecs/src/tree.c:805
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
 #, c-format
 msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
 msgstr ""
 
-#: grecs/src/tree.c:772
+#: grecs/src/tree.c:803
 #, c-format
 msgid "%s: incompatible data type in list item #%d"
 msgstr ""
 
-#: grecs/src/tree.c:792
+#: grecs/src/tree.c:823
 #, c-format
 msgid "incompatible data type for `%s'"
 msgstr ""
 
-#: grecs/src/tree.c:920 grecs/src/tree.c:930
-msgid "Unknown keyword"
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
+msgid "memory exhausted"
 msgstr ""
 
-#: grecs/src/tree.c:1139
-#, c-format
-msgid "%s: unknown keyword"
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
 msgstr ""
 
-#: grecs/src/wordsplit.c:62 grecs/src/wordsplit.c:2300
-msgid "memory exhausted"
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
 msgstr ""
 
-#: grecs/src/wordsplit.c:1073
+#: grecs/wordsplit/wordsplit.c:1607
 #, c-format
 msgid "%.*s: variable null or not set"
 msgstr ""
 
-#: grecs/src/wordsplit.c:1102
+#: grecs/wordsplit/wordsplit.c:1637
 #, c-format
 msgid "warning: undefined variable `%.*s'"
 msgstr ""
 
-#: grecs/src/wordsplit.c:1630
+#: grecs/wordsplit/wordsplit.c:2141
 #, c-format
 msgid "no files match pattern %s"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2080
+#: grecs/wordsplit/wordsplit.c:2603
 msgid "WS trimming"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2081
-msgid "tilde expansion"
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2082
-msgid "variable expansion"
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2084
-msgid "quote removal"
+#: grecs/wordsplit/wordsplit.c:2609
+msgid "tilde expansion"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2086
-msgid "command substitution"
+#: grecs/wordsplit/wordsplit.c:2611
+msgid "variable expansion"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2088
-msgid "coalesce list"
+#: grecs/wordsplit/wordsplit.c:2613
+msgid "quote removal"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2090
+#: grecs/wordsplit/wordsplit.c:2617
 msgid "path expansion"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2120
-msgid "Initial list:"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2136
-msgid "Coalesced list:"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2190
+#: grecs/wordsplit/wordsplit.c:2642
 #, c-format
 msgid "(%02d) Input:%.*s;"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2202
-#, c-format
-msgid "(%02d) Restart:%.*s;"
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2298
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2853
 msgid "no error"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2299
+#: grecs/wordsplit/wordsplit.c:2854
 msgid "missing closing quote"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2301
+#: grecs/wordsplit/wordsplit.c:2856
 msgid "invalid wordsplit usage"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2302
+#: grecs/wordsplit/wordsplit.c:2857
 msgid "unbalanced curly brace"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2303
+#: grecs/wordsplit/wordsplit.c:2858
 msgid "undefined variable"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2304
+#: grecs/wordsplit/wordsplit.c:2859
 msgid "input exhausted"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2305
+#: grecs/wordsplit/wordsplit.c:2860
 msgid "unbalanced parenthesis"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2306
+#: grecs/wordsplit/wordsplit.c:2861
 msgid "globbing error"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2318
+#: grecs/wordsplit/wordsplit.c:2862
+msgid "user-defined error"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2875
 msgid "unknown error"
 msgstr ""
 
-#: grecs/src/wordsplit.c:2327
+#: grecs/wordsplit/wordsplit.c:2884
 #, c-format
 msgid "missing closing %c (start near #%lu)"
 msgstr ""
diff --git a/po/eo.gmo b/po/eo.gmo
index 9321390..1defea0 100644
Binary files a/po/eo.gmo and b/po/eo.gmo differ
diff --git a/po/eo.po b/po/eo.po
index 6c257dc..6459780 100644
--- a/po/eo.po
+++ b/po/eo.po
@@ -1,21 +1,22 @@
 # Esperanto translation
-# Copyright (C) 2015 Free Software Foundation, Inc.
+# Copyright (C) 2015, 2017 Free Software Foundation, Inc.
 # This file is distributed under the same license as the direvent package.
-# Felipe Castro <fefcas@gmail.com>, 2015.
+# Felipe Castro <fefcas@gmail.com>, 2015, 2017.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: direvent 4.1.91\n"
+"Project-Id-Version: direvent 5.1\n"
 "Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
-"POT-Creation-Date: 2016-07-06 17:50+0300\n"
-"PO-Revision-Date: 2015-01-26 10:40-0300\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
+"PO-Revision-Date: 2017-01-23 12:35-0300\n"
 "Last-Translator: Felipe Castro <fefcas@gmail.com>\n"
 "Language-Team: Esperanto <translation-team-eo@lists.sourceforge.net>\n"
 "Language: eo\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=utf-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 1.6.10\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"X-Generator: Poedit 1.5.4\n"
 
 #: cmdline.opt:26
 msgid "increase debug level"
@@ -47,11 +48,11 @@ msgstr "resti malfone"
 
 #: cmdline.opt:53
 msgid "DIR"
-msgstr ""
+msgstr "UJO"
 
 #: cmdline.opt:53
 msgid "add include directory"
-msgstr ""
+msgstr "aldoni inkluzivan dosierujon"
 
 #: cmdline.opt:59
 msgid "PROG"
@@ -133,12 +134,12 @@ msgstr ""
 #: cmdline.opt:102
 #, c-format
 msgid "Include search path:\n"
-msgstr ""
+msgstr "Inkluziva serĉ-vojo:\n"
 
 #: cmdline.opt:105
 #, c-format
 msgid "No include search path.\n"
-msgstr ""
+msgstr "Malinkluziva serĉ-vojo.\n"
 
 #: src/config.c:63
 #, c-format
@@ -169,7 +170,7 @@ msgstr "ni atendis %s, sed trovis %s"
 msgid "unknown syslog facility `%s'"
 msgstr "nekonata utilaĵo syslog '%s'"
 
-#: src/config.c:133 src/config.c:706
+#: src/config.c:133 src/config.c:606
 msgid "name"
 msgstr "nomo"
 
@@ -182,7 +183,7 @@ msgstr ""
 "Difini utilaĵon syslog. Arg estas unu el la jena: user, daemon, auth, "
 "authpriv, mail, cron, local0 ĝis local7 (ajn usklece), aŭ numero de utilaĵo."
 
-#: src/config.c:139
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
 msgid "string"
 msgstr "ĉeno"
 
@@ -198,142 +199,132 @@ msgstr "arg"
 msgid "Prefix each message with its priority"
 msgstr "Prefiksi ĉiun mesaĝon per ĝia prioritato"
 
-#: src/config.c:209
+#: src/config.c:191
 #, c-format
 msgid "%s: recursion depth does not match previous definition"
 msgstr "%s: rikura profundo ne akordas al antaŭa difino"
 
-#: src/config.c:247
+#: src/config.c:212
 msgid "no paths configured"
 msgstr "neniu vojo estas agordita"
 
-#: src/config.c:252
+#: src/config.c:217
 msgid "no command configured"
 msgstr "neniu komando estas agordita"
 
-#: src/config.c:264 grecs/src/tree.c:634
+#: src/config.c:229 grecs/src/tree.c:665
 msgid "invalid use of block statement"
 msgstr "malvalida uzo de bloka komando"
 
-#: src/config.c:309
+#: src/config.c:274
 msgid "expected \"recursive\" or end of statement"
 msgstr "ni atendis \"recursive\" aŭ la finon de komando"
 
-#: src/config.c:324
+#: src/config.c:289
 msgid "surplus argument"
 msgstr "troa argumento"
 
-#: src/config.c:330 src/config.c:481
+#: src/config.c:295 src/config.c:446
 msgid "unexpected list"
 msgstr "ne atendita listo"
 
-#: src/config.c:361 src/config.c:376 src/config.c:391
+#: src/config.c:326 src/config.c:341 src/config.c:356
 msgid "unrecognized event code"
 msgstr "nerekonita eventkodo"
 
-#: src/config.c:473
+#: src/config.c:438
 msgid "surplus arguments"
 msgstr "troaj argumentoj"
 
-#: src/config.c:487
+#: src/config.c:452
 msgid "no such user"
 msgstr "neniu tia uzanto"
 
-#: src/config.c:494
+#: src/config.c:459
 msgid "no such group"
 msgstr "neniu tia grupo"
 
-#: src/config.c:535
-#, fuzzy
+#: src/config.c:501
 msgid "unrecognized option"
-msgstr "nerekonita flago"
-
-#: src/config.c:613
-msgid "unterminated regexp"
-msgstr "nefinigita regulesprimo"
-
-#: src/config.c:627
-#, c-format
-msgid "unrecognized flag: %c"
-msgstr "nerekonita flago: %c"
+msgstr "nerekonita modifilo"
 
-#: src/config.c:695
+#: src/config.c:595
 msgid "Pathname to watch"
 msgstr "Vojnomo por esti observata"
 
-#: src/config.c:698
+#: src/config.c:598
 msgid "Events to watch for"
 msgstr "Eventoj por esti observataj"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "regexp"
 msgstr "regulesprimo"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "Files to watch for"
 msgstr "Dosieroj por esti observataj"
 
-#: src/config.c:704
+#: src/config.c:604
 msgid "Command to execute on event"
 msgstr "Komando por esti lanĉata pro evento"
 
-#: src/config.c:706
+#: src/config.c:606
 msgid "Run command as this user"
 msgstr "Lanĉi la komandon kiel tiu ĉi uzanto"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "seconds"
 msgstr "sekundoj"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "Timeout for the command"
 msgstr "Tempolimo por la komando"
 
-#: src/config.c:711
+#: src/config.c:611
 msgid "List of additional options"
 msgstr "Listo de kromaj preferoj"
 
-#: src/config.c:714
+#: src/config.c:614
 msgid "<arg: string> <arg: string>..."
 msgstr "<arg: ĉeno> <arg: ĉeno>..."
 
-#: src/config.c:715
+#: src/config.c:615
 msgid "Modify environment"
 msgstr "Ŝanĝi medion"
 
-#: src/config.c:722
+#: src/config.c:622
 msgid "Run as this user"
 msgstr "Ruli kiel tiu ĉi uzanto"
 
-#: src/config.c:724
+#: src/config.c:624
 msgid "Run in foreground"
 msgstr "Ruli malfone"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "file"
 msgstr "dosiero"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "Set pid file name"
 msgstr "Difini pid-dosiernomon"
 
-#: src/config.c:728
+#: src/config.c:628
 msgid "Configure syslog logging"
 msgstr "Agordi protokoligo de syslog"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "level"
 msgstr "nivelo"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "Set debug level"
 msgstr "Difini ĝustigan nivelon"
 
-#: src/config.c:732
+#: src/config.c:632
 msgid "Configure event watcher"
 msgstr "Agordi event-observanton"
 
-#: src/config.c:743
+#: src/config.c:643
 msgid ""
 "Configuration file structure for direvent.\n"
 "For more information, use `info direvent configuration'."
@@ -341,36 +332,35 @@ msgstr ""
 "Strukturo de agorda dosiero por direvent.\n"
 "Por pli da informo, uzu 'info direvent configuration'."
 
-#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:86 src/watcher.c:182
-#: src/watcher.c:191
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
 msgid "not enough memory"
 msgstr "ne sufiĉe da memoro"
 
-#: src/direvent.c:272
+#: src/direvent.c:274
 #, c-format
 msgid "cannot open pidfile %s for writing: %s"
 msgstr "ne eblas malfermi la pid-dosieron %s por skribi: %s"
 
-#: src/direvent.c:300
+#: src/direvent.c:302
 #, c-format
 msgid "no user with UID %lu"
 msgstr "neniu uzanto kun UID: %lu"
 
-#: src/direvent.c:418
+#: src/direvent.c:420
 #, c-format
 msgid "cannot run `%s': fork failed: %s"
 msgstr "ne eblas lanĉi '%s': forko fiaskis: %s"
 
-#: src/direvent.c:478
+#: src/direvent.c:480
 msgid "too many arguments"
 msgstr "tro multaj argumentoj"
 
-#: src/direvent.c:520
+#: src/direvent.c:522
 #, c-format
 msgid "%s %s started"
 msgstr "%s %s lanĉita"
 
-#: src/direvent.c:541
+#: src/direvent.c:546
 #, c-format
 msgid "%s %s stopped"
 msgstr "%s %s haltigita"
@@ -379,18 +369,6 @@ msgstr "%s %s haltigita"
 msgid "environment: "
 msgstr "medio: "
 
-#: src/hashtab.c:140 grecs/src/symtab.c:206
-msgid "element not found in table"
-msgstr "elemento ne estas trovita en tabelo"
-
-#: src/hashtab.c:142 grecs/src/symtab.c:208
-msgid "symbol table is full"
-msgstr "simboltabelo estas plena"
-
-#: src/hashtab.c:144
-msgid "out of memory"
-msgstr "mankas memoro"
-
 #: src/progman.c:142
 #, c-format
 msgid "process %lu exited successfully"
@@ -450,73 +428,123 @@ msgstr "ne eblas lanĉi la redirektilon '%s': forko fiaskis: %s"
 msgid "redirector for %s started, pid=%lu"
 msgstr "redirektilo por %s komencis, pid=%lu"
 
-#: src/progman.c:454
+#: src/progman.c:455
 #, c-format
 msgid "starting %s, dir=%s, file=%s"
 msgstr "Ekigo de %s, ujo=%s, dosiero=%s"
 
-#: src/progman.c:482
+#: src/progman.c:484
 #, c-format
 msgid "cannot change to %s: %s"
 msgstr "ne eblas ŝanĝi al %s: %s"
 
-#: src/progman.c:510
+#: src/progman.c:512
 #, c-format
 msgid "%s running; dir=%s, file=%s, pid=%lu"
 msgstr "%s rulas; ujo=%s, dosiero=%s, pid=%lu"
 
-#: src/progman.c:532
+#: src/progman.c:534
 #, c-format
 msgid "waiting for %s (%lu) to terminate"
 msgstr "ni atendas ke %s (%lu) ĉesu"
 
-#: src/watcher.c:231
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr "ni forigas observanton %s"
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
 #, c-format
 msgid "creating watcher %s"
 msgstr "ni kreas observanton %s"
 
-#: src/watcher.c:240
+#: src/watcher.c:281 src/watcher.c:296
 #, c-format
 msgid "cannot set watcher on %s: %s"
 msgstr "ne eblas agordi observanton en %s: %s"
 
-#: src/watcher.c:319
+#: src/watcher.c:377
 #, c-format
 msgid "cannot create watcher %s/%s: not enough memory"
 msgstr "ne eblas krei observanton %s/%s: mankas memoro"
 
-#: src/watcher.c:326
+#: src/watcher.c:384
 #, c-format
 msgid "cannot create watcher %s/%s, stat failed: %s"
 msgstr "ne eblas krei observanton %s/%s, stat fiaksis: %s"
 
-#: src/watcher.c:355
+#: src/watcher.c:430
 #, c-format
 msgid "cannot open directory %s: %s"
 msgstr "ne eblas malfermi dosierujon %s: %s"
 
-#: src/watcher.c:371
+#: src/watcher.c:447
 #, c-format
 msgid "cannot stat %s/%s: not enough memory"
 msgstr "ne eblas apliki 'stat' %s/%s: mankas memoro"
 
-#: src/watcher.c:376
+#: src/watcher.c:452
 #, c-format
 msgid "cannot stat %s: %s"
 msgstr "Ne eblas apliki 'stat' %s: %s"
 
-#: src/watcher.c:412
+#: src/watcher.c:497
 msgid "no event handlers configured"
 msgstr "neniu evento-traktilo estas difinita"
 
-#: src/watcher.c:417
+#: src/watcher.c:502
 msgid "no event handlers installed"
 msgstr "neniu evento-traktilo estas instalita"
 
-#: src/watcher.c:425
-#, c-format
-msgid "removing watcher %s"
-msgstr "ni forigas observanton %s"
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+#, fuzzy
+msgid "hostname"
+msgstr "nomo"
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
+msgstr ""
 
 #: grecs/src/format.c:133
 msgid "Disabled;"
@@ -653,9 +681,8 @@ msgid "invalid include statement"
 msgstr "malvalida enmeta komando"
 
 #: grecs/src/preproc.c:624
-#, fuzzy
 msgid "read error"
-msgstr "analiz-eraro"
+msgstr "leg-eraro"
 
 #: grecs/src/preproc.c:632
 #, c-format
@@ -672,185 +699,235 @@ msgstr "Ne eblas ekigi eksteran antaŭprocezilon '%s'"
 msgid "Cannot run `%s'"
 msgstr "Ne eblas lanĉi '%s'"
 
-#: grecs/src/tree.c:329
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr "elemento ne estas trovita en tabelo"
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr "simboltabelo estas plena"
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+#, fuzzy
+msgid "one or more arguments"
+msgstr "tro multaj argumentoj"
+
+#: grecs/src/tree.c:75
+#, fuzzy
+msgid "unrecognized type; please report"
+msgstr "nerekonita eventkodo"
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+#, fuzzy
+msgid "unknown keyword"
+msgstr "Nekonata ŝlosilvorto"
+
+#: grecs/src/tree.c:360
 #, c-format
 msgid "%s: not a valid boolean value"
 msgstr "%s: ne estas valida bulea valoro"
 
-#: grecs/src/tree.c:360
+#: grecs/src/tree.c:391
 #, c-format
 msgid "%s: UNIX socket name too long"
 msgstr "%s: tro longa ingo-nomo de UNIX"
 
-#: grecs/src/tree.c:389 grecs/src/tree.c:613
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
 #, c-format
 msgid "%s: not a valid IP address or hostname"
 msgstr "%s: ne estas valida IP-adsero aŭ gastigant-nomo"
 
-#: grecs/src/tree.c:413
+#: grecs/src/tree.c:444
 #, c-format
 msgid "%s: not a valid port number"
 msgstr "%s: ne estas valida pord-numero"
 
-#: grecs/src/tree.c:421
+#: grecs/src/tree.c:452
 msgid "missing port number"
 msgstr "mankas pordo-numero"
 
-#: grecs/src/tree.c:470
+#: grecs/src/tree.c:501
 msgid "numeric overflow"
 msgstr "numera troo"
 
-#: grecs/src/tree.c:475
+#: grecs/src/tree.c:506
 msgid "value out of allowed range"
 msgstr "valoro estas for de permesata intervalo"
 
-#: grecs/src/tree.c:510 grecs/src/tree.c:540
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
 #, c-format
 msgid "not a number (stopped near `%s')"
 msgstr "ne estas numero (haltis proksime de '%s')"
 
-#: grecs/src/tree.c:604
+#: grecs/src/tree.c:635
 #, c-format
 msgid "%s: not a valid IP address"
 msgstr "%s: neniu valida IP-adreso"
 
-#: grecs/src/tree.c:743
+#: grecs/src/tree.c:774
 #, c-format
 msgid "too many arguments to `%s'; missing semicolon?"
 msgstr "tro multaj argumentoj por '%s'; ĉu mankas punkto-komo?"
 
-#: grecs/src/tree.c:757 grecs/src/tree.c:805
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
 #, c-format
 msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
 msgstr "INTERNA ERARO ĉe %s:%d: netraktebla datumartipo %d"
 
-#: grecs/src/tree.c:772
+#: grecs/src/tree.c:803
 #, c-format
 msgid "%s: incompatible data type in list item #%d"
 msgstr "%s: nekongrua datumartipo en listero #%d"
 
-#: grecs/src/tree.c:792
+#: grecs/src/tree.c:823
 #, c-format
 msgid "incompatible data type for `%s'"
 msgstr "nekongrua datumartipo por '%s'"
 
-#: grecs/src/tree.c:920 grecs/src/tree.c:930
-msgid "Unknown keyword"
-msgstr "Nekonata ŝlosilvorto"
-
-#: grecs/src/tree.c:1139
-#, c-format
-msgid "%s: unknown keyword"
-msgstr "%s: nekonata ŝlosilvorto"
-
-#: grecs/src/wordsplit.c:62 grecs/src/wordsplit.c:2300
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
 msgid "memory exhausted"
 msgstr "memoro estas elĉerpita"
 
-#: grecs/src/wordsplit.c:1073
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:1607
 #, c-format
 msgid "%.*s: variable null or not set"
-msgstr ""
+msgstr "%.*s: variablo nula aŭ ne difinita"
 
-#: grecs/src/wordsplit.c:1102
+#: grecs/wordsplit/wordsplit.c:1637
 #, c-format
 msgid "warning: undefined variable `%.*s'"
 msgstr "averto: nedifinita variablo '%.*s'"
 
-#: grecs/src/wordsplit.c:1630
+#: grecs/wordsplit/wordsplit.c:2141
 #, c-format
 msgid "no files match pattern %s"
-msgstr ""
+msgstr "neniu dosiero kongruas al ŝablono %s"
 
-#: grecs/src/wordsplit.c:2080
+#: grecs/wordsplit/wordsplit.c:2603
 msgid "WS trimming"
-msgstr ""
+msgstr "Agordado de WS"
+
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
+msgstr "komand-antataŭigo"
 
-#: grecs/src/wordsplit.c:2081
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
+msgstr "kunfanda listo"
+
+#: grecs/wordsplit/wordsplit.c:2609
 msgid "tilde expansion"
-msgstr ""
+msgstr "etendigo de tildo"
 
-#: grecs/src/wordsplit.c:2082
+#: grecs/wordsplit/wordsplit.c:2611
 msgid "variable expansion"
-msgstr ""
+msgstr "etendigo de variablo"
 
-#: grecs/src/wordsplit.c:2084
+#: grecs/wordsplit/wordsplit.c:2613
 msgid "quote removal"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2086
-#, fuzzy
-msgid "command substitution"
-msgstr "komand-antataŭigo ankoraŭ ne estas subtenata"
+msgstr "forigo de citilo"
 
-#: grecs/src/wordsplit.c:2088
-msgid "coalesce list"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2090
+#: grecs/wordsplit/wordsplit.c:2617
 msgid "path expansion"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2120
-msgid "Initial list:"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2136
-#, fuzzy
-msgid "Coalesced list:"
-msgstr "ne atendita listo"
+msgstr "etendigo de vojo"
 
-#: grecs/src/wordsplit.c:2190
+#: grecs/wordsplit/wordsplit.c:2642
 #, c-format
 msgid "(%02d) Input:%.*s;"
-msgstr ""
+msgstr "(%02d) Enigo:%.*s;"
 
-#: grecs/src/wordsplit.c:2202
-#, c-format
-msgid "(%02d) Restart:%.*s;"
-msgstr ""
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
+msgstr "Komenca listo:"
 
-#: grecs/src/wordsplit.c:2298
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr "Kunfandita listo:"
+
+#: grecs/wordsplit/wordsplit.c:2853
 msgid "no error"
 msgstr "neniu eraro"
 
-#: grecs/src/wordsplit.c:2299
+#: grecs/wordsplit/wordsplit.c:2854
 msgid "missing closing quote"
 msgstr "mankas ferma citilo"
 
-#: grecs/src/wordsplit.c:2301
+#: grecs/wordsplit/wordsplit.c:2856
 msgid "invalid wordsplit usage"
 msgstr "malvalida uzo de 'wordsplit'"
 
-#: grecs/src/wordsplit.c:2302
+#: grecs/wordsplit/wordsplit.c:2857
 msgid "unbalanced curly brace"
-msgstr "ne spegulita ronda krampo"
+msgstr "ne spegulita kurba krampo"
 
-#: grecs/src/wordsplit.c:2303
+#: grecs/wordsplit/wordsplit.c:2858
 msgid "undefined variable"
 msgstr "nedifinita variablo"
 
-#: grecs/src/wordsplit.c:2304
+#: grecs/wordsplit/wordsplit.c:2859
 msgid "input exhausted"
 msgstr "enigo estas elĉerpita"
 
-#: grecs/src/wordsplit.c:2305
+#: grecs/wordsplit/wordsplit.c:2860
 msgid "unbalanced parenthesis"
-msgstr ""
+msgstr "ne spegulita ronda krampo"
 
-#: grecs/src/wordsplit.c:2306
-#, fuzzy
+#: grecs/wordsplit/wordsplit.c:2861
 msgid "globbing error"
-msgstr "neniu eraro"
+msgstr "eraro de 'globbing'"
+
+#: grecs/wordsplit/wordsplit.c:2862
+#, fuzzy
+msgid "user-defined error"
+msgstr "leg-eraro"
 
-#: grecs/src/wordsplit.c:2318
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2875
 msgid "unknown error"
 msgstr "nekonata eraro"
 
-#: grecs/src/wordsplit.c:2327
+#: grecs/wordsplit/wordsplit.c:2884
 #, c-format
 msgid "missing closing %c (start near #%lu)"
 msgstr "mankas ferma %c (komencas proksime de #%lu)"
 
+#~ msgid "unterminated regexp"
+#~ msgstr "nefinigita regulesprimo"
+
+#~ msgid "unrecognized flag: %c"
+#~ msgstr "nerekonita flago: %c"
+
+#~ msgid "out of memory"
+#~ msgstr "mankas memoro"
+
+#~ msgid "%s: unknown keyword"
+#~ msgstr "%s: nekonata ŝlosilvorto"
+
+#~ msgid "(%02d) Restart:%.*s;"
+#~ msgstr "(%02d) Rekomenco:%.*s;"
+
 #~ msgid "INTERNAL ERROR at %s:%d"
 #~ msgstr "INTERNA ERARO ĉe %s:%d"
diff --git a/po/es.gmo b/po/es.gmo
new file mode 100644
index 0000000..608875d
Binary files /dev/null and b/po/es.gmo differ
diff --git a/po/es.po b/po/es.po
new file mode 100644
index 0000000..2c51ebd
--- /dev/null
+++ b/po/es.po
@@ -0,0 +1,930 @@
+# Spanish translation for direvent 5.1.
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# This file is distributed under the same license as the direvent package.
+# Francisco Javier Serrador <fserrador@gmail.com>, 2018.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: direvent 5.1\n"
+"Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
+"PO-Revision-Date: 2018-04-29 10:30+0200\n"
+"Last-Translator: Francisco Javier Serrador <fserrador@gmail.com>\n"
+"Language-Team: Spanish <es@tp.org.es>\n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"X-Generator: Poedit 2.0.4\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: cmdline.opt:26
+msgid "increase debug level"
+msgstr "incrementar nivel de depuración"
+
+#: cmdline.opt:32
+msgid "PRIO"
+msgstr "PRIO"
+
+#: cmdline.opt:32
+msgid ""
+"log everything with priority PRIO and higher to the stderr, as well as to "
+"the syslog"
+msgstr ""
+"boletinar todo elemento con prioridad PRIO y superior al stderr, además al "
+"boletín del sistema syslog"
+
+#: cmdline.opt:41
+msgid "NAME"
+msgstr "NOMBRE"
+
+#: cmdline.opt:41
+msgid "set syslog facility"
+msgstr "establecer capacidad syslog"
+
+#: cmdline.opt:47
+msgid "remain in foreground"
+msgstr "permanecer en primer plano"
+
+#: cmdline.opt:53
+msgid "DIR"
+msgstr "DIR"
+
+#: cmdline.opt:53
+msgid "add include directory"
+msgstr "añade directorio incluido"
+
+#: cmdline.opt:59
+msgid "PROG"
+msgstr "PROG"
+
+#: cmdline.opt:59
+msgid "self-test mode"
+msgstr "modo auto-probado"
+
+#: cmdline.opt:65
+msgid "FILE"
+msgstr "FICHERO"
+
+#: cmdline.opt:65
+msgid "set PID file"
+msgstr "establecer fichero PID"
+
+#: cmdline.opt:71
+msgid "check configuration file and exit"
+msgstr "marca fichero de configuración y sale"
+
+#: cmdline.opt:77
+msgid "USER"
+msgstr "USUARIO"
+
+#: cmdline.opt:77
+msgid "run as this user"
+msgstr "ejecuta como este usuario"
+
+#: cmdline.opt:87
+msgid "show configuration file summary"
+msgstr "muestra resumen del fichero de configuración"
+
+#: cmdline.opt:81
+msgid "Other options"
+msgstr "Otras opciones"
+
+#: cmdline.opt:93
+msgid "Give this help list"
+msgstr "Da este listado de ayuda"
+
+#: cmdline.opt:93
+msgid "Give a short usage message"
+msgstr "Da un mensaje de empleo corto"
+
+#: cmdline.opt:93
+msgid "Print program version"
+msgstr "Escribe la versión del programa"
+
+#: cmdline.opt:13
+msgid "GNU direvent monitors changes in directories"
+msgstr "Evento direccional GNU modifica en directorios"
+
+#: cmdline.opt:15
+msgid "[CONFIG]"
+msgstr "[CONFIGURACIÓN]"
+
+#: cmdline.opt:95
+#, c-format
+msgid ""
+"The optional CONFIG argument supplies the name of the configuration file\n"
+"to use instead of %s.\n"
+"\n"
+msgstr ""
+"El argumento CONFIG opcional suministra el nombre del fichero de "
+"configuración\n"
+"a emplear en ligar de %s\n"
+"\n"
+
+#. TRANSLATORS: %s is one of: inotify, kqueue
+#: cmdline.opt:99
+#, c-format
+msgid ""
+"This direvent uses %s interface.\n"
+"\n"
+msgstr ""
+"Este directorio de evento utiliza %s interfaz.\n"
+"\n"
+
+#: cmdline.opt:102
+#, c-format
+msgid "Include search path:\n"
+msgstr "Incluye ruta de búsqueda:\n"
+
+#: cmdline.opt:105
+#, c-format
+msgid "No include search path.\n"
+msgstr "No incluir ruta de búsqueda.\n"
+
+#: src/config.c:63
+#, c-format
+msgid "unknown syslog facility: %s"
+msgstr "capacidad de syslog desconocida: %s"
+
+#: src/config.c:80
+#, c-format
+msgid "unknown syslog priority: %s"
+msgstr "prioridad de syslog desconocida: %s"
+
+#: src/config.c:88
+msgid "unexpected block statement"
+msgstr "bloque de declaración inesperada"
+
+#: src/config.c:97
+#, c-format
+msgid "expected %s"
+msgstr "esperaba %s"
+
+#: src/config.c:102
+#, c-format
+msgid "expected %s, but found %s"
+msgstr "esperaba %s, pero encontré %s"
+
+#: src/config.c:124
+#, c-format
+msgid "unknown syslog facility `%s'"
+msgstr "capacidad de boletín de sistema desconocido «%s»"
+
+#: src/config.c:133 src/config.c:606
+msgid "name"
+msgstr "name"
+
+#: src/config.c:134
+msgid ""
+"Set syslog facility. Arg is one of the following: user, daemon, auth, "
+"authpriv, mail, cron, local0 through local7 (case-insensitive), or a "
+"facility number."
+msgstr ""
+"Establece capacidad syslog. Arg es uno de los siguientes: usuario, demonio, "
+"autoridad, autoridadpriv, correo, cron, local0 a tracés de local7 "
+"(indistinguible mayúsculas), o un número capacitado."
+
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
+msgid "string"
+msgstr "cadena"
+
+#: src/config.c:139
+msgid "Tag syslog messages with this string"
+msgstr "Etiquetar mensajes syslog con esta cadena textual"
+
+#: src/config.c:142 grecs/src/format.c:141
+msgid "arg"
+msgstr "arg"
+
+#: src/config.c:143
+msgid "Prefix each message with its priority"
+msgstr "Prefija cada mensaje con su prioridad"
+
+#: src/config.c:191
+#, c-format
+msgid "%s: recursion depth does not match previous definition"
+msgstr "%s: profundidad recursiva no coincide definición anterior"
+
+#: src/config.c:212
+msgid "no paths configured"
+msgstr "sin rutas configuradas"
+
+#: src/config.c:217
+msgid "no command configured"
+msgstr "ningún mandato configurado"
+
+#: src/config.c:229 grecs/src/tree.c:665
+msgid "invalid use of block statement"
+msgstr "empleo inválido de bloque de sentencia"
+
+#: src/config.c:274
+msgid "expected \"recursive\" or end of statement"
+msgstr "esperado «recursivo» o final de declaración"
+
+#: src/config.c:289
+msgid "surplus argument"
+msgstr "sin más argumento"
+
+#: src/config.c:295 src/config.c:446
+msgid "unexpected list"
+msgstr "lista no esperada"
+
+#: src/config.c:326 src/config.c:341 src/config.c:356
+msgid "unrecognized event code"
+msgstr "código eventual no reconocido"
+
+#: src/config.c:438
+msgid "surplus arguments"
+msgstr "sin más argumentos"
+
+#: src/config.c:452
+msgid "no such user"
+msgstr "sin tal usuario"
+
+#: src/config.c:459
+msgid "no such group"
+msgstr "sin tal grupo"
+
+#: src/config.c:501
+msgid "unrecognized option"
+msgstr "opción no reconocida"
+
+#: src/config.c:595
+msgid "Pathname to watch"
+msgstr "Ruta nombrada a vigilar"
+
+#: src/config.c:598
+msgid "Events to watch for"
+msgstr "Eventos a vigilar para"
+
+#: src/config.c:601
+msgid "regexp"
+msgstr "expreg"
+
+#: src/config.c:601
+msgid "Files to watch for"
+msgstr "VFicheros a vigilar para"
+
+#: src/config.c:604
+msgid "Command to execute on event"
+msgstr "Mandato a ejecutar en evento"
+
+#: src/config.c:606
+msgid "Run command as this user"
+msgstr "Ejecuta mandato como este usuario"
+
+#: src/config.c:609
+msgid "seconds"
+msgstr "segundos"
+
+#: src/config.c:609
+msgid "Timeout for the command"
+msgstr "Tiempo agotado para la mandato"
+
+#: src/config.c:611
+msgid "List of additional options"
+msgstr "Listado de opciones adicionales"
+
+#: src/config.c:614
+msgid "<arg: string> <arg: string>..."
+msgstr "<arg: cadena> <arg: cadena>..."
+
+#: src/config.c:615
+msgid "Modify environment"
+msgstr "Modifica entorno"
+
+#: src/config.c:622
+msgid "Run as this user"
+msgstr "Ejecuta como este usuario"
+
+#: src/config.c:624
+msgid "Run in foreground"
+msgstr "Ejecuta en primer plano"
+
+#: src/config.c:626
+msgid "file"
+msgstr "fichero"
+
+#: src/config.c:626
+msgid "Set pid file name"
+msgstr "Establece nombre del fichero de pid"
+
+#: src/config.c:628
+msgid "Configure syslog logging"
+msgstr "Configura bitácora para registro de sistema"
+
+#: src/config.c:630
+msgid "level"
+msgstr "nivel"
+
+#: src/config.c:630
+msgid "Set debug level"
+msgstr "Establecer nivel de depuración"
+
+#: src/config.c:632
+msgid "Configure event watcher"
+msgstr "Configurar vigía de evento"
+
+#: src/config.c:643
+msgid ""
+"Configuration file structure for direvent.\n"
+"For more information, use `info direvent configuration'."
+msgstr ""
+"Fichero de configuración estructurada para evento directorio.\n"
+"Para más información, emplee `info direvent configuration'."
+
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
+msgid "not enough memory"
+msgstr "sin memoria suficiente"
+
+#: src/direvent.c:274
+#, c-format
+msgid "cannot open pidfile %s for writing: %s"
+msgstr "no puede abrir fichero pid %s para escritura: %s"
+
+#: src/direvent.c:302
+#, c-format
+msgid "no user with UID %lu"
+msgstr "sin usuario con UID %lu"
+
+#: src/direvent.c:420
+#, c-format
+msgid "cannot run `%s': fork failed: %s"
+msgstr "no puede ejecutar «%s»: bifurcación fallada: %s"
+
+#: src/direvent.c:480
+msgid "too many arguments"
+msgstr "demasiados argumentos"
+
+#: src/direvent.c:522
+#, c-format
+msgid "%s %s started"
+msgstr "%s %s iniciado"
+
+#: src/direvent.c:546
+#, c-format
+msgid "%s %s stopped"
+msgstr "%s %s detenido"
+
+#: src/environ.c:25
+msgid "environment: "
+msgstr "entorno: "
+
+#: src/progman.c:142
+#, c-format
+msgid "process %lu exited successfully"
+msgstr "proceso %lu finalizado correctamente"
+
+#: src/progman.c:145
+#, c-format
+msgid "process %lu failed with status %d"
+msgstr "proceso %lu fallado con estado %d"
+
+#: src/progman.c:155
+#, c-format
+msgid "process %lu terminated on signal %d"
+msgstr "proceso %lu terminado con señal %d"
+
+#: src/progman.c:158
+#, c-format
+msgid "process %lu stopped on signal %d"
+msgstr "proceso %lu detenido con señal %d"
+
+#: src/progman.c:163
+#, c-format
+msgid "process %lu dumped core"
+msgstr "procesa %lu volcado del núcleo"
+
+#: src/progman.c:167
+#, c-format
+msgid "process %lu terminated with unrecognized status"
+msgstr "proceso %lu terminado con estado no reconocido"
+
+#: src/progman.c:228
+msgid "begin scanning process list"
+msgstr "iniciar listado de proceso analítico"
+
+#: src/progman.c:232
+#, c-format
+msgid "process %lu timed out"
+msgstr "proceso temporal %lu agotado"
+
+#: src/progman.c:241
+#, c-format
+msgid "scheduling alarm in %lu seconds"
+msgstr "horario de alarma en %lu segundos"
+
+#: src/progman.c:322
+#, c-format
+msgid "cannot start redirector for %s, pipe failed: %s"
+msgstr "no puede iniciar redirector para %s, tubería fallada: %s"
+
+#: src/progman.c:354
+#, c-format
+msgid "cannot run redirector `%s': fork failed: %s"
+msgstr "no puede ejecutar redirección «%s»: bifurcación fallada: %s"
+
+#: src/progman.c:359
+#, c-format
+msgid "redirector for %s started, pid=%lu"
+msgstr "redirector para %s iniciado, pid=%lu"
+
+#: src/progman.c:455
+#, c-format
+msgid "starting %s, dir=%s, file=%s"
+msgstr "iniciando %s, dir=%s, fichero=%s"
+
+#: src/progman.c:484
+#, c-format
+msgid "cannot change to %s: %s"
+msgstr "no puede modificar a %s: %s"
+
+#: src/progman.c:512
+#, c-format
+msgid "%s running; dir=%s, file=%s, pid=%lu"
+msgstr "%s ejecutando; dir=%s, fichero=%s, pid=%lu"
+
+#: src/progman.c:534
+#, c-format
+msgid "waiting for %s (%lu) to terminate"
+msgstr "esperando a %s (%lu) para terminar"
+
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr "quitando vigía %s"
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
+#, c-format
+msgid "creating watcher %s"
+msgstr "creando vigía %s"
+
+#: src/watcher.c:281 src/watcher.c:296
+#, c-format
+msgid "cannot set watcher on %s: %s"
+msgstr "no puede establecer vigía en: %s: %s"
+
+#: src/watcher.c:377
+#, c-format
+msgid "cannot create watcher %s/%s: not enough memory"
+msgstr "no puede crear vigía %s/%s: sin memoria suficiente"
+
+#: src/watcher.c:384
+#, c-format
+msgid "cannot create watcher %s/%s, stat failed: %s"
+msgstr "no puede crear vigía %s/%s, estadística fallada: %s"
+
+#: src/watcher.c:430
+#, c-format
+msgid "cannot open directory %s: %s"
+msgstr "no puede abrir el directorio %s: %s"
+
+#: src/watcher.c:447
+#, c-format
+msgid "cannot stat %s/%s: not enough memory"
+msgstr "no puede declarar %s/%s: sin suficiente memoria"
+
+#: src/watcher.c:452
+#, c-format
+msgid "cannot stat %s: %s"
+msgstr "no puede declarar %s: %s"
+
+#: src/watcher.c:497
+msgid "no event handlers configured"
+msgstr "ningún manipulador eventual configurado"
+
+#: src/watcher.c:502
+msgid "no event handlers installed"
+msgstr "ningún manipulador eventual instalado"
+
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+#, fuzzy
+msgid "hostname"
+msgstr "name"
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
+msgstr ""
+
+#: grecs/src/format.c:133
+msgid "Disabled;"
+msgstr "Desactivado;"
+
+#: grecs/src/opthelp.c:123 grecs/src/opthelp.c:269
+msgid "Usage:"
+msgstr "Modo de empleo:"
+
+#: grecs/src/opthelp.c:127
+msgid "OPTION"
+msgstr "OPCIÓN"
+
+#: grecs/src/opthelp.c:132 grecs/src/opthelp.c:427
+msgid "Aliases"
+msgstr "Aliases"
+
+#: grecs/src/opthelp.c:132 grecs/src/opthelp.c:427
+msgid "Alias"
+msgstr "Alias"
+
+#: grecs/src/opthelp.c:186
+msgid ""
+"Mandatory or optional arguments to long options are also mandatory or "
+"optional for any corresponding short options."
+msgstr ""
+"Argumentos obligatorios u opcionales para opciones largas son también "
+"obligatorios u opcionales para opciones correspondientes cortas."
+
+#. TRANSLATORS: The placeholder indicates the bug-reporting
+#. address for this package.  Please add _another line_ saying
+#. "Report translation bugs to <...>\n" with the address for
+#. translation bugs (typically your translation team's web or
+#. email address).
+#: grecs/src/opthelp.c:202
+#, c-format
+msgid "Report bugs to %s.\n"
+msgstr "Comunique defectos a: %s.\n"
+
+#: grecs/src/opthelp.c:205
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "%s página inicial: <%s>\n"
+
+#. TRANSLATORS: Translate "(C)" to the copyright symbol
+#. (C-in-a-circle), if this symbol is available in the user's
+#. locale.  Otherwise, do not translate "(C)"; leave it as-is.
+#: grecs/src/opthelp.c:457
+msgid "(C)"
+msgstr "©"
+
+#: grecs/src/opthelp.c:466
+msgid ""
+"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl."
+"html>\n"
+"This is free software: you are free to change and redistribute it.\n"
+"There is NO WARRANTY, to the extent permitted by law.\n"
+"\n"
+msgstr ""
+"Licencia GPLv3+: GPL de GNU versión 3 o posterior\n"
+"<http://gnu.org/licenses/gpl.html>.\n"
+"Esto es software libre: usted es libre de cambiarlo y redistribuirlo.\n"
+"No hay NINGUNA GARANTÍA, hasta donde permite la ley.\n"
+"\n"
+
+#: grecs/src/opthelp.c:483
+msgid "Written by "
+msgstr "Escrito por "
+
+#. TRANSLATORS: This string is used as a delimiter between
+#. authors' names as in:
+#.
+#. Written by Winnie the Pooh, Piglet ...
+#.
+#: grecs/src/opthelp.c:489
+msgid ", "
+msgstr ", "
+
+#. TRANSLATORS: This string acts as a delimiter before the
+#. last author's names, e.g.:
+#.
+#. Written by Winnie the Pooh, Piglet and Christopher Robin.
+#.
+#: grecs/src/opthelp.c:495
+msgid " and "
+msgstr " y "
+
+#: grecs/src/path-parser.c:62
+#, c-format
+msgid "cannot open `%s'"
+msgstr "no puede abrir «%s»"
+
+#: grecs/src/path-parser.c:108 grecs/src/path-parser.c:123
+msgid "unexpected end of file"
+msgstr "final de fichero no esperado"
+
+#: grecs/src/path-parser.c:143
+msgid "parse error"
+msgstr "incapaz resolverse lo que usted signific decir"
+
+#: grecs/src/preproc.c:448 grecs/src/preproc.c:470
+#, c-format
+msgid "Cannot stat `%s'"
+msgstr "No puedo declarar «%s»"
+
+#: grecs/src/preproc.c:453 grecs/src/preproc.c:458
+msgid "Recursive inclusion"
+msgstr "Inclusión recursiva"
+
+#: grecs/src/preproc.c:461
+#, c-format
+msgid "`%s' already included here"
+msgstr "«%s» ya incluido aquí"
+
+#: grecs/src/preproc.c:465
+#, c-format
+msgid "`%s' already included at top level"
+msgstr "«%s» ya incluido en nivel superior"
+
+#: grecs/src/preproc.c:480
+#, c-format
+msgid "Cannot open `%s'"
+msgstr "No puede abrir «%s»"
+
+#: grecs/src/preproc.c:595
+msgid "Cannot parse include line"
+msgstr "No puedo interpretar línea incluida"
+
+#: grecs/src/preproc.c:598
+msgid "invalid include statement"
+msgstr "declaración incluida inválida"
+
+#: grecs/src/preproc.c:624
+msgid "read error"
+msgstr "error de lectura"
+
+#: grecs/src/preproc.c:632
+#, c-format
+msgid "%s: No such file or directory"
+msgstr "%s: sin tal fichero o directorio"
+
+#: grecs/src/preproc.c:698
+#, c-format
+msgid "Unable to start external preprocessor `%s'"
+msgstr "Incapaz de iniciar un preprocesado externo «%s»"
+
+#: grecs/src/preproc.c:773 grecs/src/preproc.c:793
+#, c-format
+msgid "Cannot run `%s'"
+msgstr "No puedo ejecutar «%s»"
+
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr "elemento no encontrado en tabla"
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr "lista simbólica está llena"
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+#, fuzzy
+msgid "one or more arguments"
+msgstr "demasiados argumentos"
+
+#: grecs/src/tree.c:75
+#, fuzzy
+msgid "unrecognized type; please report"
+msgstr "código eventual no reconocido"
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+#, fuzzy
+msgid "unknown keyword"
+msgstr "Palabra clave desconocida"
+
+#: grecs/src/tree.c:360
+#, c-format
+msgid "%s: not a valid boolean value"
+msgstr "%s: no un valor booleana válido"
+
+#: grecs/src/tree.c:391
+#, c-format
+msgid "%s: UNIX socket name too long"
+msgstr "%s: nombre de socket UNIX demasiado largo"
+
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
+#, c-format
+msgid "%s: not a valid IP address or hostname"
+msgstr "%s: no una dirección IP válida u nombre hospedante"
+
+#: grecs/src/tree.c:444
+#, c-format
+msgid "%s: not a valid port number"
+msgstr "%s: no un número de puerto válido"
+
+#: grecs/src/tree.c:452
+msgid "missing port number"
+msgstr "falta el número de puerto"
+
+#: grecs/src/tree.c:501
+msgid "numeric overflow"
+msgstr "desbordamiento numérico"
+
+#: grecs/src/tree.c:506
+msgid "value out of allowed range"
+msgstr "valor fuera de rango permitido"
+
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
+#, c-format
+msgid "not a number (stopped near `%s')"
+msgstr "no un número (detenido cerca de «%s»)"
+
+#: grecs/src/tree.c:635
+#, c-format
+msgid "%s: not a valid IP address"
+msgstr "%s: no una dirección IP válida"
+
+#: grecs/src/tree.c:774
+#, c-format
+msgid "too many arguments to `%s'; missing semicolon?"
+msgstr "demasiados argumentos a «%s»; ¿faltan punto y como?"
+
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
+#, c-format
+msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
+msgstr "ERROR INTERNO en %s:%d: tipo de datos %d no manipulado"
+
+#: grecs/src/tree.c:803
+#, c-format
+msgid "%s: incompatible data type in list item #%d"
+msgstr "%s: tipo de datos incompatibles dentro de ítem de lista #%d"
+
+#: grecs/src/tree.c:823
+#, c-format
+msgid "incompatible data type for `%s'"
+msgstr "tipo de datos incompatible para  «%s»"
+
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
+msgid "memory exhausted"
+msgstr "memoria agotada"
+
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:1607
+#, c-format
+msgid "%.*s: variable null or not set"
+msgstr "%.*s: variable nula o no establecida"
+
+#: grecs/wordsplit/wordsplit.c:1637
+#, c-format
+msgid "warning: undefined variable `%.*s'"
+msgstr "cuidado: variable no definida `%.*s'"
+
+#: grecs/wordsplit/wordsplit.c:2141
+#, c-format
+msgid "no files match pattern %s"
+msgstr "sin ficheros coinciden con patrón %s"
+
+#: grecs/wordsplit/wordsplit.c:2603
+msgid "WS trimming"
+msgstr "Recortando WS"
+
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
+msgstr "sustitución de mandato"
+
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
+msgstr "lista cualificada"
+
+#: grecs/wordsplit/wordsplit.c:2609
+msgid "tilde expansion"
+msgstr "expansión tilde"
+
+#: grecs/wordsplit/wordsplit.c:2611
+msgid "variable expansion"
+msgstr "expansión variable"
+
+#: grecs/wordsplit/wordsplit.c:2613
+msgid "quote removal"
+msgstr "supresión de comillas"
+
+#: grecs/wordsplit/wordsplit.c:2617
+msgid "path expansion"
+msgstr "expansión de ruta"
+
+#: grecs/wordsplit/wordsplit.c:2642
+#, c-format
+msgid "(%02d) Input:%.*s;"
+msgstr "(%02d) Entrada:%.*s;"
+
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
+msgstr "Lista inicial:"
+
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr "Lista especificada:"
+
+#: grecs/wordsplit/wordsplit.c:2853
+msgid "no error"
+msgstr "sin error"
+
+#: grecs/wordsplit/wordsplit.c:2854
+msgid "missing closing quote"
+msgstr "faltando cierre de comilla"
+
+#: grecs/wordsplit/wordsplit.c:2856
+msgid "invalid wordsplit usage"
+msgstr "divisor de palabras mandado inválido"
+
+#: grecs/wordsplit/wordsplit.c:2857
+msgid "unbalanced curly brace"
+msgstr "rama curly desbalanceada"
+
+#: grecs/wordsplit/wordsplit.c:2858
+msgid "undefined variable"
+msgstr "variable no definida"
+
+#: grecs/wordsplit/wordsplit.c:2859
+msgid "input exhausted"
+msgstr "entrada agotada"
+
+#: grecs/wordsplit/wordsplit.c:2860
+msgid "unbalanced parenthesis"
+msgstr "paréntesis desequilibrados"
+
+#: grecs/wordsplit/wordsplit.c:2861
+msgid "globbing error"
+msgstr "error globalizado"
+
+#: grecs/wordsplit/wordsplit.c:2862
+#, fuzzy
+msgid "user-defined error"
+msgstr "error de lectura"
+
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2875
+msgid "unknown error"
+msgstr "error desconocido"
+
+#: grecs/wordsplit/wordsplit.c:2884
+#, c-format
+msgid "missing closing %c (start near #%lu)"
+msgstr "faltando cierre %c (inicio cerca #%lu)"
+
+#~ msgid "unterminated regexp"
+#~ msgstr "expreg sin terminar"
+
+#~ msgid "unrecognized flag: %c"
+#~ msgstr "maraca no reconocida: %c"
+
+#~ msgid "out of memory"
+#~ msgstr "memoria agotada"
+
+#~ msgid "%s: unknown keyword"
+#~ msgstr "%s: palabra clave desconocida"
+
+#~ msgid "(%02d) Restart:%.*s;"
+#~ msgstr "(%02d) Reiniciar:%.*s;"
diff --git a/po/fr.gmo b/po/fr.gmo
index c33f01a..4f0271b 100644
Binary files a/po/fr.gmo and b/po/fr.gmo differ
diff --git a/po/fr.po b/po/fr.po
index bc610f5..485a5dd 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -1,20 +1,21 @@
 # Messages français pour direvent
-# Copyright (C) 2014 Free Software Foundation, Inc.
+# Copyright (C) 2016 Free Software Foundation, Inc.
 # This file is distributed under the same license as the direvent package.
-# Frédéric Marchal <fmarchal@perso.be>, 2014.
+# Frédéric Marchal <fmarchal@perso.be>, 2016.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: direvent 4.1.91\n"
+"Project-Id-Version: direvent 5.1\n"
 "Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
-"POT-Creation-Date: 2016-07-06 17:50+0300\n"
-"PO-Revision-Date: 2014-09-02 11:56+0200\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
+"PO-Revision-Date: 2016-07-08 14:27+0200\n"
 "Last-Translator: Frédéric Marchal <fmarchal@perso.be>\n"
 "Language-Team: French <traduc@traduc.org>\n"
 "Language: fr\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms:  nplurals=2; plural=(n > 1);\n"
 
 #: cmdline.opt:26
@@ -47,11 +48,11 @@ msgstr "rester au premier plan"
 
 #: cmdline.opt:53
 msgid "DIR"
-msgstr ""
+msgstr "RÉP"
 
 #: cmdline.opt:53
 msgid "add include directory"
-msgstr ""
+msgstr "ajouter le répertoire d'inclusion"
 
 #: cmdline.opt:59
 msgid "PROG"
@@ -133,12 +134,12 @@ msgstr ""
 #: cmdline.opt:102
 #, c-format
 msgid "Include search path:\n"
-msgstr ""
+msgstr "Chemin de recherche des fichiers à inclure:\n"
 
 #: cmdline.opt:105
 #, c-format
 msgid "No include search path.\n"
-msgstr ""
+msgstr "Aucun chemin de recherche des fichiers à inclure.\n"
 
 #: src/config.c:63
 #, c-format
@@ -169,7 +170,7 @@ msgstr "%s attendu mais %s rencontré"
 msgid "unknown syslog facility `%s'"
 msgstr "catégorie syslog « %s » inconnue"
 
-#: src/config.c:133 src/config.c:706
+#: src/config.c:133 src/config.c:606
 msgid "name"
 msgstr "nom"
 
@@ -183,7 +184,7 @@ msgstr ""
 "authpriv, mail, cron, local0 à local7 (insensible à la casse) ou un numéro "
 "de catégorie."
 
-#: src/config.c:139
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
 msgid "string"
 msgstr "chaîne"
 
@@ -199,143 +200,133 @@ msgstr "arg"
 msgid "Prefix each message with its priority"
 msgstr "Préfixer chaque message avec cette priorité"
 
-#: src/config.c:209
+#: src/config.c:191
 #, c-format
 msgid "%s: recursion depth does not match previous definition"
 msgstr ""
 "%s: la profondeur de récursion ne correspond pas à la définition précédente"
 
-#: src/config.c:247
+#: src/config.c:212
 msgid "no paths configured"
 msgstr "aucun chemin configuré"
 
-#: src/config.c:252
+#: src/config.c:217
 msgid "no command configured"
 msgstr "aucune commande configurée"
 
-#: src/config.c:264 grecs/src/tree.c:634
+#: src/config.c:229 grecs/src/tree.c:665
 msgid "invalid use of block statement"
 msgstr "utilisation invalide d'une instruction bloc"
 
-#: src/config.c:309
+#: src/config.c:274
 msgid "expected \"recursive\" or end of statement"
 msgstr "« recursive » ou fin d'instruction attendu"
 
-#: src/config.c:324
+#: src/config.c:289
 msgid "surplus argument"
 msgstr "argument surnuméraire"
 
-#: src/config.c:330 src/config.c:481
+#: src/config.c:295 src/config.c:446
 msgid "unexpected list"
 msgstr "liste inattendue"
 
-#: src/config.c:361 src/config.c:376 src/config.c:391
+#: src/config.c:326 src/config.c:341 src/config.c:356
 msgid "unrecognized event code"
 msgstr "code d'événement non reconnu"
 
-#: src/config.c:473
+#: src/config.c:438
 msgid "surplus arguments"
 msgstr "arguments surnuméraires"
 
-#: src/config.c:487
+#: src/config.c:452
 msgid "no such user"
 msgstr "cet utilisateur n'existe pas"
 
-#: src/config.c:494
+#: src/config.c:459
 msgid "no such group"
 msgstr "ce group n'existe pas"
 
-#: src/config.c:535
-#, fuzzy
+#: src/config.c:501
 msgid "unrecognized option"
-msgstr "fanion non reconnu"
-
-#: src/config.c:613
-msgid "unterminated regexp"
-msgstr "expression régulière non terminée"
-
-#: src/config.c:627
-#, c-format
-msgid "unrecognized flag: %c"
-msgstr "fanion non reconnu: %c"
+msgstr "option non reconnue"
 
-#: src/config.c:695
+#: src/config.c:595
 msgid "Pathname to watch"
 msgstr "Chemin à surveiller"
 
-#: src/config.c:698
+#: src/config.c:598
 msgid "Events to watch for"
 msgstr "Événements à surveiller"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "regexp"
 msgstr "expression régulière"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "Files to watch for"
 msgstr "Fichiers à surveiller"
 
-#: src/config.c:704
+#: src/config.c:604
 msgid "Command to execute on event"
 msgstr "Commande à exécuter suite à l'événement"
 
-#: src/config.c:706
+#: src/config.c:606
 msgid "Run command as this user"
 msgstr "Exécuter la commande comme cet utilisateur"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "seconds"
 msgstr "secondes"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "Timeout for the command"
 msgstr "Délai d'expiration de la commande"
 
-#: src/config.c:711
+#: src/config.c:611
 msgid "List of additional options"
 msgstr "Liste d'options additionnelles"
 
-#: src/config.c:714
+#: src/config.c:614
 msgid "<arg: string> <arg: string>..."
 msgstr "<arg: chaîne> <arg: chaîne>…"
 
-#: src/config.c:715
+#: src/config.c:615
 msgid "Modify environment"
 msgstr "Modifier l'environnement"
 
-#: src/config.c:722
+#: src/config.c:622
 msgid "Run as this user"
 msgstr "Exécuter comme cet utilisateur"
 
-#: src/config.c:724
+#: src/config.c:624
 msgid "Run in foreground"
 msgstr "Exécuter en avant plan"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "file"
 msgstr "fichier"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "Set pid file name"
 msgstr "Sélectionner le nom du fichier pid"
 
-#: src/config.c:728
+#: src/config.c:628
 msgid "Configure syslog logging"
 msgstr "Configurer la journalisation syslog"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "level"
 msgstr "niveau"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "Set debug level"
 msgstr "Sélectionner le niveau de débogage"
 
-#: src/config.c:732
+#: src/config.c:632
 msgid "Configure event watcher"
 msgstr "Configurer la surveillance de l'événement"
 
-#: src/config.c:743
+#: src/config.c:643
 msgid ""
 "Configuration file structure for direvent.\n"
 "For more information, use `info direvent configuration'."
@@ -343,36 +334,35 @@ msgstr ""
 "Structure du fichier de configuration de direvent.\n"
 "Pour plus d'information, utilisez « info direvent configuration »."
 
-#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:86 src/watcher.c:182
-#: src/watcher.c:191
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
 msgid "not enough memory"
 msgstr "pas assez de mémoire"
 
-#: src/direvent.c:272
+#: src/direvent.c:274
 #, c-format
 msgid "cannot open pidfile %s for writing: %s"
 msgstr "impossible d'ouvrir le fichier pid %s en écriture: %s"
 
-#: src/direvent.c:300
+#: src/direvent.c:302
 #, c-format
 msgid "no user with UID %lu"
 msgstr "pas d'utilisateur avec le UID %lu"
 
-#: src/direvent.c:418
+#: src/direvent.c:420
 #, c-format
 msgid "cannot run `%s': fork failed: %s"
 msgstr "impossible d'exécuter « %s »: fork a échoué: %s"
 
-#: src/direvent.c:478
+#: src/direvent.c:480
 msgid "too many arguments"
 msgstr "trop d'arguments"
 
-#: src/direvent.c:520
+#: src/direvent.c:522
 #, c-format
 msgid "%s %s started"
 msgstr "%s %s démarré"
 
-#: src/direvent.c:541
+#: src/direvent.c:546
 #, c-format
 msgid "%s %s stopped"
 msgstr "%s %s arrêté"
@@ -381,18 +371,6 @@ msgstr "%s %s arrêté"
 msgid "environment: "
 msgstr "environnement: "
 
-#: src/hashtab.c:140 grecs/src/symtab.c:206
-msgid "element not found in table"
-msgstr "élément pas trouvé dans la table"
-
-#: src/hashtab.c:142 grecs/src/symtab.c:208
-msgid "symbol table is full"
-msgstr "la table des symboles est remplie"
-
-#: src/hashtab.c:144
-msgid "out of memory"
-msgstr "à cours de mémoire"
-
 #: src/progman.c:142
 #, c-format
 msgid "process %lu exited successfully"
@@ -452,73 +430,123 @@ msgstr "impossible d'exécuter la redirection « %s »: fork a échoué: %s"
 msgid "redirector for %s started, pid=%lu"
 msgstr "redirection pour %s démarrée, pid=%lu"
 
-#: src/progman.c:454
+#: src/progman.c:455
 #, c-format
 msgid "starting %s, dir=%s, file=%s"
 msgstr "démarrage de %s, rép=%s, fichier=%s"
 
-#: src/progman.c:482
+#: src/progman.c:484
 #, c-format
 msgid "cannot change to %s: %s"
 msgstr "impossible de changer vers %s: %s"
 
-#: src/progman.c:510
+#: src/progman.c:512
 #, c-format
 msgid "%s running; dir=%s, file=%s, pid=%lu"
 msgstr "%s en cours; rép=%s, fichier=%s, pid=%lu"
 
-#: src/progman.c:532
+#: src/progman.c:534
 #, c-format
 msgid "waiting for %s (%lu) to terminate"
 msgstr "attente que %s (%lu) se termine"
 
-#: src/watcher.c:231
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr "suppression de la supervision %s"
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
 #, c-format
 msgid "creating watcher %s"
 msgstr "création du superviseur %s"
 
-#: src/watcher.c:240
+#: src/watcher.c:281 src/watcher.c:296
 #, c-format
 msgid "cannot set watcher on %s: %s"
 msgstr "impossible de mettre un superviseur sur %s: %s"
 
-#: src/watcher.c:319
+#: src/watcher.c:377
 #, c-format
 msgid "cannot create watcher %s/%s: not enough memory"
 msgstr "impossible de créer le superviseur %s/%s: pas assez de mémoire"
 
-#: src/watcher.c:326
+#: src/watcher.c:384
 #, c-format
 msgid "cannot create watcher %s/%s, stat failed: %s"
 msgstr "impossible de créer le superviseur %s/%s, stat a échoué: %s"
 
-#: src/watcher.c:355
+#: src/watcher.c:430
 #, c-format
 msgid "cannot open directory %s: %s"
 msgstr "impossible d'ouvrir le répertoire %s: %s"
 
-#: src/watcher.c:371
+#: src/watcher.c:447
 #, c-format
 msgid "cannot stat %s/%s: not enough memory"
 msgstr "impossible d'exécuter stat sur %s/%s: pas assez de mémoire"
 
-#: src/watcher.c:376
+#: src/watcher.c:452
 #, c-format
 msgid "cannot stat %s: %s"
 msgstr "impossible d'exécuter stat %s: %s"
 
-#: src/watcher.c:412
+#: src/watcher.c:497
 msgid "no event handlers configured"
 msgstr "aucun gestionnaire d'événement configuré"
 
-#: src/watcher.c:417
+#: src/watcher.c:502
 msgid "no event handlers installed"
 msgstr "aucun gestionnaire d'événement installé"
 
-#: src/watcher.c:425
-#, c-format
-msgid "removing watcher %s"
-msgstr "suppression de la supervision %s"
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+#, fuzzy
+msgid "hostname"
+msgstr "nom"
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
+msgstr ""
 
 #: grecs/src/format.c:133
 msgid "Disabled;"
@@ -655,9 +683,8 @@ msgid "invalid include statement"
 msgstr "instruction d'inclusion invalide"
 
 #: grecs/src/preproc.c:624
-#, fuzzy
 msgid "read error"
-msgstr "erreur d'analyse"
+msgstr "erreur de lecture"
 
 #: grecs/src/preproc.c:632
 #, c-format
@@ -674,186 +701,236 @@ msgstr "Impossible de démarrer le préprocesseur externe « %s »"
 msgid "Cannot run `%s'"
 msgstr "Impossible d'exécuter « %s »"
 
-#: grecs/src/tree.c:329
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr "élément pas trouvé dans la table"
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr "la table des symboles est remplie"
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+#, fuzzy
+msgid "one or more arguments"
+msgstr "trop d'arguments"
+
+#: grecs/src/tree.c:75
+#, fuzzy
+msgid "unrecognized type; please report"
+msgstr "code d'événement non reconnu"
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+#, fuzzy
+msgid "unknown keyword"
+msgstr "Mot clé inconnu"
+
+#: grecs/src/tree.c:360
 #, c-format
 msgid "%s: not a valid boolean value"
 msgstr "%s: pas une valeur booléenne valable"
 
-#: grecs/src/tree.c:360
+#: grecs/src/tree.c:391
 #, c-format
 msgid "%s: UNIX socket name too long"
 msgstr "%s: Nom de socket UNIX trop long"
 
-#: grecs/src/tree.c:389 grecs/src/tree.c:613
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
 #, c-format
 msgid "%s: not a valid IP address or hostname"
 msgstr "%s: n'est pas une adresse IP ou un nom d'hôte valable"
 
-#: grecs/src/tree.c:413
+#: grecs/src/tree.c:444
 #, c-format
 msgid "%s: not a valid port number"
 msgstr "%s: n'est pas un numéro de port valable"
 
-#: grecs/src/tree.c:421
+#: grecs/src/tree.c:452
 msgid "missing port number"
 msgstr "numéro de port manquant"
 
-#: grecs/src/tree.c:470
+#: grecs/src/tree.c:501
 msgid "numeric overflow"
 msgstr "débordement numérique"
 
-#: grecs/src/tree.c:475
+#: grecs/src/tree.c:506
 msgid "value out of allowed range"
 msgstr "valeur hors des limites permises"
 
-#: grecs/src/tree.c:510 grecs/src/tree.c:540
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
 #, c-format
 msgid "not a number (stopped near `%s')"
 msgstr "pas un nombre (arrêté près de « %s »)"
 
-#: grecs/src/tree.c:604
+#: grecs/src/tree.c:635
 #, c-format
 msgid "%s: not a valid IP address"
 msgstr "%s: n'est pas une adresse IP valable"
 
-#: grecs/src/tree.c:743
+#: grecs/src/tree.c:774
 #, c-format
 msgid "too many arguments to `%s'; missing semicolon?"
 msgstr "trop d'arguments à « %s »: point-virgule manquant ?"
 
-#: grecs/src/tree.c:757 grecs/src/tree.c:805
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
 #, c-format
 msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
 msgstr "ERREUR INTERNE à %s:%d: type de donnée %d non géré"
 
-#: grecs/src/tree.c:772
+#: grecs/src/tree.c:803
 #, c-format
 msgid "%s: incompatible data type in list item #%d"
 msgstr "%s: type de donnée incompatible dans l'élément n°%d de la liste"
 
-#: grecs/src/tree.c:792
+#: grecs/src/tree.c:823
 #, c-format
 msgid "incompatible data type for `%s'"
 msgstr "type de donnée incompatible pour « %s »"
 
-#: grecs/src/tree.c:920 grecs/src/tree.c:930
-msgid "Unknown keyword"
-msgstr "Mot clé inconnu"
-
-#: grecs/src/tree.c:1139
-#, c-format
-msgid "%s: unknown keyword"
-msgstr "%s: mot clé inconnu"
-
-#: grecs/src/wordsplit.c:62 grecs/src/wordsplit.c:2300
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
 msgid "memory exhausted"
 msgstr "mémoire épuisée"
 
-#: grecs/src/wordsplit.c:1073
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:1607
 #, c-format
 msgid "%.*s: variable null or not set"
-msgstr ""
+msgstr "%.*s: variable nulle ou pas définie"
 
-#: grecs/src/wordsplit.c:1102
+#: grecs/wordsplit/wordsplit.c:1637
 #, c-format
 msgid "warning: undefined variable `%.*s'"
 msgstr "attention: variable « %.*s » non définie"
 
-#: grecs/src/wordsplit.c:1630
+#: grecs/wordsplit/wordsplit.c:2141
 #, c-format
 msgid "no files match pattern %s"
-msgstr ""
+msgstr "aucun fichier ne correspond au motif %s"
 
-#: grecs/src/wordsplit.c:2080
+#: grecs/wordsplit/wordsplit.c:2603
 msgid "WS trimming"
-msgstr ""
+msgstr "Suppression des espaces"
+
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
+msgstr "substitution de commande"
 
-#: grecs/src/wordsplit.c:2081
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
+msgstr "combinaison de liste"
+
+#: grecs/wordsplit/wordsplit.c:2609
 msgid "tilde expansion"
-msgstr ""
+msgstr "remplacement du tilde"
 
-#: grecs/src/wordsplit.c:2082
+#: grecs/wordsplit/wordsplit.c:2611
 msgid "variable expansion"
-msgstr ""
+msgstr "remplacement de variables"
 
-#: grecs/src/wordsplit.c:2084
+#: grecs/wordsplit/wordsplit.c:2613
 msgid "quote removal"
-msgstr ""
+msgstr "suppression des guillemets"
 
-#: grecs/src/wordsplit.c:2086
-#, fuzzy
-msgid "command substitution"
-msgstr "la substitution de commande n'est pas encore supportée"
-
-#: grecs/src/wordsplit.c:2088
-msgid "coalesce list"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2090
+#: grecs/wordsplit/wordsplit.c:2617
 msgid "path expansion"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2120
-msgid "Initial list:"
-msgstr ""
+msgstr "remplacement de chemin"
 
-#: grecs/src/wordsplit.c:2136
-#, fuzzy
-msgid "Coalesced list:"
-msgstr "liste inattendue"
-
-#: grecs/src/wordsplit.c:2190
+#: grecs/wordsplit/wordsplit.c:2642
 #, c-format
 msgid "(%02d) Input:%.*s;"
-msgstr ""
+msgstr "(%02d) Entrée:%.*s;"
 
-#: grecs/src/wordsplit.c:2202
-#, c-format
-msgid "(%02d) Restart:%.*s;"
-msgstr ""
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
+msgstr "Liste initiale:"
+
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr "Liste combinée:"
 
-#: grecs/src/wordsplit.c:2298
+#: grecs/wordsplit/wordsplit.c:2853
 msgid "no error"
 msgstr "pas d'erreur"
 
-#: grecs/src/wordsplit.c:2299
+#: grecs/wordsplit/wordsplit.c:2854
 msgid "missing closing quote"
 msgstr "parenthèse fermante manquante"
 
-#: grecs/src/wordsplit.c:2301
+#: grecs/wordsplit/wordsplit.c:2856
 msgid "invalid wordsplit usage"
 msgstr "utilisation de « wordsplit » invalide"
 
-#: grecs/src/wordsplit.c:2302
+#: grecs/wordsplit/wordsplit.c:2857
 msgid "unbalanced curly brace"
 msgstr "accolades non appariées"
 
-#: grecs/src/wordsplit.c:2303
+#: grecs/wordsplit/wordsplit.c:2858
 msgid "undefined variable"
 msgstr "variable non définie"
 
-#: grecs/src/wordsplit.c:2304
+#: grecs/wordsplit/wordsplit.c:2859
 msgid "input exhausted"
 msgstr "entrée épuisée"
 
-#: grecs/src/wordsplit.c:2305
+#: grecs/wordsplit/wordsplit.c:2860
 msgid "unbalanced parenthesis"
-msgstr ""
+msgstr "parenthèses non appariées"
 
-#: grecs/src/wordsplit.c:2306
-#, fuzzy
+#: grecs/wordsplit/wordsplit.c:2861
 msgid "globbing error"
-msgstr "pas d'erreur"
+msgstr "erreur d'expansion des jokers"
+
+#: grecs/wordsplit/wordsplit.c:2862
+#, fuzzy
+msgid "user-defined error"
+msgstr "erreur de lecture"
 
-#: grecs/src/wordsplit.c:2318
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2875
 msgid "unknown error"
 msgstr "erreur inconnue"
 
-#: grecs/src/wordsplit.c:2327
+#: grecs/wordsplit/wordsplit.c:2884
 #, c-format
 msgid "missing closing %c (start near #%lu)"
 msgstr "la fermeture de %c manque (début près de #%lu)"
 
+#~ msgid "unterminated regexp"
+#~ msgstr "expression régulière non terminée"
+
+#~ msgid "unrecognized flag: %c"
+#~ msgstr "fanion non reconnu: %c"
+
+#~ msgid "out of memory"
+#~ msgstr "à cours de mémoire"
+
+#~ msgid "%s: unknown keyword"
+#~ msgstr "%s: mot clé inconnu"
+
+#~ msgid "(%02d) Restart:%.*s;"
+#~ msgstr "(%02d) Redémarrage:%.*s;"
+
 #~ msgid "INTERNAL ERROR at %s:%d"
 #~ msgstr "ERREUR INTERNE à %s:%d"
 
diff --git a/po/hu.gmo b/po/hu.gmo
index 5b9c848..04d9ac5 100644
Binary files a/po/hu.gmo and b/po/hu.gmo differ
diff --git a/po/hu.po b/po/hu.po
index cfb487e..69817a5 100644
--- a/po/hu.po
+++ b/po/hu.po
@@ -1,20 +1,21 @@
 # Hungarian translation for direvent.
-# Copyright (C) 2014 Free Software Foundation, Inc.
+# Copyright (C) 2014, 2015, 2017 Free Software Foundation, Inc.
 # This file is distributed under the same license as the direvent package.
 #
-# Balázs Úr <urbalazs@gmail.com>, 2014, 2015.
+# Balázs Úr <urbalazs@gmail.com>, 2014, 2015, 2017.
 msgid ""
 msgstr ""
-"Project-Id-Version: direvent 4.1.91\n"
+"Project-Id-Version: direvent 5.1\n"
 "Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
-"POT-Creation-Date: 2016-07-06 17:50+0300\n"
-"PO-Revision-Date: 2015-06-14 11:15+0200\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
+"PO-Revision-Date: 2017-04-27 22:18+0200\n"
 "Last-Translator: Balázs Úr <urbalazs@gmail.com>\n"
 "Language-Team: Hungarian <translation-team-hu@lists.sourceforge.net>\n"
 "Language: hu\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Generator: Lokalize 1.2\n"
 
@@ -48,11 +49,11 @@ msgstr "maradjon előtérben"
 
 #: cmdline.opt:53
 msgid "DIR"
-msgstr ""
+msgstr "KÖNYVTÁR"
 
 #: cmdline.opt:53
 msgid "add include directory"
-msgstr ""
+msgstr "felvételi könyvtár hozzáadása"
 
 #: cmdline.opt:59
 msgid "PROG"
@@ -134,12 +135,12 @@ msgstr ""
 #: cmdline.opt:102
 #, c-format
 msgid "Include search path:\n"
-msgstr ""
+msgstr "Felvételi keresési útvonal:\n"
 
 #: cmdline.opt:105
 #, c-format
 msgid "No include search path.\n"
-msgstr ""
+msgstr "Nincs felvételi keresési útvonal.\n"
 
 #: src/config.c:63
 #, c-format
@@ -170,7 +171,7 @@ msgstr "várt érték: %s, de %s található"
 msgid "unknown syslog facility `%s'"
 msgstr "ismeretlen syslog képesség: „%s”"
 
-#: src/config.c:133 src/config.c:706
+#: src/config.c:133 src/config.c:606
 msgid "name"
 msgstr "név"
 
@@ -184,7 +185,7 @@ msgstr ""
 "daemon, auth, authpriv, mail, cron, local0 és local7 között (kis- és "
 "nagybetű érzéketlen) vagy egy képesség szám."
 
-#: src/config.c:139
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
 msgid "string"
 msgstr "szöveg"
 
@@ -200,142 +201,132 @@ msgstr "arg"
 msgid "Prefix each message with its priority"
 msgstr "Minden üzenet elé előtag tétele a prioritásával"
 
-#: src/config.c:209
+#: src/config.c:191
 #, c-format
 msgid "%s: recursion depth does not match previous definition"
 msgstr "%s: a rekurziómélység nem egyezik a korábbi meghatározással"
 
-#: src/config.c:247
+#: src/config.c:212
 msgid "no paths configured"
 msgstr "nincsenek útvonalak beállítva"
 
-#: src/config.c:252
+#: src/config.c:217
 msgid "no command configured"
 msgstr "nincs parancs beállítva"
 
-#: src/config.c:264 grecs/src/tree.c:634
+#: src/config.c:229 grecs/src/tree.c:665
 msgid "invalid use of block statement"
 msgstr "érvénytelen blokk utasítás használata"
 
-#: src/config.c:309
+#: src/config.c:274
 msgid "expected \"recursive\" or end of statement"
 msgstr "várt érték: „recursive” vagy utasítás vége"
 
-#: src/config.c:324
+#: src/config.c:289
 msgid "surplus argument"
 msgstr "többlet argumentum"
 
-#: src/config.c:330 src/config.c:481
+#: src/config.c:295 src/config.c:446
 msgid "unexpected list"
 msgstr "nem várt lista"
 
-#: src/config.c:361 src/config.c:376 src/config.c:391
+#: src/config.c:326 src/config.c:341 src/config.c:356
 msgid "unrecognized event code"
 msgstr "azonosítatlan eseménykód"
 
-#: src/config.c:473
+#: src/config.c:438
 msgid "surplus arguments"
 msgstr "többlet argumentumok"
 
-#: src/config.c:487
+#: src/config.c:452
 msgid "no such user"
 msgstr "nincs ilyen felhasználó"
 
-#: src/config.c:494
+#: src/config.c:459
 msgid "no such group"
 msgstr "nincs ilyen csoport"
 
-#: src/config.c:535
-#, fuzzy
+#: src/config.c:501
 msgid "unrecognized option"
-msgstr "azonosítatlan jelző"
-
-#: src/config.c:613
-msgid "unterminated regexp"
-msgstr "befejezetlen reguláris kifejezés"
-
-#: src/config.c:627
-#, c-format
-msgid "unrecognized flag: %c"
-msgstr "azonosítatlan jelző: %c"
+msgstr "azonosítatlan kapcsoló"
 
-#: src/config.c:695
+#: src/config.c:595
 msgid "Pathname to watch"
 msgstr "Figyelendő útvonalnév"
 
-#: src/config.c:698
+#: src/config.c:598
 msgid "Events to watch for"
 msgstr "Figyelendő események"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "regexp"
 msgstr "reguláris kifejezés"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "Files to watch for"
 msgstr "Figyelendő fájlok"
 
-#: src/config.c:704
+#: src/config.c:604
 msgid "Command to execute on event"
 msgstr "Az eseménykor végrehajtandó parancs"
 
-#: src/config.c:706
+#: src/config.c:606
 msgid "Run command as this user"
 msgstr "Parancs futtatása ezen felhasználóként"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "seconds"
 msgstr "másodperc"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "Timeout for the command"
 msgstr "A parancs időkorlátja"
 
-#: src/config.c:711
+#: src/config.c:611
 msgid "List of additional options"
 msgstr "További beállítások listája"
 
-#: src/config.c:714
+#: src/config.c:614
 msgid "<arg: string> <arg: string>..."
 msgstr "<arg: szöveg> <arg: szöveg>…"
 
-#: src/config.c:715
+#: src/config.c:615
 msgid "Modify environment"
 msgstr "Környezet módosítása"
 
-#: src/config.c:722
+#: src/config.c:622
 msgid "Run as this user"
 msgstr "Futtatás ezen felhasználóként"
 
-#: src/config.c:724
+#: src/config.c:624
 msgid "Run in foreground"
 msgstr "Futtatás az előtérben"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "file"
 msgstr "fájl"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "Set pid file name"
 msgstr "PID fájlnév beállítása"
 
-#: src/config.c:728
+#: src/config.c:628
 msgid "Configure syslog logging"
 msgstr "Syslog naplózás beállítása"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "level"
 msgstr "szint"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "Set debug level"
 msgstr "Hibakeresési szint beállítása"
 
-#: src/config.c:732
+#: src/config.c:632
 msgid "Configure event watcher"
 msgstr "Eseményfigyelő beállítása"
 
-#: src/config.c:743
+#: src/config.c:643
 msgid ""
 "Configuration file structure for direvent.\n"
 "For more information, use `info direvent configuration'."
@@ -343,36 +334,35 @@ msgstr ""
 "A direvent beállítófájl szerkezete.\n"
 "További információkért használja az „info direvent configuration” parancsot."
 
-#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:86 src/watcher.c:182
-#: src/watcher.c:191
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
 msgid "not enough memory"
 msgstr "nincs elég memória"
 
-#: src/direvent.c:272
+#: src/direvent.c:274
 #, c-format
 msgid "cannot open pidfile %s for writing: %s"
 msgstr "nem lehet megnyitni a(z) %s pid fájlt írásra: %s"
 
-#: src/direvent.c:300
+#: src/direvent.c:302
 #, c-format
 msgid "no user with UID %lu"
 msgstr "nincs %lu UID-val rendelkező felhasználó"
 
-#: src/direvent.c:418
+#: src/direvent.c:420
 #, c-format
 msgid "cannot run `%s': fork failed: %s"
 msgstr "nem lehet futtatni: „%s”: elágazás sikertelen: %s"
 
-#: src/direvent.c:478
+#: src/direvent.c:480
 msgid "too many arguments"
 msgstr "túl sok argumentum"
 
-#: src/direvent.c:520
+#: src/direvent.c:522
 #, c-format
 msgid "%s %s started"
 msgstr "%s %s elindítva"
 
-#: src/direvent.c:541
+#: src/direvent.c:546
 #, c-format
 msgid "%s %s stopped"
 msgstr "%s %s leállítva"
@@ -381,18 +371,6 @@ msgstr "%s %s leállítva"
 msgid "environment: "
 msgstr "környezet: "
 
-#: src/hashtab.c:140 grecs/src/symtab.c:206
-msgid "element not found in table"
-msgstr "az elem nem található a táblában"
-
-#: src/hashtab.c:142 grecs/src/symtab.c:208
-msgid "symbol table is full"
-msgstr "a szimbólumtábla tele van"
-
-#: src/hashtab.c:144
-msgid "out of memory"
-msgstr "nincs elég memória"
-
 #: src/progman.c:142
 #, c-format
 msgid "process %lu exited successfully"
@@ -453,73 +431,123 @@ msgstr "nem lehet a(z) „%s” átirányítót futtatni: elágazás sikertelen:
 msgid "redirector for %s started, pid=%lu"
 msgstr "a(z) %s átirányítója elindult, pid=%lu"
 
-#: src/progman.c:454
+#: src/progman.c:455
 #, c-format
 msgid "starting %s, dir=%s, file=%s"
 msgstr "%s indítása, kvt=%s, fájl=%s"
 
-#: src/progman.c:482
+#: src/progman.c:484
 #, c-format
 msgid "cannot change to %s: %s"
 msgstr "nem lehet erre változtatni: %s: %s"
 
-#: src/progman.c:510
+#: src/progman.c:512
 #, c-format
 msgid "%s running; dir=%s, file=%s, pid=%lu"
 msgstr "%s fut; kvt=%s, fájl=%s, pid=%lu"
 
-#: src/progman.c:532
+#: src/progman.c:534
 #, c-format
 msgid "waiting for %s (%lu) to terminate"
 msgstr "várakozás %s (%lu) befejezésére"
 
-#: src/watcher.c:231
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr "figyelő eltávolítása: %s"
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
 #, c-format
 msgid "creating watcher %s"
 msgstr "figyelő létrehozása: %s"
 
-#: src/watcher.c:240
+#: src/watcher.c:281 src/watcher.c:296
 #, c-format
 msgid "cannot set watcher on %s: %s"
 msgstr "nem lehet figyelőt beállítani ezen: %s: %s"
 
-#: src/watcher.c:319
+#: src/watcher.c:377
 #, c-format
 msgid "cannot create watcher %s/%s: not enough memory"
 msgstr "nem lehet létrehozni a figyelőt: %s/%s: nincs elég memória"
 
-#: src/watcher.c:326
+#: src/watcher.c:384
 #, c-format
 msgid "cannot create watcher %s/%s, stat failed: %s"
 msgstr "nem lehet létrehozni a figyelőt: %s/%s, elérés sikertelen: %s"
 
-#: src/watcher.c:355
+#: src/watcher.c:430
 #, c-format
 msgid "cannot open directory %s: %s"
 msgstr "nem lehet megnyitni a(z) %s könyvtárat: %s"
 
-#: src/watcher.c:371
+#: src/watcher.c:447
 #, c-format
 msgid "cannot stat %s/%s: not enough memory"
 msgstr "nem lehet elérni: %s/%s: nincs elég memória"
 
-#: src/watcher.c:376
+#: src/watcher.c:452
 #, c-format
 msgid "cannot stat %s: %s"
 msgstr "nem lehet elérni: %s: %s"
 
-#: src/watcher.c:412
+#: src/watcher.c:497
 msgid "no event handlers configured"
 msgstr "nincsenek eseménykezelők beállítva"
 
-#: src/watcher.c:417
+#: src/watcher.c:502
 msgid "no event handlers installed"
 msgstr "nincsenek eseménykezelők telepítve"
 
-#: src/watcher.c:425
-#, c-format
-msgid "removing watcher %s"
-msgstr "figyelő eltávolítása: %s"
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+#, fuzzy
+msgid "hostname"
+msgstr "név"
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
+msgstr ""
 
 #: grecs/src/format.c:133
 msgid "Disabled;"
@@ -653,9 +681,8 @@ msgid "invalid include statement"
 msgstr "érvénytelen felvételi utasítás"
 
 #: grecs/src/preproc.c:624
-#, fuzzy
 msgid "read error"
-msgstr "feldolgozási hiba"
+msgstr "olvasási hiba"
 
 #: grecs/src/preproc.c:632
 #, c-format
@@ -672,188 +699,232 @@ msgstr "Nem sikerült elindítani a külső előfeldolgozót: „%s”"
 msgid "Cannot run `%s'"
 msgstr "Nem lehet futtatni: „%s”"
 
-#: grecs/src/tree.c:329
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr "az elem nem található a táblában"
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr "a szimbólumtábla tele van"
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+#, fuzzy
+msgid "one or more arguments"
+msgstr "túl sok argumentum"
+
+#: grecs/src/tree.c:75
+#, fuzzy
+msgid "unrecognized type; please report"
+msgstr "azonosítatlan eseménykód"
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+#, fuzzy
+msgid "unknown keyword"
+msgstr "Ismeretlen kulcsszó"
+
+#: grecs/src/tree.c:360
 #, c-format
 msgid "%s: not a valid boolean value"
 msgstr "%s: nem érvényes logikai érték"
 
-#: grecs/src/tree.c:360
+#: grecs/src/tree.c:391
 #, c-format
 msgid "%s: UNIX socket name too long"
 msgstr "%s: a UNIX foglalat neve túl hosszú"
 
-#: grecs/src/tree.c:389 grecs/src/tree.c:613
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
 #, c-format
 msgid "%s: not a valid IP address or hostname"
 msgstr "%s: nem érvényes IP-cím vagy gépnév"
 
-#: grecs/src/tree.c:413
+#: grecs/src/tree.c:444
 #, c-format
 msgid "%s: not a valid port number"
 msgstr "%s: nem érvényes portszám"
 
-#: grecs/src/tree.c:421
+#: grecs/src/tree.c:452
 msgid "missing port number"
 msgstr "hiányzó portszám"
 
-#: grecs/src/tree.c:470
+#: grecs/src/tree.c:501
 msgid "numeric overflow"
 msgstr "számszerű túlcsordulás"
 
-#: grecs/src/tree.c:475
+#: grecs/src/tree.c:506
 msgid "value out of allowed range"
 msgstr "az érték a megengedett tartományon kívüli"
 
-#: grecs/src/tree.c:510 grecs/src/tree.c:540
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
 #, c-format
 msgid "not a number (stopped near `%s')"
 msgstr "nem szám (leállítva „%s” környékén)"
 
-#: grecs/src/tree.c:604
+#: grecs/src/tree.c:635
 #, c-format
 msgid "%s: not a valid IP address"
 msgstr "%s: nem érvényes IP-cím"
 
-#: grecs/src/tree.c:743
+#: grecs/src/tree.c:774
 #, c-format
 msgid "too many arguments to `%s'; missing semicolon?"
 msgstr "túl sok argumentum ehhez: „%s”; hiányzó pontosvessző?"
 
-#: grecs/src/tree.c:757 grecs/src/tree.c:805
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
 #, c-format
 msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
 msgstr "BELSŐ HIBA itt: %s:%d: kezeletlen %d adattípus"
 
-#: grecs/src/tree.c:772
+#: grecs/src/tree.c:803
 #, c-format
 msgid "%s: incompatible data type in list item #%d"
 msgstr "%s: összeférhetetlen adattípus a(z) #%d. listaelemben"
 
-#: grecs/src/tree.c:792
+#: grecs/src/tree.c:823
 #, c-format
 msgid "incompatible data type for `%s'"
 msgstr "összeférhetetlen adattípus ennél: „%s”"
 
-#: grecs/src/tree.c:920 grecs/src/tree.c:930
-msgid "Unknown keyword"
-msgstr "Ismeretlen kulcsszó"
-
-#: grecs/src/tree.c:1139
-#, c-format
-msgid "%s: unknown keyword"
-msgstr "%s: ismeretlen kulcsszó"
-
-#: grecs/src/wordsplit.c:62 grecs/src/wordsplit.c:2300
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
 msgid "memory exhausted"
 msgstr "elfogyott a memória"
 
-#: grecs/src/wordsplit.c:1073
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:1607
 #, c-format
 msgid "%.*s: variable null or not set"
-msgstr ""
+msgstr "%.*s: a változó üres vagy nincs beállítva"
 
-#: grecs/src/wordsplit.c:1102
+#: grecs/wordsplit/wordsplit.c:1637
 #, c-format
 msgid "warning: undefined variable `%.*s'"
 msgstr "figyelmeztetés: nem meghatározott változó: „%.*s”"
 
-#: grecs/src/wordsplit.c:1630
+#: grecs/wordsplit/wordsplit.c:2141
 #, c-format
 msgid "no files match pattern %s"
-msgstr ""
+msgstr "nem illeszkednek fájlok erre a mintára: %s"
 
-#: grecs/src/wordsplit.c:2080
+#: grecs/wordsplit/wordsplit.c:2603
 msgid "WS trimming"
-msgstr ""
+msgstr "WS levágása"
 
-#: grecs/src/wordsplit.c:2081
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
+msgstr "parancshelyettesítés"
+
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
+msgstr "lista egyesítése"
+
+#: grecs/wordsplit/wordsplit.c:2609
 msgid "tilde expansion"
-msgstr ""
+msgstr "hullámjel-kiterjesztés"
 
-#: grecs/src/wordsplit.c:2082
+#: grecs/wordsplit/wordsplit.c:2611
 msgid "variable expansion"
-msgstr ""
+msgstr "változó-kiterjesztés"
 
-#: grecs/src/wordsplit.c:2084
+#: grecs/wordsplit/wordsplit.c:2613
 msgid "quote removal"
-msgstr ""
+msgstr "idézés-eltávolítás"
 
-#: grecs/src/wordsplit.c:2086
-#, fuzzy
-msgid "command substitution"
-msgstr "a parancshelyettesítés még nem támogatott"
-
-#: grecs/src/wordsplit.c:2088
-msgid "coalesce list"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2090
+#: grecs/wordsplit/wordsplit.c:2617
 msgid "path expansion"
-msgstr ""
+msgstr "útvonal-kiterjesztés"
 
-#: grecs/src/wordsplit.c:2120
-msgid "Initial list:"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2136
-#, fuzzy
-msgid "Coalesced list:"
-msgstr "nem várt lista"
-
-#: grecs/src/wordsplit.c:2190
+#: grecs/wordsplit/wordsplit.c:2642
 #, c-format
 msgid "(%02d) Input:%.*s;"
-msgstr ""
+msgstr "(%02d) Bemenet:%.*s;"
 
-#: grecs/src/wordsplit.c:2202
-#, c-format
-msgid "(%02d) Restart:%.*s;"
-msgstr ""
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
+msgstr "Kezdeti lista:"
+
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr "Egyesített lista:"
 
-#: grecs/src/wordsplit.c:2298
+#: grecs/wordsplit/wordsplit.c:2853
 msgid "no error"
 msgstr "nincs hiba"
 
-#: grecs/src/wordsplit.c:2299
+#: grecs/wordsplit/wordsplit.c:2854
 msgid "missing closing quote"
 msgstr "hiányzó lezáró idézőjel"
 
-#: grecs/src/wordsplit.c:2301
+#: grecs/wordsplit/wordsplit.c:2856
 msgid "invalid wordsplit usage"
 msgstr "érvénytelen szófelosztás használat"
 
-#: grecs/src/wordsplit.c:2302
+#: grecs/wordsplit/wordsplit.c:2857
 msgid "unbalanced curly brace"
 msgstr "a kapcsos zárójelek száma nem egyezik"
 
-#: grecs/src/wordsplit.c:2303
+#: grecs/wordsplit/wordsplit.c:2858
 msgid "undefined variable"
 msgstr "nem meghatározott változó"
 
-#: grecs/src/wordsplit.c:2304
+#: grecs/wordsplit/wordsplit.c:2859
 msgid "input exhausted"
 msgstr "elfogyott a bemenet"
 
-#: grecs/src/wordsplit.c:2305
+#: grecs/wordsplit/wordsplit.c:2860
 msgid "unbalanced parenthesis"
-msgstr ""
+msgstr "zárójelek nincsenek egyensúlyban"
 
-#: grecs/src/wordsplit.c:2306
-#, fuzzy
+#: grecs/wordsplit/wordsplit.c:2861
 msgid "globbing error"
-msgstr "nincs hiba"
+msgstr "csillogás hiba"
 
-#: grecs/src/wordsplit.c:2318
+#: grecs/wordsplit/wordsplit.c:2862
+#, fuzzy
+msgid "user-defined error"
+msgstr "olvasási hiba"
+
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2875
 msgid "unknown error"
 msgstr "ismeretlen hiba"
 
-#: grecs/src/wordsplit.c:2327
+#: grecs/wordsplit/wordsplit.c:2884
 #, c-format
 msgid "missing closing %c (start near #%lu)"
 msgstr "hiányzó lezáró %c (#%lu környékén kezdve)"
 
-#~ msgid "INTERNAL ERROR at %s:%d"
-#~ msgstr "BELSŐ HIBA itt: %s:%d"
+#~ msgid "unterminated regexp"
+#~ msgstr "befejezetlen reguláris kifejezés"
+
+#~ msgid "unrecognized flag: %c"
+#~ msgstr "azonosítatlan jelző: %c"
+
+#~ msgid "out of memory"
+#~ msgstr "nincs elég memória"
+
+#~ msgid "%s: unknown keyword"
+#~ msgstr "%s: ismeretlen kulcsszó"
 
-#~ msgid "ignoring duplicate definition"
-#~ msgstr "kettőzött meghatározás mellőzése"
+#~ msgid "(%02d) Restart:%.*s;"
+#~ msgstr "(%02d) Újraindítás:%.*s;"
diff --git a/po/nl.gmo b/po/nl.gmo
index 8d2903a..a911307 100644
Binary files a/po/nl.gmo and b/po/nl.gmo differ
diff --git a/po/nl.po b/po/nl.po
index c3240d2..c5f3539 100644
--- a/po/nl.po
+++ b/po/nl.po
@@ -1,22 +1,23 @@
 # Dutch translations for GNU direvent.
-# Copyright (C) 2014 Free Software Foundation, Inc.
+# Copyright (C) 2016 Free Software Foundation, Inc.
 # This file is distributed under the same license as the direvent package.
 #
 # "Alsof kleine kaboutertjes zachtjes in je ballen knijpen."
 #
-# Benno Schulenberg <benno@vertaalt.nl>, 2014.
+# Benno Schulenberg <benno@vertaalt.nl>, 2014, 2016.
 msgid ""
 msgstr ""
-"Project-Id-Version: direvent-4.1.91\n"
+"Project-Id-Version: direvent-5.1\n"
 "Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
-"POT-Creation-Date: 2016-07-06 17:50+0300\n"
-"PO-Revision-Date: 2014-09-03 20:21+0200\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
+"PO-Revision-Date: 2016-08-07 19:57+0200\n"
 "Last-Translator: Benno Schulenberg <benno@vertaalt.nl>\n"
 "Language-Team: Dutch <vertaling@vrijschrift.org>\n"
 "Language: nl\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
 "X-Generator: Lokalize 1.0\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
@@ -50,11 +51,11 @@ msgstr "in de voorgrond blijven"
 
 #: cmdline.opt:53
 msgid "DIR"
-msgstr ""
+msgstr "MAP"
 
 #: cmdline.opt:53
 msgid "add include directory"
-msgstr ""
+msgstr "een include-map toevoegen"
 
 #: cmdline.opt:59
 msgid "PROG"
@@ -136,12 +137,12 @@ msgstr ""
 #: cmdline.opt:102
 #, c-format
 msgid "Include search path:\n"
-msgstr ""
+msgstr "Zoekpad voor includes:\n"
 
 #: cmdline.opt:105
 #, c-format
 msgid "No include search path.\n"
-msgstr ""
+msgstr "Geen include-zoekpad.\n"
 
 #: src/config.c:63
 #, c-format
@@ -172,7 +173,7 @@ msgstr "verwachtte %s, maar vond %s"
 msgid "unknown syslog facility `%s'"
 msgstr "onbekende syslog-faciliteit: '%s'"
 
-#: src/config.c:133 src/config.c:706
+#: src/config.c:133 src/config.c:606
 msgid "name"
 msgstr "NAAM"
 
@@ -186,7 +187,7 @@ msgstr ""
 "'auth', 'authpriv', 'mail', 'cron', 'local0'..'local7' (hoofdlettegevoelig), "
 "of een faciliteitnummer."
 
-#: src/config.c:139
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
 msgid "string"
 msgstr "TEKENREEKS"
 
@@ -202,142 +203,132 @@ msgstr "ARGUMENT"
 msgid "Prefix each message with its priority"
 msgstr "aan elk bericht de prioriteit voorvoegen"
 
-#: src/config.c:209
+#: src/config.c:191
 #, c-format
 msgid "%s: recursion depth does not match previous definition"
 msgstr "%s: recursiediepte komt niet overeen met vorige definitie"
 
-#: src/config.c:247
+#: src/config.c:212
 msgid "no paths configured"
 msgstr "geen paden geconfigureerd"
 
-#: src/config.c:252
+#: src/config.c:217
 msgid "no command configured"
 msgstr "geen commando geconfigureerd"
 
-#: src/config.c:264 grecs/src/tree.c:634
+#: src/config.c:229 grecs/src/tree.c:665
 msgid "invalid use of block statement"
 msgstr "ongeldig gebruik van blok-statement"
 
-#: src/config.c:309
+#: src/config.c:274
 msgid "expected \"recursive\" or end of statement"
 msgstr "verwachtte \"recursive\" of einde van statement"
 
-#: src/config.c:324
+#: src/config.c:289
 msgid "surplus argument"
 msgstr "overtollig argument"
 
-#: src/config.c:330 src/config.c:481
+#: src/config.c:295 src/config.c:446
 msgid "unexpected list"
 msgstr "onverwachte lijst"
 
-#: src/config.c:361 src/config.c:376 src/config.c:391
+#: src/config.c:326 src/config.c:341 src/config.c:356
 msgid "unrecognized event code"
 msgstr "niet-herkende gebeurteniscode"
 
-#: src/config.c:473
+#: src/config.c:438
 msgid "surplus arguments"
 msgstr "overtollige argumenten"
 
-#: src/config.c:487
+#: src/config.c:452
 msgid "no such user"
 msgstr "die gebruiker bestaat niet"
 
-#: src/config.c:494
+#: src/config.c:459
 msgid "no such group"
 msgstr "die groep bestaat niet"
 
-#: src/config.c:535
-#, fuzzy
+#: src/config.c:501
 msgid "unrecognized option"
-msgstr "niet-herkende vlag"
-
-#: src/config.c:613
-msgid "unterminated regexp"
-msgstr "onafgesloten reguliere expressie"
-
-#: src/config.c:627
-#, c-format
-msgid "unrecognized flag: %c"
-msgstr "niet-herkende vlag: %c"
+msgstr "onbekende optie"
 
-#: src/config.c:695
+#: src/config.c:595
 msgid "Pathname to watch"
 msgstr "te monitoren padnaam"
 
-#: src/config.c:698
+#: src/config.c:598
 msgid "Events to watch for"
 msgstr "te monitoren gebeurtenissen"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "regexp"
 msgstr "reg.exp."
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "Files to watch for"
 msgstr "te monitoren bestanden"
 
-#: src/config.c:704
+#: src/config.c:604
 msgid "Command to execute on event"
 msgstr "uit te voeren opdracht bij gebeurtenis"
 
-#: src/config.c:706
+#: src/config.c:606
 msgid "Run command as this user"
 msgstr "opdracht uitvoeren als deze gebruiker"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "seconds"
 msgstr "SECONDEN"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "Timeout for the command"
 msgstr "tijdslimiet voor de opdracht"
 
-#: src/config.c:711
+#: src/config.c:611
 msgid "List of additional options"
 msgstr "lijst van additionele opties"
 
-#: src/config.c:714
+#: src/config.c:614
 msgid "<arg: string> <arg: string>..."
 msgstr "<arg: tekenreeks> <arg: tekenreeks>..."
 
-#: src/config.c:715
+#: src/config.c:615
 msgid "Modify environment"
 msgstr "de omgeving aanpassen"
 
-#: src/config.c:722
+#: src/config.c:622
 msgid "Run as this user"
 msgstr "uitvoeren als deze gebruiker"
 
-#: src/config.c:724
+#: src/config.c:624
 msgid "Run in foreground"
 msgstr "in de voorgrond draaien"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "file"
 msgstr "BESTAND"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "Set pid file name"
-msgstr "te gebruiken pid-bestand"
+msgstr "te gebruiken PID-bestand"
 
-#: src/config.c:728
+#: src/config.c:628
 msgid "Configure syslog logging"
 msgstr "syslog-loggen instellen"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "level"
 msgstr "NIVEAU"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "Set debug level"
 msgstr "debug-niveau instellen"
 
-#: src/config.c:732
+#: src/config.c:632
 msgid "Configure event watcher"
 msgstr "gebeurtenismonitor instellen"
 
-#: src/config.c:743
+#: src/config.c:643
 msgid ""
 "Configuration file structure for direvent.\n"
 "For more information, use `info direvent configuration'."
@@ -345,36 +336,35 @@ msgstr ""
 "Structuur van het configuratiebestand voor 'direvent'.\n"
 "Zie 'info direvent configuration' voor meer informatie."
 
-#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:86 src/watcher.c:182
-#: src/watcher.c:191
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
 msgid "not enough memory"
 msgstr "onvoldoende geheugen beschikbaar"
 
-#: src/direvent.c:272
+#: src/direvent.c:274
 #, c-format
 msgid "cannot open pidfile %s for writing: %s"
 msgstr "kan PID-bestand %s niet openen om te schrijven: %s"
 
-#: src/direvent.c:300
+#: src/direvent.c:302
 #, c-format
 msgid "no user with UID %lu"
 msgstr "er is geen gebruiker met UID %lu"
 
-#: src/direvent.c:418
+#: src/direvent.c:420
 #, c-format
 msgid "cannot run `%s': fork failed: %s"
 msgstr "kan '%s' niet uitvoeren: fork() is mislukt: %s"
 
-#: src/direvent.c:478
+#: src/direvent.c:480
 msgid "too many arguments"
 msgstr "te veel argumenten"
 
-#: src/direvent.c:520
+#: src/direvent.c:522
 #, c-format
 msgid "%s %s started"
 msgstr "%s %s is gestart"
 
-#: src/direvent.c:541
+#: src/direvent.c:546
 #, c-format
 msgid "%s %s stopped"
 msgstr "%s %s is gestopt"
@@ -383,18 +373,6 @@ msgstr "%s %s is gestopt"
 msgid "environment: "
 msgstr "omgeving: "
 
-#: src/hashtab.c:140 grecs/src/symtab.c:206
-msgid "element not found in table"
-msgstr "element niet gevonden in tabel"
-
-#: src/hashtab.c:142 grecs/src/symtab.c:208
-msgid "symbol table is full"
-msgstr "symbolentabel is vol"
-
-#: src/hashtab.c:144
-msgid "out of memory"
-msgstr "onvoldoende geheugen beschikbaar"
-
 #: src/progman.c:142
 #, c-format
 msgid "process %lu exited successfully"
@@ -454,74 +432,124 @@ msgstr "kan omleider '%s' niet draaien, fork() is mislukt: %s"
 msgid "redirector for %s started, pid=%lu"
 msgstr "omleider voor %s is gestart, PID=%lu"
 
-#: src/progman.c:454
+#: src/progman.c:455
 #, c-format
 msgid "starting %s, dir=%s, file=%s"
 msgstr "starten van %s, map=%s, bestand=%s"
 
-#: src/progman.c:482
+#: src/progman.c:484
 #, c-format
 msgid "cannot change to %s: %s"
 msgstr "kan map niet wijzigen naar %s: %s"
 
-#: src/progman.c:510
+#: src/progman.c:512
 #, c-format
 msgid "%s running; dir=%s, file=%s, pid=%lu"
 msgstr "%s draait; map=%s, bestand=%s, PID=%lu"
 
-#: src/progman.c:532
+#: src/progman.c:534
 #, c-format
 msgid "waiting for %s (%lu) to terminate"
 msgstr "wachtend op afsluiten van %s (%lu)"
 
-#: src/watcher.c:231
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr "verwijderen van monitor %s"
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
 #, c-format
 msgid "creating watcher %s"
 msgstr "aanmaken van monitor %s"
 
-#: src/watcher.c:240
+#: src/watcher.c:281 src/watcher.c:296
 #, c-format
 msgid "cannot set watcher on %s: %s"
 msgstr "kan geen monitor zetten op %s: %s"
 
-#: src/watcher.c:319
+#: src/watcher.c:377
 #, c-format
 msgid "cannot create watcher %s/%s: not enough memory"
 msgstr "kan monitor %s/%s niet aanmaken: onvoldoende geheugen beschikbaar"
 
-#: src/watcher.c:326
+#: src/watcher.c:384
 #, c-format
 msgid "cannot create watcher %s/%s, stat failed: %s"
 msgstr "kan monitor %s/%s niet aanmaken, stat() is mislukt: %s"
 
-#: src/watcher.c:355
+#: src/watcher.c:430
 #, c-format
 msgid "cannot open directory %s: %s"
 msgstr "kan map %s niet openen: %s"
 
-#: src/watcher.c:371
+#: src/watcher.c:447
 #, c-format
 msgid "cannot stat %s/%s: not enough memory"
 msgstr ""
 "kan de status van %s/%s niet opvragen: onvoldoende geheugen beschikbaar"
 
-#: src/watcher.c:376
+#: src/watcher.c:452
 #, c-format
 msgid "cannot stat %s: %s"
 msgstr "kan de status van %s niet opvragen: %s"
 
-#: src/watcher.c:412
+#: src/watcher.c:497
 msgid "no event handlers configured"
 msgstr "geen gebeurtenis-afhandelaars geconfigureerd"
 
-#: src/watcher.c:417
+#: src/watcher.c:502
 msgid "no event handlers installed"
 msgstr "geen gebeurtenis-afhandelaars geïnstalleerd"
 
-#: src/watcher.c:425
-#, c-format
-msgid "removing watcher %s"
-msgstr "verwijderen van monitor %s"
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+#, fuzzy
+msgid "hostname"
+msgstr "NAAM"
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
+msgstr ""
 
 #: grecs/src/format.c:133
 msgid "Disabled;"
@@ -658,9 +686,8 @@ msgid "invalid include statement"
 msgstr "ongeldig 'include'-statement"
 
 #: grecs/src/preproc.c:624
-#, fuzzy
 msgid "read error"
-msgstr "ontledingsfout"
+msgstr "fout bij lezen"
 
 #: grecs/src/preproc.c:632
 #, c-format
@@ -677,186 +704,236 @@ msgstr "Kan externe preprocessor '%s' niet starten"
 msgid "Cannot run `%s'"
 msgstr "Kan '%s' niet uitvoeren"
 
-#: grecs/src/tree.c:329
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr "element niet gevonden in tabel"
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr "symbolentabel is vol"
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+#, fuzzy
+msgid "one or more arguments"
+msgstr "te veel argumenten"
+
+#: grecs/src/tree.c:75
+#, fuzzy
+msgid "unrecognized type; please report"
+msgstr "niet-herkende gebeurteniscode"
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+#, fuzzy
+msgid "unknown keyword"
+msgstr "Onbekend sleutelwoord"
+
+#: grecs/src/tree.c:360
 #, c-format
 msgid "%s: not a valid boolean value"
 msgstr "%s is geen geldige booleaanse waarde"
 
-#: grecs/src/tree.c:360
+#: grecs/src/tree.c:391
 #, c-format
 msgid "%s: UNIX socket name too long"
 msgstr "%s: UNIX-socketnaam is te lang"
 
-#: grecs/src/tree.c:389 grecs/src/tree.c:613
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
 #, c-format
 msgid "%s: not a valid IP address or hostname"
 msgstr "%s is geen geldig IP-adres of hostnaam"
 
-#: grecs/src/tree.c:413
+#: grecs/src/tree.c:444
 #, c-format
 msgid "%s: not a valid port number"
 msgstr "%s is geen geldig poortnummer"
 
-#: grecs/src/tree.c:421
+#: grecs/src/tree.c:452
 msgid "missing port number"
 msgstr "ontbrekend poortnummer"
 
-#: grecs/src/tree.c:470
+#: grecs/src/tree.c:501
 msgid "numeric overflow"
 msgstr "numerieke overloop"
 
-#: grecs/src/tree.c:475
+#: grecs/src/tree.c:506
 msgid "value out of allowed range"
 msgstr "waarde ligt buiten bereik"
 
-#: grecs/src/tree.c:510 grecs/src/tree.c:540
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
 #, c-format
 msgid "not a number (stopped near `%s')"
 msgstr "is geen getal (gestopt dichtbij '%s')"
 
-#: grecs/src/tree.c:604
+#: grecs/src/tree.c:635
 #, c-format
 msgid "%s: not a valid IP address"
 msgstr "%s is geen geldig IP-adres"
 
-#: grecs/src/tree.c:743
+#: grecs/src/tree.c:774
 #, c-format
 msgid "too many arguments to `%s'; missing semicolon?"
 msgstr "te veel argumenten van '%s'; ontbrekende puntkomma?"
 
-#: grecs/src/tree.c:757 grecs/src/tree.c:805
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
 #, c-format
 msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
 msgstr "**interne programmafout** bij %s:%d: onverwerkt gegevenstype %d"
 
-#: grecs/src/tree.c:772
+#: grecs/src/tree.c:803
 #, c-format
 msgid "%s: incompatible data type in list item #%d"
 msgstr "%s: incompatibel gegevenstype in lijstitem #%d"
 
-#: grecs/src/tree.c:792
+#: grecs/src/tree.c:823
 #, c-format
 msgid "incompatible data type for `%s'"
 msgstr "incompatibel gegevenstype voor '%s'"
 
-#: grecs/src/tree.c:920 grecs/src/tree.c:930
-msgid "Unknown keyword"
-msgstr "Onbekend sleutelwoord"
-
-#: grecs/src/tree.c:1139
-#, c-format
-msgid "%s: unknown keyword"
-msgstr "%s: onbekend sleutelwoord"
-
-#: grecs/src/wordsplit.c:62 grecs/src/wordsplit.c:2300
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
 msgid "memory exhausted"
 msgstr "onvoldoende geheugen beschikbaar"
 
-#: grecs/src/wordsplit.c:1073
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:1607
 #, c-format
 msgid "%.*s: variable null or not set"
-msgstr ""
+msgstr "%.*s: variabele is null of niet ingesteld"
 
-#: grecs/src/wordsplit.c:1102
+#: grecs/wordsplit/wordsplit.c:1637
 #, c-format
 msgid "warning: undefined variable `%.*s'"
 msgstr "waarschuwing: ongedefinieerde variabele '%.*s'"
 
-#: grecs/src/wordsplit.c:1630
+#: grecs/wordsplit/wordsplit.c:2141
 #, c-format
 msgid "no files match pattern %s"
-msgstr ""
+msgstr "geen bestanden die overeenkomen met patroon %s"
 
-#: grecs/src/wordsplit.c:2080
+#: grecs/wordsplit/wordsplit.c:2603
 msgid "WS trimming"
-msgstr ""
+msgstr "witruimte trimmen"
 
-#: grecs/src/wordsplit.c:2081
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
+msgstr "opdrachtsubstitutie"
+
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
+msgstr "lijst samenvoegen"
+
+#: grecs/wordsplit/wordsplit.c:2609
 msgid "tilde expansion"
-msgstr ""
+msgstr "tilde-expansie"
 
-#: grecs/src/wordsplit.c:2082
+#: grecs/wordsplit/wordsplit.c:2611
 msgid "variable expansion"
-msgstr ""
+msgstr "variabelen-expansie"
 
-#: grecs/src/wordsplit.c:2084
+#: grecs/wordsplit/wordsplit.c:2613
 msgid "quote removal"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2086
-#, fuzzy
-msgid "command substitution"
-msgstr "opdrachtsubstitutie wordt nog niet ondersteund"
-
-#: grecs/src/wordsplit.c:2088
-msgid "coalesce list"
-msgstr ""
+msgstr "aanhalingstekenverwijdering"
 
-#: grecs/src/wordsplit.c:2090
+#: grecs/wordsplit/wordsplit.c:2617
 msgid "path expansion"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2120
-msgid "Initial list:"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2136
-#, fuzzy
-msgid "Coalesced list:"
-msgstr "onverwachte lijst"
+msgstr "padexpansie"
 
-#: grecs/src/wordsplit.c:2190
+#: grecs/wordsplit/wordsplit.c:2642
 #, c-format
 msgid "(%02d) Input:%.*s;"
-msgstr ""
+msgstr "(%02d) Invoer:%.*s;"
 
-#: grecs/src/wordsplit.c:2202
-#, c-format
-msgid "(%02d) Restart:%.*s;"
-msgstr ""
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
+msgstr "Beginlijst:"
+
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr "Samengevoegde lijst:"
 
-#: grecs/src/wordsplit.c:2298
+#: grecs/wordsplit/wordsplit.c:2853
 msgid "no error"
 msgstr "geen fout"
 
-#: grecs/src/wordsplit.c:2299
+#: grecs/wordsplit/wordsplit.c:2854
 msgid "missing closing quote"
 msgstr "ontbrekend afsluitend aanhalingsteken"
 
-#: grecs/src/wordsplit.c:2301
+#: grecs/wordsplit/wordsplit.c:2856
 msgid "invalid wordsplit usage"
 msgstr "ongeldig gebruik van woordscheiding"
 
-#: grecs/src/wordsplit.c:2302
+#: grecs/wordsplit/wordsplit.c:2857
 msgid "unbalanced curly brace"
 msgstr "ongepaarde accolade"
 
-#: grecs/src/wordsplit.c:2303
+#: grecs/wordsplit/wordsplit.c:2858
 msgid "undefined variable"
 msgstr "ongedefinieerde variabele"
 
-#: grecs/src/wordsplit.c:2304
+#: grecs/wordsplit/wordsplit.c:2859
 msgid "input exhausted"
 msgstr "de invoer is op"
 
-#: grecs/src/wordsplit.c:2305
+#: grecs/wordsplit/wordsplit.c:2860
 msgid "unbalanced parenthesis"
-msgstr ""
+msgstr "ongepaard haakje"
 
-#: grecs/src/wordsplit.c:2306
-#, fuzzy
+#: grecs/wordsplit/wordsplit.c:2861
 msgid "globbing error"
-msgstr "geen fout"
+msgstr "globbing-fout"
+
+#: grecs/wordsplit/wordsplit.c:2862
+#, fuzzy
+msgid "user-defined error"
+msgstr "fout bij lezen"
 
-#: grecs/src/wordsplit.c:2318
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2875
 msgid "unknown error"
 msgstr "onbekende fout"
 
-#: grecs/src/wordsplit.c:2327
+#: grecs/wordsplit/wordsplit.c:2884
 #, c-format
 msgid "missing closing %c (start near #%lu)"
 msgstr "ontbrekend afsluitend %c (begon ongeveer bij #%lu)"
 
+#~ msgid "unterminated regexp"
+#~ msgstr "onafgesloten reguliere expressie"
+
+#~ msgid "unrecognized flag: %c"
+#~ msgstr "niet-herkende vlag: %c"
+
+#~ msgid "out of memory"
+#~ msgstr "onvoldoende geheugen beschikbaar"
+
+#~ msgid "%s: unknown keyword"
+#~ msgstr "%s: onbekend sleutelwoord"
+
+#~ msgid "(%02d) Restart:%.*s;"
+#~ msgstr "(%02d) Herstart:%.*s;"
+
 #~ msgid "INTERNAL ERROR at %s:%d"
 #~ msgstr "**interne programmafout** bij %s:%d"
 
diff --git a/po/pl.gmo b/po/pl.gmo
index 0cf6681..41a3b35 100644
Binary files a/po/pl.gmo and b/po/pl.gmo differ
diff --git a/po/pl.po b/po/pl.po
index 3e8cb4d..b372758 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -1,21 +1,22 @@
 # Polish translations for GNU Direvent.
 # This file is distributed under the same license as the direvent package.
-# Copyright (C) 2014 Free Software Foundation, Inc.
+# Copyright (C) 2016 Free Software Foundation, Inc.
 #      
-# Sergey Poznyakoff <gray@gnu.org>, 2014.
+# Sergey Poznyakoff <gray@gnu.org>, 2014, 2016.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: direvent 4.1.91\n"
+"Project-Id-Version: direvent 5.1\n"
 "Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
-"POT-Creation-Date: 2016-07-06 17:50+0300\n"
-"PO-Revision-Date: 2014-09-02 12:39+0300\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
+"PO-Revision-Date: 2016-08-08 16:54+0300\n"
 "Last-Translator: Sergey Poznyakoff <gray@gnu.org>\n"
 "Language-Team: Polish <translation-team-pl@lists.sourceforge.net>\n"
 "Language: pl\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
 "|| n%100>=20) ? 1 : 2;\n"
 
@@ -48,11 +49,11 @@ msgstr "działanie na pierwszym planie"
 
 #: cmdline.opt:53
 msgid "DIR"
-msgstr ""
+msgstr "KATALOG"
 
 #: cmdline.opt:53
 msgid "add include directory"
-msgstr ""
+msgstr "dodaje katalog plików nagłówkowych"
 
 #: cmdline.opt:59
 msgid "PROG"
@@ -93,15 +94,15 @@ msgstr "Inne opcje"
 
 #: cmdline.opt:93
 msgid "Give this help list"
-msgstr "Wyświetla ten tekst pomocy"
+msgstr "Wyświetl ten tekst pomocy"
 
 #: cmdline.opt:93
 msgid "Give a short usage message"
-msgstr "Wyświetla krótkie informacje o składni polecenia"
+msgstr "Wyświetl krótkie informacje o składni polecenia"
 
 #: cmdline.opt:93
 msgid "Print program version"
-msgstr "Wyświetla wersję programu"
+msgstr "Wyświetl wersję programu"
 
 #: cmdline.opt:13
 msgid "GNU direvent monitors changes in directories"
@@ -133,12 +134,12 @@ msgstr "Ten direvent używa interfejsu %s.\n"
 #: cmdline.opt:102
 #, c-format
 msgid "Include search path:\n"
-msgstr ""
+msgstr "Ścieżka szukania plików nagłówkowych\n"
 
 #: cmdline.opt:105
 #, c-format
 msgid "No include search path.\n"
-msgstr ""
+msgstr "Brak katalogów plików nagłówkowych\n"
 
 #: src/config.c:63
 #, c-format
@@ -169,7 +170,7 @@ msgstr "oczekiwano %s, ale znaleziono %s"
 msgid "unknown syslog facility `%s'"
 msgstr "nieznane urządzenie syslog `%s'"
 
-#: src/config.c:133 src/config.c:706
+#: src/config.c:133 src/config.c:606
 msgid "name"
 msgstr "nazwa"
 
@@ -179,11 +180,11 @@ msgid ""
 "authpriv, mail, cron, local0 through local7 (case-insensitive), or a "
 "facility number."
 msgstr ""
-"Ustawia urządzenie syslogu. Dozwolone wartości argumentu: user, daemon, "
-"auth, authpriv, mail, cron, local0 do local7 (bez rozróżniania małych i "
-"wielkich liter), lub numer urządzenia."
+"Ustawia urządzenie syslog. Dozwolone wartości argumentu: user, daemon, auth, "
+"authpriv, mail, cron, local0 do local7 (bez rozróżniania małych i wielkich "
+"liter), lub numer urządzenia."
 
-#: src/config.c:139
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
 msgid "string"
 msgstr "łańcuch"
 
@@ -199,143 +200,133 @@ msgstr "arg"
 msgid "Prefix each message with its priority"
 msgstr "Dodaje przedrostek priorytety do komunikatów"
 
-#: src/config.c:209
+#: src/config.c:191
 #, c-format
 msgid "%s: recursion depth does not match previous definition"
 msgstr "%s: głębokość rekurencji nie pasuje do poprzednio zdefiniowanej"
 
 #
-#: src/config.c:247
+#: src/config.c:212
 msgid "no paths configured"
 msgstr "brak skonfigurowanych ścieżek"
 
-#: src/config.c:252
+#: src/config.c:217
 msgid "no command configured"
 msgstr "brak skonfigurowanego polecenia"
 
-#: src/config.c:264 grecs/src/tree.c:634
+#: src/config.c:229 grecs/src/tree.c:665
 msgid "invalid use of block statement"
 msgstr "nieprawidłowe użycie instrukcji blokowej"
 
-#: src/config.c:309
+#: src/config.c:274
 msgid "expected \"recursive\" or end of statement"
 msgstr "oczekiwano \"recursive\" lub końca instrukcji"
 
-#: src/config.c:324
+#: src/config.c:289
 msgid "surplus argument"
 msgstr "za wiele argumentów"
 
-#: src/config.c:330 src/config.c:481
+#: src/config.c:295 src/config.c:446
 msgid "unexpected list"
 msgstr "nieoczekiwana lista"
 
-#: src/config.c:361 src/config.c:376 src/config.c:391
+#: src/config.c:326 src/config.c:341 src/config.c:356
 msgid "unrecognized event code"
 msgstr "nieznany kod wydarzenia"
 
-#: src/config.c:473
+#: src/config.c:438
 msgid "surplus arguments"
 msgstr "dodatkowe argumenty"
 
-#: src/config.c:487
+#: src/config.c:452
 msgid "no such user"
 msgstr "nie ma takiego użytkownika"
 
-#: src/config.c:494
+#: src/config.c:459
 msgid "no such group"
 msgstr "nie ma takiej grupy"
 
-#: src/config.c:535
-#, fuzzy
+#: src/config.c:501
 msgid "unrecognized option"
-msgstr "nieznany znacznik"
+msgstr "nierozpoznana opcja"
 
-#: src/config.c:613
-msgid "unterminated regexp"
-msgstr "niezakończone wyrażenie regularne"
-
-#: src/config.c:627
-#, c-format
-msgid "unrecognized flag: %c"
-msgstr "nierozpoznany znacznik: %c"
-
-#: src/config.c:695
+#: src/config.c:595
 msgid "Pathname to watch"
 msgstr "Ścieżka do obserwacji"
 
-#: src/config.c:698
+#: src/config.c:598
 msgid "Events to watch for"
 msgstr "Wydarzenia do obserwacji"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "regexp"
 msgstr "wyr.reg."
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "Files to watch for"
 msgstr "Pliki do obserwowania"
 
-#: src/config.c:704
+#: src/config.c:604
 msgid "Command to execute on event"
 msgstr "Polecenie do wykonania w razie nastąpienia wydarzenia"
 
-#: src/config.c:706
+#: src/config.c:606
 msgid "Run command as this user"
 msgstr "Wykonywanie poleceń z uprawnieniami podanego użytkownika"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "seconds"
 msgstr "sekundy"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "Timeout for the command"
 msgstr "Czas oczekiwania na zakończenie wykonania polecenia"
 
-#: src/config.c:711
+#: src/config.c:611
 msgid "List of additional options"
 msgstr "Lista dodatkowych opcji"
 
-#: src/config.c:714
+#: src/config.c:614
 msgid "<arg: string> <arg: string>..."
 msgstr "<arg: łańcuch> <arg: łańcuch>..."
 
-#: src/config.c:715
+#: src/config.c:615
 msgid "Modify environment"
 msgstr "Modyfikacja środowiska"
 
-#: src/config.c:722
+#: src/config.c:622
 msgid "Run as this user"
 msgstr "Wykonywanie z uprawnieniami podanego użytkownika"
 
-#: src/config.c:724
+#: src/config.c:624
 msgid "Run in foreground"
 msgstr "Działanie w trybie pierwszoplanowym"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "file"
 msgstr "plik"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "Set pid file name"
 msgstr "Ustawia nazwę pliku PID"
 
-#: src/config.c:728
+#: src/config.c:628
 msgid "Configure syslog logging"
 msgstr "Konfiguracja rejestrowania zdarzeń przez syslog"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "level"
 msgstr "poziom"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "Set debug level"
 msgstr "Ustawienie poziomu diagnostyki"
 
-#: src/config.c:732
+#: src/config.c:632
 msgid "Configure event watcher"
 msgstr "Konfiguracja obserwatora wydarzeń"
 
-#: src/config.c:743
+#: src/config.c:643
 msgid ""
 "Configuration file structure for direvent.\n"
 "For more information, use `info direvent configuration'."
@@ -343,36 +334,35 @@ msgstr ""
 "Struktura pliku konfiguracyjnego programu direvent.\n"
 "Żeby otrzymać więcej informacji uruchom `info direvent configuration'."
 
-#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:86 src/watcher.c:182
-#: src/watcher.c:191
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
 msgid "not enough memory"
 msgstr "brak pamięci"
 
-#: src/direvent.c:272
+#: src/direvent.c:274
 #, c-format
 msgid "cannot open pidfile %s for writing: %s"
 msgstr "nie można otworzyć pliku %s do zapisu: %s"
 
-#: src/direvent.c:300
+#: src/direvent.c:302
 #, c-format
 msgid "no user with UID %lu"
 msgstr "brak użytkownika o UID %lu"
 
-#: src/direvent.c:418
+#: src/direvent.c:420
 #, c-format
 msgid "cannot run `%s': fork failed: %s"
 msgstr "nie udaje się uruchomić `%s': wywołanie fork nie powiodło się: %s"
 
-#: src/direvent.c:478
+#: src/direvent.c:480
 msgid "too many arguments"
 msgstr "za dużo argumentów"
 
-#: src/direvent.c:520
+#: src/direvent.c:522
 #, c-format
 msgid "%s %s started"
 msgstr "%s %s uruchomiony"
 
-#: src/direvent.c:541
+#: src/direvent.c:546
 #, c-format
 msgid "%s %s stopped"
 msgstr "%s %s skończył pracę"
@@ -381,18 +371,6 @@ msgstr "%s %s skończył pracę"
 msgid "environment: "
 msgstr "środowisko: "
 
-#: src/hashtab.c:140 grecs/src/symtab.c:206
-msgid "element not found in table"
-msgstr "nie znaleziono elementu w tabeli"
-
-#: src/hashtab.c:142 grecs/src/symtab.c:208
-msgid "symbol table is full"
-msgstr "tabela symboli przepełniona"
-
-#: src/hashtab.c:144
-msgid "out of memory"
-msgstr "brak pamięci"
-
 #: src/progman.c:142
 #, c-format
 msgid "process %lu exited successfully"
@@ -454,74 +432,124 @@ msgstr ""
 msgid "redirector for %s started, pid=%lu"
 msgstr "uruchomiono urządzenie przekierowywujące %s, pid=%lu"
 
-#: src/progman.c:454
+#: src/progman.c:455
 #, c-format
 msgid "starting %s, dir=%s, file=%s"
 msgstr "rozruch %s, katalog=%s, plik=%s"
 
-#: src/progman.c:482
+#: src/progman.c:484
 #, c-format
 msgid "cannot change to %s: %s"
 msgstr "nie można przejść do katalogu %s: %s"
 
-#: src/progman.c:510
+#: src/progman.c:512
 #, c-format
 msgid "%s running; dir=%s, file=%s, pid=%lu"
 msgstr "uruchomiono %s; katalog=%s, plik=%s, pid=%lu"
 
-#: src/progman.c:532
+#: src/progman.c:534
 #, c-format
 msgid "waiting for %s (%lu) to terminate"
 msgstr "czekanie na zakończenie %s (%lu)"
 
-#: src/watcher.c:231
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr "usunięcie obserwatora %s"
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
 #, c-format
 msgid "creating watcher %s"
 msgstr "utworzenie obserwatora %s"
 
-#: src/watcher.c:240
+#: src/watcher.c:281 src/watcher.c:296
 #, c-format
 msgid "cannot set watcher on %s: %s"
 msgstr "nie można ustawić obserwatora na %s: %s"
 
-#: src/watcher.c:319
+#: src/watcher.c:377
 #, c-format
 msgid "cannot create watcher %s/%s: not enough memory"
 msgstr "nie można stworzyć obserwatora %s/%s: brak pamięci"
 
-#: src/watcher.c:326
+#: src/watcher.c:384
 #, c-format
 msgid "cannot create watcher %s/%s, stat failed: %s"
 msgstr "cannot create watcher %s/%s: błąd wywołania stat: %s"
 
-#: src/watcher.c:355
+#: src/watcher.c:430
 #, c-format
 msgid "cannot open directory %s: %s"
 msgstr "nie można otworzyć katalogu %s: %s"
 
-#: src/watcher.c:371
+#: src/watcher.c:447
 #, c-format
 msgid "cannot stat %s/%s: not enough memory"
 msgstr "stat %s/%s: brak pamięci"
 
-#: src/watcher.c:376
+#: src/watcher.c:452
 #, c-format
 msgid "cannot stat %s: %s"
 msgstr "stat(%s) nie powiódł się: %s"
 
 #
-#: src/watcher.c:412
+#: src/watcher.c:497
 msgid "no event handlers configured"
 msgstr "brak skonfigurowanych programów obsługi wydarzeń"
 
-#: src/watcher.c:417
+#: src/watcher.c:502
 msgid "no event handlers installed"
 msgstr "nie zainstalowano żadnych programów obsługi wydarzeń"
 
-#: src/watcher.c:425
-#, c-format
-msgid "removing watcher %s"
-msgstr "usunięcie obserwatora %s"
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+#, fuzzy
+msgid "hostname"
+msgstr "nazwa"
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
+msgstr ""
 
 #: grecs/src/format.c:133
 msgid "Disabled;"
@@ -655,9 +683,8 @@ msgid "invalid include statement"
 msgstr "nieprawidłowe polecenie dołączania"
 
 #: grecs/src/preproc.c:624
-#, fuzzy
 msgid "read error"
-msgstr "błąd analizy"
+msgstr "błąd odczytu"
 
 #: grecs/src/preproc.c:632
 #, c-format
@@ -674,185 +701,232 @@ msgstr "Nie mogę uruchomić preprocesora `%s'"
 msgid "Cannot run `%s'"
 msgstr "Nie można wykonać `%s'"
 
-#: grecs/src/tree.c:329
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr "nie znaleziono elementu w tablicy"
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr "tablica symboli przepełniona"
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+#, fuzzy
+msgid "one or more arguments"
+msgstr "za dużo argumentów"
+
+#: grecs/src/tree.c:75
+#, fuzzy
+msgid "unrecognized type; please report"
+msgstr "nieznany kod wydarzenia"
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+#, fuzzy
+msgid "unknown keyword"
+msgstr "Nieznane słowo kluczowe"
+
+#: grecs/src/tree.c:360
 #, c-format
 msgid "%s: not a valid boolean value"
 msgstr "%s nie jest poprawną wartością boole'owską"
 
-#: grecs/src/tree.c:360
+#: grecs/src/tree.c:391
 #, c-format
 msgid "%s: UNIX socket name too long"
-msgstr "%s: za długa nazwa gniazda UNIX"
+msgstr "%s: za długa nazwa gniazda"
 
-#: grecs/src/tree.c:389 grecs/src/tree.c:613
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
 #, c-format
 msgid "%s: not a valid IP address or hostname"
-msgstr "%s: niepoprawny adres IP lub nazwa hosta"
+msgstr "%s: niepoprawny adres IPv4 lub nazwa hosta"
 
-#: grecs/src/tree.c:413
+#: grecs/src/tree.c:444
 #, c-format
 msgid "%s: not a valid port number"
 msgstr "%s: niepoprawny numer portu"
 
-#: grecs/src/tree.c:421
+#: grecs/src/tree.c:452
 msgid "missing port number"
 msgstr "brak numeru portu"
 
-#: grecs/src/tree.c:470
+#: grecs/src/tree.c:501
 msgid "numeric overflow"
 msgstr "przepełnienie arytmetyczne"
 
-#: grecs/src/tree.c:475
+#: grecs/src/tree.c:506
 msgid "value out of allowed range"
 msgstr "wartość poza dozwolonym zakresem"
 
-#: grecs/src/tree.c:510 grecs/src/tree.c:540
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
 #, c-format
 msgid "not a number (stopped near `%s')"
 msgstr "nie jest liczbą (zatrzymano przy `%s')"
 
-#: grecs/src/tree.c:604
+#: grecs/src/tree.c:635
 #, c-format
 msgid "%s: not a valid IP address"
 msgstr "%s: niepoprawny adres IP"
 
-#: grecs/src/tree.c:743
+#: grecs/src/tree.c:774
 #, c-format
 msgid "too many arguments to `%s'; missing semicolon?"
 msgstr "zbyt dużo argumentów do `%s': brak średnika?"
 
-#: grecs/src/tree.c:757 grecs/src/tree.c:805
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
 #, c-format
 msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
 msgstr "BŁĄD WEWNĘTRZNY przy %s:%d: nieobsługiwany typ danych %d"
 
-#: grecs/src/tree.c:772
+#: grecs/src/tree.c:803
 #, c-format
 msgid "%s: incompatible data type in list item #%d"
 msgstr "%s: element listy #%d ma niekompatybilny typ danych"
 
-#: grecs/src/tree.c:792
+#: grecs/src/tree.c:823
 #, c-format
 msgid "incompatible data type for `%s'"
 msgstr "niekompatybilny typ danych dla `%s'"
 
-#: grecs/src/tree.c:920 grecs/src/tree.c:930
-msgid "Unknown keyword"
-msgstr "Nieznane słowo kluczowe"
-
-#: grecs/src/tree.c:1139
-#, c-format
-msgid "%s: unknown keyword"
-msgstr "%s: nieznane słowo kluczowe"
-
-#: grecs/src/wordsplit.c:62 grecs/src/wordsplit.c:2300
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
 msgid "memory exhausted"
 msgstr "pamięć wyczerpana"
 
-#: grecs/src/wordsplit.c:1073
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:1607
 #, c-format
 msgid "%.*s: variable null or not set"
-msgstr ""
+msgstr "%.*s: zmienna pusta lub nie ustawiona"
 
-#: grecs/src/wordsplit.c:1102
+#: grecs/wordsplit/wordsplit.c:1637
 #, c-format
 msgid "warning: undefined variable `%.*s'"
 msgstr "ostrzeżenie: niezdefiniowana zmienna `%.*s'"
 
-#: grecs/src/wordsplit.c:1630
+#: grecs/wordsplit/wordsplit.c:2141
 #, c-format
 msgid "no files match pattern %s"
-msgstr ""
+msgstr "żaden plik nie pasuje do wzoru %s"
 
-#: grecs/src/wordsplit.c:2080
+#: grecs/wordsplit/wordsplit.c:2603
 msgid "WS trimming"
-msgstr ""
+msgstr "usunięcie białych znaków"
+
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
+msgstr "rozszerzenie poleceń"
 
-#: grecs/src/wordsplit.c:2081
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
+msgstr "zjednoczenie listy"
+
+#: grecs/wordsplit/wordsplit.c:2609
 msgid "tilde expansion"
-msgstr ""
+msgstr "rozszerzenie tyldy"
 
-#: grecs/src/wordsplit.c:2082
+#: grecs/wordsplit/wordsplit.c:2611
 msgid "variable expansion"
-msgstr ""
+msgstr "rozszerzenie zmiennych"
 
-#: grecs/src/wordsplit.c:2084
+#: grecs/wordsplit/wordsplit.c:2613
 msgid "quote removal"
-msgstr ""
+msgstr "usunięcie cudzysłowów"
 
-#: grecs/src/wordsplit.c:2086
-#, fuzzy
-msgid "command substitution"
-msgstr "rozszerzenie poleceń jeszcze nie jest obsługiwane"
-
-#: grecs/src/wordsplit.c:2088
-msgid "coalesce list"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2090
+#: grecs/wordsplit/wordsplit.c:2617
 msgid "path expansion"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2120
-msgid "Initial list:"
-msgstr ""
+msgstr "rozszerzenie ścieżek"
 
-#: grecs/src/wordsplit.c:2136
-#, fuzzy
-msgid "Coalesced list:"
-msgstr "nieoczekiwana lista"
-
-#: grecs/src/wordsplit.c:2190
+#: grecs/wordsplit/wordsplit.c:2642
 #, c-format
 msgid "(%02d) Input:%.*s;"
-msgstr ""
+msgstr "(%02d) Wejście:%.*s;"
 
-#: grecs/src/wordsplit.c:2202
-#, c-format
-msgid "(%02d) Restart:%.*s;"
-msgstr ""
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
+msgstr "Lista początkowa:"
+
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr "Zjednoczona lista:"
 
-#: grecs/src/wordsplit.c:2298
+#: grecs/wordsplit/wordsplit.c:2853
 msgid "no error"
 msgstr "żadnego błędu"
 
-#: grecs/src/wordsplit.c:2299
+#: grecs/wordsplit/wordsplit.c:2854
 msgid "missing closing quote"
 msgstr "brak cudzysłowu zamykającego"
 
-#: grecs/src/wordsplit.c:2301
+#: grecs/wordsplit/wordsplit.c:2856
 msgid "invalid wordsplit usage"
 msgstr "niepoprawne użycie funkcji wordsplit"
 
-#: grecs/src/wordsplit.c:2302
+#: grecs/wordsplit/wordsplit.c:2857
 msgid "unbalanced curly brace"
 msgstr "niezbilansowany nawias klamrowy"
 
-#: grecs/src/wordsplit.c:2303
+#: grecs/wordsplit/wordsplit.c:2858
 msgid "undefined variable"
 msgstr "niezdefiniowana zmienna"
 
-#: grecs/src/wordsplit.c:2304
+#: grecs/wordsplit/wordsplit.c:2859
 msgid "input exhausted"
 msgstr "wejście wyczerpane"
 
-#: grecs/src/wordsplit.c:2305
+#: grecs/wordsplit/wordsplit.c:2860
 msgid "unbalanced parenthesis"
-msgstr ""
+msgstr "niezbilansowane nawiasy"
 
-#: grecs/src/wordsplit.c:2306
-#, fuzzy
+#: grecs/wordsplit/wordsplit.c:2861
 msgid "globbing error"
-msgstr "żadnego błędu"
+msgstr "błąd dopasowania"
+
+#: grecs/wordsplit/wordsplit.c:2862
+#, fuzzy
+msgid "user-defined error"
+msgstr "błąd odczytu"
+
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
 
-#: grecs/src/wordsplit.c:2318
+#: grecs/wordsplit/wordsplit.c:2875
 msgid "unknown error"
 msgstr "nieznany błąd"
 
-#: grecs/src/wordsplit.c:2327
+#: grecs/wordsplit/wordsplit.c:2884
 #, c-format
 msgid "missing closing %c (start near #%lu)"
 msgstr "brak zamykającego znaku %c (początek przy #%lu)"
 
-#~ msgid "INTERNAL ERROR at %s:%d"
-#~ msgstr "BŁĄD WEWNĘTRZNY przy %s:%d"
+#~ msgid "unterminated regexp"
+#~ msgstr "niezakończone wyrażenie regularne"
+
+#~ msgid "unrecognized flag: %c"
+#~ msgstr "nierozpoznany znacznik: %c"
+
+#~ msgid "out of memory"
+#~ msgstr "brak pamięci"
+
+#~ msgid "%s: unknown keyword"
+#~ msgstr "%s: nieznane słowo kluczowe"
+
+#~ msgid "(%02d) Restart:%.*s;"
+#~ msgstr "(%02d) Restart:%.*s;"
diff --git a/po/pt_BR.gmo b/po/pt_BR.gmo
index 15ae865..d775a58 100644
Binary files a/po/pt_BR.gmo and b/po/pt_BR.gmo differ
diff --git a/po/pt_BR.po b/po/pt_BR.po
index 0c42037..16ea656 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -1,24 +1,24 @@
 # Brazilian Portuguese translation for direvent
-# Copyright (C) 2014 Free Software Foundation, Inc.
-# Copyright (C) 2014 Sergey Poznyakoff
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# Copyright (C) 2016 Sergey Poznyakoff
 # This file is distributed under the same license as the direvent package.
-# Rafael Ferreira <rafael.f.f1@gmail.com>, 2014.
-#
+# Rafael Fontenelle <rafaelff@gnome.org>, 2014, 2016.
 msgid ""
 msgstr ""
-"Project-Id-Version: direvent 4.1.91\n"
+"Project-Id-Version: direvent 5.1\n"
 "Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
-"POT-Creation-Date: 2016-07-06 17:50+0300\n"
-"PO-Revision-Date: 2014-09-02 08:37-0300\n"
-"Last-Translator: Rafael Ferreira <rafael.f.f1@gmail.com>\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
+"PO-Revision-Date: 2016-08-09 15:33-0200\n"
+"Last-Translator: Rafael Fontenelle <rafaelff@gnome.org>\n"
 "Language-Team: Brazilian Portuguese <ldpbr-translation@lists.sourceforge."
 "net>\n"
 "Language: pt_BR\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 1.6.7\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Virtaal 0.7.1\n"
 
 #: cmdline.opt:26
 msgid "increase debug level"
@@ -50,11 +50,11 @@ msgstr "mantém em primeiro plano"
 
 #: cmdline.opt:53
 msgid "DIR"
-msgstr ""
+msgstr "DIR"
 
 #: cmdline.opt:53
 msgid "add include directory"
-msgstr ""
+msgstr "adiciona diretório de inclusão"
 
 #: cmdline.opt:59
 msgid "PROG"
@@ -74,7 +74,7 @@ msgstr "define arquivo PID"
 
 #: cmdline.opt:71
 msgid "check configuration file and exit"
-msgstr "verifica arquivo arquivo de configuração e sai"
+msgstr "verifica arquivo de configuração e sai"
 
 #: cmdline.opt:77
 msgid "USER"
@@ -94,15 +94,15 @@ msgstr "Outras opções"
 
 #: cmdline.opt:93
 msgid "Give this help list"
-msgstr "fornece essa lista de ajuda"
+msgstr "Fornece essa lista de ajuda"
 
 #: cmdline.opt:93
 msgid "Give a short usage message"
-msgstr "fornece uma mensagem curta de uso"
+msgstr "Fornece uma mensagem curta de uso"
 
 #: cmdline.opt:93
 msgid "Print program version"
-msgstr "exibe a versão do programa"
+msgstr "Exibe a versão do programa"
 
 #: cmdline.opt:13
 msgid "GNU direvent monitors changes in directories"
@@ -136,12 +136,12 @@ msgstr ""
 #: cmdline.opt:102
 #, c-format
 msgid "Include search path:\n"
-msgstr ""
+msgstr "Caminho de pesquisa de inclusão:\n"
 
 #: cmdline.opt:105
 #, c-format
 msgid "No include search path.\n"
-msgstr ""
+msgstr "Nenhum caminho de pesquisa de inclusão.\n"
 
 #: src/config.c:63
 #, c-format
@@ -172,7 +172,7 @@ msgstr "esperava %s, mas encontrou %s"
 msgid "unknown syslog facility `%s'"
 msgstr "facilidade syslog desconhecida \"%s\""
 
-#: src/config.c:133 src/config.c:706
+#: src/config.c:133 src/config.c:606
 msgid "name"
 msgstr "nome"
 
@@ -186,7 +186,7 @@ msgstr ""
 "authpriv, mail, cron, local0 até local7 (sem diferenciação de maiúsculo/"
 "minúsculo) ou uo número de uma facilidade."
 
-#: src/config.c:139
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
 msgid "string"
 msgstr "texto"
 
@@ -202,142 +202,132 @@ msgstr "arg"
 msgid "Prefix each message with its priority"
 msgstr "Prefixa cada mensagem com essa prioridade"
 
-#: src/config.c:209
+#: src/config.c:191
 #, c-format
 msgid "%s: recursion depth does not match previous definition"
 msgstr "%s: a profundidade de recursão não corresponde ao definido previamente"
 
-#: src/config.c:247
+#: src/config.c:212
 msgid "no paths configured"
 msgstr "nenhum caminho configurado"
 
-#: src/config.c:252
+#: src/config.c:217
 msgid "no command configured"
 msgstr "nenhum comando configurado"
 
-#: src/config.c:264 grecs/src/tree.c:634
+#: src/config.c:229 grecs/src/tree.c:665
 msgid "invalid use of block statement"
 msgstr "uso inválido de declaração de bloco"
 
-#: src/config.c:309
+#: src/config.c:274
 msgid "expected \"recursive\" or end of statement"
 msgstr "esperado \"recursive\" ou fim de declaração"
 
-#: src/config.c:324
+#: src/config.c:289
 msgid "surplus argument"
 msgstr "argumento em excesso"
 
-#: src/config.c:330 src/config.c:481
+#: src/config.c:295 src/config.c:446
 msgid "unexpected list"
 msgstr "lista inesperada"
 
-#: src/config.c:361 src/config.c:376 src/config.c:391
+#: src/config.c:326 src/config.c:341 src/config.c:356
 msgid "unrecognized event code"
 msgstr "código de evento não reconhecido"
 
-#: src/config.c:473
+#: src/config.c:438
 msgid "surplus arguments"
 msgstr "argumentos em excesso"
 
-#: src/config.c:487
+#: src/config.c:452
 msgid "no such user"
 msgstr "usuário inexistente"
 
-#: src/config.c:494
+#: src/config.c:459
 msgid "no such group"
 msgstr "grupo inexistente"
 
-#: src/config.c:535
-#, fuzzy
+#: src/config.c:501
 msgid "unrecognized option"
 msgstr "opção não reconhecida"
 
-#: src/config.c:613
-msgid "unterminated regexp"
-msgstr "expressão regular não terminada"
-
-#: src/config.c:627
-#, c-format
-msgid "unrecognized flag: %c"
-msgstr "opção não reconhecida: %c"
-
-#: src/config.c:695
+#: src/config.c:595
 msgid "Pathname to watch"
 msgstr "Caminho a observar"
 
-#: src/config.c:698
+#: src/config.c:598
 msgid "Events to watch for"
 msgstr "Eventos a observar por"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "regexp"
 msgstr "expressão regular"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "Files to watch for"
 msgstr "Arquivos a observar por"
 
-#: src/config.c:704
+#: src/config.c:604
 msgid "Command to execute on event"
 msgstr "Comando para executar no evento"
 
-#: src/config.c:706
+#: src/config.c:606
 msgid "Run command as this user"
 msgstr "Executa comando como esse usuário"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "seconds"
 msgstr "segundos"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "Timeout for the command"
 msgstr "Tempo limite de espera pelo comando"
 
-#: src/config.c:711
+#: src/config.c:611
 msgid "List of additional options"
 msgstr "Lista de opções adicionais"
 
-#: src/config.c:714
+#: src/config.c:614
 msgid "<arg: string> <arg: string>..."
 msgstr "<arg: texto> <arg: texto>..."
 
-#: src/config.c:715
+#: src/config.c:615
 msgid "Modify environment"
 msgstr "Modifica ambiente"
 
-#: src/config.c:722
+#: src/config.c:622
 msgid "Run as this user"
 msgstr "Executa como esse usuário"
 
-#: src/config.c:724
+#: src/config.c:624
 msgid "Run in foreground"
 msgstr "Executa em primeiro plano"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "file"
 msgstr "arquivo"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "Set pid file name"
 msgstr "Define nome de arquivo pid"
 
-#: src/config.c:728
+#: src/config.c:628
 msgid "Configure syslog logging"
 msgstr "Configura registro syslog"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "level"
 msgstr "nível"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "Set debug level"
 msgstr "Define nível de depuração"
 
-#: src/config.c:732
+#: src/config.c:632
 msgid "Configure event watcher"
 msgstr "Configure observador de evento"
 
-#: src/config.c:743
+#: src/config.c:643
 msgid ""
 "Configuration file structure for direvent.\n"
 "For more information, use `info direvent configuration'."
@@ -345,36 +335,35 @@ msgstr ""
 "Estrutura de arquivo de configuração para direvent.\n"
 "Para mais informação, use \"info direvent configuration\"."
 
-#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:86 src/watcher.c:182
-#: src/watcher.c:191
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
 msgid "not enough memory"
 msgstr "memória insuficiente"
 
-#: src/direvent.c:272
+#: src/direvent.c:274
 #, c-format
 msgid "cannot open pidfile %s for writing: %s"
 msgstr "não é possível abrir o arquivo PID %s para escrita: %s"
 
-#: src/direvent.c:300
+#: src/direvent.c:302
 #, c-format
 msgid "no user with UID %lu"
 msgstr "nenhum usuário com UID %lu"
 
-#: src/direvent.c:418
+#: src/direvent.c:420
 #, c-format
 msgid "cannot run `%s': fork failed: %s"
 msgstr "não é possível \"%s\": fork falhou: %s"
 
-#: src/direvent.c:478
+#: src/direvent.c:480
 msgid "too many arguments"
 msgstr "argumentos demais"
 
-#: src/direvent.c:520
+#: src/direvent.c:522
 #, c-format
 msgid "%s %s started"
 msgstr "%s %s iniciou"
 
-#: src/direvent.c:541
+#: src/direvent.c:546
 #, c-format
 msgid "%s %s stopped"
 msgstr "%s %s parou"
@@ -383,22 +372,10 @@ msgstr "%s %s parou"
 msgid "environment: "
 msgstr "ambiente: "
 
-#: src/hashtab.c:140 grecs/src/symtab.c:206
-msgid "element not found in table"
-msgstr "elemento não encontrado na tabela"
-
-#: src/hashtab.c:142 grecs/src/symtab.c:208
-msgid "symbol table is full"
-msgstr "tabela de símbolos está completo"
-
-#: src/hashtab.c:144
-msgid "out of memory"
-msgstr "memória insuficiente"
-
 #: src/progman.c:142
 #, c-format
 msgid "process %lu exited successfully"
-msgstr "O processo %lu saiu com sucesso"
+msgstr "o processo %lu saiu com sucesso"
 
 #: src/progman.c:145
 #, c-format
@@ -454,73 +431,123 @@ msgstr "não foi possível redirecionar \"%s\": fork falhou: %s"
 msgid "redirector for %s started, pid=%lu"
 msgstr "redirecionador para %s iniciado, pid=%lu"
 
-#: src/progman.c:454
+#: src/progman.c:455
 #, c-format
 msgid "starting %s, dir=%s, file=%s"
 msgstr "iniciando %s, dir=%s, arquivo=%s"
 
-#: src/progman.c:482
+#: src/progman.c:484
 #, c-format
 msgid "cannot change to %s: %s"
 msgstr "não foi possível alterar para %s: %s"
 
-#: src/progman.c:510
+#: src/progman.c:512
 #, c-format
 msgid "%s running; dir=%s, file=%s, pid=%lu"
 msgstr "%s em execução, dir=%s, arquivo=%s, pid=%lu"
 
-#: src/progman.c:532
+#: src/progman.c:534
 #, c-format
 msgid "waiting for %s (%lu) to terminate"
 msgstr "esperando por %s (%lu) ser terminado"
 
-#: src/watcher.c:231
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr "removendo observador %s"
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
 #, c-format
 msgid "creating watcher %s"
 msgstr "criando observador %s"
 
-#: src/watcher.c:240
+#: src/watcher.c:281 src/watcher.c:296
 #, c-format
 msgid "cannot set watcher on %s: %s"
 msgstr "não foi definir observador em %s: %s"
 
-#: src/watcher.c:319
+#: src/watcher.c:377
 #, c-format
 msgid "cannot create watcher %s/%s: not enough memory"
 msgstr "não foi possível criar observador %s/%s: memória insuficiente"
 
-#: src/watcher.c:326
+#: src/watcher.c:384
 #, c-format
 msgid "cannot create watcher %s/%s, stat failed: %s"
 msgstr "não foi possível criar observador %s/%s, stat falhou: %s"
 
-#: src/watcher.c:355
+#: src/watcher.c:430
 #, c-format
 msgid "cannot open directory %s: %s"
 msgstr "não foi possível abrir o diretório %s: %s"
 
-#: src/watcher.c:371
+#: src/watcher.c:447
 #, c-format
 msgid "cannot stat %s/%s: not enough memory"
 msgstr "não foi possível obter status %s/%s: memória insuficiente"
 
-#: src/watcher.c:376
+#: src/watcher.c:452
 #, c-format
 msgid "cannot stat %s: %s"
-msgstr "Não foi possível obter status de %s: %s"
+msgstr "não foi possível obter status de %s: %s"
 
-#: src/watcher.c:412
+#: src/watcher.c:497
 msgid "no event handlers configured"
 msgstr "nenhum manipulador de evento configurado"
 
-#: src/watcher.c:417
+#: src/watcher.c:502
 msgid "no event handlers installed"
 msgstr "nenhum manipulador de evento instalado"
 
-#: src/watcher.c:425
-#, c-format
-msgid "removing watcher %s"
-msgstr "removendo observador %s"
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+#, fuzzy
+msgid "hostname"
+msgstr "nome"
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
+msgstr ""
 
 #: grecs/src/format.c:133
 msgid "Disabled;"
@@ -563,7 +590,7 @@ msgstr "Relate erros para %s.\n"
 #: grecs/src/opthelp.c:205
 #, c-format
 msgid "%s home page: <%s>\n"
-msgstr "Página inicial do %s: <%s>\n"
+msgstr "Site do %s: <%s>\n"
 
 #. TRANSLATORS: Translate "(C)" to the copyright symbol
 #. (C-in-a-circle), if this symbol is available in the user's
@@ -655,9 +682,8 @@ msgid "invalid include statement"
 msgstr "declaração inclusa inválida"
 
 #: grecs/src/preproc.c:624
-#, fuzzy
 msgid "read error"
-msgstr "erro de analise"
+msgstr "erro de leitura"
 
 #: grecs/src/preproc.c:632
 #, c-format
@@ -674,186 +700,236 @@ msgstr "Não foi possível iniciar preprocessador externo \"%s\""
 msgid "Cannot run `%s'"
 msgstr "Não foi possível executar \"%s\""
 
-#: grecs/src/tree.c:329
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr "elemento não encontrado na tabela"
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr "tabela de símbolos está completo"
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+#, fuzzy
+msgid "one or more arguments"
+msgstr "argumentos demais"
+
+#: grecs/src/tree.c:75
+#, fuzzy
+msgid "unrecognized type; please report"
+msgstr "código de evento não reconhecido"
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+#, fuzzy
+msgid "unknown keyword"
+msgstr "Palavra-chave desconhecida"
+
+#: grecs/src/tree.c:360
 #, c-format
 msgid "%s: not a valid boolean value"
 msgstr "%s: não é um valor booleano válido"
 
-#: grecs/src/tree.c:360
+#: grecs/src/tree.c:391
 #, c-format
 msgid "%s: UNIX socket name too long"
 msgstr "%s: nome de soquete UNIX longo demais"
 
-#: grecs/src/tree.c:389 grecs/src/tree.c:613
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
 #, c-format
 msgid "%s: not a valid IP address or hostname"
 msgstr "%s: não é um endereço de IP ou nome de máquina válidos"
 
-#: grecs/src/tree.c:413
+#: grecs/src/tree.c:444
 #, c-format
 msgid "%s: not a valid port number"
 msgstr "%s: não é um número de porta válido"
 
-#: grecs/src/tree.c:421
+#: grecs/src/tree.c:452
 msgid "missing port number"
 msgstr "faltando número de porta"
 
-#: grecs/src/tree.c:470
+#: grecs/src/tree.c:501
 msgid "numeric overflow"
-msgstr "Estouro numérico"
+msgstr "estouro numérico"
 
-#: grecs/src/tree.c:475
+#: grecs/src/tree.c:506
 msgid "value out of allowed range"
 msgstr "valor fora do intervalo permitido"
 
-#: grecs/src/tree.c:510 grecs/src/tree.c:540
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
 #, c-format
 msgid "not a number (stopped near `%s')"
 msgstr "não é um número (parou perto de \"%s\")"
 
-#: grecs/src/tree.c:604
+#: grecs/src/tree.c:635
 #, c-format
 msgid "%s: not a valid IP address"
 msgstr "%s: não é um endereço IP válido"
 
-#: grecs/src/tree.c:743
+#: grecs/src/tree.c:774
 #, c-format
 msgid "too many arguments to `%s'; missing semicolon?"
 msgstr "argumentos demais para \"%s\"; faltando ponto-e-vírgula?"
 
-#: grecs/src/tree.c:757 grecs/src/tree.c:805
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
 #, c-format
 msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
 msgstr "ERRO INTERNO em %s:%d: tipo de dados não lidado %d"
 
-#: grecs/src/tree.c:772
+#: grecs/src/tree.c:803
 #, c-format
 msgid "%s: incompatible data type in list item #%d"
 msgstr "%s: tipo de dados incompatível na item de lista #%d"
 
-#: grecs/src/tree.c:792
+#: grecs/src/tree.c:823
 #, c-format
 msgid "incompatible data type for `%s'"
 msgstr "tipo de dados incompatível para \"%s\""
 
-#: grecs/src/tree.c:920 grecs/src/tree.c:930
-msgid "Unknown keyword"
-msgstr "Palavra-chave desconhecida"
-
-#: grecs/src/tree.c:1139
-#, c-format
-msgid "%s: unknown keyword"
-msgstr "%s: palavra-chave desconhecida"
-
-#: grecs/src/wordsplit.c:62 grecs/src/wordsplit.c:2300
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
 msgid "memory exhausted"
 msgstr "memória esgotada"
 
-#: grecs/src/wordsplit.c:1073
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:1607
 #, c-format
 msgid "%.*s: variable null or not set"
-msgstr ""
+msgstr "%.*s: variável nula ou não definida"
 
-#: grecs/src/wordsplit.c:1102
+#: grecs/wordsplit/wordsplit.c:1637
 #, c-format
 msgid "warning: undefined variable `%.*s'"
 msgstr "aviso: variável não definida \"%.*s\""
 
-#: grecs/src/wordsplit.c:1630
+#: grecs/wordsplit/wordsplit.c:2141
 #, c-format
 msgid "no files match pattern %s"
-msgstr ""
+msgstr "nenhum arquivo corresponde ao padrão %s"
 
-#: grecs/src/wordsplit.c:2080
+#: grecs/wordsplit/wordsplit.c:2603
 msgid "WS trimming"
-msgstr ""
+msgstr "Aparar alterações"
 
-#: grecs/src/wordsplit.c:2081
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
+msgstr "substituição de comando"
+
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
+msgstr "lista de coalescência"
+
+#: grecs/wordsplit/wordsplit.c:2609
 msgid "tilde expansion"
-msgstr ""
+msgstr "expansão de til"
 
-#: grecs/src/wordsplit.c:2082
+#: grecs/wordsplit/wordsplit.c:2611
 msgid "variable expansion"
-msgstr ""
+msgstr "expansão de variável"
 
-#: grecs/src/wordsplit.c:2084
+#: grecs/wordsplit/wordsplit.c:2613
 msgid "quote removal"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2086
-#, fuzzy
-msgid "command substitution"
-msgstr "não há ainda suporte a substituição de comando"
-
-#: grecs/src/wordsplit.c:2088
-msgid "coalesce list"
-msgstr ""
+msgstr "remoção de aspas"
 
-#: grecs/src/wordsplit.c:2090
+#: grecs/wordsplit/wordsplit.c:2617
 msgid "path expansion"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2120
-msgid "Initial list:"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2136
-#, fuzzy
-msgid "Coalesced list:"
-msgstr "lista inesperada"
+msgstr "expansão de caminho"
 
-#: grecs/src/wordsplit.c:2190
+#: grecs/wordsplit/wordsplit.c:2642
 #, c-format
 msgid "(%02d) Input:%.*s;"
-msgstr ""
+msgstr "(%02d) Entrada:%.*s;"
 
-#: grecs/src/wordsplit.c:2202
-#, c-format
-msgid "(%02d) Restart:%.*s;"
-msgstr ""
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
+msgstr "Lista inicial:"
+
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr "Lista coalescida:"
 
-#: grecs/src/wordsplit.c:2298
+#: grecs/wordsplit/wordsplit.c:2853
 msgid "no error"
 msgstr "nenhum erro"
 
-#: grecs/src/wordsplit.c:2299
+#: grecs/wordsplit/wordsplit.c:2854
 msgid "missing closing quote"
 msgstr "faltando fechar aspas"
 
-#: grecs/src/wordsplit.c:2301
+#: grecs/wordsplit/wordsplit.c:2856
 msgid "invalid wordsplit usage"
 msgstr "uso inválido de separação de palavra"
 
-#: grecs/src/wordsplit.c:2302
+#: grecs/wordsplit/wordsplit.c:2857
 msgid "unbalanced curly brace"
-msgstr "chave \"{}\"não balanceada"
+msgstr "chave \"{}\" não balanceada"
 
-#: grecs/src/wordsplit.c:2303
+#: grecs/wordsplit/wordsplit.c:2858
 msgid "undefined variable"
 msgstr "variável não definida"
 
-#: grecs/src/wordsplit.c:2304
+#: grecs/wordsplit/wordsplit.c:2859
 msgid "input exhausted"
 msgstr "entrada esgotada"
 
-#: grecs/src/wordsplit.c:2305
+#: grecs/wordsplit/wordsplit.c:2860
 msgid "unbalanced parenthesis"
-msgstr ""
+msgstr "parênteses não balanceados"
 
-#: grecs/src/wordsplit.c:2306
-#, fuzzy
+#: grecs/wordsplit/wordsplit.c:2861
 msgid "globbing error"
-msgstr "nenhum erro"
+msgstr "erro de casamento de padrões (globbing)"
+
+#: grecs/wordsplit/wordsplit.c:2862
+#, fuzzy
+msgid "user-defined error"
+msgstr "erro de leitura"
 
-#: grecs/src/wordsplit.c:2318
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2875
 msgid "unknown error"
 msgstr "erro desconhecido"
 
-#: grecs/src/wordsplit.c:2327
+#: grecs/wordsplit/wordsplit.c:2884
 #, c-format
 msgid "missing closing %c (start near #%lu)"
 msgstr "faltando fechar %c (início próximo a #%lu)"
 
+#~ msgid "unterminated regexp"
+#~ msgstr "expressão regular não terminada"
+
+#~ msgid "unrecognized flag: %c"
+#~ msgstr "opção não reconhecida: %c"
+
+#~ msgid "out of memory"
+#~ msgstr "memória insuficiente"
+
+#~ msgid "%s: unknown keyword"
+#~ msgstr "%s: palavra-chave desconhecida"
+
+#~ msgid "(%02d) Restart:%.*s;"
+#~ msgstr "(%02d) Reiniciar:%.*s;"
+
 #~ msgid "INTERNAL ERROR at %s:%d"
 #~ msgstr "ERRO INTERNO em %s:%d"
 
diff --git a/po/sr.gmo b/po/sr.gmo
index 27377e2..e7d9a8e 100644
Binary files a/po/sr.gmo and b/po/sr.gmo differ
diff --git a/po/sr.po b/po/sr.po
index 0d33073..cb82dad 100644
--- a/po/sr.po
+++ b/po/sr.po
@@ -1,19 +1,20 @@
 # Serbian translation for direvent.
-# Copyright © 2014 Free Software Foundation, Inc.
+# Copyright © 2016 Free Software Foundation, Inc.
 # This file is distributed under the same license as the direvent package.
 # Мирослав Николић <miroslavnikolic@rocketmail.com>, 2016.
 msgid ""
 msgstr ""
-"Project-Id-Version: direvent-4.1.91\n"
+"Project-Id-Version: direvent-5.1\n"
 "Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
-"POT-Creation-Date: 2016-07-06 17:50+0300\n"
-"PO-Revision-Date: 2016-03-06 13:50+0200\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
+"PO-Revision-Date: 2016-08-07 19:04+0200\n"
 "Last-Translator: Мирослав Николић <miroslavnikolic@rocketmail.com>\n"
 "Language-Team: Serbian <(nothing)>\n"
 "Language: sr\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
 
@@ -47,11 +48,11 @@ msgstr "остаје у позадини"
 
 #: cmdline.opt:53
 msgid "DIR"
-msgstr ""
+msgstr "ДИР"
 
 #: cmdline.opt:53
 msgid "add include directory"
-msgstr ""
+msgstr "додаје укључујући директоријум"
 
 #: cmdline.opt:59
 msgid "PROG"
@@ -133,12 +134,12 @@ msgstr ""
 #: cmdline.opt:102
 #, c-format
 msgid "Include search path:\n"
-msgstr ""
+msgstr "Укључите путању претраге:\n"
 
 #: cmdline.opt:105
 #, c-format
 msgid "No include search path.\n"
-msgstr ""
+msgstr "Не укључује путању претраге.\n"
 
 #: src/config.c:63
 #, c-format
@@ -169,7 +170,7 @@ msgstr "очекивах „%s“, али добих „%s“"
 msgid "unknown syslog facility `%s'"
 msgstr "непознат помоћник системског дневника „%s“"
 
-#: src/config.c:133 src/config.c:706
+#: src/config.c:133 src/config.c:606
 msgid "name"
 msgstr "name"
 
@@ -183,7 +184,7 @@ msgstr ""
 "auth, authpriv, mail, cron, од local0 до local7 (не разликује величину "
 "слова), или број помоћника."
 
-#: src/config.c:139
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
 msgid "string"
 msgstr "string"
 
@@ -199,142 +200,132 @@ msgstr "arg"
 msgid "Prefix each message with its priority"
 msgstr "Ставља приоритет сваке поруке као префикс"
 
-#: src/config.c:209
+#: src/config.c:191
 #, c-format
 msgid "%s: recursion depth does not match previous definition"
 msgstr "%s: дубина дубачења не одговара претходној одредници"
 
-#: src/config.c:247
+#: src/config.c:212
 msgid "no paths configured"
 msgstr "нема подешених путања"
 
-#: src/config.c:252
+#: src/config.c:217
 msgid "no command configured"
 msgstr "нема подешених наредби"
 
-#: src/config.c:264 grecs/src/tree.c:634
+#: src/config.c:229 grecs/src/tree.c:665
 msgid "invalid use of block statement"
 msgstr "неисправна употреба изјаве блока"
 
-#: src/config.c:309
+#: src/config.c:274
 msgid "expected \"recursive\" or end of statement"
 msgstr "очекивах „recursive“ или крај изјаве"
 
-#: src/config.c:324
+#: src/config.c:289
 msgid "surplus argument"
 msgstr "сувишан аргумент"
 
-#: src/config.c:330 src/config.c:481
+#: src/config.c:295 src/config.c:446
 msgid "unexpected list"
 msgstr "неочекивани списак"
 
-#: src/config.c:361 src/config.c:376 src/config.c:391
+#: src/config.c:326 src/config.c:341 src/config.c:356
 msgid "unrecognized event code"
 msgstr "непозната шифра догађаја"
 
-#: src/config.c:473
+#: src/config.c:438
 msgid "surplus arguments"
 msgstr "сувишни аргументи"
 
-#: src/config.c:487
+#: src/config.c:452
 msgid "no such user"
 msgstr "нема таквог корисника"
 
-#: src/config.c:494
+#: src/config.c:459
 msgid "no such group"
 msgstr "нема такве групе"
 
-#: src/config.c:535
-#, fuzzy
+#: src/config.c:501
 msgid "unrecognized option"
-msgstr "непозната заставица"
-
-#: src/config.c:613
-msgid "unterminated regexp"
-msgstr "недовршен рег. израз"
-
-#: src/config.c:627
-#, c-format
-msgid "unrecognized flag: %c"
-msgstr "непозната заставица: %c"
+msgstr "непозната опција"
 
-#: src/config.c:695
+#: src/config.c:595
 msgid "Pathname to watch"
 msgstr "Путања за осматрање"
 
-#: src/config.c:698
+#: src/config.c:598
 msgid "Events to watch for"
 msgstr "Догађаји за осматрање"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "regexp"
 msgstr "regexp"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "Files to watch for"
 msgstr "Датотеке за осматрање"
 
-#: src/config.c:704
+#: src/config.c:604
 msgid "Command to execute on event"
 msgstr "Наредба за извршавање при догађају"
 
-#: src/config.c:706
+#: src/config.c:606
 msgid "Run command as this user"
 msgstr "Покрени наредбу као овај корисник"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "seconds"
 msgstr "seconds"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "Timeout for the command"
 msgstr "Временски рок за наредбу"
 
-#: src/config.c:711
+#: src/config.c:611
 msgid "List of additional options"
 msgstr "Списак додатних могућности"
 
-#: src/config.c:714
+#: src/config.c:614
 msgid "<arg: string> <arg: string>..."
 msgstr "<arg: ниска> <arg: ниска>..."
 
-#: src/config.c:715
+#: src/config.c:615
 msgid "Modify environment"
 msgstr "Мења окружење"
 
-#: src/config.c:722
+#: src/config.c:622
 msgid "Run as this user"
 msgstr "Покреће се као овај корисник"
 
-#: src/config.c:724
+#: src/config.c:624
 msgid "Run in foreground"
 msgstr "Ради у позадини"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "file"
 msgstr "file"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "Set pid file name"
 msgstr "Подешава назив датотеке броја процеса"
 
-#: src/config.c:728
+#: src/config.c:628
 msgid "Configure syslog logging"
 msgstr "Подешава записивање системског дневника"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "level"
 msgstr "level"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "Set debug level"
 msgstr "Подешава ниво прочишћавања"
 
-#: src/config.c:732
+#: src/config.c:632
 msgid "Configure event watcher"
 msgstr "Подешава осматрача догађаја"
 
-#: src/config.c:743
+#: src/config.c:643
 msgid ""
 "Configuration file structure for direvent.\n"
 "For more information, use `info direvent configuration'."
@@ -342,36 +333,35 @@ msgstr ""
 "Структура датотеке подешавања за диревент.\n"
 "За више података, користите „info direvent configuration“."
 
-#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:86 src/watcher.c:182
-#: src/watcher.c:191
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
 msgid "not enough memory"
 msgstr "нема довољно меморије"
 
-#: src/direvent.c:272
+#: src/direvent.c:274
 #, c-format
 msgid "cannot open pidfile %s for writing: %s"
 msgstr "не могу да отворим датотеку броја процеса „%s“ зарад писања: %s"
 
-#: src/direvent.c:300
+#: src/direvent.c:302
 #, c-format
 msgid "no user with UID %lu"
 msgstr "нема корисника са одредником %lu"
 
-#: src/direvent.c:418
+#: src/direvent.c:420
 #, c-format
 msgid "cannot run `%s': fork failed: %s"
 msgstr "не могу да покренем „%s“: рачвање није успело: %s"
 
-#: src/direvent.c:478
+#: src/direvent.c:480
 msgid "too many arguments"
 msgstr "превише аргумената"
 
-#: src/direvent.c:520
+#: src/direvent.c:522
 #, c-format
 msgid "%s %s started"
 msgstr "„%s“ %s је покренут"
 
-#: src/direvent.c:541
+#: src/direvent.c:546
 #, c-format
 msgid "%s %s stopped"
 msgstr "„%s“ %s је заустављен"
@@ -380,18 +370,6 @@ msgstr "„%s“ %s је заустављен"
 msgid "environment: "
 msgstr "окружење:"
 
-#: src/hashtab.c:140 grecs/src/symtab.c:206
-msgid "element not found in table"
-msgstr "нисам нашао елемент у табели"
-
-#: src/hashtab.c:142 grecs/src/symtab.c:208
-msgid "symbol table is full"
-msgstr "табела симбола је пуна"
-
-#: src/hashtab.c:144
-msgid "out of memory"
-msgstr "нема више меморије"
-
 #: src/progman.c:142
 #, c-format
 msgid "process %lu exited successfully"
@@ -451,74 +429,124 @@ msgstr "не могу да покренем преусмеривача „%s“:
 msgid "redirector for %s started, pid=%lu"
 msgstr "преусмеривач за „%s“ је покренут, пид=%lu"
 
-#: src/progman.c:454
+#: src/progman.c:455
 #, c-format
 msgid "starting %s, dir=%s, file=%s"
 msgstr "покрећем „%s“, дир=%s, датотека=%s"
 
-#: src/progman.c:482
+#: src/progman.c:484
 #, c-format
 msgid "cannot change to %s: %s"
 msgstr "не могу да пређем у „%s“: %s"
 
-#: src/progman.c:510
+#: src/progman.c:512
 #, c-format
 msgid "%s running; dir=%s, file=%s, pid=%lu"
 msgstr "„%s“ је покренут; дир=%s, датотека=%s, пид=%lu"
 
-#: src/progman.c:532
+#: src/progman.c:534
 #, c-format
 msgid "waiting for %s (%lu) to terminate"
 msgstr "чекам на „%s“ (%lu) да заврши"
 
-#: src/watcher.c:231
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr "уклањам осматрача „%s“"
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
 #, c-format
 msgid "creating watcher %s"
 msgstr "правим осматрача „%s“"
 
-#: src/watcher.c:240
+#: src/watcher.c:281 src/watcher.c:296
 #, c-format
 msgid "cannot set watcher on %s: %s"
 msgstr "не могу да подесим осматрача на „%s“: %s"
 
-#: src/watcher.c:319
+#: src/watcher.c:377
 #, c-format
 msgid "cannot create watcher %s/%s: not enough memory"
 msgstr "не могу да направим осматрача „%s/%s“: нема довољно меморије"
 
-#: src/watcher.c:326
+#: src/watcher.c:384
 #, c-format
 msgid "cannot create watcher %s/%s, stat failed: %s"
 msgstr ""
 "не могу да направим осматрача „%s/%s“, нисам успео да добавим податке: %s"
 
-#: src/watcher.c:355
+#: src/watcher.c:430
 #, c-format
 msgid "cannot open directory %s: %s"
 msgstr "не могу да отворим директоријум „%s“: %s"
 
-#: src/watcher.c:371
+#: src/watcher.c:447
 #, c-format
 msgid "cannot stat %s/%s: not enough memory"
 msgstr "не могу да добавим податке за „%s/%s“: нема довољно меморије"
 
-#: src/watcher.c:376
+#: src/watcher.c:452
 #, c-format
 msgid "cannot stat %s: %s"
 msgstr "не могу да добавим податке за „%s“: %s"
 
-#: src/watcher.c:412
+#: src/watcher.c:497
 msgid "no event handlers configured"
 msgstr "нема подешених руковалаца догађаја"
 
-#: src/watcher.c:417
+#: src/watcher.c:502
 msgid "no event handlers installed"
 msgstr "нема инсталираних руковалаца догађаја"
 
-#: src/watcher.c:425
-#, c-format
-msgid "removing watcher %s"
-msgstr "уклањам осматрача „%s“"
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+#, fuzzy
+msgid "hostname"
+msgstr "name"
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
+msgstr ""
 
 #: grecs/src/format.c:133
 msgid "Disabled;"
@@ -652,9 +680,8 @@ msgid "invalid include statement"
 msgstr "неисправна изјава укључивања"
 
 #: grecs/src/preproc.c:624
-#, fuzzy
 msgid "read error"
-msgstr "грешка обраде"
+msgstr "грешка читања"
 
 #: grecs/src/preproc.c:632
 #, c-format
@@ -671,185 +698,235 @@ msgstr "Не могу да покренем спољног предобрађи
 msgid "Cannot run `%s'"
 msgstr "Не могу да покренем „%s“"
 
-#: grecs/src/tree.c:329
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr "нисам нашао елемент у табели"
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr "табела симбола је пуна"
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+#, fuzzy
+msgid "one or more arguments"
+msgstr "превише аргумената"
+
+#: grecs/src/tree.c:75
+#, fuzzy
+msgid "unrecognized type; please report"
+msgstr "непозната шифра догађаја"
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+#, fuzzy
+msgid "unknown keyword"
+msgstr "Непозната кључна реч"
+
+#: grecs/src/tree.c:360
 #, c-format
 msgid "%s: not a valid boolean value"
 msgstr "%s: није исправна логичка вредност"
 
-#: grecs/src/tree.c:360
+#: grecs/src/tree.c:391
 #, c-format
 msgid "%s: UNIX socket name too long"
 msgstr "%s: назив ЈУНИКС прикључнице је предуг"
 
-#: grecs/src/tree.c:389 grecs/src/tree.c:613
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
 #, c-format
 msgid "%s: not a valid IP address or hostname"
 msgstr "%s: није исправна ИП адреса или назив домаћина"
 
-#: grecs/src/tree.c:413
+#: grecs/src/tree.c:444
 #, c-format
 msgid "%s: not a valid port number"
 msgstr "%s: није исправан број прикључника"
 
-#: grecs/src/tree.c:421
+#: grecs/src/tree.c:452
 msgid "missing port number"
 msgstr "недостаје број прикључника"
 
-#: grecs/src/tree.c:470
+#: grecs/src/tree.c:501
 msgid "numeric overflow"
 msgstr "прекорачење бројева"
 
-#: grecs/src/tree.c:475
+#: grecs/src/tree.c:506
 msgid "value out of allowed range"
 msgstr "вредност је изван дозвољеног опсега"
 
-#: grecs/src/tree.c:510 grecs/src/tree.c:540
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
 #, c-format
 msgid "not a number (stopped near `%s')"
 msgstr "није број (стадох близу „%s“)"
 
-#: grecs/src/tree.c:604
+#: grecs/src/tree.c:635
 #, c-format
 msgid "%s: not a valid IP address"
 msgstr "%s: није исправна ИП адреса"
 
-#: grecs/src/tree.c:743
+#: grecs/src/tree.c:774
 #, c-format
 msgid "too many arguments to `%s'; missing semicolon?"
 msgstr "превише аргумената за „%s“; недостаје запетачка?"
 
-#: grecs/src/tree.c:757 grecs/src/tree.c:805
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
 #, c-format
 msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
 msgstr "УНУТРАШЊА ГРЕШКА на „%s“:%d: непозната врста података „%d“"
 
-#: grecs/src/tree.c:772
+#: grecs/src/tree.c:803
 #, c-format
 msgid "%s: incompatible data type in list item #%d"
 msgstr "%s: несагласна врста података у %d. ставци списка"
 
-#: grecs/src/tree.c:792
+#: grecs/src/tree.c:823
 #, c-format
 msgid "incompatible data type for `%s'"
 msgstr "несагласна врста података за „%s“"
 
-#: grecs/src/tree.c:920 grecs/src/tree.c:930
-msgid "Unknown keyword"
-msgstr "Непозната кључна реч"
-
-#: grecs/src/tree.c:1139
-#, c-format
-msgid "%s: unknown keyword"
-msgstr "%s: непозната кључна реч"
-
-#: grecs/src/wordsplit.c:62 grecs/src/wordsplit.c:2300
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
 msgid "memory exhausted"
 msgstr "нема више меморије"
 
-#: grecs/src/wordsplit.c:1073
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:1607
 #, c-format
 msgid "%.*s: variable null or not set"
-msgstr ""
+msgstr "%.*s: променљива је ништавна или није постављена"
 
-#: grecs/src/wordsplit.c:1102
+#: grecs/wordsplit/wordsplit.c:1637
 #, c-format
 msgid "warning: undefined variable `%.*s'"
 msgstr "упозорење: неодређена променљива „%.*s“"
 
-#: grecs/src/wordsplit.c:1630
+#: grecs/wordsplit/wordsplit.c:2141
 #, c-format
 msgid "no files match pattern %s"
-msgstr ""
+msgstr "нема датотека које одговарају обрасцу „%s“"
 
-#: grecs/src/wordsplit.c:2080
+#: grecs/wordsplit/wordsplit.c:2603
 msgid "WS trimming"
-msgstr ""
+msgstr "скраћивање поделе речи"
 
-#: grecs/src/wordsplit.c:2081
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
+msgstr "замена наредбе"
+
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
+msgstr "спаја списак"
+
+#: grecs/wordsplit/wordsplit.c:2609
 msgid "tilde expansion"
-msgstr ""
+msgstr "ширење тилде"
 
-#: grecs/src/wordsplit.c:2082
+#: grecs/wordsplit/wordsplit.c:2611
 msgid "variable expansion"
-msgstr ""
+msgstr "ширење променљиве"
 
-#: grecs/src/wordsplit.c:2084
+#: grecs/wordsplit/wordsplit.c:2613
 msgid "quote removal"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2086
-#, fuzzy
-msgid "command substitution"
-msgstr "замена наредбе још увек није подржана"
-
-#: grecs/src/wordsplit.c:2088
-msgid "coalesce list"
-msgstr ""
+msgstr "уклањање цитата"
 
-#: grecs/src/wordsplit.c:2090
+#: grecs/wordsplit/wordsplit.c:2617
 msgid "path expansion"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2120
-msgid "Initial list:"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2136
-#, fuzzy
-msgid "Coalesced list:"
-msgstr "неочекивани списак"
+msgstr "ширење путање"
 
-#: grecs/src/wordsplit.c:2190
+#: grecs/wordsplit/wordsplit.c:2642
 #, c-format
 msgid "(%02d) Input:%.*s;"
-msgstr ""
+msgstr "(%02d) Улаз:%.*s;"
 
-#: grecs/src/wordsplit.c:2202
-#, c-format
-msgid "(%02d) Restart:%.*s;"
-msgstr ""
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
+msgstr "Почетни списак:"
+
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr "Спојени списак:"
 
-#: grecs/src/wordsplit.c:2298
+#: grecs/wordsplit/wordsplit.c:2853
 msgid "no error"
 msgstr "нема грешке"
 
-#: grecs/src/wordsplit.c:2299
+#: grecs/wordsplit/wordsplit.c:2854
 msgid "missing closing quote"
 msgstr "недостају затварајући наводници"
 
-#: grecs/src/wordsplit.c:2301
+#: grecs/wordsplit/wordsplit.c:2856
 msgid "invalid wordsplit usage"
 msgstr "неисправна употреба поделе речи"
 
-#: grecs/src/wordsplit.c:2302
+#: grecs/wordsplit/wordsplit.c:2857
 msgid "unbalanced curly brace"
 msgstr "неуравнотежена витичаста заграда"
 
-#: grecs/src/wordsplit.c:2303
+#: grecs/wordsplit/wordsplit.c:2858
 msgid "undefined variable"
 msgstr "неодређена променљива"
 
-#: grecs/src/wordsplit.c:2304
+#: grecs/wordsplit/wordsplit.c:2859
 msgid "input exhausted"
 msgstr "нема више улаза"
 
-#: grecs/src/wordsplit.c:2305
+#: grecs/wordsplit/wordsplit.c:2860
 msgid "unbalanced parenthesis"
-msgstr ""
+msgstr "неуравнотежени наводници"
 
-#: grecs/src/wordsplit.c:2306
-#, fuzzy
+#: grecs/wordsplit/wordsplit.c:2861
 msgid "globbing error"
-msgstr "нема грешке"
+msgstr "грешка шаблонирања"
+
+#: grecs/wordsplit/wordsplit.c:2862
+#, fuzzy
+msgid "user-defined error"
+msgstr "грешка читања"
 
-#: grecs/src/wordsplit.c:2318
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2875
 msgid "unknown error"
 msgstr "непозната грешка"
 
-#: grecs/src/wordsplit.c:2327
+#: grecs/wordsplit/wordsplit.c:2884
 #, c-format
 msgid "missing closing %c (start near #%lu)"
 msgstr "недостаје затварајућа %c (почиње близу #%lu)"
 
+#~ msgid "unterminated regexp"
+#~ msgstr "недовршен рег. израз"
+
+#~ msgid "unrecognized flag: %c"
+#~ msgstr "непозната заставица: %c"
+
+#~ msgid "out of memory"
+#~ msgstr "нема више меморије"
+
+#~ msgid "%s: unknown keyword"
+#~ msgstr "%s: непозната кључна реч"
+
+#~ msgid "(%02d) Restart:%.*s;"
+#~ msgstr "(%02d) Поновно покретање:%.*s;"
+
 #~ msgid "INTERNAL ERROR at %s:%d"
 #~ msgstr "УНУТРАШЊА ГРЕШКА на „%s“:%d"
diff --git a/po/sv.gmo b/po/sv.gmo
new file mode 100644
index 0000000..22e3b46
Binary files /dev/null and b/po/sv.gmo differ
diff --git a/po/sv.po b/po/sv.po
new file mode 100644
index 0000000..848f6e4
--- /dev/null
+++ b/po/sv.po
@@ -0,0 +1,930 @@
+# Swedish translation for direvent.
+# Copyright © 2017 Free Software Foundation, Inc.
+# This file is distributed under the same license as the direvent package.
+# Anders Jonsson <anders.jonsson@norsjovallen.se>, 2017.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: direvent 5.1\n"
+"Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
+"PO-Revision-Date: 2017-07-17 23:18+0200\n"
+"Last-Translator: Anders Jonsson <anders.jonsson@norsjovallen.se>\n"
+"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
+"Language: sv\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"X-Generator: Poedit 2.0.2\n"
+
+#: cmdline.opt:26
+msgid "increase debug level"
+msgstr "öka felsökningsnivå"
+
+#: cmdline.opt:32
+msgid "PRIO"
+msgstr "PRIO"
+
+#: cmdline.opt:32
+msgid ""
+"log everything with priority PRIO and higher to the stderr, as well as to "
+"the syslog"
+msgstr ""
+"logga allt med prioritet PRIO och högre till standard fel, så väl som till "
+"syslog"
+
+#: cmdline.opt:41
+msgid "NAME"
+msgstr "NAMN"
+
+#: cmdline.opt:41
+msgid "set syslog facility"
+msgstr "ställ in syslog-funktionalitet"
+
+#: cmdline.opt:47
+msgid "remain in foreground"
+msgstr "stanna kvar i förgrunden"
+
+#: cmdline.opt:53
+msgid "DIR"
+msgstr "KAT"
+
+#: cmdline.opt:53
+msgid "add include directory"
+msgstr "lägg till inkluderingskatalog"
+
+#: cmdline.opt:59
+msgid "PROG"
+msgstr "PROG"
+
+#: cmdline.opt:59
+msgid "self-test mode"
+msgstr "självtestsläge"
+
+#: cmdline.opt:65
+msgid "FILE"
+msgstr "FIL"
+
+#: cmdline.opt:65
+msgid "set PID file"
+msgstr "ställ in PID-fil"
+
+#: cmdline.opt:71
+msgid "check configuration file and exit"
+msgstr "kontrollera konfigurationsfil och avsluta"
+
+#: cmdline.opt:77
+msgid "USER"
+msgstr "ANVÄNDARE"
+
+#: cmdline.opt:77
+msgid "run as this user"
+msgstr "kör som denna användare"
+
+#: cmdline.opt:87
+msgid "show configuration file summary"
+msgstr "visa sammanfattning av konfigurationsfil"
+
+#: cmdline.opt:81
+msgid "Other options"
+msgstr "Andra flaggor"
+
+#: cmdline.opt:93
+msgid "Give this help list"
+msgstr "Visa denna hjälplista"
+
+#: cmdline.opt:93
+msgid "Give a short usage message"
+msgstr "Visa ett kort användningsmeddelande"
+
+#: cmdline.opt:93
+msgid "Print program version"
+msgstr "Skriv ut programversion"
+
+#: cmdline.opt:13
+msgid "GNU direvent monitors changes in directories"
+msgstr "GNU direvent övervakar ändringar i kataloger"
+
+#: cmdline.opt:15
+msgid "[CONFIG]"
+msgstr "[KONFIG]"
+
+#: cmdline.opt:95
+#, c-format
+msgid ""
+"The optional CONFIG argument supplies the name of the configuration file\n"
+"to use instead of %s.\n"
+"\n"
+msgstr ""
+"Det valfria KONFIG-argumentet tillhandahåller namnet på\n"
+"konfigurationsfilen att använda istället för %s.\n"
+"\n"
+
+#. TRANSLATORS: %s is one of: inotify, kqueue
+#: cmdline.opt:99
+#, c-format
+msgid ""
+"This direvent uses %s interface.\n"
+"\n"
+msgstr ""
+"Detta direvent använder gränssnittet %s.\n"
+"\n"
+
+#: cmdline.opt:102
+#, c-format
+msgid "Include search path:\n"
+msgstr "Sökväg för inkludering:\n"
+
+#: cmdline.opt:105
+#, c-format
+msgid "No include search path.\n"
+msgstr "Ingen sökväg för inkludering.\n"
+
+#: src/config.c:63
+#, c-format
+msgid "unknown syslog facility: %s"
+msgstr "okänd syslog-funktionalitet: %s"
+
+#: src/config.c:80
+#, c-format
+msgid "unknown syslog priority: %s"
+msgstr "okänd syslog-prioritet: %s"
+
+#: src/config.c:88
+msgid "unexpected block statement"
+msgstr "oväntad blocksats"
+
+#: src/config.c:97
+#, c-format
+msgid "expected %s"
+msgstr "förväntade %s"
+
+#: src/config.c:102
+#, c-format
+msgid "expected %s, but found %s"
+msgstr "förväntade %s, men hittade %s"
+
+#: src/config.c:124
+#, c-format
+msgid "unknown syslog facility `%s'"
+msgstr "okänd syslog-funktionalitet ”%s”"
+
+#: src/config.c:133 src/config.c:606
+msgid "name"
+msgstr "namn"
+
+#: src/config.c:134
+msgid ""
+"Set syslog facility. Arg is one of the following: user, daemon, auth, "
+"authpriv, mail, cron, local0 through local7 (case-insensitive), or a "
+"facility number."
+msgstr ""
+"Ställ in syslog-funktionalitet. Arg är en av följande: user, daemon, auth, "
+"authpriv, mail, cron, local0 till local7 (inte skiftlägeskänsligt), eller "
+"ett funktionalitetstal."
+
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
+msgid "string"
+msgstr "sträng"
+
+#: src/config.c:139
+msgid "Tag syslog messages with this string"
+msgstr "Tagga syslog-meddelanden med denna sträng"
+
+#: src/config.c:142 grecs/src/format.c:141
+msgid "arg"
+msgstr "arg"
+
+#: src/config.c:143
+msgid "Prefix each message with its priority"
+msgstr "Föregå varje meddelande med dess prioritet"
+
+#: src/config.c:191
+#, c-format
+msgid "%s: recursion depth does not match previous definition"
+msgstr "%s: rekursionsdjup matchar inte föregående definition"
+
+#: src/config.c:212
+msgid "no paths configured"
+msgstr "inga sökvägar konfigurerade"
+
+#: src/config.c:217
+msgid "no command configured"
+msgstr "inget kommando konfigurerat"
+
+#: src/config.c:229 grecs/src/tree.c:665
+msgid "invalid use of block statement"
+msgstr "ogiltig användning av blocksats"
+
+#: src/config.c:274
+msgid "expected \"recursive\" or end of statement"
+msgstr "förväntade ”recursive” eller slut på sats"
+
+#: src/config.c:289
+msgid "surplus argument"
+msgstr "överflödigt argument"
+
+#: src/config.c:295 src/config.c:446
+msgid "unexpected list"
+msgstr "oväntad lista"
+
+#: src/config.c:326 src/config.c:341 src/config.c:356
+msgid "unrecognized event code"
+msgstr "okänd händelsekod"
+
+#: src/config.c:438
+msgid "surplus arguments"
+msgstr "överflödiga argument"
+
+#: src/config.c:452
+msgid "no such user"
+msgstr "ingen sådan användare"
+
+#: src/config.c:459
+msgid "no such group"
+msgstr "ingen sådan grupp"
+
+#: src/config.c:501
+msgid "unrecognized option"
+msgstr "okänd flagga"
+
+#: src/config.c:595
+msgid "Pathname to watch"
+msgstr "Sökväg att övervaka"
+
+#: src/config.c:598
+msgid "Events to watch for"
+msgstr "Händelser att övervaka"
+
+#: src/config.c:601
+msgid "regexp"
+msgstr "reguttr"
+
+#: src/config.c:601
+msgid "Files to watch for"
+msgstr "Filer att övervaka"
+
+#: src/config.c:604
+msgid "Command to execute on event"
+msgstr "Kommando att exekvera vid händelse"
+
+#: src/config.c:606
+msgid "Run command as this user"
+msgstr "Kör kommando som denna användare"
+
+#: src/config.c:609
+msgid "seconds"
+msgstr "sekunder"
+
+#: src/config.c:609
+msgid "Timeout for the command"
+msgstr "Tidsgräns för kommandot"
+
+#: src/config.c:611
+msgid "List of additional options"
+msgstr "Lista över ytterligare flaggor"
+
+#: src/config.c:614
+msgid "<arg: string> <arg: string>..."
+msgstr "<arg: sträng> <arg: sträng>…"
+
+#: src/config.c:615
+msgid "Modify environment"
+msgstr "Modifiera miljö"
+
+#: src/config.c:622
+msgid "Run as this user"
+msgstr "Kör som denna användare"
+
+#: src/config.c:624
+msgid "Run in foreground"
+msgstr "Kör i förgrunden"
+
+#: src/config.c:626
+msgid "file"
+msgstr "fil"
+
+#: src/config.c:626
+msgid "Set pid file name"
+msgstr "Ställ in pid-filnamn"
+
+#: src/config.c:628
+msgid "Configure syslog logging"
+msgstr "Konfigurera syslog-loggning"
+
+#: src/config.c:630
+msgid "level"
+msgstr "nivå"
+
+#: src/config.c:630
+msgid "Set debug level"
+msgstr "Ställ in felsökningsnivå"
+
+#: src/config.c:632
+msgid "Configure event watcher"
+msgstr "Konfigurera händelseövervakare"
+
+#: src/config.c:643
+msgid ""
+"Configuration file structure for direvent.\n"
+"For more information, use `info direvent configuration'."
+msgstr ""
+"Konfigurationsfilstruktur för direvent.\n"
+"För mer information, använd ”info direvent configuration”."
+
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
+msgid "not enough memory"
+msgstr "för lite minne"
+
+#: src/direvent.c:274
+#, c-format
+msgid "cannot open pidfile %s for writing: %s"
+msgstr "det går inte att öppna pidfilen %s för skrivning: %s"
+
+#: src/direvent.c:302
+#, c-format
+msgid "no user with UID %lu"
+msgstr "ingen användare med UID %lu"
+
+#: src/direvent.c:420
+#, c-format
+msgid "cannot run `%s': fork failed: %s"
+msgstr "det går inte att köra ”%s”: ”fork” misslyckades: %s"
+
+#: src/direvent.c:480
+msgid "too many arguments"
+msgstr "för många argument"
+
+#: src/direvent.c:522
+#, c-format
+msgid "%s %s started"
+msgstr "%s %s startades"
+
+#: src/direvent.c:546
+#, c-format
+msgid "%s %s stopped"
+msgstr "%s %s stoppades"
+
+#: src/environ.c:25
+msgid "environment: "
+msgstr "miljö: "
+
+#: src/progman.c:142
+#, c-format
+msgid "process %lu exited successfully"
+msgstr "process %lu avslutades utan problem"
+
+#: src/progman.c:145
+#, c-format
+msgid "process %lu failed with status %d"
+msgstr "process %lu misslyckades med status %d"
+
+#: src/progman.c:155
+#, c-format
+msgid "process %lu terminated on signal %d"
+msgstr "process %lu avslutades av signal %d"
+
+#: src/progman.c:158
+#, c-format
+msgid "process %lu stopped on signal %d"
+msgstr "process %lu stoppades av signal %d"
+
+#: src/progman.c:163
+#, c-format
+msgid "process %lu dumped core"
+msgstr "process %lu skapade en minnesutskrift"
+
+#: src/progman.c:167
+#, c-format
+msgid "process %lu terminated with unrecognized status"
+msgstr "process %lu avslutades med okänd status"
+
+#: src/progman.c:228
+msgid "begin scanning process list"
+msgstr "börja genomsökning av processlista"
+
+#: src/progman.c:232
+#, c-format
+msgid "process %lu timed out"
+msgstr "tidsgräns överskreds för process %lu"
+
+#: src/progman.c:241
+#, c-format
+msgid "scheduling alarm in %lu seconds"
+msgstr "schemalägger alarm om %lu sekunder"
+
+#: src/progman.c:322
+#, c-format
+msgid "cannot start redirector for %s, pipe failed: %s"
+msgstr "det går inte att starta omdirigerare för %s, ”pipe” misslyckades: %s"
+
+#: src/progman.c:354
+#, c-format
+msgid "cannot run redirector `%s': fork failed: %s"
+msgstr "det går inte att köra omdirigeraren ”%s”, ”fork” misslyckades: %s"
+
+#: src/progman.c:359
+#, c-format
+msgid "redirector for %s started, pid=%lu"
+msgstr "omdirigerare för %s startades, pid=%lu"
+
+#: src/progman.c:455
+#, c-format
+msgid "starting %s, dir=%s, file=%s"
+msgstr "startar %s, kat=%s, fil=%s"
+
+#: src/progman.c:484
+#, c-format
+msgid "cannot change to %s: %s"
+msgstr "det går inte att byta katalog till %s: %s"
+
+#: src/progman.c:512
+#, c-format
+msgid "%s running; dir=%s, file=%s, pid=%lu"
+msgstr "%s kör; kat=%s, fil=%s, pid=%lu"
+
+#: src/progman.c:534
+#, c-format
+msgid "waiting for %s (%lu) to terminate"
+msgstr "väntar på att %s (%lu) ska avslutas"
+
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr "tar bort övervakare %s"
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
+#, c-format
+msgid "creating watcher %s"
+msgstr "skapar övervakare %s"
+
+#: src/watcher.c:281 src/watcher.c:296
+#, c-format
+msgid "cannot set watcher on %s: %s"
+msgstr "det går inte att ställa in övervakare på %s: %s"
+
+#: src/watcher.c:377
+#, c-format
+msgid "cannot create watcher %s/%s: not enough memory"
+msgstr "det går inte att skapa övervakare %s/%s: för lite minne"
+
+#: src/watcher.c:384
+#, c-format
+msgid "cannot create watcher %s/%s, stat failed: %s"
+msgstr "det går inte att skapa övervakaren %s/%s, ”stat” misslyckades: %s"
+
+#: src/watcher.c:430
+#, c-format
+msgid "cannot open directory %s: %s"
+msgstr "det går inte att öppna katalogen %s: %s"
+
+#: src/watcher.c:447
+#, c-format
+msgid "cannot stat %s/%s: not enough memory"
+msgstr "det går inte att ta status på %s/%s: för lite minne"
+
+#: src/watcher.c:452
+#, c-format
+msgid "cannot stat %s: %s"
+msgstr "det går inte att ta status på %s: %s"
+
+#: src/watcher.c:497
+msgid "no event handlers configured"
+msgstr "inga händelsehanterare konfigurerade"
+
+#: src/watcher.c:502
+msgid "no event handlers installed"
+msgstr "inga händelsehanterare installerade"
+
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+#, fuzzy
+msgid "hostname"
+msgstr "namn"
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
+msgstr ""
+
+#: grecs/src/format.c:133
+msgid "Disabled;"
+msgstr "Inaktiverad;"
+
+#: grecs/src/opthelp.c:123 grecs/src/opthelp.c:269
+msgid "Usage:"
+msgstr "Användning:"
+
+#: grecs/src/opthelp.c:127
+msgid "OPTION"
+msgstr "FLAGGA"
+
+#: grecs/src/opthelp.c:132 grecs/src/opthelp.c:427
+msgid "Aliases"
+msgstr "Alias"
+
+#: grecs/src/opthelp.c:132 grecs/src/opthelp.c:427
+msgid "Alias"
+msgstr "Alias"
+
+#: grecs/src/opthelp.c:186
+msgid ""
+"Mandatory or optional arguments to long options are also mandatory or "
+"optional for any corresponding short options."
+msgstr ""
+"Obligatoriska eller valfria argument till långa flaggor är också "
+"obligatoriska eller valfria för motsvarande korta flaggor."
+
+#. TRANSLATORS: The placeholder indicates the bug-reporting
+#. address for this package.  Please add _another line_ saying
+#. "Report translation bugs to <...>\n" with the address for
+#. translation bugs (typically your translation team's web or
+#. email address).
+#: grecs/src/opthelp.c:202
+#, c-format
+msgid "Report bugs to %s.\n"
+msgstr ""
+"Rapportera fel till %s\n"
+"Skicka synpunkter på översättningen till <tp-sv@listor.tp-sv.se>\n"
+
+#: grecs/src/opthelp.c:205
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "Webbsida för %s: <%s>\n"
+
+#. TRANSLATORS: Translate "(C)" to the copyright symbol
+#. (C-in-a-circle), if this symbol is available in the user's
+#. locale.  Otherwise, do not translate "(C)"; leave it as-is.
+#: grecs/src/opthelp.c:457
+msgid "(C)"
+msgstr "©"
+
+#: grecs/src/opthelp.c:466
+msgid ""
+"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl."
+"html>\n"
+"This is free software: you are free to change and redistribute it.\n"
+"There is NO WARRANTY, to the extent permitted by law.\n"
+"\n"
+msgstr ""
+"Licens GPLv3+: GNU GPL version 3 eller senare <http://gnu.org/licenses/gpl."
+"html>\n"
+"Det här är fri programvara: du får ändra och distribuera den.\n"
+"Det finns INGEN GARANTI, så långt som tillåts enligt lag.\n"
+"\n"
+
+#: grecs/src/opthelp.c:483
+msgid "Written by "
+msgstr "Skriven av "
+
+#. TRANSLATORS: This string is used as a delimiter between
+#. authors' names as in:
+#.
+#. Written by Winnie the Pooh, Piglet ...
+#.
+#: grecs/src/opthelp.c:489
+msgid ", "
+msgstr ", "
+
+#. TRANSLATORS: This string acts as a delimiter before the
+#. last author's names, e.g.:
+#.
+#. Written by Winnie the Pooh, Piglet and Christopher Robin.
+#.
+#: grecs/src/opthelp.c:495
+msgid " and "
+msgstr " och "
+
+#: grecs/src/path-parser.c:62
+#, c-format
+msgid "cannot open `%s'"
+msgstr "det går inte att öppna ”%s”"
+
+#: grecs/src/path-parser.c:108 grecs/src/path-parser.c:123
+msgid "unexpected end of file"
+msgstr "oväntat filslut"
+
+#: grecs/src/path-parser.c:143
+msgid "parse error"
+msgstr "tolkningsfel"
+
+#: grecs/src/preproc.c:448 grecs/src/preproc.c:470
+#, c-format
+msgid "Cannot stat `%s'"
+msgstr "Det går inte att ta status på ”%s”"
+
+#: grecs/src/preproc.c:453 grecs/src/preproc.c:458
+msgid "Recursive inclusion"
+msgstr "Rekursiv inkludering"
+
+#: grecs/src/preproc.c:461
+#, c-format
+msgid "`%s' already included here"
+msgstr "”%s” redan inkluderad här"
+
+#: grecs/src/preproc.c:465
+#, c-format
+msgid "`%s' already included at top level"
+msgstr "”%s” redan inkluderad på toppnivå"
+
+#: grecs/src/preproc.c:480
+#, c-format
+msgid "Cannot open `%s'"
+msgstr "Det går inte att öppna ”%s”"
+
+#: grecs/src/preproc.c:595
+msgid "Cannot parse include line"
+msgstr "Det går inte att tolka inkluderingsrad"
+
+#: grecs/src/preproc.c:598
+msgid "invalid include statement"
+msgstr "ogiltig inkluderingssats"
+
+#: grecs/src/preproc.c:624
+msgid "read error"
+msgstr "läsfel"
+
+#: grecs/src/preproc.c:632
+#, c-format
+msgid "%s: No such file or directory"
+msgstr "%s: Ingen sådan fil eller katalog"
+
+#: grecs/src/preproc.c:698
+#, c-format
+msgid "Unable to start external preprocessor `%s'"
+msgstr "Kan inte starta extern preprocessor ”%s”"
+
+#: grecs/src/preproc.c:773 grecs/src/preproc.c:793
+#, c-format
+msgid "Cannot run `%s'"
+msgstr "Det går inte att köra ”%s”"
+
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr "element hittades inte i tabell"
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr "symboltabellen är full"
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+#, fuzzy
+msgid "one or more arguments"
+msgstr "för många argument"
+
+#: grecs/src/tree.c:75
+#, fuzzy
+msgid "unrecognized type; please report"
+msgstr "okänd händelsekod"
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+#, fuzzy
+msgid "unknown keyword"
+msgstr "Okänt nyckelord"
+
+#: grecs/src/tree.c:360
+#, c-format
+msgid "%s: not a valid boolean value"
+msgstr "%s: inte ett giltigt booleskt värde"
+
+#: grecs/src/tree.c:391
+#, c-format
+msgid "%s: UNIX socket name too long"
+msgstr "%s: namn på UNIX-uttag (socket) för långt"
+
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
+#, c-format
+msgid "%s: not a valid IP address or hostname"
+msgstr "%s: inte en giltig IP-adress eller värdnamn"
+
+#: grecs/src/tree.c:444
+#, c-format
+msgid "%s: not a valid port number"
+msgstr "%s: inte ett giltigt portnummer"
+
+#: grecs/src/tree.c:452
+msgid "missing port number"
+msgstr "saknar portnummer"
+
+#: grecs/src/tree.c:501
+msgid "numeric overflow"
+msgstr "numeriskt överspill"
+
+#: grecs/src/tree.c:506
+msgid "value out of allowed range"
+msgstr "värde utanför tillåtet intervall"
+
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
+#, c-format
+msgid "not a number (stopped near `%s')"
+msgstr "inte ett tal (stoppade nära ”%s”)"
+
+#: grecs/src/tree.c:635
+#, c-format
+msgid "%s: not a valid IP address"
+msgstr "%s: inte en giltig IP-adress"
+
+#: grecs/src/tree.c:774
+#, c-format
+msgid "too many arguments to `%s'; missing semicolon?"
+msgstr "för många argument till ”%s”, saknas semikolon?"
+
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
+#, c-format
+msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
+msgstr "INTERNT FEL vid %s:%d: ohanterad datatyp %d"
+
+#: grecs/src/tree.c:803
+#, c-format
+msgid "%s: incompatible data type in list item #%d"
+msgstr "%s: inkompatibel datatyp i listpost #%d"
+
+#: grecs/src/tree.c:823
+#, c-format
+msgid "incompatible data type for `%s'"
+msgstr "inkompatibel datatyp för ”%s”"
+
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
+msgid "memory exhausted"
+msgstr "minne uttömt"
+
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:1607
+#, c-format
+msgid "%.*s: variable null or not set"
+msgstr "%.*s: variabel null eller inte inställd"
+
+#: grecs/wordsplit/wordsplit.c:1637
+#, c-format
+msgid "warning: undefined variable `%.*s'"
+msgstr "varning: odefinierad variabel ”%.*s”"
+
+#: grecs/wordsplit/wordsplit.c:2141
+#, c-format
+msgid "no files match pattern %s"
+msgstr "inga filer matchar mönstret %s"
+
+#: grecs/wordsplit/wordsplit.c:2603
+msgid "WS trimming"
+msgstr "blankteckentrimning"
+
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
+msgstr "kommandosubstitution"
+
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
+msgstr "förena lista"
+
+#: grecs/wordsplit/wordsplit.c:2609
+msgid "tilde expansion"
+msgstr "tilde-expansion"
+
+#: grecs/wordsplit/wordsplit.c:2611
+msgid "variable expansion"
+msgstr "variabelexpansion"
+
+#: grecs/wordsplit/wordsplit.c:2613
+msgid "quote removal"
+msgstr "citatborttagning"
+
+#: grecs/wordsplit/wordsplit.c:2617
+msgid "path expansion"
+msgstr "sökvägsexpansion"
+
+#: grecs/wordsplit/wordsplit.c:2642
+#, c-format
+msgid "(%02d) Input:%.*s;"
+msgstr "(%02d) Indata:%.*s;"
+
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
+msgstr "Ursprunglig lista:"
+
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr "Förenad lista:"
+
+#: grecs/wordsplit/wordsplit.c:2853
+msgid "no error"
+msgstr "inget fel"
+
+#: grecs/wordsplit/wordsplit.c:2854
+msgid "missing closing quote"
+msgstr "saknar avslutande citattecken"
+
+#: grecs/wordsplit/wordsplit.c:2856
+msgid "invalid wordsplit usage"
+msgstr "ogiltig orddelningsanvändning"
+
+#: grecs/wordsplit/wordsplit.c:2857
+msgid "unbalanced curly brace"
+msgstr "obalanserad klammerparentes"
+
+#: grecs/wordsplit/wordsplit.c:2858
+msgid "undefined variable"
+msgstr "odefinierad variabel"
+
+#: grecs/wordsplit/wordsplit.c:2859
+msgid "input exhausted"
+msgstr "slut på indata"
+
+#: grecs/wordsplit/wordsplit.c:2860
+msgid "unbalanced parenthesis"
+msgstr "obalanserad parentes"
+
+#: grecs/wordsplit/wordsplit.c:2861
+msgid "globbing error"
+msgstr "matchningsfel"
+
+#: grecs/wordsplit/wordsplit.c:2862
+#, fuzzy
+msgid "user-defined error"
+msgstr "läsfel"
+
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2875
+msgid "unknown error"
+msgstr "okänt fel"
+
+#: grecs/wordsplit/wordsplit.c:2884
+#, c-format
+msgid "missing closing %c (start near #%lu)"
+msgstr "saknar stängande %c (starten nära #%lu)"
+
+#~ msgid "unterminated regexp"
+#~ msgstr "oavslutat reguttr"
+
+#~ msgid "unrecognized flag: %c"
+#~ msgstr "okänd flagga: %c"
+
+#~ msgid "out of memory"
+#~ msgstr "slut på minne"
+
+#~ msgid "%s: unknown keyword"
+#~ msgstr "%s: okänt nyckelord"
+
+#~ msgid "(%02d) Restart:%.*s;"
+#~ msgstr "(%02d) Omstart:%.*s;"
diff --git a/po/uk.gmo b/po/uk.gmo
index 305ebd9..ed09a8d 100644
Binary files a/po/uk.gmo and b/po/uk.gmo differ
diff --git a/po/uk.po b/po/uk.po
index 2d25c99..76a94d6 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -3,19 +3,20 @@
 # Copyright (C) 2014 Sergey Poznyakoff
 # This file is distributed under the same license as the direvent package.
 #
-# Yuri Chornoivan <yurchor@ukr.net>, 2014.
+# Yuri Chornoivan <yurchor@ukr.net>, 2014, 2016.
 msgid ""
 msgstr ""
-"Project-Id-Version: direvent 4.1.91\n"
+"Project-Id-Version: direvent 5.1\n"
 "Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
-"POT-Creation-Date: 2016-07-06 17:50+0300\n"
-"PO-Revision-Date: 2014-09-02 12:25+0300\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
+"PO-Revision-Date: 2016-07-07 22:43+0300\n"
 "Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
 "Language-Team: Ukrainian <translation-team-uk@lists.sourceforge.net>\n"
 "Language: uk\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
 "X-Generator: Lokalize 1.5\n"
@@ -50,11 +51,11 @@ msgstr "не переходити у фоновий режим"
 
 #: cmdline.opt:53
 msgid "DIR"
-msgstr ""
+msgstr "КАТ"
 
 #: cmdline.opt:53
 msgid "add include directory"
-msgstr ""
+msgstr "додати каталог включення"
 
 #: cmdline.opt:59
 msgid "PROG"
@@ -136,12 +137,12 @@ msgstr ""
 #: cmdline.opt:102
 #, c-format
 msgid "Include search path:\n"
-msgstr ""
+msgstr "Шлях пошуку включень:\n"
 
 #: cmdline.opt:105
 #, c-format
 msgid "No include search path.\n"
-msgstr ""
+msgstr "Немає шляху пошуку включень.\n"
 
 #: src/config.c:63
 #, c-format
@@ -172,7 +173,7 @@ msgstr "мало бути %s, виявлено %s"
 msgid "unknown syslog facility `%s'"
 msgstr "невідомі можливості syslog: «%s»"
 
-#: src/config.c:133 src/config.c:706
+#: src/config.c:133 src/config.c:606
 msgid "name"
 msgstr "назва"
 
@@ -186,7 +187,7 @@ msgstr ""
 "рядків: user, daemon, auth, authpriv, mail, cron, local0 through local7 (без "
 "врахування регістру) або номер можливості."
 
-#: src/config.c:139
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
 msgid "string"
 msgstr "рядок"
 
@@ -202,142 +203,132 @@ msgstr "арг"
 msgid "Prefix each message with its priority"
 msgstr "Додавати перед кожним повідомленням його рівень пріоритетності"
 
-#: src/config.c:209
+#: src/config.c:191
 #, c-format
 msgid "%s: recursion depth does not match previous definition"
 msgstr "%s: глибина рекурсії не відповідає попередньому визначенню"
 
-#: src/config.c:247
+#: src/config.c:212
 msgid "no paths configured"
 msgstr "шляхів не налаштовано"
 
-#: src/config.c:252
+#: src/config.c:217
 msgid "no command configured"
 msgstr "команд не налаштовано"
 
-#: src/config.c:264 grecs/src/tree.c:634
+#: src/config.c:229 grecs/src/tree.c:665
 msgid "invalid use of block statement"
 msgstr "некоректне використання блокової команди"
 
-#: src/config.c:309
+#: src/config.c:274
 msgid "expected \"recursive\" or end of statement"
 msgstr "мало бути вказано «recursive» або завершено команду"
 
-#: src/config.c:324
+#: src/config.c:289
 msgid "surplus argument"
 msgstr "зайвий аргумент"
 
-#: src/config.c:330 src/config.c:481
+#: src/config.c:295 src/config.c:446
 msgid "unexpected list"
 msgstr "неочікуваний список"
 
-#: src/config.c:361 src/config.c:376 src/config.c:391
+#: src/config.c:326 src/config.c:341 src/config.c:356
 msgid "unrecognized event code"
 msgstr "нерозпізнаний код події"
 
-#: src/config.c:473
+#: src/config.c:438
 msgid "surplus arguments"
 msgstr "зайві аргументи"
 
-#: src/config.c:487
+#: src/config.c:452
 msgid "no such user"
 msgstr "такого запису користувача не існує"
 
-#: src/config.c:494
+#: src/config.c:459
 msgid "no such group"
 msgstr "такої групи немає"
 
-#: src/config.c:535
-#, fuzzy
+#: src/config.c:501
 msgid "unrecognized option"
-msgstr "нерозпізнаний прапорець"
-
-#: src/config.c:613
-msgid "unterminated regexp"
-msgstr "незавершений формальний вираз"
-
-#: src/config.c:627
-#, c-format
-msgid "unrecognized flag: %c"
-msgstr "нерозпізнаний прапорець: %c"
+msgstr "нерозпізнаний параметр"
 
-#: src/config.c:695
+#: src/config.c:595
 msgid "Pathname to watch"
 msgstr "Шлях до каталогу, за яким вестиметься спостереження"
 
-#: src/config.c:698
+#: src/config.c:598
 msgid "Events to watch for"
 msgstr "Події, за якими слід вести спостереження"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "regexp"
 msgstr "форм. вираз"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "Files to watch for"
 msgstr "Файли, за якими слід вести спостереження"
 
-#: src/config.c:704
+#: src/config.c:604
 msgid "Command to execute on event"
 msgstr "Команда, яку слід виконати, якщо станеться подія"
 
-#: src/config.c:706
+#: src/config.c:606
 msgid "Run command as this user"
 msgstr "Користувач, від імені якого слід виконати команду"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "seconds"
 msgstr "секунди"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "Timeout for the command"
 msgstr "Тайм-аут для команди"
 
-#: src/config.c:711
+#: src/config.c:611
 msgid "List of additional options"
 msgstr "Список додаткових параметрів"
 
-#: src/config.c:714
+#: src/config.c:614
 msgid "<arg: string> <arg: string>..."
 msgstr "<арг: рядок> <арг: рядок>..."
 
-#: src/config.c:715
+#: src/config.c:615
 msgid "Modify environment"
 msgstr "Змінити середовище"
 
-#: src/config.c:722
+#: src/config.c:622
 msgid "Run as this user"
 msgstr "Виконати від імені вказаного користувача"
 
-#: src/config.c:724
+#: src/config.c:624
 msgid "Run in foreground"
 msgstr "Не переходити у фоновий режим під час виконання"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "file"
 msgstr "файл"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "Set pid file name"
 msgstr "Встановити назву файла pid"
 
-#: src/config.c:728
+#: src/config.c:628
 msgid "Configure syslog logging"
 msgstr "Налаштувати ведення журналу syslog"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "level"
 msgstr "рівень"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "Set debug level"
 msgstr "Встановити рівень діагностики"
 
-#: src/config.c:732
+#: src/config.c:632
 msgid "Configure event watcher"
 msgstr "Налаштувати засіб стеження за подіями"
 
-#: src/config.c:743
+#: src/config.c:643
 msgid ""
 "Configuration file structure for direvent.\n"
 "For more information, use `info direvent configuration'."
@@ -345,36 +336,35 @@ msgstr ""
 "Структура файла налаштувань для direvent.\n"
 "Щоб дізнатися більше, віддайте команду «info direvent configuration»."
 
-#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:86 src/watcher.c:182
-#: src/watcher.c:191
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
 msgid "not enough memory"
 msgstr "недостатньо пам’яті"
 
-#: src/direvent.c:272
+#: src/direvent.c:274
 #, c-format
 msgid "cannot open pidfile %s for writing: %s"
 msgstr "не вдалося відкрити файл pid %s для запису даних: %s"
 
-#: src/direvent.c:300
+#: src/direvent.c:302
 #, c-format
 msgid "no user with UID %lu"
 msgstr "немає користувача з UID %lu"
 
-#: src/direvent.c:418
+#: src/direvent.c:420
 #, c-format
 msgid "cannot run `%s': fork failed: %s"
 msgstr "не вдалося запустити «%s»: помилка розгалуження: %s"
 
-#: src/direvent.c:478
+#: src/direvent.c:480
 msgid "too many arguments"
 msgstr "забагато аргументів"
 
-#: src/direvent.c:520
+#: src/direvent.c:522
 #, c-format
 msgid "%s %s started"
 msgstr "Запущено %s %s"
 
-#: src/direvent.c:541
+#: src/direvent.c:546
 #, c-format
 msgid "%s %s stopped"
 msgstr "Завершено роботу %s %s"
@@ -383,18 +373,6 @@ msgstr "Завершено роботу %s %s"
 msgid "environment: "
 msgstr "середовище: "
 
-#: src/hashtab.c:140 grecs/src/symtab.c:206
-msgid "element not found in table"
-msgstr "елемента немає у таблиці"
-
-#: src/hashtab.c:142 grecs/src/symtab.c:208
-msgid "symbol table is full"
-msgstr "у таблиці символів не залишилося місця"
-
-#: src/hashtab.c:144
-msgid "out of memory"
-msgstr "недостатньо пам’яті"
-
 #: src/progman.c:142
 #, c-format
 msgid "process %lu exited successfully"
@@ -455,75 +433,125 @@ msgstr "не вдалося виконати переспрямовування
 msgid "redirector for %s started, pid=%lu"
 msgstr "запущено переспрямовування для %s, pid=%lu"
 
-#: src/progman.c:454
+#: src/progman.c:455
 #, c-format
 msgid "starting %s, dir=%s, file=%s"
 msgstr "розпочинаємо роботу %s, каталог=%s, файл=%s"
 
-#: src/progman.c:482
+#: src/progman.c:484
 #, c-format
 msgid "cannot change to %s: %s"
 msgstr "не вдалося перейти до %s: %s"
 
-#: src/progman.c:510
+#: src/progman.c:512
 #, c-format
 msgid "%s running; dir=%s, file=%s, pid=%lu"
 msgstr "працює %s; каталог=%s, файл=%s, pid=%lu"
 
-#: src/progman.c:532
+#: src/progman.c:534
 #, c-format
 msgid "waiting for %s (%lu) to terminate"
 msgstr "очікуємо на завершення роботи %s (%lu)"
 
-#: src/watcher.c:231
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr "вилучаємо стеження %s"
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
 #, c-format
 msgid "creating watcher %s"
 msgstr "створюємо засіб стеження %s"
 
-#: src/watcher.c:240
+#: src/watcher.c:281 src/watcher.c:296
 #, c-format
 msgid "cannot set watcher on %s: %s"
 msgstr "не вдалося встановити стеження за %s: %s"
 
-#: src/watcher.c:319
+#: src/watcher.c:377
 #, c-format
 msgid "cannot create watcher %s/%s: not enough memory"
 msgstr "не вдалося створити засіб стеження %s/%s, недостатньо пам’яті"
 
-#: src/watcher.c:326
+#: src/watcher.c:384
 #, c-format
 msgid "cannot create watcher %s/%s, stat failed: %s"
 msgstr ""
 "не вдалося створити засіб стеження %s/%s, помилка отримання статистичних "
 "даних: %s"
 
-#: src/watcher.c:355
+#: src/watcher.c:430
 #, c-format
 msgid "cannot open directory %s: %s"
 msgstr "не вдалося відкрити каталог %s: %s"
 
-#: src/watcher.c:371
+#: src/watcher.c:447
 #, c-format
 msgid "cannot stat %s/%s: not enough memory"
 msgstr "не вдалося отримати статистичні дані щодо %s/%s: недостатньо пам’яті"
 
-#: src/watcher.c:376
+#: src/watcher.c:452
 #, c-format
 msgid "cannot stat %s: %s"
 msgstr "не вдалося отримати статистичні дані щодо %s: %s"
 
-#: src/watcher.c:412
+#: src/watcher.c:497
 msgid "no event handlers configured"
 msgstr "не налаштовано жодного обробника подій"
 
-#: src/watcher.c:417
+#: src/watcher.c:502
 msgid "no event handlers installed"
 msgstr "не встановлено жодного обробника подій"
 
-#: src/watcher.c:425
-#, c-format
-msgid "removing watcher %s"
-msgstr "вилучаємо стеження %s"
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+#, fuzzy
+msgid "hostname"
+msgstr "назва"
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
+msgstr ""
 
 #: grecs/src/format.c:133
 msgid "Disabled;"
@@ -658,9 +686,8 @@ msgid "invalid include statement"
 msgstr "некоректна команда включення"
 
 #: grecs/src/preproc.c:624
-#, fuzzy
 msgid "read error"
-msgstr "помилка обробки"
+msgstr "помилка читання"
 
 #: grecs/src/preproc.c:632
 #, c-format
@@ -677,186 +704,236 @@ msgstr "Не вдалося запустити зовнішній засіб п
 msgid "Cannot run `%s'"
 msgstr "Не вдалося виконати «%s»"
 
-#: grecs/src/tree.c:329
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr "елемента немає у таблиці"
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr "у таблиці символів не залишилося місця"
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+#, fuzzy
+msgid "one or more arguments"
+msgstr "забагато аргументів"
+
+#: grecs/src/tree.c:75
+#, fuzzy
+msgid "unrecognized type; please report"
+msgstr "нерозпізнаний код події"
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+#, fuzzy
+msgid "unknown keyword"
+msgstr "Невідоме ключове слово"
+
+#: grecs/src/tree.c:360
 #, c-format
 msgid "%s: not a valid boolean value"
 msgstr "%s: не є коректним булевим значенням"
 
-#: grecs/src/tree.c:360
+#: grecs/src/tree.c:391
 #, c-format
 msgid "%s: UNIX socket name too long"
 msgstr "%s: назва сокета UNIX є надто довгою"
 
-#: grecs/src/tree.c:389 grecs/src/tree.c:613
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
 #, c-format
 msgid "%s: not a valid IP address or hostname"
 msgstr "%s: не є коректною IP-адресою або назвою вузла"
 
-#: grecs/src/tree.c:413
+#: grecs/src/tree.c:444
 #, c-format
 msgid "%s: not a valid port number"
 msgstr "%s: не є коректним номером порту"
 
-#: grecs/src/tree.c:421
+#: grecs/src/tree.c:452
 msgid "missing port number"
 msgstr "не вказано номера порту"
 
-#: grecs/src/tree.c:470
+#: grecs/src/tree.c:501
 msgid "numeric overflow"
 msgstr "переповнення числового типу"
 
-#: grecs/src/tree.c:475
+#: grecs/src/tree.c:506
 msgid "value out of allowed range"
 msgstr "значення поза припустимим діапазоном"
 
-#: grecs/src/tree.c:510 grecs/src/tree.c:540
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
 #, c-format
 msgid "not a number (stopped near `%s')"
 msgstr "не є числом (зупинено у районі «%s»)"
 
-#: grecs/src/tree.c:604
+#: grecs/src/tree.c:635
 #, c-format
 msgid "%s: not a valid IP address"
 msgstr "%s: не є коректною IP-адресою"
 
-#: grecs/src/tree.c:743
+#: grecs/src/tree.c:774
 #, c-format
 msgid "too many arguments to `%s'; missing semicolon?"
 msgstr "забагато аргументів до «%s»; пропущено крапку з комою?"
 
-#: grecs/src/tree.c:757 grecs/src/tree.c:805
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
 #, c-format
 msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
 msgstr "ВНУТРІШНЯ ПОМИЛКА, %s:%d: непридатний до обробки тип даних %d"
 
-#: grecs/src/tree.c:772
+#: grecs/src/tree.c:803
 #, c-format
 msgid "%s: incompatible data type in list item #%d"
 msgstr "%s: несумісний тип даних у пункті списку %d"
 
-#: grecs/src/tree.c:792
+#: grecs/src/tree.c:823
 #, c-format
 msgid "incompatible data type for `%s'"
 msgstr "несумісний тип даних для «%s»"
 
-#: grecs/src/tree.c:920 grecs/src/tree.c:930
-msgid "Unknown keyword"
-msgstr "Невідоме ключове слово"
-
-#: grecs/src/tree.c:1139
-#, c-format
-msgid "%s: unknown keyword"
-msgstr "%s: невідоме ключове слово"
-
-#: grecs/src/wordsplit.c:62 grecs/src/wordsplit.c:2300
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
 msgid "memory exhausted"
 msgstr "пам'ять вичерпано"
 
-#: grecs/src/wordsplit.c:1073
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:1607
 #, c-format
 msgid "%.*s: variable null or not set"
-msgstr ""
+msgstr "%.*s: змінна порожня або її значення не встановлено"
 
-#: grecs/src/wordsplit.c:1102
+#: grecs/wordsplit/wordsplit.c:1637
 #, c-format
 msgid "warning: undefined variable `%.*s'"
 msgstr "попередження: невизначена змінна «%.*s»"
 
-#: grecs/src/wordsplit.c:1630
+#: grecs/wordsplit/wordsplit.c:2141
 #, c-format
 msgid "no files match pattern %s"
-msgstr ""
+msgstr "жоден файл не відповідає зразку %s"
 
-#: grecs/src/wordsplit.c:2080
+#: grecs/wordsplit/wordsplit.c:2603
 msgid "WS trimming"
-msgstr ""
+msgstr "Обрізання пробілів"
 
-#: grecs/src/wordsplit.c:2081
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
+msgstr "заміна команд"
+
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
+msgstr "об’єднати список"
+
+#: grecs/wordsplit/wordsplit.c:2609
 msgid "tilde expansion"
-msgstr ""
+msgstr "розгортання тильди"
 
-#: grecs/src/wordsplit.c:2082
+#: grecs/wordsplit/wordsplit.c:2611
 msgid "variable expansion"
-msgstr ""
+msgstr "розгортання змінних"
 
-#: grecs/src/wordsplit.c:2084
+#: grecs/wordsplit/wordsplit.c:2613
 msgid "quote removal"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2086
-#, fuzzy
-msgid "command substitution"
-msgstr "підтримки заміни команд у поточній версії ще не передбачено"
-
-#: grecs/src/wordsplit.c:2088
-msgid "coalesce list"
-msgstr ""
+msgstr "вилучення лапок"
 
-#: grecs/src/wordsplit.c:2090
+#: grecs/wordsplit/wordsplit.c:2617
 msgid "path expansion"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2120
-msgid "Initial list:"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2136
-#, fuzzy
-msgid "Coalesced list:"
-msgstr "неочікуваний список"
+msgstr "розгортання шляху"
 
-#: grecs/src/wordsplit.c:2190
+#: grecs/wordsplit/wordsplit.c:2642
 #, c-format
 msgid "(%02d) Input:%.*s;"
-msgstr ""
+msgstr "(%02d) Вхідні дані:%.*s;"
 
-#: grecs/src/wordsplit.c:2202
-#, c-format
-msgid "(%02d) Restart:%.*s;"
-msgstr ""
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
+msgstr "Початковий список:"
+
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr "Об’єднаний список:"
 
-#: grecs/src/wordsplit.c:2298
+#: grecs/wordsplit/wordsplit.c:2853
 msgid "no error"
 msgstr "без помилок"
 
-#: grecs/src/wordsplit.c:2299
+#: grecs/wordsplit/wordsplit.c:2854
 msgid "missing closing quote"
 msgstr "пропущено кінцеві лапки"
 
-#: grecs/src/wordsplit.c:2301
+#: grecs/wordsplit/wordsplit.c:2856
 msgid "invalid wordsplit usage"
 msgstr "некоректне використання поділу слів"
 
-#: grecs/src/wordsplit.c:2302
+#: grecs/wordsplit/wordsplit.c:2857
 msgid "unbalanced curly brace"
 msgstr "незакрита фігурна дужка"
 
-#: grecs/src/wordsplit.c:2303
+#: grecs/wordsplit/wordsplit.c:2858
 msgid "undefined variable"
 msgstr "невизначена змінна"
 
-#: grecs/src/wordsplit.c:2304
+#: grecs/wordsplit/wordsplit.c:2859
 msgid "input exhausted"
 msgstr "вичерпано вхідні дані"
 
-#: grecs/src/wordsplit.c:2305
+#: grecs/wordsplit/wordsplit.c:2860
 msgid "unbalanced parenthesis"
-msgstr ""
+msgstr "дужка без відповідника"
 
-#: grecs/src/wordsplit.c:2306
-#, fuzzy
+#: grecs/wordsplit/wordsplit.c:2861
 msgid "globbing error"
-msgstr "без помилок"
+msgstr "помилка використання замінників"
+
+#: grecs/wordsplit/wordsplit.c:2862
+#, fuzzy
+msgid "user-defined error"
+msgstr "помилка читання"
 
-#: grecs/src/wordsplit.c:2318
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2875
 msgid "unknown error"
 msgstr "невідома помилка"
 
-#: grecs/src/wordsplit.c:2327
+#: grecs/wordsplit/wordsplit.c:2884
 #, c-format
 msgid "missing closing %c (start near #%lu)"
 msgstr "пропущено кінцеве %c (початок у районі %lu)"
 
+#~ msgid "unterminated regexp"
+#~ msgstr "незавершений формальний вираз"
+
+#~ msgid "unrecognized flag: %c"
+#~ msgstr "нерозпізнаний прапорець: %c"
+
+#~ msgid "out of memory"
+#~ msgstr "недостатньо пам’яті"
+
+#~ msgid "%s: unknown keyword"
+#~ msgstr "%s: невідоме ключове слово"
+
+#~ msgid "(%02d) Restart:%.*s;"
+#~ msgstr "(%02d) Перезапуск:%.*s;"
+
 #~ msgid "INTERNAL ERROR at %s:%d"
 #~ msgstr "ВНУТРІШНЯ ПОМИЛКА, %s:%d"
 
diff --git a/po/vi.gmo b/po/vi.gmo
index ce0ec32..6d266b0 100644
Binary files a/po/vi.gmo and b/po/vi.gmo differ
diff --git a/po/vi.po b/po/vi.po
index 481cd73..6f86edc 100644
--- a/po/vi.po
+++ b/po/vi.po
@@ -1,23 +1,25 @@
 # Vietnamese translations for direvent package.
 # Bản dịch tiếng Việt cho gói direvent.
-# Copyright (C) 2014 Free Software Foundation, Inc.
-# Copyright (C) 2014 Sergey Poznyakoff (msgid).
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# Copyright (C) 2016 Sergey Poznyakoff (msgid).
 # This file is distributed under the same license as the direvent package.
-# Trần Ngọc Quân <vnwildman@gmail.com>, 2014.
+# Trần Ngọc Quân <vnwildman@gmail.com>, 2014, 2016.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: direvent 4.1.91\n"
+"Project-Id-Version: direvent 5.1\n"
 "Report-Msgid-Bugs-To: bug-direvent@gnu.org.ua\n"
-"POT-Creation-Date: 2016-07-06 17:50+0300\n"
-"PO-Revision-Date: 2014-09-03 07:54+0700\n"
+"POT-Creation-Date: 2019-07-13 19:23+0300\n"
+"PO-Revision-Date: 2016-07-08 07:55+0700\n"
 "Last-Translator: Trần Ngọc Quân <vnwildman@gmail.com>\n"
 "Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n"
 "Language: vi\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Gtranslator 2.91.7\n"
 
 #: cmdline.opt:26
 msgid "increase debug level"
@@ -49,11 +51,11 @@ msgstr "vẫn ở trên tiền cảnh"
 
 #: cmdline.opt:53
 msgid "DIR"
-msgstr ""
+msgstr "TMỤC"
 
 #: cmdline.opt:53
 msgid "add include directory"
-msgstr ""
+msgstr "thêm thư mục bao gồm"
 
 #: cmdline.opt:59
 msgid "PROG"
@@ -135,12 +137,12 @@ msgstr ""
 #: cmdline.opt:102
 #, c-format
 msgid "Include search path:\n"
-msgstr ""
+msgstr "Đường dẫn tìm kiếm bao gồm:\n"
 
 #: cmdline.opt:105
 #, c-format
 msgid "No include search path.\n"
-msgstr ""
+msgstr "Đường dẫn tìm kiếm không bao gồm:\n"
 
 #: src/config.c:63
 #, c-format
@@ -171,7 +173,7 @@ msgstr "cần %s, nhưng lại nhận được %s"
 msgid "unknown syslog facility `%s'"
 msgstr "không hiểu cơ sở hạ tầng ghi nhật ký “%s”"
 
-#: src/config.c:133 src/config.c:706
+#: src/config.c:133 src/config.c:606
 msgid "name"
 msgstr "tên"
 
@@ -185,7 +187,7 @@ msgstr ""
 "authpriv, mail, cron, local0 đến local7 (phân biệt HOA/thường), hoặc là số "
 "của cơ sở hạ tầng."
 
-#: src/config.c:139
+#: src/config.c:139 grecs/src/format.c:36 grecs/src/tree.c:69
 msgid "string"
 msgstr "chuỗi"
 
@@ -201,142 +203,132 @@ msgstr "đối-số"
 msgid "Prefix each message with its priority"
 msgstr "Nối thêm tiền tố từng lời nhắn bằng mức ưu tiên của nó"
 
-#: src/config.c:209
+#: src/config.c:191
 #, c-format
 msgid "%s: recursion depth does not match previous definition"
 msgstr "%s: độ sâu đệ quy không khớp với định nghĩa trước đó"
 
-#: src/config.c:247
+#: src/config.c:212
 msgid "no paths configured"
 msgstr "chưa có đường dẫn nào được cấu hình"
 
-#: src/config.c:252
+#: src/config.c:217
 msgid "no command configured"
 msgstr "chưa cấu hình lệnh nào"
 
-#: src/config.c:264 grecs/src/tree.c:634
+#: src/config.c:229 grecs/src/tree.c:665
 msgid "invalid use of block statement"
 msgstr "cách dùng biểu thức khối không hợp lệ"
 
-#: src/config.c:309
+#: src/config.c:274
 msgid "expected \"recursive\" or end of statement"
 msgstr "cần \"recursive\" hoặc kết thúc câu lệnh"
 
-#: src/config.c:324
+#: src/config.c:289
 msgid "surplus argument"
 msgstr "tham số thừa"
 
-#: src/config.c:330 src/config.c:481
+#: src/config.c:295 src/config.c:446
 msgid "unexpected list"
 msgstr "gặp danh sách không cần"
 
-#: src/config.c:361 src/config.c:376 src/config.c:391
+#: src/config.c:326 src/config.c:341 src/config.c:356
 msgid "unrecognized event code"
 msgstr "không nhận ra mã sự kiện"
 
-#: src/config.c:473
+#: src/config.c:438
 msgid "surplus arguments"
 msgstr "các đối số thừa"
 
-#: src/config.c:487
+#: src/config.c:452
 msgid "no such user"
 msgstr "không có người dùng như vậy"
 
-#: src/config.c:494
+#: src/config.c:459
 msgid "no such group"
 msgstr "không có nhóm như vậy"
 
-#: src/config.c:535
-#, fuzzy
+#: src/config.c:501
 msgid "unrecognized option"
-msgstr "không nhận ra cờ"
-
-#: src/config.c:613
-msgid "unterminated regexp"
-msgstr "biểu thức chính quy chưa được chấm dứt"
-
-#: src/config.c:627
-#, c-format
-msgid "unrecognized flag: %c"
-msgstr "không nhận ra cờ: “%c”"
+msgstr "không nhận ra tùy chọn"
 
-#: src/config.c:695
+#: src/config.c:595
 msgid "Pathname to watch"
 msgstr "Tên đường dẫn cần theo dõi"
 
-#: src/config.c:698
+#: src/config.c:598
 msgid "Events to watch for"
 msgstr "Sự kiện cần theo dõi"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "regexp"
 msgstr "BTCQ"
 
-#: src/config.c:701
+#: src/config.c:601
 msgid "Files to watch for"
 msgstr "Các tập tin cần theo dõi"
 
-#: src/config.c:704
+#: src/config.c:604
 msgid "Command to execute on event"
 msgstr "Lệnh thực thi cho sự kiện"
 
-#: src/config.c:706
+#: src/config.c:606
 msgid "Run command as this user"
 msgstr "Chạy lệnh dưới tư cách người dùng này"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "seconds"
 msgstr "giây"
 
-#: src/config.c:709
+#: src/config.c:609
 msgid "Timeout for the command"
 msgstr "Thời gian chờ lệnh tối đa"
 
-#: src/config.c:711
+#: src/config.c:611
 msgid "List of additional options"
 msgstr "Danh sách các tùy chọn bổ xung"
 
-#: src/config.c:714
+#: src/config.c:614
 msgid "<arg: string> <arg: string>..."
-msgstr "<đối-số: chuỗi> <đối-số: chuỗi>..."
+msgstr "<đối-số: chuỗi> <đối-số: chuỗi>…"
 
-#: src/config.c:715
+#: src/config.c:615
 msgid "Modify environment"
 msgstr "Biến đổi biến môi trường"
 
-#: src/config.c:722
+#: src/config.c:622
 msgid "Run as this user"
 msgstr "chạy như là người dùng này"
 
-#: src/config.c:724
+#: src/config.c:624
 msgid "Run in foreground"
 msgstr "Chạy trên nền"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "file"
 msgstr "tập_tin"
 
-#: src/config.c:726
+#: src/config.c:626
 msgid "Set pid file name"
 msgstr "Đặt tên tập tin lưu mã số tiến trình"
 
-#: src/config.c:728
+#: src/config.c:628
 msgid "Configure syslog logging"
 msgstr "Cấu hình ghi nhật ký syslog"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "level"
 msgstr "mức"
 
-#: src/config.c:730
+#: src/config.c:630
 msgid "Set debug level"
 msgstr "Đặt mức gỡ lỗi"
 
-#: src/config.c:732
+#: src/config.c:632
 msgid "Configure event watcher"
 msgstr "Cấu hình bộ theo dõi sự kiện"
 
-#: src/config.c:743
+#: src/config.c:643
 msgid ""
 "Configuration file structure for direvent.\n"
 "For more information, use `info direvent configuration'."
@@ -344,36 +336,35 @@ msgstr ""
 "Cấu trúc tập tin cấu hình cho direvent.\n"
 "Để biết thêm thông tin vui lòng xem “info direvent configuration”."
 
-#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:86 src/watcher.c:182
-#: src/watcher.c:191
+#: src/direvent.c:142 src/direvent.c:164 src/watcher.c:93 src/watcher.c:125
 msgid "not enough memory"
 msgstr "không đủ bộ nhớ"
 
-#: src/direvent.c:272
+#: src/direvent.c:274
 #, c-format
 msgid "cannot open pidfile %s for writing: %s"
 msgstr "không thể mở tập-tin mã số tiến trình %s để ghi: %s"
 
-#: src/direvent.c:300
+#: src/direvent.c:302
 #, c-format
 msgid "no user with UID %lu"
 msgstr "không có người dùng với mã số là %lu"
 
-#: src/direvent.c:418
+#: src/direvent.c:420
 #, c-format
 msgid "cannot run `%s': fork failed: %s"
 msgstr "không thể chạy “%s”: gặp lỗi khi rẽ nhánh tiến trình: %s"
 
-#: src/direvent.c:478
+#: src/direvent.c:480
 msgid "too many arguments"
 msgstr "quá nhiều đối số"
 
-#: src/direvent.c:520
+#: src/direvent.c:522
 #, c-format
 msgid "%s %s started"
 msgstr "%s %s đã chạy"
 
-#: src/direvent.c:541
+#: src/direvent.c:546
 #, c-format
 msgid "%s %s stopped"
 msgstr "%s %s đã dừng"
@@ -382,18 +373,6 @@ msgstr "%s %s đã dừng"
 msgid "environment: "
 msgstr "môi trường: "
 
-#: src/hashtab.c:140 grecs/src/symtab.c:206
-msgid "element not found in table"
-msgstr "phần tử không tìm thấy trong bảng"
-
-#: src/hashtab.c:142 grecs/src/symtab.c:208
-msgid "symbol table is full"
-msgstr "bảng ký hiệu đã đầy"
-
-#: src/hashtab.c:144
-msgid "out of memory"
-msgstr "hết bộ nhớ"
-
 #: src/progman.c:142
 #, c-format
 msgid "process %lu exited successfully"
@@ -454,73 +433,123 @@ msgstr ""
 msgid "redirector for %s started, pid=%lu"
 msgstr "bộ chuyển hướng cho %s đã khởi chạy, pid=%lu"
 
-#: src/progman.c:454
+#: src/progman.c:455
 #, c-format
 msgid "starting %s, dir=%s, file=%s"
 msgstr "đang khởi chạy %s, thư-mục=%s, tập-tin=%s"
 
-#: src/progman.c:482
+#: src/progman.c:484
 #, c-format
 msgid "cannot change to %s: %s"
 msgstr "không thể chuyển đổi sang %s: %s"
 
-#: src/progman.c:510
+#: src/progman.c:512
 #, c-format
 msgid "%s running; dir=%s, file=%s, pid=%lu"
 msgstr "%s đang chạy; thư-mục=%s, tập-tin=%s, mã-số-tiến-trình=%lu"
 
-#: src/progman.c:532
+#: src/progman.c:534
 #, c-format
 msgid "waiting for %s (%lu) to terminate"
 msgstr "chờ %s (%lu) chấm dứt"
 
-#: src/watcher.c:231
+#: src/watcher.c:183 src/watcher.c:513
+#, c-format
+msgid "removing watcher %s"
+msgstr "gỡ bỏ bộ theo dõi %s"
+
+#: src/watcher.c:195
+msgid "no watchers left; exiting now"
+msgstr ""
+
+#: src/watcher.c:262
+#, c-format
+msgid "installing CREATE sentinel for %s"
+msgstr ""
+
+#: src/watcher.c:275
 #, c-format
 msgid "creating watcher %s"
 msgstr "đang tạo bộ theo dõi %s"
 
-#: src/watcher.c:240
+#: src/watcher.c:281 src/watcher.c:296
 #, c-format
 msgid "cannot set watcher on %s: %s"
 msgstr "không thể đặt bộ theo dõi trên %s: %s"
 
-#: src/watcher.c:319
+#: src/watcher.c:377
 #, c-format
 msgid "cannot create watcher %s/%s: not enough memory"
 msgstr "không thể tạo bộ theo dõi %s/%s: không đủ bộ nhớ"
 
-#: src/watcher.c:326
+#: src/watcher.c:384
 #, c-format
 msgid "cannot create watcher %s/%s, stat failed: %s"
 msgstr "không thể tạo bộ theo dõi %s/%s, gặp lỗi khi lấy thống kê: %s"
 
-#: src/watcher.c:355
+#: src/watcher.c:430
 #, c-format
 msgid "cannot open directory %s: %s"
 msgstr "không thể mở thư mục %s: %s"
 
-#: src/watcher.c:371
+#: src/watcher.c:447
 #, c-format
 msgid "cannot stat %s/%s: not enough memory"
 msgstr "không thể lấy thống kê %s/%s: không đủ bộ nhớ"
 
-#: src/watcher.c:376
+#: src/watcher.c:452
 #, c-format
 msgid "cannot stat %s: %s"
 msgstr "không thể lấy thống kê %s: %s"
 
-#: src/watcher.c:412
+#: src/watcher.c:497
 msgid "no event handlers configured"
 msgstr "chưa cấu hình bộ tiếp hợp sự kiện nào"
 
-#: src/watcher.c:417
+#: src/watcher.c:502
 msgid "no event handlers installed"
 msgstr "chưa cài đặt bộ tiếp hợp sự kiện nào"
 
-#: src/watcher.c:425
-#, c-format
-msgid "removing watcher %s"
-msgstr "gỡ bỏ bộ theo dõi %s"
+#: grecs/src/format.c:33
+msgid "void"
+msgstr ""
+
+#: grecs/src/format.c:46
+msgid "number"
+msgstr ""
+
+#: grecs/src/format.c:49
+msgid "time"
+msgstr ""
+
+#: grecs/src/format.c:52
+msgid "boolean"
+msgstr ""
+
+#: grecs/src/format.c:55
+msgid "IPv4"
+msgstr ""
+
+#: grecs/src/format.c:58
+msgid "CIDR"
+msgstr ""
+
+#: grecs/src/format.c:61
+#, fuzzy
+msgid "hostname"
+msgstr "tên"
+
+#: grecs/src/format.c:64
+msgid "sockaddr"
+msgstr ""
+
+#: grecs/src/format.c:67
+msgid "section"
+msgstr ""
+
+#: grecs/src/format.c:70
+msgid "null"
+msgstr ""
 
 #: grecs/src/format.c:133
 msgid "Disabled;"
@@ -657,9 +686,8 @@ msgid "invalid include statement"
 msgstr "câu lệnh bao gồm sai"
 
 #: grecs/src/preproc.c:624
-#, fuzzy
 msgid "read error"
-msgstr "lỗi phân tích cú pháp"
+msgstr "lỗi đọc"
 
 #: grecs/src/preproc.c:632
 #, c-format
@@ -676,186 +704,236 @@ msgstr "Không thể khởi động bộ tiền xử lý bên ngoài “%s”"
 msgid "Cannot run `%s'"
 msgstr " Không thể chạy “%s”"
 
-#: grecs/src/tree.c:329
+#: grecs/src/symtab.c:236
+msgid "element not found in table"
+msgstr "phần tử không tìm thấy trong bảng"
+
+#: grecs/src/symtab.c:238
+msgid "symbol table is full"
+msgstr "bảng ký hiệu đã đầy"
+
+#: grecs/src/tree.c:70
+msgid "list"
+msgstr ""
+
+#: grecs/src/tree.c:71
+#, fuzzy
+msgid "one or more arguments"
+msgstr "quá nhiều đối số"
+
+#: grecs/src/tree.c:75
+#, fuzzy
+msgid "unrecognized type; please report"
+msgstr "không nhận ra mã sự kiện"
+
+#: grecs/src/tree.c:320
+msgid "section keyword used as a scalar"
+msgstr ""
+
+#: grecs/src/tree.c:322
+msgid "scalar keyword used as a section"
+msgstr ""
+
+#: grecs/src/tree.c:325
+#, fuzzy
+msgid "unknown keyword"
+msgstr "Không hiểu từ khóa"
+
+#: grecs/src/tree.c:360
 #, c-format
 msgid "%s: not a valid boolean value"
 msgstr "%s: không phải là giá trị lô gíc"
 
-#: grecs/src/tree.c:360
+#: grecs/src/tree.c:391
 #, c-format
 msgid "%s: UNIX socket name too long"
 msgstr "%s: tên ổ cắm UNIX quá dài"
 
-#: grecs/src/tree.c:389 grecs/src/tree.c:613
+#: grecs/src/tree.c:420 grecs/src/tree.c:644
 #, c-format
 msgid "%s: not a valid IP address or hostname"
 msgstr "%s: không phải là địa chỉ IP hay tên máy hợp lệ"
 
-#: grecs/src/tree.c:413
+#: grecs/src/tree.c:444
 #, c-format
 msgid "%s: not a valid port number"
 msgstr "%s: số hiệu cổng không hợp lệ"
 
-#: grecs/src/tree.c:421
+#: grecs/src/tree.c:452
 msgid "missing port number"
 msgstr "thiếu số hiệu của cổng"
 
-#: grecs/src/tree.c:470
+#: grecs/src/tree.c:501
 msgid "numeric overflow"
 msgstr "tràn số"
 
-#: grecs/src/tree.c:475
+#: grecs/src/tree.c:506
 msgid "value out of allowed range"
 msgstr "số nằm ngoài phạm vi được phép"
 
-#: grecs/src/tree.c:510 grecs/src/tree.c:540
+#: grecs/src/tree.c:541 grecs/src/tree.c:571
 #, c-format
 msgid "not a number (stopped near `%s')"
 msgstr "không là kiểu số (dừng ở gần “%s”)"
 
-#: grecs/src/tree.c:604
+#: grecs/src/tree.c:635
 #, c-format
 msgid "%s: not a valid IP address"
 msgstr "%s: không phải là địa chỉ IP hợp lệ"
 
-#: grecs/src/tree.c:743
+#: grecs/src/tree.c:774
 #, c-format
 msgid "too many arguments to `%s'; missing semicolon?"
-msgstr "quá nhiều đối số cho “%s'; thiếu dấu chấm phẩy à?"
+msgstr "quá nhiều đối số cho “%s”; thiếu dấu chấm phẩy à?"
 
-#: grecs/src/tree.c:757 grecs/src/tree.c:805
+#: grecs/src/tree.c:788 grecs/src/tree.c:836
 #, c-format
 msgid "INTERNAL ERROR at %s:%d: unhandled data type %d"
 msgstr "LỖI NỘI TẠI ở %s:%d: kiểu dữ liệu không thể xử lý %d"
 
-#: grecs/src/tree.c:772
+#: grecs/src/tree.c:803
 #, c-format
 msgid "%s: incompatible data type in list item #%d"
 msgstr "%s: kiểu dữ liệu không tương thích trong mục tin #%d của danh sách"
 
-#: grecs/src/tree.c:792
+#: grecs/src/tree.c:823
 #, c-format
 msgid "incompatible data type for `%s'"
 msgstr "kiểu dữ liệu không tương thích với “%s”"
 
-#: grecs/src/tree.c:920 grecs/src/tree.c:930
-msgid "Unknown keyword"
-msgstr "Không hiểu từ khóa"
-
-#: grecs/src/tree.c:1139
-#, c-format
-msgid "%s: unknown keyword"
-msgstr "%s: không hiểu từ khóa"
-
-#: grecs/src/wordsplit.c:62 grecs/src/wordsplit.c:2300
+#: grecs/wordsplit/wordsplit.c:69 grecs/wordsplit/wordsplit.c:2855
 msgid "memory exhausted"
 msgstr "hết bộ nhớ"
 
-#: grecs/src/wordsplit.c:1073
+#: grecs/wordsplit/wordsplit.c:121
+msgid "memory exhausted while trying to store error context"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:868
+msgid "Restarting"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:1607
 #, c-format
 msgid "%.*s: variable null or not set"
-msgstr ""
+msgstr "%.*s: biến null hoặc chưa được đặt"
 
-#: grecs/src/wordsplit.c:1102
+#: grecs/wordsplit/wordsplit.c:1637
 #, c-format
 msgid "warning: undefined variable `%.*s'"
 msgstr "cảnh báo: chưa định nghĩa biến “%.*s”"
 
-#: grecs/src/wordsplit.c:1630
+#: grecs/wordsplit/wordsplit.c:2141
 #, c-format
 msgid "no files match pattern %s"
-msgstr ""
+msgstr "không có tập tin nào khớp mẫu %s"
 
-#: grecs/src/wordsplit.c:2080
+#: grecs/wordsplit/wordsplit.c:2603
 msgid "WS trimming"
-msgstr ""
+msgstr "cắt WS"
 
-#: grecs/src/wordsplit.c:2081
+#: grecs/wordsplit/wordsplit.c:2605
+msgid "command substitution"
+msgstr "thay thế lệnh"
+
+#: grecs/wordsplit/wordsplit.c:2607 grecs/wordsplit/wordsplit.c:2615
+msgid "coalesce list"
+msgstr "co danh sách"
+
+#: grecs/wordsplit/wordsplit.c:2609
 msgid "tilde expansion"
-msgstr ""
+msgstr "khai triển dấu ~"
 
-#: grecs/src/wordsplit.c:2082
+#: grecs/wordsplit/wordsplit.c:2611
 msgid "variable expansion"
-msgstr ""
+msgstr "khai triển biến"
 
-#: grecs/src/wordsplit.c:2084
+#: grecs/wordsplit/wordsplit.c:2613
 msgid "quote removal"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2086
-#, fuzzy
-msgid "command substitution"
-msgstr "lệnh thay thế vẫn chưa được hỗ trợ"
-
-#: grecs/src/wordsplit.c:2088
-msgid "coalesce list"
-msgstr ""
+msgstr "gỡ bỏ dấu trích dẫn"
 
-#: grecs/src/wordsplit.c:2090
+#: grecs/wordsplit/wordsplit.c:2617
 msgid "path expansion"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2120
-msgid "Initial list:"
-msgstr ""
-
-#: grecs/src/wordsplit.c:2136
-#, fuzzy
-msgid "Coalesced list:"
-msgstr "gặp danh sách không cần"
+msgstr "khai triển đường dẫn"
 
-#: grecs/src/wordsplit.c:2190
+#: grecs/wordsplit/wordsplit.c:2642
 #, c-format
 msgid "(%02d) Input:%.*s;"
-msgstr ""
+msgstr "(%02d) Đầu vào:%.*s;"
 
-#: grecs/src/wordsplit.c:2202
-#, c-format
-msgid "(%02d) Restart:%.*s;"
-msgstr ""
+#: grecs/wordsplit/wordsplit.c:2668
+msgid "Initial list:"
+msgstr "Danh sách khởi tạo:"
+
+#: grecs/wordsplit/wordsplit.c:2683
+msgid "Coalesced list:"
+msgstr "Danh sách đã co:"
 
-#: grecs/src/wordsplit.c:2298
+#: grecs/wordsplit/wordsplit.c:2853
 msgid "no error"
 msgstr "không lỗi"
 
-#: grecs/src/wordsplit.c:2299
+#: grecs/wordsplit/wordsplit.c:2854
 msgid "missing closing quote"
 msgstr "thiếu dấu trích dẫn đóng"
 
-#: grecs/src/wordsplit.c:2301
+#: grecs/wordsplit/wordsplit.c:2856
 msgid "invalid wordsplit usage"
 msgstr "cách dùng wordsplit (tách chữ) không hợp lệ"
 
-#: grecs/src/wordsplit.c:2302
+#: grecs/wordsplit/wordsplit.c:2857
 msgid "unbalanced curly brace"
 msgstr "chưa khớp cặp dấu ngoặc"
 
-#: grecs/src/wordsplit.c:2303
+#: grecs/wordsplit/wordsplit.c:2858
 msgid "undefined variable"
 msgstr "biến chưa được định nghĩa"
 
-#: grecs/src/wordsplit.c:2304
+#: grecs/wordsplit/wordsplit.c:2859
 msgid "input exhausted"
 msgstr "đầu vào đã hết"
 
-#: grecs/src/wordsplit.c:2305
+#: grecs/wordsplit/wordsplit.c:2860
 msgid "unbalanced parenthesis"
-msgstr ""
+msgstr "Chưa đủ cặp ngoặc đơn"
 
-#: grecs/src/wordsplit.c:2306
-#, fuzzy
+#: grecs/wordsplit/wordsplit.c:2861
 msgid "globbing error"
-msgstr "không lỗi"
+msgstr "lỗi globbing"
+
+#: grecs/wordsplit/wordsplit.c:2862
+#, fuzzy
+msgid "user-defined error"
+msgstr "lỗi đọc"
 
-#: grecs/src/wordsplit.c:2318
+#: grecs/wordsplit/wordsplit.c:2863
+msgid "invalid parameter number in assignment"
+msgstr ""
+
+#: grecs/wordsplit/wordsplit.c:2875
 msgid "unknown error"
 msgstr "lỗi không rõ"
 
-#: grecs/src/wordsplit.c:2327
+#: grecs/wordsplit/wordsplit.c:2884
 #, c-format
 msgid "missing closing %c (start near #%lu)"
 msgstr "thiếu đóng %c (bắt đầu gần #%lu)"
 
+#~ msgid "unterminated regexp"
+#~ msgstr "biểu thức chính quy chưa được chấm dứt"
+
+#~ msgid "unrecognized flag: %c"
+#~ msgstr "không nhận ra cờ: “%c”"
+
+#~ msgid "out of memory"
+#~ msgstr "hết bộ nhớ"
+
+#~ msgid "%s: unknown keyword"
+#~ msgstr "%s: không hiểu từ khóa"
+
+#~ msgid "(%02d) Restart:%.*s;"
+#~ msgstr "(%02d) Khởi động lại:%.*s;"
+
 #~ msgid "INTERNAL ERROR at %s:%d"
 #~ msgstr "LỖI NỘI BỘ ở %s:%d"
 
diff --git a/src/Makefile.am b/src/Makefile.am
index b6f4201..df09967 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,7 +23,7 @@ direvent_SOURCES=\
  environ.c\
  event.c\
  fnpat.c\
- hashtab.c\
+ handler.c\
  watcher.c\
  progman.c\
  sigv.c
@@ -44,6 +44,7 @@ endif
 LDADD=@GRECS_LDADD@ @LIBINTL@
 AM_CPPFLAGS=\
  @GRECS_INCLUDES@\
+ -DSYSCONFDIR=\"$(sysconfdir)\"\
  -DLOCALEDIR=\"$(localedir)\"\
  -DINCLUDE_PATH_ARGS='$(INCLUDE_PATH_ARGS)'
 
diff --git a/src/Makefile.in b/src/Makefile.in
index 8ba9af7..fc52206 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -32,7 +32,17 @@
 
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -101,8 +111,6 @@ bin_PROGRAMS = direvent$(EXEEXT)
 @DIREVENT_KQUEUE_TRUE@@DIREVENT_RFORK_TRUE@am__append_3 = detach-bsd.c
 @DIREVENT_KQUEUE_TRUE@@DIREVENT_RFORK_FALSE@am__append_4 = detach-darwin.c
 subdir = src
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp $(noinst_HEADERS)
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/am/gettext.m4 $(top_srcdir)/am/iconv.m4 \
@@ -113,6 +121,8 @@ am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+	$(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -120,7 +130,7 @@ CONFIG_CLEAN_VPATH_FILES =
 am__installdirs = "$(DESTDIR)$(bindir)"
 PROGRAMS = $(bin_PROGRAMS)
 am__direvent_SOURCES_DIST = direvent.c direvent.h cmdline.h config.c \
-	environ.c event.c fnpat.c hashtab.c watcher.c progman.c sigv.c \
+	environ.c event.c fnpat.c handler.c watcher.c progman.c sigv.c \
 	ev_inotify.c detach-std.c ev_kqueue.c detach-bsd.c \
 	detach-darwin.c
 @DIREVENT_INOTIFY_TRUE@am__objects_1 = ev_inotify.$(OBJEXT) \
@@ -130,7 +140,7 @@ am__direvent_SOURCES_DIST = direvent.c direvent.h cmdline.h config.c \
 @DIREVENT_KQUEUE_TRUE@@DIREVENT_RFORK_FALSE@am__objects_4 = detach-darwin.$(OBJEXT)
 am_direvent_OBJECTS = direvent.$(OBJEXT) config.$(OBJEXT) \
 	environ.$(OBJEXT) event.$(OBJEXT) fnpat.$(OBJEXT) \
-	hashtab.$(OBJEXT) watcher.$(OBJEXT) progman.$(OBJEXT) \
+	handler.$(OBJEXT) watcher.$(OBJEXT) progman.$(OBJEXT) \
 	sigv.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
 	$(am__objects_3) $(am__objects_4)
 direvent_OBJECTS = $(am_direvent_OBJECTS)
@@ -191,6 +201,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -222,7 +234,9 @@ GRECS_CHANGELOG = @GRECS_CHANGELOG@
 GRECS_DISTCK_AT = @GRECS_DISTCK_AT@
 GRECS_DISTDOC = @GRECS_DISTDOC@
 GRECS_DOCDIR = @GRECS_DOCDIR@
+GRECS_EXTRA_DIST = @GRECS_EXTRA_DIST@
 GRECS_HOST_PROJECT_INCLUDES = @GRECS_HOST_PROJECT_INCLUDES@
+GRECS_HOST_PROJECT_LDADD = @GRECS_HOST_PROJECT_LDADD@
 GRECS_INCLUDES = @GRECS_INCLUDES@
 GRECS_INCLUDE_DIR = @GRECS_INCLUDE_DIR@
 GRECS_LDADD = @GRECS_LDADD@
@@ -332,12 +346,13 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 direvent_SOURCES = direvent.c direvent.h cmdline.h config.c environ.c \
-	event.c fnpat.c hashtab.c watcher.c progman.c sigv.c \
+	event.c fnpat.c handler.c watcher.c progman.c sigv.c \
 	$(am__append_1) $(am__append_2) $(am__append_3) \
 	$(am__append_4)
 LDADD = @GRECS_LDADD@ @LIBINTL@
 AM_CPPFLAGS = \
  @GRECS_INCLUDES@\
+ -DSYSCONFDIR=\"$(sysconfdir)\"\
  -DLOCALEDIR=\"$(localedir)\"\
  -DINCLUDE_PATH_ARGS='$(INCLUDE_PATH_ARGS)'
 
@@ -362,7 +377,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits src/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnits src/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -459,7 +473,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ev_kqueue.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fnpat.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hashtab.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/handler.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/progman.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sigv.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/watcher.Po@am__quote@
@@ -685,6 +699,8 @@ uninstall-am: uninstall-binPROGRAMS
 	mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am uninstall-binPROGRAMS
 
+.PRECIOUS: Makefile
+
 .opt.h:
 	$(AM_V_GEN)m4 -s $(top_srcdir)/@GRECS_SUBDIR@/build-aux/getopt.m4 $< > $@
 
diff --git a/src/cmdline.h b/src/cmdline.h
index fb85f8a..c747cf7 100644
--- a/src/cmdline.h
+++ b/src/cmdline.h
@@ -1,4 +1,4 @@
-#line 416 "../grecs/build-aux/getopt.m4"
+#line 424 "../grecs/build-aux/getopt.m4"
 /* -*- buffer-read-only: t -*- vi: set ro:
    THIS FILE IS GENERATED AUTOMATICALLY.  PLEASE DO NOT EDIT.
 */
@@ -621,6 +621,8 @@ parse_options(int argc, char *argv[], int *index)
 	}
 #line 111
     }
+#line 111
+
 #line 111
   *index = optind;
 #line 111
diff --git a/src/config.c b/src/config.c
index 1ab990f..3bbe36b 100644
--- a/src/config.c
+++ b/src/config.c
@@ -148,85 +148,50 @@ static struct grecs_keyword syslog_kw[] = {
 
 struct eventconf {
 	struct grecs_list *pathlist;
-        event_mask eventmask;
-	struct grecs_list *fnames;
-	char *command;
-	uid_t uid;           /* Run as this user (unless 0) */
-	gid_t *gidv;         /* Run with these groups' privileges */
-	size_t gidc;         /* Number of elements in gidv */
-	unsigned timeout;
-	int flags;
-	char **env;
+	event_mask ev_mask;
+	filpatlist_t fpat;
+	struct prog_handler prog_handler;
 };
 
 static struct eventconf eventconf;
 
 static void
-envfree(char **env)
-{
-	int i;
-
-	if (!env)
-		return;
-	for (i = 0; env[i]; i++)
-		free(env[i]);
-	free(env);
-}
-
-static void
-eventconf_init()
+eventconf_init(void)
 {
 	memset(&eventconf, 0, sizeof eventconf);
-	eventconf.timeout = DEFAULT_TIMEOUT;
+	eventconf.prog_handler.timeout = DEFAULT_TIMEOUT;
 }
 
 static void
-eventconf_free()
+eventconf_free(void)
 {
 	grecs_list_free(eventconf.pathlist);
-	grecs_list_free(eventconf.fnames);
-	free(eventconf.command);
-	free(eventconf.gidv);
-	envfree(eventconf.env);
+	prog_handler_free(&eventconf.prog_handler);
+	filpatlist_destroy(&eventconf.fpat);
 }
 
 void
 eventconf_flush(grecs_locus_t *loc)
 {
 	struct grecs_list_entry *ep;
-	
+	struct handler *hp = prog_handler_alloc(eventconf.ev_mask,
+						eventconf.fpat,
+						&eventconf.prog_handler);
+
 	for (ep = eventconf.pathlist->head; ep; ep = ep->next) {
 		struct pathent *pe = ep->data;
-		struct dirwatcher *dwp;
-		struct handler *hp;
+		struct watchpoint *wpt;
 		int isnew;
 		
-		dwp = dirwatcher_install(pe->path, &isnew);
-		if (!dwp)
+		wpt = watchpoint_install(pe->path, &isnew);
+		if (!wpt)
 			abort();
-		if (!isnew && dwp->depth != pe->depth)
+		if (!isnew && wpt->depth != pe->depth)
 			grecs_error(loc, 0,
 				    _("%s: recursion depth does not match previous definition"),
 				    pe->path);
-		dwp->depth = pe->depth;
-		
-		hp = emalloc(sizeof(*hp));
-		hp->next = NULL;
-		hp->ev_mask = eventconf.eventmask;
-		hp->fnames = eventconf.fnames;
-		hp->flags = eventconf.flags;
-		hp->timeout = eventconf.timeout;
-		hp->prog = eventconf.command;
-		hp->uid = eventconf.uid;
-		hp->gidc = eventconf.gidc;
-		hp->gidv = eventconf.gidv;
-		hp->env = eventconf.env;
-		
-		if (dwp->handler_tail)
-			dwp->handler_tail->next = hp;
-		else
-			dwp->handler_list = hp;
-		dwp->handler_tail = hp;
+		wpt->depth = pe->depth;
+		handler_list_append(wpt->handler_list, hp);
 	}
 	grecs_list_free(eventconf.pathlist);
 	eventconf_init();
@@ -247,13 +212,13 @@ cb_watcher(enum grecs_callback_command cmd, grecs_node_t *node,
 			grecs_error(&node->locus, 0, _("no paths configured"));
 			++err;
 		}
-		if (!eventconf.command) {
+		if (!eventconf.prog_handler.command) {
 			grecs_error(&node->locus, 0,
 				    _("no command configured"));
 			++err;
 		}
-		if (evtnullp(&eventconf.eventmask))
-			evtsetall(&eventconf.eventmask);
+		if (evtnullp(&eventconf.ev_mask))
+			evtsetall(&eventconf.ev_mask);
 		if (err == 0)
 			eventconf_flush(&node->locus);
 		else
@@ -498,8 +463,9 @@ cb_user(enum grecs_callback_command cmd, grecs_node_t *node,
 	} else
 		gid = pw->pw_gid;
 
-	eventconf.uid = pw->pw_uid;
-	get_user_groups(uv->v.string, gid, &eventconf.gidc, &eventconf.gidv);
+	eventconf.prog_handler.uid = pw->pw_uid;
+	get_user_groups(uv->v.string, gid,
+			&eventconf.prog_handler.gidc, &eventconf.prog_handler.gidv);
 	
 	return 0;
 }
@@ -522,15 +488,15 @@ cb_option(enum grecs_callback_command cmd, grecs_node_t *node,
 					    GRECS_TYPE_STRING))
 			return 1;
 		if (strcmp(vp->v.string, "nowait") == 0)
-			eventconf.flags |= HF_NOWAIT;
+			eventconf.prog_handler.flags |= HF_NOWAIT;
 		else if (strcmp(vp->v.string, "wait") == 0)
-			eventconf.flags &= ~HF_NOWAIT;
+			eventconf.prog_handler.flags &= ~HF_NOWAIT;
 		else if (strcmp(vp->v.string, "stdout") == 0)
-			eventconf.flags |= HF_STDOUT;
+			eventconf.prog_handler.flags |= HF_STDOUT;
 		else if (strcmp(vp->v.string, "stderr") == 0)
-			eventconf.flags |= HF_STDERR;
+			eventconf.prog_handler.flags |= HF_STDERR;
 		else if (strcmp(vp->v.string, "shell") == 0)
-			eventconf.flags |= HF_SHELL;
+			eventconf.prog_handler.flags |= HF_SHELL;
 		else 
 			grecs_error(&vp->locus, 0, _("unrecognized option"));
 	}
@@ -544,7 +510,7 @@ cb_environ(enum grecs_callback_command cmd, grecs_node_t *node,
         grecs_locus_t *locus = &node->locus;
 	grecs_value_t *val = node->v.value;
 	struct grecs_list_entry *ep;
-	int i;
+	int i, j;
 	
 	ASSERT_SCALAR(cmd, locus);
 	switch (val->type) {
@@ -552,103 +518,44 @@ cb_environ(enum grecs_callback_command cmd, grecs_node_t *node,
 		if (assert_grecs_value_type(&val->locus, val,
 					    GRECS_TYPE_STRING))
 			return 1;
-		eventconf.env = ecalloc(2, sizeof(eventconf.env[0]));
-		eventconf.env[0] = estrdup(val->v.string);
-		eventconf.env[1] = NULL;
+		i = prog_handler_envrealloc(&eventconf.prog_handler, 1);
+		eventconf.prog_handler.env[i] = estrdup(val->v.string);
+		eventconf.prog_handler.env[i+1] = NULL;
 		break;
 		
 	case GRECS_TYPE_ARRAY:
-		eventconf.env = ecalloc(val->v.arg.c + 1,
-					sizeof(eventconf.env[0]));
-		for (i = 0; i < val->v.arg.c; i++) {
+		j = prog_handler_envrealloc(&eventconf.prog_handler, val->v.arg.c);
+		for (i = 0; i < val->v.arg.c; i++, j++) {
 			if (assert_grecs_value_type(&val->v.arg.v[i]->locus,
 						    val->v.arg.v[i],
 						    GRECS_TYPE_STRING))
 				return 1;
-			eventconf.env[i] = estrdup(val->v.arg.v[i]->v.string);
+			eventconf.prog_handler.env[j] = estrdup(val->v.arg.v[i]->v.string);
 		}
-		eventconf.env[i] = NULL;
+		eventconf.prog_handler.env[j] = NULL;
 		break;
 
 	case GRECS_TYPE_LIST:
-		eventconf.env = ecalloc(val->v.list->count + 1,
-					sizeof(eventconf.env[0]));
-		for (i = 0, ep = val->v.list->head; ep; ep = ep->next, i++) {
+		j = prog_handler_envrealloc(&eventconf.prog_handler,
+					    val->v.list->count);
+		for (ep = val->v.list->head; ep; ep = ep->next, j++) {
 			grecs_value_t *vp = ep->data;
 			if (assert_grecs_value_type(&vp->locus, vp,
 						    GRECS_TYPE_STRING))
 				return 1;
-			eventconf.env[i] = estrdup(vp->v.string);
+			eventconf.prog_handler.env[j] = estrdup(vp->v.string);
 		}
-		eventconf.env[i] = NULL;
+		eventconf.prog_handler.env[j] = NULL;
 	}
 	return 0;
 }		
 
 static int
-file_name_pattern(struct grecs_list *lp, grecs_value_t *val)
+file_name_pattern(filpatlist_t *fptr, grecs_value_t *val)
 {
-	char *arg;
-	int rc;
-	int flags = REG_EXTENDED|REG_NOSUB;
-	struct filename_pattern *pat;
-	
 	if (assert_grecs_value_type(&val->locus, val, GRECS_TYPE_STRING))
 		return 1;
-	arg = val->v.string;
-
-	pat = emalloc(sizeof(*pat));
-	if (*arg == '!') {
-		pat->neg = 1;
-		++arg;
-	} else
-		pat->neg = 0;
-	if (arg[0] == '/') {
-		char *q, *p;
-
-		pat->type = PAT_REGEX;
-		
-		p = strchr(arg+1, '/');
-		if (!p) {
-			grecs_error(&val->locus, 0, _("unterminated regexp"));
-			free(pat);
-			return 1;
-		}
-		for (q = p + 1; *q; q++) {
-			switch (*q) {
-			case 'b':
-				flags &= ~REG_EXTENDED;
-				break;
-			case 'i':
-				flags |= REG_ICASE;
-				break;
-			default:
-				grecs_error(&val->locus, 0,
-					    _("unrecognized flag: %c"), *q);
-				free(pat);
-				return 1;
-			}
-		}
-		
-		*p = 0;
-		rc = regcomp(&pat->v.re, arg + 1, flags);
-		*p = '/';
-
-		if (rc) {
-			char errbuf[128];
-			regerror(rc, &pat->v.re, errbuf, sizeof(errbuf));
-			grecs_error(&val->locus, 0, "%s", errbuf);
-			filename_pattern_free(pat);
-			return 1;
-		}
-	} else {
-		pat->type = PAT_GLOB;
-		pat->v.glob = estrdup(arg);
-	}
-
-	grecs_list_append(lp, pat);
-
-	return 0;
+	return filpatlist_add(fptr, val->v.string, &val->locus);
 }
 
 static int
@@ -656,33 +563,26 @@ cb_file_pattern(enum grecs_callback_command cmd, grecs_node_t *node,
 		void *varptr, void *cb_data)
 {
 	grecs_value_t *val = node->v.value;
+	filpatlist_t *fpat = varptr;
 	struct grecs_list_entry *ep;
-	struct grecs_list *lp, **lpp = varptr;
 	int i;
 	
 	ASSERT_SCALAR(cmd, &node->locus);
 
-	if (!*lpp) {
-		lp = grecs_list_create();
-		lp->free_entry = filename_pattern_free;
-		*lpp = lp;
-	} else
-		lp = *lpp;
-	
 	switch (val->type) {
 	case GRECS_TYPE_STRING:
-		file_name_pattern(lp, val);
+		file_name_pattern(fpat, val);
 		break;
 
 	case GRECS_TYPE_ARRAY:
 		for (i = 0; i < val->v.arg.c; i++)
-			if (file_name_pattern(lp, val->v.arg.v[i]))
+			if (file_name_pattern(fpat, val->v.arg.v[i]))
 				break;
 		break;
 
 	case GRECS_TYPE_LIST:
 		for (ep = val->v.list->head; ep; ep = ep->next)
-			if (file_name_pattern(lp,
+			if (file_name_pattern(fpat,
 					      (grecs_value_t *) ep->data))
 				break;
 		break;
@@ -696,18 +596,18 @@ static struct grecs_keyword watcher_kw[] = {
 	  grecs_type_string, GRECS_DFLT, &eventconf.pathlist, 0,
 	  cb_path },
 	{ "event", NULL, N_("Events to watch for"),
-	  grecs_type_string, GRECS_LIST, &eventconf.eventmask, 0,
+	  grecs_type_string, GRECS_LIST, &eventconf.ev_mask, 0,
 	  cb_eventlist },
 	{ "file", N_("regexp"), N_("Files to watch for"),
-	  grecs_type_string, GRECS_LIST, &eventconf.fnames, 0,
+	  grecs_type_string, GRECS_LIST, &eventconf.fpat, 0,
 	  cb_file_pattern },
 	{ "command", NULL, N_("Command to execute on event"),
-	  grecs_type_string, GRECS_DFLT, &eventconf.command },
+	  grecs_type_string, GRECS_DFLT, &eventconf.prog_handler.command },
 	{ "user", N_("name"), N_("Run command as this user"),
 	  grecs_type_string, GRECS_DFLT, NULL, 0,
 	  cb_user },
 	{ "timeout", N_("seconds"), N_("Timeout for the command"),
-	  grecs_type_uint, GRECS_DFLT, &eventconf.timeout },
+	  grecs_type_uint, GRECS_DFLT, &eventconf.prog_handler.timeout },
 	{ "option", NULL, N_("List of additional options"),
 	  grecs_type_string, GRECS_LIST, NULL, 0,
 	  cb_option },
@@ -757,6 +657,7 @@ config_parse(char const *conffile)
 {
 	struct grecs_node *tree;
 
+	grecs_parser_options = GRECS_OPTION_QUOTED_STRING_CONCAT;
 	tree = grecs_parse(conffile);
 	if (!tree)
 		exit(1);
diff --git a/src/direvent.c b/src/direvent.c
index c2d6cac..703026c 100644
--- a/src/direvent.c
+++ b/src/direvent.c
@@ -186,6 +186,8 @@ mkfilename(const char *dir, const char *file)
 	size_t fillen = strlen(file);
 	size_t len;
 
+	if (!file || file[0] == 0)
+		return strdup(dir);
 	while (dirlen > 0 && dir[dirlen-1] == '/')
 		dirlen--;
 
@@ -362,7 +364,7 @@ setuser(const char *user)
 }
 
 void
-ev_log(int flags, struct dirwatcher *dp)
+ev_log(int flags, struct watchpoint *dp)
 {
 	int i;
 	char *p;
@@ -536,8 +538,11 @@ main(int argc, char **argv)
 	while (!stop && sysev_select() == 0) {
 		process_timeouts();
 		process_cleanup(0);
+		watchpoint_gc();
 	}
 
+	shutdown_watchers();
+
 	diag(LOG_INFO, _("%s %s stopped"), program_name, VERSION);
 
 	if (pidfile)
diff --git a/src/direvent.h b/src/direvent.h
index 60808e6..0bdfac5 100644
--- a/src/direvent.h
+++ b/src/direvent.h
@@ -24,7 +24,8 @@
 #include <unistd.h>
 #include <signal.h>
 #include <regex.h>
-
+#include <grecs/list.h>
+#include <grecs/symtab.h>
 #include "gettext.h"
 
 #define _(s) gettext(s)
@@ -37,10 +38,10 @@
 #define GENEV_DELETE  0x08
 
 /* Handler flags. */
-#define HF_NOWAIT 0x01       /* Don't wait for termination */
-#define HF_STDOUT 0x02       /* Capture stdout */
-#define HF_STDERR 0x04       /* Capture stderr */
-#define HF_SHELL  0x08       /* Call program via /bin/sh -c */ 
+#define HF_NOWAIT  0x01   /* Don't wait for termination */
+#define HF_STDOUT  0x02   /* Capture stdout */
+#define HF_STDERR  0x04   /* Capture stderr */
+#define HF_SHELL   0x08   /* Call program via /bin/sh -c */ 
 
 #ifndef DEFAULT_TIMEOUT
 # define DEFAULT_TIMEOUT 5
@@ -57,11 +58,14 @@ struct transtab {
 	int tok;
 };
 
-#define PAT_GLOB  0
-#define PAT_REGEX 1
+enum pattern_type {
+	PAT_EXACT,
+	PAT_GLOB,
+	PAT_REGEX
+};
 
 struct filename_pattern {
-	int type;
+	enum pattern_type type;
 	int neg;
 	union {
 		regex_t re;
@@ -69,29 +73,40 @@ struct filename_pattern {
 	} v;
 };
 
+typedef struct filpatlist *filpatlist_t;
+
+struct watchpoint;
+
+typedef int (*event_handler_fn) (struct watchpoint *wp,
+				 event_mask *event,
+				 const char *dir,
+				 const char *file,
+				 void *data);
+typedef void (*handler_free_fn) (void *data);
+
 /* Handler structure */
 struct handler {
-	struct handler *next;
-	event_mask ev_mask;  /* Event mask */
-	struct grecs_list *fnames;  /* File name patterns */
-	int flags;           /* Handler flags */
-	const char *prog;    /* Handler program (with eventual arguments) */
-	uid_t uid;           /* Run as this user (unless 0) */
-	gid_t *gidv;         /* Run with these groups' privileges */
-	size_t gidc;         /* Number of elements in gidv */
-	unsigned timeout;    /* Handler timeout */
-	char **env;          /* Environment */
+	size_t refcnt;        /* Reference counter */
+	event_mask ev_mask;   /* Event mask */
+	filpatlist_t fnames;  /* File name patterns */
+	event_handler_fn run;
+	handler_free_fn free;
+	void *data;
 };
 
-/* A directory watcher is described by the following structure */
-struct dirwatcher {
-	int refcnt;
+typedef struct handler_list *handler_list_t;
+typedef struct handler_iterator *handler_iterator_t;
+
+/* Watchpoint links the directory being monitored and a list of
+   handlers for various events: */
+struct watchpoint {
+	size_t refcnt;
 	int wd;                              /* Watch descriptor */
-	struct dirwatcher *parent;           /* Points to the parent watcher.
+	struct watchpoint *parent;           /* Points to the parent watcher.
 					        NULL for top-level watchers */
 	char *dirname;                       /* Pathname being watched */
-	struct handler *handler_list;        /* List of handlers */
-	struct handler *handler_tail;        /* Tail of the handler list */
+	int isdir;                           /* Is it directory */
+	handler_list_t handler_list;         /* List of handlers */
 	int depth;                           /* Recursion depth */
 	char *split_p;                       /* Points to the deleted directory
 						separator in dirname (see
@@ -105,8 +120,26 @@ struct dirwatcher {
 
 #define __cat2__(a,b) a ## b
 #define handler_matches_event(h,m,f,n)		\
-	(((h)->ev_mask.__cat2__(m,_mask) & (f)) && \
-	 filename_pattern_match((h)->fnames, n) == 0)
+	(((h)->ev_mask.__cat2__(m,_mask) & (f)) &&	\
+	 filpatlist_match((h)->fnames, n) == 0)
+
+struct handler *handler_alloc(event_mask ev_mask);
+void handler_free(struct handler *hp);
+
+struct prog_handler {
+	int flags;     /* Handler flags */
+	char *command; /* Handler command (with eventual arguments) */
+	uid_t uid;     /* Run as this user (unless 0) */
+	gid_t *gidv;   /* Run with these groups' privileges */
+	size_t gidc;   /* Number of elements in gidv */
+	unsigned timeout; /* Handler timeout */
+	char **env;    /* Environment */
+};
+
+struct handler *prog_handler_alloc(event_mask ev_mask, filpatlist_t fpat,
+				   struct prog_handler *p);
+void prog_handler_free(struct prog_handler *);
+size_t prog_handler_envrealloc(struct prog_handler *hp, size_t count);
 
 
 extern int foreground;
@@ -140,10 +173,10 @@ void debugprt(const char *fmt, ...);
 void signal_setup(void (*sf) (int));
 int detach(void (*)(void));
 
-int sysev_filemask(struct dirwatcher *dp);
+int sysev_filemask(struct watchpoint *dp);
 void sysev_init(void);
-int sysev_add_watch(struct dirwatcher *dwp, event_mask mask);
-void sysev_rm_watch(struct dirwatcher *dwp);
+int sysev_add_watch(struct watchpoint *dwp, event_mask mask);
+void sysev_rm_watch(struct watchpoint *dwp);
 int sysev_select(void);
 int sysev_name_to_code(const char *name);
 const char *sysev_code_to_name(int code);
@@ -165,34 +198,6 @@ int trans_strtotok(struct transtab *tab, const char *str, int *ret);
 char *trans_toktostr(struct transtab *tab, int tok);
 char *trans_tokfirst(struct transtab *tab, int tok, int *next);
 char *trans_toknext(struct transtab *tab, int tok, int *next);
-
-
-struct hashtab;
-struct hashent {
-	int used;
-};
-int hashtab_replace(struct hashtab *st, void *ent, void **old_ent);
-const char *hashtab_strerror(int rc);
-int hashtab_remove(struct hashtab *st, void *elt);
-int hashtab_get_index(unsigned *idx, struct hashtab *st, void *key,
-		      int *install);
-void *hashtab_lookup_or_install(struct hashtab *st, void *key, int *install);
-void hashtab_clear(struct hashtab *st);
-struct hashtab *hashtab_create(size_t elsize, 
-			       unsigned (*hash_fun)(void *, unsigned long),
-			       int (*cmp_fun)(const void *, const void *),
-			       int (*copy_fun)(void *, void *),
-			       void *(*alloc_fun)(size_t),
-			       void (*free_fun)(void *));
-void hashtab_free(struct hashtab *st);
-size_t hashtab_count_entries(struct hashtab *st);
-
-typedef int (*hashtab_enumerator_t) (struct hashent *, void *);
-int hashtab_foreach(struct hashtab *st, hashtab_enumerator_t fun,
-		    void *data);
-size_t hashtab_count(struct hashtab *st);
-
-unsigned hash_string(const char *name, unsigned long hashsize);
 
 struct pathent {
 	long depth;
@@ -207,27 +212,61 @@ void config_parse(const char *file);
 int get_facility(const char *arg);
 int get_priority(const char *arg);
 
-void setup_watchers(void);
-struct dirwatcher *dirwatcher_lookup(const char *dirname);
-struct dirwatcher *dirwatcher_lookup_wd(int wd);
-int check_new_watcher(const char *dir, const char *name);
-struct dirwatcher *dirwatcher_install(const char *path, int *pnew);
-void dirwatcher_destroy(struct dirwatcher *dwp);
-int watch_pathname(struct dirwatcher *parent, const char *dirname, int isdir, int notify);
+int  watchpoint_init(struct watchpoint *dwp);
+void watchpoint_ref(struct watchpoint *dw);
+void watchpoint_unref(struct watchpoint *dw);
+void watchpoint_gc(void);
+
+int watchpoint_pattern_match(struct watchpoint *dwp, const char *file_name);
 
-char *split_pathname(struct dirwatcher *dp, char **dirname);
-void unsplit_pathname(struct dirwatcher *dp);
+void watchpoint_run_handlers(struct watchpoint *wp, int evflags,
+			      const char *dirname, const char *filename);
 
-void ev_log(int flags, struct dirwatcher *dp);
-void deliver_ev_create(struct dirwatcher *dp, const char *name);
-int subwatcher_create(struct dirwatcher *parent, const char *dirname,
-		      int isdir, int notify);
+
+void setup_watchers(void);
+void shutdown_watchers(void);
+
+struct watchpoint *watchpoint_lookup(const char *dirname);
+int check_new_watcher(const char *dir, const char *name);
+struct watchpoint *watchpoint_install(const char *path, int *pnew);
+struct watchpoint *watchpoint_install_ptr(struct watchpoint *dw);
+void watchpoint_suspend(struct watchpoint *dwp);
+void watchpoint_destroy(struct watchpoint *dwp);
+int watchpoint_install_sentinel(struct watchpoint *dwp);
+
+int watch_pathname(struct watchpoint *parent, const char *dirname, int isdir, int notify);
+
+char *split_pathname(struct watchpoint *dp, char **dirname);
+void unsplit_pathname(struct watchpoint *dp);
+
+void ev_log(int flags, struct watchpoint *dp);
+void deliver_ev_create(struct watchpoint *dp,
+		       const char *dirname, const char *filename);
+int subwatcher_create(struct watchpoint *parent, const char *dirname,
+		      int notify);
+
+struct handler *handler_itr_first(struct watchpoint *dp,
+				       handler_iterator_t *itr);
+struct handler *handler_itr_next(handler_iterator_t *itr);
+struct handler *handler_itr_current(handler_iterator_t itr);
+
+#define for_each_handler(d,i,h)				\
+	for (h = handler_itr_first(d, &(i));	\
+	     h;						\
+	     h = handler_itr_next(&(i)))
+	
+
+handler_list_t handler_list_create(void);
+handler_list_t handler_list_copy(handler_list_t);
+void handler_list_unref(handler_list_t hlist);
+void handler_list_append(handler_list_t hlist,
+				  struct handler *hp);
+size_t handler_list_remove(handler_list_t hlist, struct handler *hp);
+size_t handler_list_size(handler_list_t hlist);
 
 struct process *process_lookup(pid_t pid);
 void process_cleanup(int expect_term);
 void process_timeouts(void);
-int run_handler(struct handler *hp, event_mask *event,
-		const char *dir, const char *file);
 char **environ_setup(char **hint, char **kve);
 
 #define NITEMS(a) ((sizeof(a)/sizeof((a)[0])))
@@ -242,6 +281,11 @@ int sigv_set_all(void (*handler)(int), int sigc, int *sigv,
 int sigv_set_tab(int sigc, struct sigtab *sigtab, struct sigaction *retsa);
 int sigv_set_action_tab(int sigc, struct sigtab *sigtab, struct sigaction *sa);
 
-void filename_pattern_free(void *p);
-int filename_pattern_match(struct grecs_list *lp, const char *name);
+struct grecs_locus;
+int filpatlist_add(filpatlist_t *fptr, char const *arg,
+		   struct grecs_locus *loc);
+void filpatlist_add_exact(filpatlist_t *fptr, char const *arg);
+void filpatlist_destroy(filpatlist_t *fptr);
+int filpatlist_match(filpatlist_t fp, const char *name);
+int filpatlist_is_empty(filpatlist_t fp);
 
diff --git a/src/environ.c b/src/environ.c
index 659b724..eb22fbd 100644
--- a/src/environ.c
+++ b/src/environ.c
@@ -29,34 +29,45 @@ extern char **environ;    /* Environment */
 	}							\
 	} while (0)
 
-static char *
-find_env(const char *name, int val)
+static int
+find_env_pos(char **env, char *name, size_t *idx, size_t *valoff)
 {
-	if (environ) {
-		int nlen = strcspn(name, "+=");
-		int i;
-
-		for (i = 0; environ[i]; i++) {
-			size_t elen = strcspn(environ[i], "=");
-			if (elen == nlen &&
-			    memcmp(name, environ[i], nlen) == 0)
-				return val ? environ[i] + elen + 1 : environ[i];
+        size_t nlen = strcspn(name, "+=");
+        size_t i;
+
+        for (i = 0; env[i]; i++) {
+                size_t elen = strcspn(env[i], "=");
+                if (elen == nlen && memcmp(name, env[i], nlen) == 0) {
+			if (idx)
+				*idx = i;
+			if (valoff)
+				*valoff = elen + 1;
+			return 0;
 		}
-	}
-	return NULL;
+        }
+        return -1;
+}
+
+static char *
+find_env_ptr(char **env, char *name, int val)
+{
+	size_t i, j;
+	if (find_env_pos(env, name, &i, &j))
+		return NULL;
+	return val ? env[i] + j : env[i];
 }
 
 static int
-locate_unset(char **env, const char *name)
+var_is_unset(char **env, const char *name)
 {
 	int i;
 	int nlen = strcspn(name, "=");
 
 	for (i = 0; env[i]; i++) {
 		if (env[i][0] == '-') {
-			size_t elen = strcspn (env[i] + 1, "=");
+			size_t elen = strcspn(env[i] + 1, "=");
 			if (elen == nlen &&
-			    memcmp (name, env[i] + 1, nlen) == 0) {
+			    memcmp(name, env[i] + 1, nlen) == 0) {
 				if (env[i][nlen + 1])
 					return strcmp(name + nlen,
 						      env[i] + 1 + nlen) == 0;
@@ -77,7 +88,7 @@ env_concat(const char *name, size_t namelen, const char *a, const char *b)
 	if (a && b) {
 		res = emalloc(namelen + 1 + strlen(a) + strlen(b) + 1);
 		strcpy(res + namelen + 1, a);
-		strcat(res, b);
+		strcat(res + namelen + 1, b);
 	} else if (a) {
 		len = strlen(a);
 		if (ispunct(a[len-1]))
@@ -115,7 +126,7 @@ environ_setup(char **hint, char **kve)
 	char **new_env;
 	char **addenv = defenv;
 	char *var;
-	size_t count, i, n;
+	size_t count, i, j, n;
 	struct wordsplit ws;
 	int wsflags = WRDSF_NOCMD | WRDSF_QUOTE | WRDSF_NOSPLIT |
 		      WRDSF_ENV | WRDSF_ENV_KV;
@@ -154,12 +165,12 @@ environ_setup(char **hint, char **kve)
   
 	if (old_env)
 		for (i = 0; old_env[i]; i++) {
-			if (!locate_unset(hint, old_env[i]))
+			if (!var_is_unset(hint, old_env[i]))
 				new_env[n++] = old_env[i];
 		}
 
 	for (i = 0; addenv[i]; i++)
-		if (!locate_unset(hint, addenv[i])) {
+		if (!var_is_unset(hint, addenv[i])) {
 			if (wordsplit(addenv[i], &ws, wsflags)) {
 				diag(LOG_CRIT, "wordsplit: %s",
 				     wordsplit_strerror(&ws));
@@ -185,26 +196,36 @@ environ_setup(char **hint, char **kve)
 		wsflags |= WRDSF_REUSE;
 		var = ws.ws_wordv[0];
 		
+		/* Find the slot for the variable.  Use next available
+		   slot if there's no such variable in new_env */
+		if (find_env_pos(new_env, hint[i], &j, NULL))
+			j = n;
+			
 		if ((p = strchr(var, '='))) {
 			if (p == var)
 				continue; /* Ignore erroneous entry */
+
 			if (p[-1] == '+') 
-				new_env[n++] = env_concat(var,
-							  p - var - 1,
-							  find_env(var, 1),
-							  p + 1);
+				new_env[j] = env_concat(var,
+							p - var - 1,
+							find_env_ptr(environ,
+								     var, 1),
+							p + 1);
 			else if (p[1] == '+')
-				new_env[n++] = env_concat(var,
-							  p - var,
-							  p + 2,
-							  find_env(var, 1));
+				new_env[j] = env_concat(var,
+							p - var,
+							p + 2,
+							find_env_ptr(environ,
+								     var, 1));
 			else
-				new_env[n++] = estrdup(var);
-		} else {
-			p = find_env(var, 0);
-			if (p)
-				new_env[n++] = p;
-		}
+				new_env[j] = estrdup(var);
+                } else if ((p = find_env_ptr(environ, hint[i], 0)))
+			new_env[j] = p;
+		else
+			continue;
+		/* Adjust environment size */
+		if (j == n)
+			++n;
 	}
 	if (self_test_pid) {
 		char buf[512];
diff --git a/src/ev_inotify.c b/src/ev_inotify.c
index 83008ea..d79b5f0 100644
--- a/src/ev_inotify.c
+++ b/src/ev_inotify.c
@@ -45,8 +45,67 @@ event_mask genev_xlat[] = {
 
 static int ifd;
 
+static struct watchpoint **wptab;
+static size_t wpsize;
+
+static int
+wpreg(int wd, struct watchpoint *wpt)
+{
+	if (wd < 0)
+		abort();
+	if (wd >= wpsize) {
+		size_t n = wpsize;
+		struct watchpoint **p;
+
+		if (n == 0)
+			n = sysconf(_SC_OPEN_MAX);
+		while (wd >= n) {
+			n *= 2;
+			if (n < wpsize) {
+				diag(LOG_CRIT,
+				     _("can't allocate memory for fd %d"),
+				     wd);
+				return -1;
+			}
+		}
+		p = realloc(wptab, n * sizeof(wptab[0]));
+		if (!p) {
+			diag(LOG_CRIT,
+			     _("can't allocate memory for fd %d"),
+			     wd);
+			return -1;
+		}
+
+		memset(p + wpsize, 0, (n - wpsize) * sizeof(wptab[0]));
+		wptab = p;
+		wpsize = n;
+	}
+	watchpoint_ref(wpt);
+	wptab[wd] = wpt;
+	return 0;
+}
+
+static void
+wpunreg(int wd)
+{
+	if (wd < 0 || wd > wpsize)
+		abort();
+	if (wptab[wd]) {
+		watchpoint_unref(wptab[wd]);
+		wptab[wd] = NULL;
+	}
+}
+
+static struct watchpoint *
+wpget(int wd)
+{
+	if (wd >= 0 && wd < wpsize)
+		return wptab[wd];
+	return NULL;
+}
+
 int
-sysev_filemask(struct dirwatcher *dp)
+sysev_filemask(struct watchpoint *dp)
 {
 	return 0;
 }
@@ -62,46 +121,61 @@ sysev_init()
 }
 
 int
-sysev_add_watch(struct dirwatcher *dwp, event_mask mask)
+sysev_add_watch(struct watchpoint *wpt, event_mask mask)
 {
-	return inotify_add_watch(ifd, dwp->dirname, mask.sys_mask);
+	int wd = inotify_add_watch(ifd, wpt->dirname, mask.sys_mask);
+	if (wd >= 0 && wpreg(wd, wpt)) {
+		inotify_rm_watch(ifd, wd);
+		return -1;
+	}
+	return wd;
 }
 
 void
-sysev_rm_watch(struct dirwatcher *dwp)
+sysev_rm_watch(struct watchpoint *wpt)
 {
-	inotify_rm_watch(ifd, dwp->wd);
+	wpunreg(wpt->wd);
+	inotify_rm_watch(ifd, wpt->wd);
 }
 
 /* Remove a watcher identified by its directory and file name */
 void
 remove_watcher(const char *dir, const char *name)
 {
-	struct dirwatcher *dwp;
+	struct watchpoint *wpt;
 	char *fullname = mkfilename(dir, name);
 	if (!fullname) {
 		diag(LOG_EMERG, "not enough memory: "
 		     "cannot look up a watcher to delete");
 		return;
 	}
-	dwp = dirwatcher_lookup(fullname);
+	wpt = watchpoint_lookup(fullname);
 	free(fullname);
-	if (dwp)
-		dirwatcher_destroy(dwp);
+	if (wpt)
+		watchpoint_suspend(wpt);
 }
 
 static void
 process_event(struct inotify_event *ep)
 {
-	struct dirwatcher *dp;
-	struct handler *h;
-	event_mask m;
+	struct watchpoint *wpt;
 	char *dirname, *filename;
 	
-	dp = dirwatcher_lookup_wd(ep->wd);
-	if (ep->mask & IN_IGNORED)
+	wpt = wpget(ep->wd);
+	if (!wpt) {
+		if (!(ep->mask & IN_IGNORED))
+			diag(LOG_NOTICE, _("watcher not found: %d (%s)"),
+			     ep->wd, ep->name);
 		return;
-	else if (ep->mask & IN_Q_OVERFLOW) {
+	}
+	
+	if (ep->mask & IN_IGNORED) {
+		diag(LOG_NOTICE, _("%s deleted"), wpt->dirname);
+		watchpoint_suspend(wpt);
+		return;
+	}
+	
+	if (ep->mask & IN_Q_OVERFLOW) {
 		diag(LOG_NOTICE,
 		     "event queue overflow");
 		return;
@@ -112,7 +186,7 @@ process_event(struct inotify_event *ep)
 		   were located under the mountpoint
 		*/
 		return;
-	} else if (!dp) {
+	} else if (!wpt) {
 		if (ep->name)
 			diag(LOG_NOTICE, "unrecognized event %x"
 			     "for %s", ep->mask, ep->name);
@@ -122,31 +196,29 @@ process_event(struct inotify_event *ep)
 		return;
 	}
 
-	ev_log(ep->mask, dp);
+	ev_log(ep->mask, wpt);
 
 	if (ep->mask & IN_CREATE) {
-		debug(1, ("%s/%s created", dp->dirname, ep->name));
-		if (check_new_watcher(dp->dirname, ep->name) > 0)
+		debug(1, ("%s/%s created", wpt->dirname, ep->name));
+		if (check_new_watcher(wpt->dirname, ep->name) > 0)
 			return;
-	} else if (ep->mask & (IN_DELETE|IN_MOVED_FROM)) {
-		debug(1, ("%s/%s deleted", dp->dirname, ep->name));
-		remove_watcher(dp->dirname, ep->name);
 	}
 
 	if (ep->len == 0)
-		filename = split_pathname(dp, &dirname);
+		filename = split_pathname(wpt, &dirname);
 	else {
-		dirname = dp->dirname;
+		dirname = wpt->dirname;
 		filename = ep->name;
 	}
-	for (h = dp->handler_list; h; h = h->next) {
-		if (handler_matches_event(h, sys, ep->mask, filename))
-			run_handler(h, event_mask_init(&m,
-						       ep->mask,
-						       &h->ev_mask),
-				    dirname, filename);
+
+	watchpoint_run_handlers(wpt, ep->mask, dirname, filename);
+	
+	unsplit_pathname(wpt);
+
+	if (ep->mask & (IN_DELETE|IN_MOVED_FROM)) {
+		debug(1, ("%s/%s deleted", wpt->dirname, ep->name));
+		remove_watcher(wpt->dirname, ep->name);
 	}
-	unsplit_pathname(dp);
 }	
 
 int
@@ -160,7 +232,7 @@ sysev_select()
 	rdbytes = read(ifd, buffer, sizeof(buffer));
 	if (rdbytes == -1) {
 		if (errno == EINTR) {
-			if (signo == SIGCHLD || signo == SIGALRM)
+			if (!signo || signo == SIGCHLD || signo == SIGALRM)
 				return 0;
 			diag(LOG_NOTICE, "got signal %d", signo);
 			return 1;
diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c
index d509e56..14772d8 100644
--- a/src/ev_kqueue.c
+++ b/src/ev_kqueue.c
@@ -60,11 +60,12 @@ sysev_init()
 }
 
 int
-sysev_filemask(struct dirwatcher *dp)
+sysev_filemask(struct watchpoint *dp)
 {
 	struct handler *h;
+	handler_iterator_t itr;
 
-	for (h = dp->handler_list; h; h = h->next) {
+	for_each_handler(dp, itr, h) {
 		if (h->ev_mask.sys_mask)
 			return S_IFMT;
 	}
@@ -72,9 +73,9 @@ sysev_filemask(struct dirwatcher *dp)
 }
 
 int
-sysev_add_watch(struct dirwatcher *dwp, event_mask mask)
+sysev_add_watch(struct watchpoint *wpt, event_mask mask)
 {
-	int wd = open(dwp->dirname, O_RDONLY);
+	int wd = open(wpt->dirname, O_RDONLY);
 	if (wd >= 0) {
 		struct stat st;
 		int sysmask;
@@ -83,26 +84,26 @@ sysev_add_watch(struct dirwatcher *dwp, event_mask mask)
 			close(wd);
 			return -1;
 		}
-		dwp->file_mode = st.st_mode;
-		dwp->file_ctime = st.st_ctime;
-		sysmask = mask.sys_mask;
+		wpt->file_mode = st.st_mode;
+		wpt->file_ctime = st.st_ctime;
+		sysmask = mask.sys_mask | NOTE_DELETE;
 		if (S_ISDIR(st.st_mode) && mask.gen_mask & GENEV_CREATE)
 			sysmask |= NOTE_WRITE;
 		EV_SET(chtab + chcnt, wd, EVFILT_VNODE,
 		       EV_ADD | EV_ENABLE | EV_CLEAR, sysmask,
-		       0, dwp);
+		       0, wpt);
 		wd = chcnt++;
 	}
 	return wd;
 }
 
 void
-sysev_rm_watch(struct dirwatcher *dwp)
+sysev_rm_watch(struct watchpoint *wpt)
 {
-	close(chtab[dwp->wd].ident);
-	chtab[dwp->wd].ident = -1;
-	if (chclosed == -1 || chclosed > dwp->wd)
-		chclosed = dwp->wd;
+	close(chtab[wpt->wd].ident);
+	chtab[wpt->wd].ident = -1;
+	if (chclosed == -1 || chclosed > wpt->wd)
+		chclosed = wpt->wd;
 }
 
 static void
@@ -115,11 +116,11 @@ chclosed_elim()
 
 	for (i = chclosed, j = chclosed + 1; j < chcnt; j++)
 		if (chtab[j].ident != -1) {
-			struct dirwatcher *dwp;
+			struct watchpoint *wpt;
 			
 			chtab[i] = chtab[j];
-			dwp = chtab[i].udata;
-			dwp->wd = i;
+			wpt = chtab[i].udata;
+			wpt->wd = i;
 			i++;
 		}
 	chcnt = i;
@@ -127,11 +128,10 @@ chclosed_elim()
 }
 
 static void
-check_created(struct dirwatcher *dp)
+check_created(struct watchpoint *dp)
 {
 	DIR *dir;
 	struct dirent *ent;
-	struct handler *h;
 
 	dir = opendir(dp->dirname);
 	if (!dir) {
@@ -148,6 +148,9 @@ check_created(struct dirwatcher *dp)
 		    (ent->d_name[1] == 0 ||
 		     (ent->d_name[1] == '.' && ent->d_name[2] == 0)))
 			continue;
+
+		if (watchpoint_pattern_match(dp, ent->d_name))
+			continue;
 		
 		pathname = mkfilename(dp->dirname, ent->d_name);
 		if (!pathname) {
@@ -167,10 +170,9 @@ check_created(struct dirwatcher *dp)
 		   know about that file.  If the file is new, register
 		   a watcher for it. */
 		} else if (st.st_ctime > dp->file_ctime ||
-			   !dirwatcher_lookup(pathname)) {
-			deliver_ev_create(dp, ent->d_name);
-			subwatcher_create(dp, pathname,
-					  S_ISDIR(st.st_mode), 1);
+			   !watchpoint_lookup(pathname)) {
+			deliver_ev_create(dp, dp->dirname, ent->d_name);
+			subwatcher_create(dp, pathname, 1);
 			dp->file_ctime = st.st_ctime;
 		}
 		free(pathname);
@@ -181,9 +183,7 @@ check_created(struct dirwatcher *dp)
 static void
 process_event(struct kevent *ep)
 {
-	struct dirwatcher *dp = ep->udata;
-	struct handler *h;
-	event_mask m;
+	struct watchpoint *dp = ep->udata;
 	char *filename, *dirname;
 	
 	if (!dp) {
@@ -193,31 +193,27 @@ process_event(struct kevent *ep)
 
 	ev_log(ep->fflags, dp);
 
-	if (S_ISDIR(dp->file_mode)) {
+	if (S_ISDIR(dp->file_mode)
+	    && !(ep->fflags & (NOTE_DELETE|NOTE_RENAME))) {
 		/* Check if new files have appeared. */
-		if (ep->fflags & NOTE_WRITE)
+		if (ep->fflags & NOTE_WRITE) 
 			check_created(dp);
 		return;
 	}
 
 	filename = split_pathname(dp, &dirname);
-	for (h = dp->handler_list; h; h = h->next) {
-		if (handler_matches_event(h, sys, ep->fflags, filename)) {
-			run_handler(h,
-				    event_mask_init(&m, ep->fflags, &h->ev_mask),
-				    dirname, filename);
-		}
-	}
+
+	watchpoint_run_handlers(dp, ep->fflags, dirname, filename);
+
 	unsplit_pathname(dp);
 	
 	if (ep->fflags & (NOTE_DELETE|NOTE_RENAME)) {
 		debug(1, ("%s deleted", dp->dirname));
-		dirwatcher_destroy(dp);
+		watchpoint_suspend(dp);
 		return;
 	}
 }	
 
-
 int
 sysev_select()
 {
@@ -227,7 +223,7 @@ sysev_select()
 	n = kevent(kq, chtab, chcnt, evtab, chcnt, NULL);
 	if (n == -1) {
 		if (errno == EINTR) {
-			if (signo == SIGCHLD || signo == SIGALRM)
+			if (signo == 0 || signo == SIGCHLD || signo == SIGALRM)
 				return 0;
 			diag(LOG_NOTICE, "got signal %d", signo);
 		}
@@ -237,7 +233,7 @@ sysev_select()
 
 	for (i = 0; i < n; i++) 
 		process_event(&evtab[i]);
-
+		
 	return 0;
 }
 		
diff --git a/src/event.c b/src/event.c
index 225cd4a..e977f0f 100644
--- a/src/event.c
+++ b/src/event.c
@@ -18,13 +18,12 @@
 
 
 struct symevt {
-	int used;
 	char *name;
 	event_mask mask;
 	int line;
 };
 
-struct hashtab *evtab;
+struct grecs_symtab *evtab;
 
 unsigned
 hash_string(const char *name, unsigned long hashsize)
@@ -60,7 +59,6 @@ symevt_copy(void *a, void *b)
 	struct symevt *syma = a;
 	struct symevt *symb = b;
 
-	syma->used = 1;
 	syma->name = estrdup(symb->name);
 	return 0;
 }
@@ -81,10 +79,10 @@ defevt(const char *name, event_mask *mask, int line)
 	int install = 1;
 	
 	if (!evtab) {
-		evtab = hashtab_create(sizeof(struct symevt),
-				       symevt_hash, symevt_cmp,
-				       symevt_copy,
-				       NULL, symevt_free);
+		evtab = grecs_symtab_create(sizeof(struct symevt),
+					    symevt_hash, symevt_cmp,
+					    symevt_copy,
+					    NULL, symevt_free);
 		if (!evtab) {
 			diag(LOG_CRIT, "not enough memory");
 			exit(1);
@@ -92,7 +90,7 @@ defevt(const char *name, event_mask *mask, int line)
 	}
 
 	key.name = (char *) name;
-	evp = hashtab_lookup_or_install(evtab, &key, &install);
+	evp = grecs_symtab_lookup_or_install(evtab, &key, &install);
 	if (!install)
 		return evp->line;
 	evp->mask = *mask;
@@ -106,7 +104,7 @@ getevt(const char *name, event_mask *mask)
 	if (evtab) {
 		struct symevt key, *evp;
 		key.name = (char *) name;
-		evp = hashtab_lookup_or_install(evtab, &key, NULL);
+		evp = grecs_symtab_lookup_or_install(evtab, &key, NULL);
 		if (evp) {
 			*mask = evp->mask;
 			return 0;
diff --git a/src/fnpat.c b/src/fnpat.c
index 2ac4d11..3e282b3 100644
--- a/src/fnpat.c
+++ b/src/fnpat.c
@@ -18,11 +18,12 @@
 #include <fnmatch.h>
 #include <grecs.h>
 
-void
+static void
 filename_pattern_free(void *p)
 {
 	struct filename_pattern *pat = p;
 	switch (pat->type) {
+	case PAT_EXACT:
 	case PAT_GLOB:
 		free(pat->v.glob);
 		break;
@@ -32,18 +33,132 @@ filename_pattern_free(void *p)
 	free(pat);
 }
 
+struct filpatlist {
+	grecs_list_ptr_t list;
+};
+
+static int
+is_glob(char const *str)
+{
+	return strcspn(str, "[]*?") < strlen(str);
+}
+
+void
+filpatlist_add_pattern(filpatlist_t *fptr, struct filename_pattern *pat)
+{
+	grecs_list_ptr_t list;
+	if (!*fptr) {
+		*fptr = emalloc(sizeof(*fptr));
+		(*fptr)->list = grecs_list_create();
+		(*fptr)->list->free_entry = filename_pattern_free;
+	}
+	list = (*fptr)->list;
+	grecs_list_append(list, pat);
+}
+	
+void
+filpatlist_add_exact(filpatlist_t *fptr, char const *arg)
+{
+	struct filename_pattern *pat = emalloc(sizeof(*pat));
+	
+	pat->neg = 0;
+	pat->type = PAT_EXACT;
+	pat->v.glob = estrdup(arg);
+	filpatlist_add_pattern(fptr, pat);
+}	
+
 int
-filename_pattern_match(struct grecs_list *lp, const char *name)
+filpatlist_add(filpatlist_t *fptr, char const *arg, grecs_locus_t *loc)
+{
+	int flags = REG_EXTENDED|REG_NOSUB;
+	struct filename_pattern *pat;
+	
+	pat = emalloc(sizeof(*pat));
+	if (*arg == '!') {
+		pat->neg = 1;
+		++arg;
+	} else
+		pat->neg = 0;
+	if (arg[0] == '/') {
+		int rc;
+		char *q, *p;
+
+		pat->type = PAT_REGEX;
+		
+		p = strchr(arg+1, '/');
+		if (!p) {
+			grecs_error(loc, 0, _("unterminated regexp"));
+			free(pat);
+			return 1;
+		}
+		for (q = p + 1; *q; q++) {
+			switch (*q) {
+			case 'b':
+				flags &= ~REG_EXTENDED;
+				break;
+			case 'i':
+				flags |= REG_ICASE;
+				break;
+			default:
+				grecs_error(loc, 0,
+					    _("unrecognized flag: %c"), *q);
+				free(pat);
+				return 1;
+			}
+		}
+		
+		*p = 0;
+		rc = regcomp(&pat->v.re, arg + 1, flags);
+		*p = '/';
+
+		if (rc) {
+			char errbuf[128];
+			regerror(rc, &pat->v.re, errbuf, sizeof(errbuf));
+			grecs_error(loc, 0, "%s", errbuf);
+			filename_pattern_free(pat);
+			return 1;
+		}
+	} else {
+		pat->type = is_glob(arg) ? PAT_GLOB : PAT_EXACT;
+		pat->v.glob = estrdup(arg);
+	}
+	filpatlist_add_pattern(fptr, pat);
+	return 0;
+}
+
+void
+filpatlist_destroy(filpatlist_t *fptr)
+{
+	if (fptr && *fptr) {
+		grecs_list_free((*fptr)->list);
+		free(*fptr);
+		*fptr = NULL;
+	}
+}
+
+int
+filpatlist_is_empty(filpatlist_t fp)
+{
+	if (!fp)
+		return 1;
+	return grecs_list_size(fp->list) == 0;
+}
+
+int
+filpatlist_match(filpatlist_t fp, const char *name)
 {
 	struct grecs_list_entry *ep;
 
-	if (!lp)
+	if (!fp || !fp->list)
 		return 0;
-	for (ep = lp->head; ep; ep = ep->next) {
+	for (ep = fp->list->head; ep; ep = ep->next) {
 		struct filename_pattern *pat = ep->data;
 		int rc;
 		
 		switch (pat->type) {
+		case PAT_EXACT:
+			rc = strcmp(pat->v.glob, name);
+			break;
 		case PAT_GLOB:
 			rc = fnmatch(pat->v.glob, name, FNM_PATHNAME);
 			break;
diff --git a/src/handler.c b/src/handler.c
new file mode 100644
index 0000000..a4b07d7
--- /dev/null
+++ b/src/handler.c
@@ -0,0 +1,230 @@
+/* direvent - directory content watcher daemon
+   Copyright (C) 2012-2016 Sergey Poznyakoff
+
+   Direvent 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.
+
+   Direvent 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 direvent. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "direvent.h"
+#include <grecs.h>
+
+struct handler *
+handler_alloc(event_mask ev_mask)
+{
+	struct handler *hp = ecalloc(1, sizeof(*hp));
+	hp->refcnt = 0;
+	hp->ev_mask = ev_mask;
+	return hp;
+}
+
+void
+watchpoint_run_handlers(struct watchpoint *wp, int evflags,
+			const char *dirname, const char *filename)
+{
+	handler_iterator_t itr;
+	struct handler *hp;
+	event_mask m;
+
+	for_each_handler(wp, itr, hp) {
+		if (handler_matches_event(hp, sys, evflags, filename))
+			hp->run(wp, event_mask_init(&m, evflags, &hp->ev_mask),
+				dirname, filename, hp->data);
+	}
+}
+
+static void
+handler_ref(struct handler *hp)
+{
+	++hp->refcnt;
+}
+
+void
+handler_free(struct handler *hp)
+{
+	filpatlist_destroy(&hp->fnames);
+	if (hp->free)
+		hp->free(hp->data);
+}
+
+static void
+handler_unref(struct handler *hp)
+{
+	if (hp && --hp->refcnt) {
+		handler_free(hp);
+		free(hp);
+	}
+}
+
+/* Handler lists */
+
+static void
+handler_listent_free(void *p)
+{
+	struct handler *hp = p;
+	handler_unref(hp);
+}
+
+struct handler_list {
+	size_t refcnt;
+	grecs_list_ptr_t list;
+	struct handler_iterator *itr_chain;
+};
+
+struct handler_iterator {
+	struct handler_iterator *prev, *next;
+	handler_list_t hlist;
+	struct grecs_list_entry *ent;
+	int advanced;
+};
+
+static struct handler_iterator *itr_avail;
+
+struct handler *
+handler_itr_first(struct watchpoint *wpt, handler_iterator_t *ret_itr)
+{
+	struct handler_iterator *itr;
+		
+	if (!wpt->handler_list)
+		return NULL;
+
+	if (itr_avail) {
+		itr = itr_avail;
+		itr_avail = itr->next;
+		if (itr_avail)
+			itr_avail->prev = NULL;
+	} else 
+		itr = emalloc(sizeof *itr);
+
+	itr->prev = NULL;
+	itr->next = wpt->handler_list->itr_chain;
+	itr->hlist = wpt->handler_list;
+	if (wpt->handler_list->itr_chain)
+	    wpt->handler_list->itr_chain->prev = itr;
+	wpt->handler_list->itr_chain = itr;
+
+	itr->ent = wpt->handler_list->list->head;
+	itr->advanced = 0;
+	*ret_itr = itr;
+	return handler_itr_current(itr);
+}
+
+struct handler *
+handler_itr_next(handler_iterator_t *pitr)
+{
+	struct handler_iterator *itr;
+	
+	if (!pitr || (itr = *pitr) == NULL)
+		return NULL;
+	if (itr->advanced)
+		itr->advanced = 0;
+	else 
+		itr->ent = itr->ent->next;
+
+	if (!itr->ent) {
+		/* Remove from iterator chain */
+		struct handler_iterator *p;
+		if ((p = itr->prev) != NULL)
+			p->next = itr->next;
+		else
+			itr->hlist->itr_chain = itr->next;
+		if ((p = itr->next) != NULL)
+			p->prev = itr->prev;
+			
+		/* Add to the available chain */
+		if (itr_avail)
+			itr_avail->prev = itr;
+		itr->prev = NULL;
+		itr->next = itr_avail;
+		itr->hlist = NULL;
+		itr_avail = itr;
+		*pitr = NULL;
+		return NULL;
+	}
+	return handler_itr_current(itr);
+}
+		
+struct handler *
+handler_itr_current(handler_iterator_t itr)
+{
+	if (!itr)
+		return NULL;
+	return itr->ent ? itr->ent->data : NULL;
+}
+
+handler_list_t
+handler_list_create(void)
+{
+	handler_list_t hlist = emalloc(sizeof(*hlist));
+	hlist->list = grecs_list_create();
+	hlist->list->free_entry = handler_listent_free;
+	hlist->refcnt = 1;
+	hlist->itr_chain = NULL;
+	return hlist;
+}
+
+size_t
+handler_list_size(handler_list_t hlist)
+{
+	return grecs_list_size(hlist->list);
+}
+
+handler_list_t
+handler_list_copy(handler_list_t orig)
+{
+	if (!orig)
+		return handler_list_create();
+	++orig->refcnt;
+	return orig;
+}
+
+void
+handler_list_unref(handler_list_t hlist)
+{
+	if (hlist) {
+		if (--hlist->refcnt == 0) {
+			grecs_list_free(hlist->list);
+			free(hlist);
+		}
+	}
+}
+		
+void
+handler_list_append(handler_list_t hlist, struct handler *hp)
+{
+	handler_ref(hp);
+	grecs_list_append(hlist->list, hp);
+}
+
+size_t
+handler_list_remove(handler_list_t hlist, struct handler *hp)
+{
+	struct grecs_list_entry *ep;
+	for (ep = hlist->list->head; ep; ep = ep->next)
+		if (ep->data == hp)
+			break;
+	if (!ep)
+		abort();
+
+	if (hlist->itr_chain) {
+		struct handler_iterator *itr;
+
+		for (itr = hlist->itr_chain; itr; itr = itr->next)
+			if (itr->ent == ep) {
+				itr->ent = ep->next;
+				itr->advanced = 1;
+			}
+	}
+	
+	grecs_list_remove_entry(hlist->list, ep);
+	return grecs_list_size(hlist->list);
+}
+
diff --git a/src/hashtab.c b/src/hashtab.c
deleted file mode 100644
index 674ec11..0000000
--- a/src/hashtab.c
+++ /dev/null
@@ -1,357 +0,0 @@
-/* This file is part of Direvent.
-   Copyright (C) 2012-2016 Sergey Poznyakoff.
- 
-   Direvent 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, or (at your option)
-   any later version.
- 
-   Direvent 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 Direvent.  If not, see <http://www.gnu.org/licenses/>. */
-
-#include "direvent.h"
-
-/* |hash_size| defines a sequence of symbol table sizes. These are prime
-   numbers, each of which is approximately twice its predecessor. */
-
-static unsigned int hash_size[] = {
-	7, 17, 37, 101, 229, 487, 1009, 2039, 4091, 8191, 16411,
-	32831, 65647, 131231, 262469, 524921, 1049849, 2099707
-};
-
-/* |max_rehash| keeps the number of entries in |hash_size| table. */
-static unsigned int max_rehash = sizeof(hash_size) / sizeof(hash_size[0]);
-
-struct hashtab {
-	int flags;
-	unsigned int hash_num;  /* Index to hash_size table */
-	size_t elsize;          /* Size of an element */
-	struct hashent **tab;
-	unsigned (*hash_fun)(void *, unsigned long hash_num);
-	int (*cmp_fun)(const void *, const void *);
-	int (*copy_fun)(void *, void *);
-	void *(*hashent_alloc_fun)(size_t size);
-	void (*hashent_free_fun) (void *);
-};
-
-static void
-hashent_free(struct hashtab *st, void *ptr)
-{
-	if (st->hashent_free_fun)
-		st->hashent_free_fun(ptr);
-	else
-		free(ptr);
-}
-
-static struct hashent *
-hashent_alloc(struct hashtab *st, void *key)
-{
-	struct hashent *ent;
-	
-	ent = st->hashent_alloc_fun ?
-		st->hashent_alloc_fun(st->elsize) : malloc(st->elsize);
-	if (ent) {
-		memset(ent, 0, st->elsize);
-		if (st->copy_fun(ent, key)) {
-			int ec = errno;
-			hashent_free(st, ent);
-			errno = ec;
-			return NULL;
-		}
-	}
-	return ent;
-}
-
-
-static unsigned
-hashtab_insert_pos(struct hashtab *st, void *elt)
-{
-	unsigned i;
-	unsigned pos = st->hash_fun(elt, hash_size[st->hash_num]);
-	
-	for (i = pos; st->tab[i];) {
-		if (++i >= hash_size[st->hash_num])
-			i = 0;
-		if (i == pos)
-			/* FIXME: Error message? */
-			abort();
-	}
-	return i;
-}
-
-int
-hashtab_replace(struct hashtab *st, void *ent, void **old_ent)
-{
-	struct hashent *entry;
-	unsigned i, pos = st->hash_fun(ent, hash_size[st->hash_num]);
-	for (i = pos; entry = st->tab[i];) {
-		if (st->cmp_fun(entry, ent) == 0)
-			break;
-		if (++i >= hash_size[st->hash_num])
-			i = 0;
-		if (i == pos)
-			return ENOENT;
-	}
-	if (old_ent)
-		*old_ent = entry;
-	st->tab[i] = ent;
-	return 0;
-}
-
-static int
-hashtab_rehash(struct hashtab *st)
-{
-	struct hashent **old_tab = st->tab;
-	struct hashent **new_tab;
-	unsigned int i;
-	unsigned int hash_num = st->hash_num + 1;
-	
-	if (hash_num >= max_rehash)
-		return E2BIG;
-
-	new_tab = calloc(hash_size[hash_num], sizeof(*new_tab));
-	if (!new_tab)
-		return ENOMEM;
-	st->tab = new_tab;
-	if (old_tab) {
-		st->hash_num = hash_num;
-		for (i = 0; i < hash_size[hash_num-1]; i++) {
-			struct hashent *elt = old_tab[i];
-			if (elt->used) {
-				unsigned n = hashtab_insert_pos(st, elt);
-				new_tab[n] = elt;
-			}
-		}
-		free(old_tab);
-	}
-	return 0;
-}
-
-const char *
-hashtab_strerror(int rc)
-{
-	switch (rc) {
-	case ENOENT:
-		return _("element not found in table");
-	case E2BIG:
-		return _("symbol table is full");
-	case ENOMEM:
-		return _("out of memory");
-	}
-	return strerror(rc);
-}
-
-int
-hashtab_remove(struct hashtab *st, void *elt)
-{
-	unsigned int pos, i, j, r;
-	struct hashent *entry;
-	
-	pos = st->hash_fun(elt, hash_size[st->hash_num]);
-	for (i = pos; entry = st->tab[i];) {
-		if (st->cmp_fun(entry, elt) == 0)
-			break;
-		if (++i >= hash_size[st->hash_num])
-			i = 0;
-		if (i == pos)
-			return ENOENT;
-	}
-	
-	hashent_free(st, entry);
-
-	for (;;) {
-		st->tab[i] = NULL;
-		j = i;
-
-		do {
-			if (++i >= hash_size[st->hash_num])
-				i = 0;
-			if (!st->tab[i])
-				return 0;
-			r = st->hash_fun(st->tab[i], hash_size[st->hash_num]);
-		}
-		while ((j < r && r <= i)
-		       || (i < j && j < r) || (r <= i && i < j));
-		st->tab[j] = st->tab[i];
-	}
-	return 0;
-}
-
-int
-hashtab_get_index(unsigned *idx, struct hashtab *st, void *key, int *install)
-{
-	int rc;
-	unsigned i, pos;
-	struct hashent *elem;
-  
-	if (!st->tab) {
-		if (install) {
-			rc = hashtab_rehash(st);
-			if (rc)
-				return rc;
-		} else
-			return ENOENT;
-	}
-
-	pos = st->hash_fun(key, hash_size[st->hash_num]);
-
-	for (i = pos; elem = st->tab[i];) {
-		if (st->cmp_fun(elem, key) == 0) {
-			if (install)
-				*install = 0;
-			*idx = i; 
-			return 0;
-		}
-      
-		if (++i >= hash_size[st->hash_num])
-			i = 0;
-		if (i == pos)
-			break;
-	}
-
-	if (!install)
-		return ENOENT;
-  
-	if (!elem) {
-		*install = 1;
-		*idx = i;
-		return 0;
-	}
-
-	if ((rc = hashtab_rehash(st)) != 0)
-		return rc;
-
-	return hashtab_get_index(idx, st, key, install);
-}
-
-void *
-hashtab_lookup_or_install(struct hashtab *st, void *key, int *install)
-{
-	unsigned i;
-	int rc = hashtab_get_index(&i, st, key, install);
-	if (rc == 0) {
-		if (install && *install == 1) {
-			struct hashent *ent = hashent_alloc(st, key);
-			if (!ent) {
-				errno = ENOMEM;
-				return NULL;
-			}
-			st->tab[i] = ent;
-			return ent;
-		} else
-			return st->tab[i];
-	}
-	errno = rc;
-	return NULL;
-}
-
-void
-hashtab_clear(struct hashtab *st)
-{
-	unsigned i, hs;
-  
-	if (!st || !st->tab)
-		return;
-
-	hs = hash_size[st->hash_num];
-	for (i = 0; i < hs; i++) {
-		struct hashent *elem = st->tab[i];
-		if (elem) {
-			hashent_free(st, elem);
-			st->tab[i] = NULL;
-		}
-	}
-}
-
-struct hashtab *
-hashtab_create(size_t elsize, 
-	       unsigned (*hash_fun)(void *, unsigned long),
-	       int (*cmp_fun)(const void *, const void *),
-	       int (*copy_fun)(void *, void *),
-	       void *(*alloc_fun)(size_t), void (*free_fun)(void *))
-{
-	struct hashtab *st = malloc(sizeof(*st));
-	if (st) {
-		memset(st, 0, sizeof(*st));
-		st->elsize = elsize;
-		st->hash_fun = hash_fun;
-		st->cmp_fun = cmp_fun;
-		st->copy_fun = copy_fun;
-		st->hashent_alloc_fun = alloc_fun;
-		st->hashent_free_fun = free_fun;
-		st->tab = calloc(hash_size[st->hash_num], sizeof(*st->tab));
-		if (!st->tab) {
-			free(st);
-			st = NULL;
-		}
-	}
-	return st;
-}
-
-void
-hashtab_free(struct hashtab *st)
-{
-	if (st) {
-		hashtab_clear(st);
-		free(st->tab);
-		free(st);
-	}
-}
-
-size_t
-hashtab_count_entries(struct hashtab *st)
-{
-	unsigned i;
-	size_t count = 0;
-	
-	for (i = 0; i < hash_size[st->hash_num]; i++)
-		if (st->tab[i])
-			count++;
-	return count;
-}
-
-int
-hashtab_foreach(struct hashtab *st, hashtab_enumerator_t fun, void *data)
-{
-	unsigned i;
-
-	if (!st)
-		return 0;
-	for (i = 0; i < hash_size[st->hash_num]; i++) {
-		struct hashent *ep = st->tab[i];
-		if (ep) {
-			int rc = fun(ep, data);
-			if (rc)
-				return rc;
-		}
-	}
-	return 0;
-}
-
-size_t
-hashtab_count(struct hashtab *st)
-{
-	unsigned i;
-	size_t count = 0;
-	
-	if (!st)
-		return 0;
-	for (i = 0; i < hash_size[st->hash_num]; i++) {
-		if (st->tab[i])
-			++count;
-	}
-	return count;
-}
-
-
-
-
-
-
-
-   
diff --git a/src/progman.c b/src/progman.c
index 4fff8bb..b96933b 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -246,7 +246,7 @@ process_timeouts()
 }
 
 int
-switchpriv(struct handler *hp)
+switchpriv(struct prog_handler *hp)
 {
 	if (hp->uid == 0 || hp->uid == getuid())
 		return 0;
@@ -293,7 +293,7 @@ close_fds(bigfd_set fdset)
 {
 	int i;
 
-	for (i = sysconf(_SC_OPEN_MAX) - 1; i >= 0; i--) {
+	for (i = dup(0); i >= 0; i--) {
 		if (fdset && BIGFD_ISSET(i, fdset))
 			continue;
 		close(i);
@@ -439,24 +439,26 @@ runcmd(const char *cmd, char **envhint, event_mask *event, const char *file,
 	_exit(127);
 }
 
-int
-run_handler(struct handler *hp, event_mask *event,
-	    const char *dirname, const char *file)
+static int
+prog_handler_run(struct watchpoint *wp, event_mask *event,
+		 const char *dirname, const char *file, void *data)
 {
 	pid_t pid;
 	int redir_fd[2] = { -1, -1 };
 	struct process *redir_proc[2] = { NULL, NULL };
 	struct process *p;
+	struct prog_handler *hp = data;
 
-	if (!hp->prog)
+	if (!hp->command)
 		return 0;
 	
-	debug(1, (_("starting %s, dir=%s, file=%s"), hp->prog, dirname, file));
+	debug(1, (_("starting %s, dir=%s, file=%s"),
+		  hp->command, dirname, file));
 	if (hp->flags & HF_STDERR)
-		redir_fd[REDIR_ERR] = open_redirector(hp->prog, LOG_ERR,
+		redir_fd[REDIR_ERR] = open_redirector(hp->command, LOG_ERR,
 						      &redir_proc[REDIR_ERR]);
 	if (hp->flags & HF_STDOUT)
-		redir_fd[REDIR_OUT] = open_redirector(hp->prog, LOG_INFO,
+		redir_fd[REDIR_OUT] = open_redirector(hp->command, LOG_INFO,
 						      &redir_proc[REDIR_OUT]);
 	
 	pid = fork();
@@ -503,12 +505,12 @@ run_handler(struct handler *hp, event_mask *event,
 		close_fds(fdset);
 		alarm(0);
 		signal_setup(SIG_DFL);
-		runcmd(hp->prog, hp->env, event, file, hp->flags & HF_SHELL);
+		runcmd(hp->command, hp->env, event, file, hp->flags & HF_SHELL);
 	}
 
 	/* master */
 	debug(1, (_("%s running; dir=%s, file=%s, pid=%lu"),
-		  hp->prog, dirname, file, (unsigned long)pid));
+		  hp->command, dirname, file, (unsigned long)pid));
 
 	p = register_process(PROC_HANDLER, pid, time(NULL), hp->timeout);
 
@@ -530,7 +532,7 @@ run_handler(struct handler *hp, event_mask *event,
 	}
 
 	debug(1, (_("waiting for %s (%lu) to terminate"),
-		  hp->prog, (unsigned long)pid));
+		  hp->command, (unsigned long)pid));
 	while (time(NULL) - p->start < 2 * p->timeout) {
 		sleep(1);
 		process_cleanup(1);
@@ -539,3 +541,74 @@ run_handler(struct handler *hp, event_mask *event,
 	}
 	return 0;
 }
+
+static void
+envfree(char **env)
+{
+	int i;
+
+	if (!env)
+		return;
+	for (i = 0; env[i]; i++)
+		free(env[i]);
+	free(env);
+}
+
+void
+prog_handler_free(struct prog_handler *hp)
+{
+	free(hp->command);
+	free(hp->gidv);
+	envfree(hp->env);
+}
+
+static void
+prog_handler_free_data(void *ptr)
+{
+	prog_handler_free((struct prog_handler *)ptr);
+}
+
+struct handler *
+prog_handler_alloc(event_mask ev_mask, filpatlist_t fpat,
+		   struct prog_handler *p)
+{
+	struct handler *hp = handler_alloc(ev_mask);
+	struct prog_handler *mem;
+
+	hp->fnames = fpat;
+	hp->run = prog_handler_run;
+	hp->free = prog_handler_free_data;
+	mem = emalloc(sizeof(*mem));
+	*mem = *p;
+	hp->data = mem;
+	memset(p, 0, sizeof(*p));
+	return hp;
+}
+
+/* Reallocate environment of handler HP to accomodate COUNT more
+   entries (not bytes) plus a final NULL entry.
+
+   Return offset of the first unused entry.
+*/
+size_t
+prog_handler_envrealloc(struct prog_handler *hp, size_t count)
+{
+	size_t i;
+
+	if (!hp->env) {
+		hp->env = ecalloc(count + 1, sizeof(hp->env[0]));
+		i = 0;
+	} else {
+		for (i = 0; hp->env[i]; i++)
+			;
+		hp->env = erealloc(hp->env,
+				   (i + count + 1) * sizeof(hp->env[0]));
+		memset(hp->env + i, 0, (count + 1) * sizeof(hp->env[0]));
+	}
+	return i;
+}
+
+
+
+
+		
diff --git a/src/watcher.c b/src/watcher.c
index 689ee2f..c16b0e6 100644
--- a/src/watcher.c
+++ b/src/watcher.c
@@ -19,285 +19,343 @@
 #include <sys/stat.h>
 
 void
-dirwatcher_unref(struct dirwatcher *dw)
+watchpoint_ref(struct watchpoint *wpt)
 {
-	if (--dw->refcnt)
+	++wpt->refcnt;
+}
+
+void
+watchpoint_unref(struct watchpoint *wpt)
+{
+	if (--wpt->refcnt)
 		return;
-	free(dw->dirname);
-	free(dw);
+	free(wpt->dirname);
+	handler_list_unref(wpt->handler_list);
+	free(wpt);
 }
 
 
-struct dwref {
+struct wpref {
 	int used;
-	struct dirwatcher *dw;
+	struct watchpoint *wpt;
 };
 
 static unsigned
-dwname_hash(void *data, unsigned long hashsize)
+wpref_hash(void *data, unsigned long hashsize)
 {
-	struct dwref *sym = data;
-	return hash_string(sym->dw->dirname, hashsize);
+	struct wpref *sym = data;
+	return grecs_hash_string(sym->wpt->dirname, hashsize);
 }
 
 static int
-dwname_cmp(const void *a, const void *b)
+wpref_cmp(const void *a, const void *b)
 {
-	struct dwref const *syma = a;
-	struct dwref const *symb = b;
+	struct wpref const *syma = a;
+	struct wpref const *symb = b;
 
-	return strcmp(syma->dw->dirname, symb->dw->dirname);
+	return strcmp(syma->wpt->dirname, symb->wpt->dirname);
 }
 
 static int
-dwname_copy(void *a, void *b)
+wpref_copy(void *a, void *b)
 {
-	struct dwref *syma = a;
-	struct dwref *symb = b;
+	struct wpref *syma = a;
+	struct wpref *symb = b;
 
 	syma->used = 1;
-	syma->dw = symb->dw;
+	syma->wpt = symb->wpt;
 	return 0;
 }
 
 static void
-dwref_free(void *p)
+wpref_free(void *p)
 {
-	struct dwref *dwref = p;
-	dirwatcher_unref(dwref->dw);
-	free(dwref);
+	struct wpref *wpref = p;
+	watchpoint_unref(wpref->wpt);
+	free(wpref);
 }
 
-struct hashtab *texttab;
+struct grecs_symtab *nametab;
 
-struct dirwatcher *
-dirwatcher_install(const char *path, int *pnew)
+struct watchpoint *
+watchpoint_install(const char *path, int *pnew)
 {
-	struct dirwatcher *dw, dwkey;
-	struct dwref key;
-	struct dwref *ent;
+	struct watchpoint wpkey;
+	struct wpref key;
+	struct wpref *ent;
 	int install = 1;
 
-	if (!texttab) {
-		texttab = hashtab_create(sizeof(struct dwref),
-					 dwname_hash, dwname_cmp, dwname_copy,
-					 NULL, dwref_free);
-		if (!texttab) {
-			diag(LOG_CRIT, N_("not enough memory"));
+	if (!nametab) {
+		nametab = grecs_symtab_create(sizeof(struct wpref),
+					      wpref_hash, wpref_cmp, wpref_copy,
+					      NULL, wpref_free);
+		if (!nametab) {
+			diag(LOG_CRIT, _("not enough memory"));
 			exit(1);
 		}
 	}
 
-	dwkey.dirname = (char*) path;
-	key.dw = &dwkey;
-	ent = hashtab_lookup_or_install(texttab, &key, &install);
+	wpkey.dirname = (char*) path;
+	key.wpt = &wpkey;
+	ent = grecs_symtab_lookup_or_install(nametab, &key, &install);
 	if (install) {
-		dw = ecalloc(1, sizeof(*dw));
-		dw->dirname = estrdup(path);
-		dw->wd = -1;
-		dw->refcnt++;
-		ent->dw = dw;
+	        struct watchpoint *wpt = ecalloc(1, sizeof(*wpt));
+		wpt->dirname = estrdup(path);
+		wpt->wd = -1;
+		wpt->handler_list = handler_list_create();
+		wpt->refcnt = 0;
+		ent->wpt = wpt;
 	}
 	if (!ent)
 		abort(); /* FIXME */
+	watchpoint_ref(ent->wpt);
 	if (pnew)
 		*pnew = install;
-	return ent->dw;
+	return ent->wpt;
 }
 
-struct dirwatcher *
-dirwatcher_lookup(const char *dirname)
+struct watchpoint *
+watchpoint_install_ptr(struct watchpoint *wpt)
 {
-	struct dirwatcher dwkey;
-	struct dwref key;
-	struct dwref *ent;
-
-	if (!texttab)
-		return NULL;
+	struct wpref key;
+	int install = 1;
+	key.wpt = wpt;
+	
+	if (!grecs_symtab_lookup_or_install(nametab, &key, &install)) {
+		diag(LOG_CRIT, _("not enough memory"));
+		exit(1);
+	}
+	watchpoint_ref(wpt);
+	return wpt;
+}	
 	
-	dwkey.dirname = (char*) dirname;
-	key.dw = &dwkey;
-	ent = hashtab_lookup_or_install(texttab, &key, NULL);
-	return ent ? ent->dw : NULL;
-}
-
 static void
-dirwatcher_remove(const char *dirname)
+wpref_destroy(void *data)
 {
-	struct dirwatcher dwkey;
-	struct dwref key;
-
-	if (!texttab)
-		return;
-	
-	dwkey.dirname = (char*) dirname;
-	key.dw = &dwkey;
-	hashtab_remove(texttab, &key);
+	struct watchpoint *wpt = data;
+	watchpoint_destroy(wpt);
 }
 
-
-struct hashtab *watchtab;
+static grecs_list_ptr_t watchpoint_gc_list;
 
-static unsigned
-dw_hash(void *data, unsigned long hashsize)
+void
+watchpoint_gc(void)
 {
-	struct dwref *ent = data;
-	return ent->dw->wd % hashsize;
+	if (watchpoint_gc_list) {
+		grecs_list_free(watchpoint_gc_list);
+		watchpoint_gc_list = NULL;
+	}
 }
 
-static int
-dw_cmp(const void *a, const void *b)
+struct watchpoint *
+watchpoint_lookup(const char *dirname)
 {
-	struct dwref const *ha = a;
-	struct dwref const *hb = b;
-	return ha->dw->wd != hb->dw->wd;
+	struct watchpoint wpkey;
+	struct wpref key;
+	struct wpref *ent;
+
+	if (!nametab)
+		return NULL;
+	
+	wpkey.dirname = (char*) dirname;
+	key.wpt = &wpkey;
+	ent = grecs_symtab_lookup_or_install(nametab, &key, NULL);
+	return ent ? ent->wpt : NULL;
 }
 
-static int
-dw_copy(void *a, void *b)
+static void
+watchpoint_remove(const char *dirname)
 {
-	struct dwref *ha = a;
-	struct dwref *hb = b;
+	struct watchpoint wpkey;
+	struct wpref key;
 
-	ha->used = 1;
-	ha->dw = hb->dw;
-	ha->dw->refcnt++;
-	return 0;
+	if (!nametab)
+		return;
+	
+	wpkey.dirname = (char*) dirname;
+	key.wpt = &wpkey;
+	grecs_symtab_remove(nametab, &key);
 }
 
-struct hashtab *dwtab;
-
 void
-dirwatcher_register(struct dirwatcher *dw)
+watchpoint_destroy(struct watchpoint *wpt)
 {
-	struct dwref key;
-	struct dwref *ent;
-	int install = 1;
+	debug(1, (_("removing watcher %s"), wpt->dirname));
+	sysev_rm_watch(wpt);
+	watchpoint_remove(wpt->dirname);
+}
 
-	if (!dwtab) {
-		dwtab = hashtab_create(sizeof(struct dwref),
-				       dw_hash, dw_cmp, dw_copy,
-				       NULL, dwref_free);
-		if (!dwtab) {
-			diag(LOG_ERR, _("not enough memory"));
-			exit(1);
-		}
+void
+watchpoint_suspend(struct watchpoint *wpt)
+{
+	if (!wpt->parent) /* A top-level watchpoint */
+		watchpoint_install_sentinel(wpt);//FIXME: error checking
+	watchpoint_destroy(wpt);
+	if (grecs_symtab_count(nametab) == 0) {
+		diag(LOG_CRIT, _("no watchers left; exiting now"));
+		stop = 1;
 	}
+}
+
+struct sentinel {
+	struct handler *hp;
+	struct watchpoint *watchpoint;
+};
 
-	memset(&key, 0, sizeof(key));
-	key.dw = dw;
-	ent = hashtab_lookup_or_install(dwtab, &key, &install);
-	if (!ent) {
-		diag(LOG_ERR, _("not enough memory"));
-		exit(1);
+static int
+sentinel_handler_run(struct watchpoint *wp, event_mask *event,
+		     const char *dirname, const char *file, void *data)
+{
+	struct sentinel *sentinel = data;
+	struct watchpoint *wpt = sentinel->watchpoint;
+	
+	watchpoint_init(wpt);
+	watchpoint_install_ptr(wpt);
+	deliver_ev_create(wpt, dirname, file);
+	
+	if (handler_list_remove(wp->handler_list, sentinel->hp) == 0) {
+		if (!watchpoint_gc_list) {
+			watchpoint_gc_list = grecs_list_create();
+			watchpoint_gc_list->free_entry = wpref_destroy;
+		}
+		grecs_list_append(watchpoint_gc_list, wp);
 	}
+	return 0;
 }
 
-struct dirwatcher *
-dirwatcher_lookup_wd(int wd)
+static void
+sentinel_handler_free(void *ptr)
 {
-	struct dirwatcher dwkey;
-	struct dwref dwref, *ent;
-
-	if (!dwtab) 
-		return NULL;
-	dwkey.wd = wd;
-	dwref.dw = &dwkey;
-	ent = hashtab_lookup_or_install(dwtab, &dwref, NULL);
-	return ent ? ent->dw : NULL;
+	struct sentinel *sentinel = ptr;
+	watchpoint_unref(sentinel->watchpoint);
+	free(sentinel);
 }
 
-void
-dirwatcher_remove_wd(int wd)
+int
+watchpoint_install_sentinel(struct watchpoint *wpt)
 {
-	struct dirwatcher dwkey;
-	struct dwref dwref;
-
-	if (!dwtab) 
-		return;
-	dwkey.wd = wd;
-	dwref.dw = &dwkey;
-	hashtab_remove(dwtab, &dwref);
+	struct watchpoint *sent;
+	char *dirname;
+	char *filename;
+	struct handler *hp;
+	event_mask ev_mask;
+	struct sentinel *sentinel;
+	
+	filename = split_pathname(wpt, &dirname);
+	sent = watchpoint_install(dirname, NULL);
+
+	getevt("create", &ev_mask);
+	hp = handler_alloc(ev_mask);
+	hp->run = sentinel_handler_run;
+	hp->free = sentinel_handler_free;
+
+	sentinel = emalloc(sizeof(*sentinel));
+	sentinel->watchpoint = wpt;
+	sentinel->hp = hp;
+	watchpoint_ref(wpt);
+	
+	hp->data = sentinel;
+	
+	filpatlist_add_exact(&hp->fnames, filename);
+	handler_list_append(sent->handler_list, hp);
+	unsplit_pathname(wpt);
+	diag(LOG_NOTICE, _("installing CREATE sentinel for %s"), wpt->dirname);
+	return watchpoint_init(sent);
 }
-
-
+	
 int 
-dirwatcher_init(struct dirwatcher *dwp)
+watchpoint_init(struct watchpoint *wpt)
 {
+	struct stat st;
 	event_mask mask = { 0, 0 };
 	struct handler *hp;
+	handler_iterator_t itr;	
 	int wd;
 
-	debug(1, (_("creating watcher %s"), dwp->dirname));
+	debug(1, (_("creating watcher %s"), wpt->dirname));
+
+	if (stat(wpt->dirname, &st)) {
+		if (errno == ENOENT) {
+			return watchpoint_install_sentinel(wpt);
+		} else {
+			diag(LOG_ERR, _("cannot set watcher on %s: %s"),
+			     wpt->dirname, strerror(errno));
+			return 1;
+		}
+	}
 
-	for (hp = dwp->handler_list; hp; hp = hp->next) {
+	wpt->isdir = S_ISDIR(st.st_mode);
+	
+	for_each_handler(wpt, itr, hp) {
 		mask.sys_mask |= hp->ev_mask.sys_mask;
 		mask.gen_mask |= hp->ev_mask.gen_mask;
 	}
 	
-	wd = sysev_add_watch(dwp, mask);
+	wd = sysev_add_watch(wpt, mask);
 	if (wd == -1) {
 		diag(LOG_ERR, _("cannot set watcher on %s: %s"),
-		     dwp->dirname, strerror(errno));
+		     wpt->dirname, strerror(errno));
 		return 1;
 	}
 
-	dwp->wd = wd;
-	dirwatcher_register(dwp);
+	wpt->wd = wd;
 
 	return 0;
 }
 
-static int watch_subdirs(struct dirwatcher *parent, int notify);
+static int watch_subdirs(struct watchpoint *parent, int notify);
 
 int
-subwatcher_create(struct dirwatcher *parent, const char *dirname,
-		  int isdir, int notify)
+subwatcher_create(struct watchpoint *parent, const char *dirname,
+		  int notify)
 {
-	struct dirwatcher *dwp;
+	struct watchpoint *wpt;
 	int inst;
 	
-	dwp = dirwatcher_install(dirname, &inst);
+	wpt = watchpoint_install(dirname, &inst);
 	if (!inst)
 		return -1;
 
-	dwp->handler_list = parent->handler_list;
-	dwp->parent = parent;
+	wpt->handler_list = handler_list_copy(parent->handler_list);
+	wpt->parent = parent;
 	
 	if (parent->depth == -1)
-		dwp->depth = parent->depth;
+		wpt->depth = parent->depth;
 	else if (parent->depth)
-		dwp->depth = parent->depth - 1;
+		wpt->depth = parent->depth - 1;
 	else
-		dwp->depth = 0;
+		wpt->depth = 0;
 	
-	if (dirwatcher_init(dwp)) {
-		//FIXME dirwatcher_free(dwp);
+	if (watchpoint_init(wpt)) {
+		//FIXME watchpoint_free(wpt);
 		return -1;
 	}
 
-	return 1 + (isdir ? watch_subdirs(dwp, notify) : 0);
+	return 1 + watch_subdirs(wpt, notify);
 }
 
 /* Deliver GENEV_CREATE event */
 void
-deliver_ev_create(struct dirwatcher *dp, const char *name)
+deliver_ev_create(struct watchpoint *wp, const char *dirname, const char *name)
 {
 	event_mask m = { GENEV_CREATE, 0 };
-	struct handler *h;
-
-	for (h = dp->handler_list; h; h = h->next) {
-		if (handler_matches_event(h, gen, GENEV_CREATE, name))
-			run_handler(h, &m, dp->dirname, name);
+	struct handler *hp;
+	handler_iterator_t itr;
+	
+	for_each_handler(wp, itr, hp) {
+		if (handler_matches_event(hp, gen, GENEV_CREATE, name))
+			hp->run(wp, &m, dirname, name, hp->data);
 	}
 }
 
 /* Check if a new watcher must be created and create it if so.
 
-   A watcher must be created if its parent's autowatch has a non-null
-   value.  If it has a negative value, it will be inherited by the new
-   watcher.  Otherwise, the new watcher will inherit the parent's autowatch
-   decreased by one.
+   A watcher must be created if its parent's recursion depth has a non-null
+   value.  If it has a negative value, which means "recursively watch new
+   subdirectories without limit on their nesting level", it will be inherited
+   by the new watcher.  Otherwise, the new watcher will inherit the parent's
+   depth decreased by one, thus eventually cutting off creation of new
+   watchers.
 
    Return 0 on success, -1 on error.
 */
@@ -307,9 +365,9 @@ check_new_watcher(const char *dir, const char *name)
 	int rc;
 	char *fname;
 	struct stat st;
-	struct dirwatcher *parent;
+	struct watchpoint *parent;
 
-	parent = dirwatcher_lookup(dir);
+	parent = watchpoint_lookup(dir);
 	if (!parent || !parent->depth)
 		return 0;
 	
@@ -327,24 +385,41 @@ check_new_watcher(const char *dir, const char *name)
 		     dir, name, strerror(errno));
 		rc = -1;
 	} else if (S_ISDIR(st.st_mode)) {
-		deliver_ev_create(parent, name);
-		rc = subwatcher_create(parent, fname, 1, 1);
+		deliver_ev_create(parent, parent->dirname, name);
+		rc = subwatcher_create(parent, fname, 1);
 	} else
 		rc = 0;
 	free(fname);
 	return rc;
 }
 
+int
+watchpoint_pattern_match(struct watchpoint *wpt, const char *file_name)
+{
+	struct handler *hp;
+	handler_iterator_t itr;
+
+	for_each_handler(wpt, itr, hp) {
+		if (filpatlist_match(hp->fnames, file_name) == 0)
+			return 0;
+	}
+	return 1;
+}
+
 /* Recursively scan subdirectories of parent and add them to the
-   watcher list, as requested by the parent's autowatch value. */
+   watcher list, as requested by the parent's recursion depth value. */
 static int
-watch_subdirs(struct dirwatcher *parent, int notify)
+watch_subdirs(struct watchpoint *parent, int notify)
 {
 	DIR *dir;
 	struct dirent *ent;
-	int filemask = sysev_filemask(parent);
+	int filemask;
 	int total = 0;
 
+	if (!parent->isdir)
+		return 0;
+
+	filemask = sysev_filemask(parent);
 	if (parent->depth)
 		filemask |= S_IFDIR;
 	if (!filemask)
@@ -368,19 +443,21 @@ watch_subdirs(struct dirwatcher *parent, int notify)
 		
 		dirname = mkfilename(parent->dirname, ent->d_name);
 		if (!dirname) {
-			diag(LOG_ERR, _("cannot stat %s/%s: not enough memory"),
+			diag(LOG_ERR,
+			     _("cannot stat %s/%s: not enough memory"),
 			     parent->dirname, ent->d_name);
 			continue;
 		}
 		if (stat(dirname, &st)) {
 			diag(LOG_ERR, _("cannot stat %s: %s"),
 			     dirname, strerror(errno));
-		} else {
+		} else if (watchpoint_pattern_match(parent, ent->d_name)
+			   == 0) {
 			if (notify)
-				deliver_ev_create(parent, ent->d_name);
+				deliver_ev_create(parent, parent->dirname,
+						  ent->d_name);
 			if (st.st_mode & filemask) {
 				int rc = subwatcher_create(parent, dirname,
-							   S_ISDIR(st.st_mode),
 							   notify);
 				if (rc > 0)
 					total += rc;
@@ -393,44 +470,62 @@ watch_subdirs(struct dirwatcher *parent, int notify)
 }
 
 
-int
-setwatcher(struct hashent *ent, void *null)
+static int
+setwatcher(void *ent, void *data)
 {
-	struct dwref *dwref = (struct dwref *) ent;
-	struct dirwatcher *dwp = dwref->dw;
+	struct wpref *wpref = (struct wpref *) ent;
+	struct watchpoint *wpt = wpref->wpt;
 	
-	if (dwp->wd == -1 && dirwatcher_init(dwp) == 0)
-		watch_subdirs(dwp, 0);
+	if (wpt->wd == -1 && watchpoint_init(wpt) == 0)
+		watch_subdirs(wpt, 0);
 	return 0;
 }
 
+static int
+checkwatcher(void *ent, void *data)
+{
+	struct wpref *wpref = (struct wpref *) ent;
+	struct watchpoint *wpt = wpref->wpt;
+	return wpt->wd >= 0;
+}
+	
 void
-setup_watchers()
+setup_watchers(void)
 {
 	sysev_init();
-	if (hashtab_count(texttab) == 0) {
+	if (grecs_symtab_count(nametab) == 0) {
 		diag(LOG_CRIT, _("no event handlers configured"));
 		exit(1);
 	}
-	hashtab_foreach(texttab, setwatcher, NULL);
-	if (hashtab_count(dwtab) == 0) {
+	grecs_symtab_foreach(nametab, setwatcher, NULL);
+	if (!grecs_symtab_foreach(nametab, checkwatcher, NULL)) {
 		diag(LOG_CRIT, _("no event handlers installed"));
 		exit(2);
 	}
 }
 
-void
-dirwatcher_destroy(struct dirwatcher *dwp)
+static int
+stopwatcher(void *ent, void *data)
 {
-	debug(1, (_("removing watcher %s"), dwp->dirname));
-	sysev_rm_watch(dwp);
+	struct wpref *wpref = (struct wpref *) ent;
+	struct watchpoint *wpt = wpref->wpt;
+	if (wpt->wd != -1) {
+		debug(1, (_("removing watcher %s"), wpt->dirname));
+		sysev_rm_watch(wpt);
+	}
+	return 0;
+}
 
-	dirwatcher_remove_wd(dwp->wd);
-	dirwatcher_remove(dwp->dirname);
+void
+shutdown_watchers(void)
+{
+	grecs_symtab_foreach(nametab, stopwatcher, NULL);
+	grecs_symtab_clear(nametab);
 }
+
 
 char *
-split_pathname(struct dirwatcher *dp, char **dirname)
+split_pathname(struct watchpoint *dp, char **dirname)
 {
 	char *p = strrchr(dp->dirname, '/');
 	if (p) {
@@ -445,7 +540,7 @@ split_pathname(struct dirwatcher *dp, char **dirname)
 }
 
 void
-unsplit_pathname(struct dirwatcher *dp)
+unsplit_pathname(struct watchpoint *dp)
 {
 	if (dp->split_p) {
 		*dp->split_p = '/';
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f797790..0e11f58 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -48,6 +48,7 @@ TESTSUITE_AT = \
   env01.at\
   env02.at\
   env03.at\
+  file.at\
   glob01.at\
   glob02.at\
   re01.at\
@@ -57,6 +58,7 @@ TESTSUITE_AT = \
   re05.at\
   samepath.at\
   shell.at\
+  sent.at\
   testsuite.at\
   write.at
 
diff --git a/tests/Makefile.in b/tests/Makefile.in
index 1153614..659267b 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -31,7 +31,17 @@
 # along with Direvent.  If not, see <http://www.gnu.org/licenses/>.
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -96,8 +106,6 @@ build_triplet = @build@
 host_triplet = @host@
 noinst_PROGRAMS = envdump$(EXEEXT)
 subdir = tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(srcdir)/atlocal.in $(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/am/gettext.m4 $(top_srcdir)/am/iconv.m4 \
@@ -108,6 +116,7 @@ am__aclocal_m4_deps = $(top_srcdir)/grecs/am/grecs.m4 \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES = atlocal
@@ -170,6 +179,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/atlocal.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -201,7 +212,9 @@ GRECS_CHANGELOG = @GRECS_CHANGELOG@
 GRECS_DISTCK_AT = @GRECS_DISTCK_AT@
 GRECS_DISTDOC = @GRECS_DISTDOC@
 GRECS_DOCDIR = @GRECS_DOCDIR@
+GRECS_EXTRA_DIST = @GRECS_EXTRA_DIST@
 GRECS_HOST_PROJECT_INCLUDES = @GRECS_HOST_PROJECT_INCLUDES@
+GRECS_HOST_PROJECT_LDADD = @GRECS_HOST_PROJECT_LDADD@
 GRECS_INCLUDES = @GRECS_INCLUDES@
 GRECS_INCLUDE_DIR = @GRECS_INCLUDE_DIR@
 GRECS_LDADD = @GRECS_LDADD@
@@ -325,6 +338,7 @@ TESTSUITE_AT = \
   env01.at\
   env02.at\
   env03.at\
+  file.at\
   glob01.at\
   glob02.at\
   re01.at\
@@ -334,6 +348,7 @@ TESTSUITE_AT = \
   re05.at\
   samepath.at\
   shell.at\
+  sent.at\
   testsuite.at\
   write.at
 
@@ -356,7 +371,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnits tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -610,6 +624,8 @@ uninstall-am:
 	mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 $(srcdir)/package.m4: $(top_srcdir)/configure.ac
 	$(AM_V_GEN){                                      \
diff --git a/tests/file.at b/tests/file.at
new file mode 100644
index 0000000..f05c796
--- /dev/null
+++ b/tests/file.at
@@ -0,0 +1,61 @@
+# This file is part of Direvent testsuite. -*- Autotest -*-
+# Copyright (C) 2013-2016 Sergey Poznyakoff
+#
+# Direvent 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, or (at your option)
+# any later version.
+#
+# Direvent 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 Direvent.  If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([File watcher])
+AT_KEYWORDS([special file])
+
+AT_DIREVENT_TEST_UNQUOTED([
+debug 10;
+syslog {
+	facility ${TESTSUITE_FACILITY:-local0};
+	tag direvent-test:create;
+}
+watcher {
+	path $cwd/file;
+	event (create,write,delete);
+	option (stdout,stderr);
+	command "$TESTDIR/envdump -s -i DIREVENT_FILE=:DIREVENT_GENEV_ -f $outfile -k\$self_test_pid";	
+}
+],
+[echo "foo" > file
+],
+[outfile=$cwd/dump
+echo "file" > file
+],
+[sed '/^argv\[[[0-9]]\]=-k/d' $outfile
+],
+[0],
+[# Dump of execution environment
+cwd is $cwd
+# Arguments
+argv[[0]]=$TESTDIR/envdump
+argv[[1]]=-s
+argv[[2]]=-i
+argv[[3]]=DIREVENT_FILE=:DIREVENT_GENEV_
+argv[[4]]=-f
+argv[[5]]=$cwd/dump
+# Environment
+DIREVENT_FILE=file
+DIREVENT_GENEV_CODE=2
+DIREVENT_GENEV_NAME=write
+# End
+])
+
+AT_CLEANUP
+
+
+
+	
diff --git a/tests/package.m4 b/tests/package.m4
index ba214fd..00981a5 100644
--- a/tests/package.m4
+++ b/tests/package.m4
@@ -1,6 +1,6 @@
 # Signature of the current package.
 m4_define([AT_PACKAGE_NAME],      [GNU Direvent])
 m4_define([AT_PACKAGE_TARNAME],   [direvent])
-m4_define([AT_PACKAGE_VERSION],   [5.1])
-m4_define([AT_PACKAGE_STRING],    [GNU Direvent 5.1])
+m4_define([AT_PACKAGE_VERSION],   [5.2])
+m4_define([AT_PACKAGE_STRING],    [GNU Direvent 5.2])
 m4_define([AT_PACKAGE_BUGREPORT], [bug-direvent@gnu.org.ua])
diff --git a/tests/sent.at b/tests/sent.at
new file mode 100644
index 0000000..7ad5a61
--- /dev/null
+++ b/tests/sent.at
@@ -0,0 +1,68 @@
+# This file is part of Direvent testsuite. -*- Autotest -*-
+# Copyright (C) 2013-2016 Sergey Poznyakoff
+#
+# Direvent 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, or (at your option)
+# any later version.
+#
+# Direvent 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 Direvent.  If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([Sentinel])
+AT_KEYWORDS([special sent sentinel])
+
+AT_DIREVENT_TEST_UNQUOTED([
+debug 10;
+syslog {
+	facility ${TESTSUITE_FACILITY:-local0};
+	tag direvent-test:create;
+}
+watcher {
+	path $cwd/dir/sub;
+	file "foo";
+	event (create);
+	option (stdout,stderr);
+	command "$TESTDIR/envdump -s -i DIREVENT_FILE=:DIREVENT_GENEV_ -a -f $outfile -k\$self_test_pid";	
+}
+],
+[sleep 1
+mkdir $cwd/dir
+sleep 1
+mkdir $cwd/dir/sub
+sleep 1
+echo "bar" > $cwd/dir/sub/bar
+echo "foo" > $cwd/dir/sub/foo
+],
+[outfile=$cwd/dump
+],
+[sed "s^$cwd^(CWD)^;s^$TESTDIR^(TESTDIR)^;/^argv\[[[0-9]]\]=-k/d" $outfile
+],
+[0],
+[# Dump of execution environment
+cwd is (CWD)/dir/sub
+# Arguments
+argv[[0]]=(TESTDIR)/envdump
+argv[[1]]=-s
+argv[[2]]=-i
+argv[[3]]=DIREVENT_FILE=:DIREVENT_GENEV_
+argv[[4]]=-a
+argv[[5]]=-f
+argv[[6]]=(CWD)/dump
+# Environment
+DIREVENT_FILE=foo
+DIREVENT_GENEV_CODE=1
+DIREVENT_GENEV_NAME=create
+# End
+],
+[direvent: [[NOTICE]] installing CREATE sentinel for $cwd/dir/sub
+direvent: [[NOTICE]] installing CREATE sentinel for $cwd/dir
+])
+
+AT_CLEANUP
+
diff --git a/tests/testsuite b/tests/testsuite
index 4ee7071..90ceacb 100755
--- a/tests/testsuite
+++ b/tests/testsuite
@@ -609,6 +609,8 @@ at_help_all="1;create.at:17;Create;create create01;
 17;re03.at:17;Basic case-sensitive;create fname regexp re re03;
 18;re04.at:17;Basic case-insensitive;create fname regexp re re04;
 19;re05.at:17;Regexp negation;create fname regexp re re05 neg;
+20;file.at:17;File watcher;special file;
+21;sent.at:17;Sentinel;special sent sentinel;
 "
 # List of the all the test groups.
 at_groups_all=`$as_echo "$at_help_all" | sed 's/;.*//'`
@@ -622,7 +624,7 @@ at_fn_validate_ranges ()
   for at_grp
   do
     eval at_value=\$$at_grp
-    if test $at_value -lt 1 || test $at_value -gt 19; then
+    if test $at_value -lt 1 || test $at_value -gt 21; then
       $as_echo "invalid test group: $at_value" >&2
       exit 1
     fi
@@ -921,7 +923,7 @@ fi
 # List of tests.
 if $at_list_p; then
   cat <<_ATEOF || at_write_fail=1
-GNU Direvent 5.1 test suite test groups:
+GNU Direvent 5.2 test suite test groups:
 
  NUM: FILE-NAME:LINE     TEST-GROUP-NAME
       KEYWORDS
@@ -962,7 +964,7 @@ _ATEOF
   exit $at_write_fail
 fi
 if $at_version_p; then
-  $as_echo "$as_me (GNU Direvent 5.1)" &&
+  $as_echo "$as_me (GNU Direvent 5.2)" &&
   cat <<\_ATEOF || at_write_fail=1
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -979,12 +981,15 @@ case $at_groups in #(
   * ) at_print_banners=false ;;
 esac
 # Text for banner N, set to a single space once printed.
-# Banner 1. testsuite.at:56
+# Banner 1. testsuite.at:60
 # Category starts at test group 9.
 at_banner_text_1="Environment modifications"
-# Banner 2. testsuite.at:62
+# Banner 2. testsuite.at:66
 # Category starts at test group 13.
 at_banner_text_2="Filename selection"
+# Banner 3. testsuite.at:75
+# Category starts at test group 20.
+at_banner_text_3="Special watchpoints"
 
 # Take any -C into account.
 if $at_change_dir ; then
@@ -1145,11 +1150,11 @@ exec 5>>"$at_suite_log"
 
 # Banners and logs.
 $as_echo "## ---------------------------- ##
-## GNU Direvent 5.1 test suite. ##
+## GNU Direvent 5.2 test suite. ##
 ## ---------------------------- ##"
 {
   $as_echo "## ---------------------------- ##
-## GNU Direvent 5.1 test suite. ##
+## GNU Direvent 5.2 test suite. ##
 ## ---------------------------- ##"
   echo
 
@@ -1394,7 +1399,7 @@ IFS=$as_save_IFS
   esac
   if test -f "$at_program_"; then
     {
-      $as_echo "$at_srcdir/testsuite.at:44: $at_program_ --version"
+      $as_echo "$at_srcdir/testsuite.at:48: $at_program_ --version"
       "$at_program_" --version </dev/null
       echo
     } >&5 2>&1
@@ -1993,7 +1998,7 @@ _ASBOX
   $as_echo "Please send $at_msg and all information you think might help:
 
    To: <bug-direvent@gnu.org.ua>
-   Subject: [GNU Direvent 5.1] $as_me: $at_fail_list${at_fail_list:+ failed${at_xpass_list:+, }}$at_xpass_list${at_xpass_list:+ passed unexpectedly}
+   Subject: [GNU Direvent 5.2] $as_me: $at_fail_list${at_fail_list:+ failed${at_xpass_list:+, }}$at_xpass_list${at_xpass_list:+ passed unexpectedly}
 
 You may investigate any problem if you feel able to do so, in which
 case the test suite provides a good starting point.  Its output may
@@ -2018,9 +2023,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/create.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 
@@ -2050,9 +2055,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "create.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "create.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 
@@ -2123,9 +2127,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/createrec.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 mkdir a
@@ -2163,9 +2167,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^\" \$outfile | sort
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "createrec.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "createrec.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 mkdir a
@@ -2237,9 +2240,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/delete.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 > dir/file
@@ -2270,9 +2273,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "delete.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "delete.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 > dir/file
@@ -2344,9 +2346,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/write.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 cat > dir/file <<EOT
@@ -2381,9 +2383,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "write.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "write.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 cat > dir/file <<EOT
@@ -2459,9 +2460,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/attrib.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 > dir/file
@@ -2493,9 +2494,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "attrib.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "attrib.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 > dir/file
@@ -2568,9 +2568,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/cmdexp.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 cat > dir/testfile <<EOT
@@ -2605,9 +2605,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "cmdexp.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "cmdexp.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 cat > dir/testfile <<EOT
@@ -2685,9 +2684,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/samepath.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 >dir/file
@@ -2723,9 +2722,8 @@ chmod +x selftest.sh
 direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d\" \$outfile
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "samepath.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "samepath.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 >dir/file
@@ -2815,9 +2813,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/shell.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 
@@ -2848,9 +2846,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "shell.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "shell.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 
@@ -2923,9 +2920,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/env00.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 cat > dir/testfile <<EOT
@@ -2965,9 +2962,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;s^\\(DIREVENT_SYS.*\\)=.*^\\1=X^;/^argv\\[[0-9]]\\=-k/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "env00.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "env00.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 cat > dir/testfile <<EOT
@@ -3052,9 +3048,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/env01.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 cat > dir/testfile <<EOT
@@ -3090,9 +3086,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;s^\\(DIREVENT_SYS.*\\)=.*^\\1=X^;/^argv\\[[0-9]]\\=-k/d;/DIREVENT_SELF_TEST_PID/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "env01.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "env01.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 cat > dir/testfile <<EOT
@@ -3169,9 +3164,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/env02.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 cat > dir/testfile <<EOT
@@ -3207,9 +3202,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;s^\\(DIREVENT_SYS.*\\)=.*^\\1=X^;/^argv\\[[0-9]]\\=-k/d;/DIREVENT_SELF_TEST_PID/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "env02.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "env02.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 cat > dir/testfile <<EOT
@@ -3281,9 +3275,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/env03.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 cat > dir/testfile <<EOT
@@ -3323,9 +3317,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;s^\\(DIREVENT_SYS.*\\)=.*^\\1=X^;/^argv\\[[0-9]]\\=-k/d;/DIREVENT_SELF_TEST_PID/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "env03.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "env03.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 cat > dir/testfile <<EOT
@@ -3405,9 +3398,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/glob01.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 
@@ -3440,9 +3433,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d;/DIREVENT_SELF_TEST_PID/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "glob01.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "glob01.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 
@@ -3516,9 +3508,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/glob02.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 
@@ -3551,9 +3543,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d;/DIREVENT_SELF_TEST_PID/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "glob02.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "glob02.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 
@@ -3628,9 +3619,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/re01.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 
@@ -3663,9 +3654,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d;/DIREVENT_SELF_TEST_PID/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "re01.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "re01.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 
@@ -3739,9 +3729,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/re02.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 
@@ -3773,9 +3763,8 @@ chmod +x selftest.sh
 direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d;/DIREVENT_SELF_TEST_PID/d\" \$outfile
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "re02.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "re02.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 
@@ -3848,9 +3837,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/re03.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 
@@ -3883,9 +3872,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d;/DIREVENT_SELF_TEST_PID/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "re03.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "re03.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 
@@ -3959,9 +3947,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/re04.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 
@@ -3994,9 +3982,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d;/DIREVENT_SELF_TEST_PID/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "re04.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "re04.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 
@@ -4070,9 +4057,9 @@ at_xfail=no
 
 
 
+cwd=`pwd -P`
 { set +x
 $as_echo "$at_srcdir/re05.at:20:
-cwd=\`pwd -P\`
 outfile=\$cwd/dump
 mkdir dir
 
@@ -4105,9 +4092,8 @@ direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
 sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d;/DIREVENT_SELF_TEST_PID/d\" \$outfile
 
 "
-at_fn_check_prepare_notrace 'a `...` command substitution' "re05.at:20"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "re05.at:20"
 ( $at_check_trace;
-cwd=`pwd -P`
 outfile=$cwd/dump
 mkdir dir
 
@@ -4171,3 +4157,231 @@ $at_traceon; }
 ) 5>&1 2>&1 7>&- | eval $at_tee_pipe
 read at_status <"$at_status_file"
 #AT_STOP_19
+#AT_START_20
+at_fn_group_banner 20 'file.at:17' \
+  "File watcher" "                                   " 3
+at_xfail=no
+(
+  $as_echo "20. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+
+cwd=`pwd -P`
+{ set +x
+$as_echo "$at_srcdir/file.at:20:
+outfile=\$cwd/dump
+echo \"file\" > file
+
+cat > test.conf <<EOT
+
+debug 10;
+syslog {
+	facility \${TESTSUITE_FACILITY:-local0};
+	tag direvent-test:create;
+}
+watcher {
+	path \$cwd/file;
+	event (create,write,delete);
+	option (stdout,stderr);
+	command \"\$TESTDIR/envdump -s -i DIREVENT_FILE=:DIREVENT_GENEV_ -f \$outfile -k\\\$self_test_pid\";
+}
+
+EOT
+cat > selftest.sh <<EOT
+#!/bin/sh
+echo \"foo\" > file
+
+sleep 10
+exit 21
+EOT
+chmod +x selftest.sh
+direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
+sed '/^argv\\[[0-9]]\\=-k/d' \$outfile
+
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "file.at:20"
+( $at_check_trace;
+outfile=$cwd/dump
+echo "file" > file
+
+cat > test.conf <<EOT
+
+debug 10;
+syslog {
+	facility ${TESTSUITE_FACILITY:-local0};
+	tag direvent-test:create;
+}
+watcher {
+	path $cwd/file;
+	event (create,write,delete);
+	option (stdout,stderr);
+	command "$TESTDIR/envdump -s -i DIREVENT_FILE=:DIREVENT_GENEV_ -f $outfile -k\$self_test_pid";
+}
+
+EOT
+cat > selftest.sh <<EOT
+#!/bin/sh
+echo "foo" > file
+
+sleep 10
+exit 21
+EOT
+chmod +x selftest.sh
+direvent -lnotice -f --self-test $cwd/selftest.sh test.conf || exit $?
+sed '/^argv\[[0-9]]\=-k/d' $outfile
+
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "# Dump of execution environment
+cwd is $cwd
+# Arguments
+argv[0]=$TESTDIR/envdump
+argv[1]=-s
+argv[2]=-i
+argv[3]=DIREVENT_FILE=:DIREVENT_GENEV_
+argv[4]=-f
+argv[5]=$cwd/dump
+# Environment
+DIREVENT_FILE=file
+DIREVENT_GENEV_CODE=2
+DIREVENT_GENEV_NAME=write
+# End
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/file.at:20"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_20
+#AT_START_21
+at_fn_group_banner 21 'sent.at:17' \
+  "Sentinel" "                                       " 3
+at_xfail=no
+(
+  $as_echo "21. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+
+cwd=`pwd -P`
+{ set +x
+$as_echo "$at_srcdir/sent.at:20:
+outfile=\$cwd/dump
+
+cat > test.conf <<EOT
+
+debug 10;
+syslog {
+	facility \${TESTSUITE_FACILITY:-local0};
+	tag direvent-test:create;
+}
+watcher {
+	path \$cwd/dir/sub;
+	file \"foo\";
+	event (create);
+	option (stdout,stderr);
+	command \"\$TESTDIR/envdump -s -i DIREVENT_FILE=:DIREVENT_GENEV_ -a -f \$outfile -k\\\$self_test_pid\";
+}
+
+EOT
+cat > selftest.sh <<EOT
+#!/bin/sh
+sleep 1
+mkdir \$cwd/dir
+sleep 1
+mkdir \$cwd/dir/sub
+sleep 1
+echo \"bar\" > \$cwd/dir/sub/bar
+echo \"foo\" > \$cwd/dir/sub/foo
+
+sleep 10
+exit 21
+EOT
+chmod +x selftest.sh
+direvent -lnotice -f --self-test \$cwd/selftest.sh test.conf || exit \$?
+sed \"s^\$cwd^(CWD)^;s^\$TESTDIR^(TESTDIR)^;/^argv\\[[0-9]]\\=-k/d\" \$outfile
+
+"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "sent.at:20"
+( $at_check_trace;
+outfile=$cwd/dump
+
+cat > test.conf <<EOT
+
+debug 10;
+syslog {
+	facility ${TESTSUITE_FACILITY:-local0};
+	tag direvent-test:create;
+}
+watcher {
+	path $cwd/dir/sub;
+	file "foo";
+	event (create);
+	option (stdout,stderr);
+	command "$TESTDIR/envdump -s -i DIREVENT_FILE=:DIREVENT_GENEV_ -a -f $outfile -k\$self_test_pid";
+}
+
+EOT
+cat > selftest.sh <<EOT
+#!/bin/sh
+sleep 1
+mkdir $cwd/dir
+sleep 1
+mkdir $cwd/dir/sub
+sleep 1
+echo "bar" > $cwd/dir/sub/bar
+echo "foo" > $cwd/dir/sub/foo
+
+sleep 10
+exit 21
+EOT
+chmod +x selftest.sh
+direvent -lnotice -f --self-test $cwd/selftest.sh test.conf || exit $?
+sed "s^$cwd^(CWD)^;s^$TESTDIR^(TESTDIR)^;/^argv\[[0-9]]\=-k/d" $outfile
+
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; $as_echo "direvent: [NOTICE] installing CREATE sentinel for $cwd/dir/sub
+direvent: [NOTICE] installing CREATE sentinel for $cwd/dir
+" | \
+  $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; $as_echo "# Dump of execution environment
+cwd is (CWD)/dir/sub
+# Arguments
+argv[0]=(TESTDIR)/envdump
+argv[1]=-s
+argv[2]=-i
+argv[3]=DIREVENT_FILE=:DIREVENT_GENEV_
+argv[4]=-a
+argv[5]=-f
+argv[6]=(CWD)/dump
+# Environment
+DIREVENT_FILE=foo
+DIREVENT_GENEV_CODE=1
+DIREVENT_GENEV_NAME=create
+# End
+" | \
+  $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/sent.at:20"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_21
diff --git a/tests/testsuite.at b/tests/testsuite.at
index cbe9906..a34de35 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -18,28 +18,32 @@ m4_version_prereq([2.52g])
 
 m4_define([AT_SKIP_TEST],[exit 77])
 
-dnl AT_DIREVENT_TEST([CONFIG],[SELFTEST],[PROLOGUE],[EPILOGUE],[CODE],[STDOUT],
+dnl m4_direvent_test([MOD],
+dnl                  [CONFIG],[SELFTEST],[PROLOGUE],[EPILOGUE],[CODE],[STDOUT],
 dnl                  [STDERR])                 
-m4_define([AT_DIREVENT_TEST],[
-AT_CHECK([
+m4_define([m4_direvent_test],[
 cwd=`pwd -P`
-$3
+AT_CHECK$1([
+$4
 cat > test.conf <<EOT
-[$1]
+[$2]
 EOT
 cat > selftest.sh <<EOT
 #!/bin/sh
-[$2]
+[$3]
 sleep 10
 exit 21
 EOT
 chmod +x selftest.sh
 direvent -lnotice -f --self-test $cwd/selftest.sh test.conf || exit $?
-$4
+$5
 ],
-[$5],
 [$6],
-[$7])])
+[$7],
+[$8])])
+
+m4_define([AT_DIREVENT_TEST],[m4_direvent_test([],$@)])
+m4_define([AT_DIREVENT_TEST_UNQUOTED],[m4_direvent_test([_UNQUOTED], $@)])
 
 AT_INIT
 AT_TESTED([direvent])
@@ -68,3 +72,6 @@ m4_include([re03.at])
 m4_include([re04.at])
 m4_include([re05.at])
 
+AT_BANNER([Special watchpoints])
+m4_include([file.at])
+m4_include([sent.at])

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/lib/debug/.build-id/4b/5f70bb92e746af47e3047f516747642375a95b.debug
-rw-r--r--  root/root   /usr/share/locale/es/LC_MESSAGES/direvent.mo
-rw-r--r--  root/root   /usr/share/locale/sv/LC_MESSAGES/direvent.mo

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/lib/debug/.build-id/44/b7f44fb2220862458f607a5d7810ae5b0d637b.debug

Control files of package direvent: lines which differ (wdiff format)

  • Homepage: http://www.gnu.org.ua/software/direvent/ https://www.gnu.org.ua/software/direvent/
  • Pre-Depends: init-system-helpers (>= 1.54~)

Control files of package direvent-dbgsym: lines which differ (wdiff format)

  • Build-Ids: 44b7f44fb2220862458f607a5d7810ae5b0d637b 4b5f70bb92e746af47e3047f516747642375a95b

Run locally

More details

Full run details