summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-07-10 07:09:45 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-07-10 07:09:45 (GMT)
commitd73567ebdf054eb6de6dea72250ef164e4c50eec (patch) (side-by-side diff)
treec8d48504b02786e13215923b3e2654fe42275f0d
parentee35adccec058a5a8cc62f5030b9a925168236d6 (diff)
downloadgrecs-d73567ebdf054eb6de6dea72250ef164e4c50eec.tar.gz
grecs-d73567ebdf054eb6de6dea72250ef164e4c50eec.tar.bz2
Import wordsplit as a submodule
* .gitmodules: New module: wordsplit * Makefile.am: Distribute wordsplit files. * am/grecs.m4 (GRECS_INCLUDES): Add wordsplit directory * doc/Makefile.am (dist_man_MANS): Distribute wordsplit/wordsplit.3 * doc/wordsplit.3: Remove. * include/Makefile.am (GRECS_HDR): Add wordsplit/wordsplit. * include/wordsplit.h: Remove. * src/Make-inst.am: Define nodist_libgrecs_la_SOURCES. * src/Make-shared.am: Likewise. * src/Make-static.am: Define nodist_libgrecs_a_SOURCES. * src/Make.am (GRECS_SRC): Remove wordsplit.c (NODIST_GRECS_SRC): Define to wordsplit.c (VPATH): Add the wordsplit directory. * src/wordsplit.c: Remove. * tests/wordsplit.at: Remove. * tests/wsp.c: Remove. * tests/Makefile.am: Build separate testsuite for wordsplit. Use VPATH to build wsp. * tests/.gitignore: Update.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--.gitmodules3
-rw-r--r--Makefile.am6
-rw-r--r--am/grecs.m44
-rw-r--r--doc/Makefile.am6
-rw-r--r--doc/wordsplit.31036
-rw-r--r--include/Makefile.am2
-rw-r--r--include/wordsplit.h306
-rw-r--r--src/Make-inst.am4
-rw-r--r--src/Make-shared.am3
-rw-r--r--src/Make-static.am3
-rw-r--r--src/Make.am6
-rw-r--r--src/wordsplit.c2892
-rw-r--r--tests/.gitignore4
-rw-r--r--tests/Makefile.am54
-rw-r--r--tests/testsuite.at2
-rw-r--r--tests/wordsplit.at1030
-rw-r--r--tests/wsp.c756
m---------wordsplit0
18 files changed, 76 insertions, 6041 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..ec3950b
--- a/dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "wordsplit"]
+ path = wordsplit
+ url = git://git.gnu.org.ua/wordsplit.git
diff --git a/Makefile.am b/Makefile.am
index 3eaa8df..b8482a1 100644
--- a/Makefile.am
+++ b/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,9 @@
ACLOCAL_AMFLAGS = -I am
SUBDIRS=. include src @GRECS_TESTDIR@ @GRECS_DOCDIR@
-EXTRA_DIST=build-aux/yyrename @GRECS_BUILD_AUX@ @GRECS_DISTDOC@ gitid.h
+EXTRA_DIST=build-aux/yyrename @GRECS_BUILD_AUX@ @GRECS_DISTDOC@ gitid.h\
+ wordsplit/wordsplit.c wordsplit/wordsplit.h wordsplit/wordsplit.3 \
+ wordsplit/wordsplit.at wordsplit/wsp.c
noinst_HEADERS = gitid.h
BUILT_SOURCES = gitid.h README
diff --git a/am/grecs.m4 b/am/grecs.m4
index 33a6809..8bf3d21 100644
--- a/am/grecs.m4
+++ b/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
@@ -202,7 +202,7 @@ AC_DEFUN([GRECS_SETUP],[
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])
diff --git a/doc/Makefile.am b/doc/Makefile.am
index a646367..009537d 100644
--- a/doc/Makefile.am
+++ b/doc/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
@@ -29,5 +29,5 @@ dist_man_MANS = \
grecs_parse.3\
grecs_stmt_path.5\
grecs_strdup.3\
- grecs_tree_free.3
-
+ grecs_tree_free.3\
+ $(top_srcdir)/@GRECS_SUBDIR@/wordsplit/wordsplit.3
diff --git a/doc/wordsplit.3 b/doc/wordsplit.3
deleted file mode 100644
index 1a6f80b..0000000
--- a/doc/wordsplit.3
+++ b/dev/null
@@ -1,1036 +0,0 @@
-.\" This file is part of grecs -*- nroff -*-
-.\" Copyright (C) 2007-2018 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/>.
-.\"
-.TH WORDSPLIT 3 "May 22, 2018" "GRECS" "Grecs User Reference"
-.SH NAME
-wordsplit \- split string into words
-.SH SYNOPSIS
-.B #include <wordsplit.h>
-.sp
-\fBint wordsplit (const char *\fIs\fB,\
- wordsplit_t *\fIws\fB, int \fIflags\fB);\fR
-.sp
-\fBint wordsplit_len (const char *\fIs\fB,\
- \fBsize_t \fIlen\fR,\
- \fBwordsplit_t *\fIp\fB,\
- int \fIflags\fB);
-.sp
-\fBvoid wordsplit_free (wordsplit_t *\fIp\fB);\fR
-.sp
-\fBvoid wordsplit_free_words (wordsplit_t *\fIws\fB);\fR
-.sp
-\fBvoid wordsplit_getwords (wordsplit_t *\fIws\fB,\
- int *\fIwordc\fB, char ***\fIwordv\fB);
-.sp
-\fBvoid wordsplit_perror (wordsplit_t *\fIws\fB);\fR
-.sp
-\fBconst char *wordsplit_strerror (wordsplit_t *\fIws\fB);\fR
-.sp
-\fBvoid wordsplit_clearerr (wordsplit_t *\fIws\fB);\fR
-.SH DESCRIPTION
-The function \fBwordsplit\fR splits the string \fIs\fR into words
-using a set of rules governed by \fIflags\fR. Depending on
-\fIflags\fR, the function performs the following operations:
-whitespace trimming, tilde expansion, variable expansion, quote
-removal, command substitution, and path expansion. On success,
-\fBwordsplit\fR returns 0 and stores the words found in the member
-\fBws_wordv\fR and the number of words in the member \fBws_wordc\fR.
-On error, a non-zero error code is returned.
-.PP
-The function \fBwordsplit_len\fR acts similarly, except that it
-accesses only first \fBlen\fR bytes of the string \fIs\fR, which is
-not required to be null-terminated.
-.PP
-When no longer needed, the resources allocated by a call to one of
-these functions must be freed using
-.BR wordsplit_free .
-.PP
-The function
-.B wordsplit_free_words
-frees only the memory allocated for elements of
-.I ws_wordv
-and initializes
-.I ws_wordc
-to zero.
-.PP
-The usual calling sequence is:
-.PP
-.EX
-wordsplit_t ws;
-int rc;
-
-if (wordsplit(s, &ws, WRDSF_DEFFLAGS)) {
- wordsplit_perror(&ws);
- return;
-}
-for (i = 0; i < ws.ws_wordc; i++) {
- /* do something with ws.ws_wordv[i] */
-}
-wordsplit_free(&ws);
-.EE
-.PP
-The function
-.B wordsplit_getwords
-returns in \fIwordv\fR an array of words, and in \fIwordc\fR the number
-of elements in \fIwordv\fR. The array can be used after calling
-.BR wordsplit_free .
-The caller becomes responsible for freeing the memory allocated for
-each element of the array and the array pointer itself.
-.PP
-The function
-.B wordsplit_perror
-prints error message from the last invocation of \fBwordsplit\fR. It
-uses the function pointed to by the
-.I ws_error
-member. By default, it outputs the message on the standard error.
-.PP
-For more sophisticated error reporting, the function
-.B wordsplit_strerror
-can be used. It returns a pointer to the string describing the error.
-The caller should treat this pointer as a constant string. It should
-not try to alter or deallocate it.
-.PP
-The function
-.B wordsplit_clearerr
-clears the error condition associated with \fIws\fR.
-.SH INCREMENTAL MODE
-In incremental mode \fBwordsplit\fR parses one word per invocation.
-It returns \fBWRDSF_OK\fR on success and \fBWRDSF_NOINPUT\fR when
-entire input string has been processed.
-.PP
-This mode is enabled if the flag \fBWRDSF_INCREMENTAL\fR is set in
-the \fIflags\fR argument. Subsequent calls to \fBwordsplit\fR must
-have \fBNULL\fR as first argument. Each successful
-call will return exactly one word in \fBws.ws_wordv[0]\fR.
-.PP
-An example usage:
-.PP
-.EX
-wordsplit_t ws;
-int rc;
-flags = WRDSF_DEFFLAGS|WRDSF_INCREMENTAL;
-
-for (rc = wordsplit(s, &ws, flags); rc == WRDSF_OK;
- rc = wordsplit(NULL, &ws, flags)) {
- process(ws.ws_wordv[0]);
-}
-
-if (rc != WRDSE_NOINPUT)
- wordsplit_perror(&ws);
-
-wordsplit_free(&ws);
-.EE
-.SH OPTIONS
-The number of flags is limited to 32 (the width of \fBuint32_t\fR data
-type) and each bit is occupied by a corresponding flag. However, the
-number of features \fBwordsplit\fR provides required still
-more. Additional features can be requested by setting a corresponding
-\fIoption bit\fR in the \fBws_option\fR field of the \fBstruct
-wordsplit\fR argument. To inform wordsplit functions that this field
-is initialized the \fBWRDSF_OPTIONS\fR flag must be set.
-.PP
-Option symbolic names begin with \fBWRDSO_\fR. They are discussed in
-detail in the subsequent chapters.
-.SH EXPANSION
-Expansion is performed on the input after it has been split into
-words. There are several kinds of expansion, which of them are
-performed is controlled by appropriate bits set in the \fIflags\fR
-argument. Whatever expansion kinds are enabled, they are always run
-in the same order as described in this section.
-.SS Whitespace trimming
-Whitespace trimming removes any leading and trailing whitespace from
-the initial word array. It is enabled by the
-.B WRDSF_WS
-flag. Whitespace trimming is needed only if you redefine
-word delimiters (\fIws_delim\fR member) so that they don't contain
-whitespace characters (\fB\(dq \\t\\n\(dq\fR).
-.SS Tilde expansion
-Tilde expansion is enabled if the
-.B WRDSF_PATHEXPAND
-bit is set. It expands all words that begin with an unquoted tilde
-character (`\fB~\fR'). If tilde is followed immediately by a slash,
-it is replaced with the home directory of the current user (as
-determined by his \fBpasswd\fR entry). A tilde alone is handled the
-same way. Otherwise, the characters between the tilde and first slash
-character (or end of string, if it doesn't contain any) are treated as
-a login name. and are replaced (along with the tilde itself) with the
-home directory of that user. If there is no user with such login
-name, the word is left unchanged.
-.SS Variable expansion
-Variable expansion replaces each occurrence of
-.BI $ NAME
-or
-.BI ${ NAME }
-with the value of the variable \fINAME\fR. It is enabled if the
-flag \fBWRDSF_NOVAR\fR is not set. The caller is responsible for
-supplying the table of available variables. Two mechanisms are
-provided: environment array and a callback function.
-.PP
-Environment array is a \fBNULL\fR-terminated array of variables,
-stored in the \fIws_env\fR member. The \fBWRDSF_ENV\fR flag must be
-set in order to instruct \fBwordsplit\fR to use this array.
-.PP
-By default, elements of the \fIws_env\fR array have the form
-.IR NAME = VALUE .
-An alternative format is enabled by the
-.B WRDSF_ENV_KV
-flag. When it is set, each variable is described by two consecutive
-elements in the array:
-.IR ws_env [ n ]
-containing the variable name, and
-.IR ws_env [ "n+1" ]
-containing its value. If the latter is \fBNULL\fR, the corresponding
-variable is undefined.
-.PP
-More sophisticated variable tables can be implemented using
-callback function. The \fIws_getvar\fR member should be set to point
-to that function and \fBWRDSF_GETVAR\fR flag must be set. The
-function itself shall be defined as
-.PP
-.EX
-int getvar (char **ret, const char *var, size_t len, void *clos);
-.EE
-.PP
-The function shall look up for the variable identified by the first
-\fIlen\fR bytes of the string \fIvar\fR. If such variable is found,
-the function shall store a copy of its value (allocated using
-\fBmalloc\fR(3)) in the memory location pointed to by \fBret\fR, and
-return \fBWRDSE_OK\fR. If the variable is not found, the function shall
-return \fBWRDSE_UNDEF\fR. Otherwise, a non-zero error code shall be
-returned.
-.PP
-If \fIws_getvar\fR returns
-.BR WRDSE_USERERR ,
-it must store the pointer to the error description string in
-.BR *ret .
-In any case (whether returning \fB0\fR or \fBWRDSE_USERERR\fR) , the
-data returned in \fBret\fR must be allocated using
-.BR malloc (3).
-.PP
-If both
-.I ws_env
-and
-.I ws_getvar
-are used, the variable is first looked up in
-.IR ws_env ,
-and if not found there, the
-.I ws_getvar
-function is called.
-.PP
-During variable expansion, the forms below cause
-.B wordsplit
-to test for a variable that is unset or null. Omitting the
-colon results in a test only for a variable that is unset.
-.TP
-.BI ${ variable :- word }
-.BR "Use Default Values" .
-If \fIvariable\fR is unset or null, the expansion of \fIword\fR is substituted.
-Otherwise, the value of \fIvariable\fR is substituted.
-.TP
-.BI ${ variable := word }
-.BR "Assign Default Values" .
-If \fIvariable\fR is unset or null, the expansion of \fIword\fR is
-assigned to \fIvariable\fR. The value of \fIvariable\fR is then substituted.
-.TP
-.BI ${ variable :? word }
-.BR "Display Error if Null or Unset" .
-If \fIvariable\fR is null or unset, the expansion of \fIword\fR (or a
-message to that effect if word is not present) is output using
-.IR ws_error .
-Otherwise, the value of \fIvariable\fR is substituted.
-.TP
-.BI ${ variable :+ word }
-.BR "Use Alternate Value" .
-If \fIvariable\fR is null or unset, nothing is substituted, otherwise the
-expansion of \fIword\fR is substituted.
-.SS Quote removal
-Quote removal translates unquoted escape sequences into corresponding bytes.
-An escape sequence is a backslash followed by one or more characters. By
-default, each sequence \fB\\\fIC\fR appearing in unquoted words is
-replaced with the character \fIC\fR. In doubly-quoted strings, two
-backslash sequences are recognized: \fB\\\\\fR translates to a single
-backslash, and \fB\\\(dq\fR translates to a double-quote.
-.PP
-Two flags are provided to modify this behavior. If
-.I WRDSF_CESCAPES
-flag is set, the following escape sequences are recognized:
-.sp
-.nf
-.ta 8n 18n 42n
-.ul
- Sequence Expansion ASCII
- \fB\\\\\fR \fB\\\fR 134
- \fB\\\(dq\fR \fB\(dq\fR 042
- \fB\\a\fR audible bell 007
- \fB\\b\fR backspace 010
- \fB\\f\fR form-feed 014
- \fB\\n\fR new line 012
- \fB\\r\fR charriage return 015
- \fB\\t\fR horizontal tabulation 011
- \fB\\v\fR vertical tabulation 013
-.fi
-.sp
-The sequence \fB\\x\fINN\fR or \fB\\X\fINN\fR, where \fINN\fR stands
-for a two-digit hex number is replaced with ASCII character \fINN\fR.
-The sequence \fB\\0\fINNN\fR, where \fINNN\fR stands for a three-digit
-octal number is replaced with ASCII character whose code is \fINNN\fR.
-.PP
-The \fBWRDSF_ESCAPE\fR flag allows the caller to customize escape
-sequences. If it is set, the \fBws_escape\fR member must be
-initialized. This member provides escape tables for unquoted words
-(\fBws_escape[0]\fR) and quoted strings (\fBws_escape[1]\fR). Each
-table is a string consisting of even number of charactes. In each
-pair of characters, the first one is a character that can appear after
-backslash, and the following one is its translation. For example, the
-above table of C escapes is represented as
-\fB\(dqa\\ab\\bf\\fn\\nr\\rt\\tv\\v\(dq\fR.
-.PP
-It is valid to initialize \fBws_escape\fR elements to zero. In this
-case, no backslash translation occurs.
-.PP
-The handling of octal and hex escapes is controlled by the following
-bits in \fBws_options\fR:
-.TP
-.B WRDSO_BSKEEP_WORD
-When an unrecognized escape sequence is encountered in a word,
-preserve it on output. If that bit is not set, the backslash is
-removed from such sequences.
-.TP
-.B WRDSO_OESC_WORD
-Handle octal escapes in words.
-.TP
-.B WRDSO_XESC_WORD
-Handle hex escapes in words.
-.TP
-.B WRDSO_BSKEEP_QUOTE
-When an unrecognized escape sequence is encountered in a doubly-quoted
-string, preserve it on output. If that bit is not set, the backslash is
-removed from such sequences.
-.TP
-.B WRDSO_OESC_QUOTE
-Handle octal escapes in doubly-quoted strings.
-.TP
-.B WRDSO_XESC_QUOTE
-Handle hex escapes in doubly-quoted strings.
-.SS Command substitution
-During \fIcommand substitution\fR, each word is scanned for commands.
-Each command found is executed and replaced by the output it creates.
-.PP
-The syntax is:
-.PP
-.RS +4
-.BI $( command )
-.RE
-.PP
-Command substitutions may be nested.
-.PP
-Unless the substitution appears within double quotes, word splitting and
-pathname expansion are performed on its result.
-.PP
-To enable command substitution, the caller must initialize the
-.I ws_command
-member with the address of the substitution function and make sure the
-.B WRDSF_NOCMD
-flag is not set.
-.PP
-The substitution function should be defined as follows:
-.PP
-.RS +4
-\fBint \fIcommand\fB\
- (char **\fIret\fB,\
- const char *\fIcmd\fB,\
- size_t \fIlen,\fB\
- char **\fIargv\fB,\
- void *\fIclos\fB);\fR
-.RE
-.PP
-First \fIlen\fR bytes of \fIcmd\fR contain the command invocation as
-it appeared between
-.BR $( and ),
-with all expansions performed.
-.PP
-The \fIargv\fR parameter contains the command
-line split into words using the same settings as the input \fIws\fR structure.
-.PP
-The \fIclos\fR parameter supplies user-specific data, passed in the
-\fIws_closure\fR member).
-.PP
-On success, the function stores a pointer to the
-output string in the memory location pointed to by \fIret\fR and
-returns \fBWRDSE_OK\fR (\fB0\fR). On error, it must return one of the
-error codes described in the section
-.BR "ERROR CODES" .
-If
-.BR WRDSE_USERERR ,
-is returned, a pointer to the error description string must be stored in
-.BR *ret .
-.PP
-When \fBWRDSE_OK\fR or \fBWRDSE_USERERR\fR is returned, the
-data stored in \fB*ret\fR must be allocated using
-.BR malloc (3).
-.SS Pathname expansion
-Pathname expansion is performed if the \fBWRDSF_PATHEXPAND\fR flag is
-set. Each unquoted word is scanned for characters
-.BR * , ? ", and " [ .
-If one of these appears, the word is considered a \fIpattern\fR (in
-the sense of
-.BR glob (3))
-and is replaced with an alphabetically sorted list of file names matching the
-pattern.
-.PP
-If no matches are found for a word
-and the \fIws_options\fR member has the
-.B WRDSO_NULLGLOB
-bit set, the word is removed.
-.PP
-If the \fBWRDSO_FAILGLOB\fR option is set, an error message is output
-for each such word using
-.IR ws_error .
-.PP
-When matching a pattern, the dot at the start of a name or immediately
-following a slash must be matched explicitly, unless
-the \fBWRDSO_DOTGLOB\fR option is set.
-.SH LIMITING THE NUMBER OF WORDS
-The maximum number of words to be returned can be limited by setting
-the \fBws_maxwords\fR member to the desired count, and setting the
-\fBWRDSO_MAXWORDS\fR option, e.g.:
-.sp
-.EX
-struct wordsplit ws;
-ws.ws_maxwords = 3;
-ws.ws_options = WRDSO_MAXWORDS;
-wordsplit(str, &ws, WRDSF_DEFFLAGS|WRDSF_OPTIONS);
-.EE
-.PP
-If the actual number of words in the expanded input is greater than
-the supplied limit, the trailing part of the input will be returned in
-the last word. For example, if the input to the above fragment were
-\fBNow is the time for all good men\fR, then the returned words would be:
-.sp
-.EX
-"Now"
-"is"
-"the time for all good men"
-.EE
-.SH WORDSPLIT_T STRUCTURE
-The data type \fBwordsplit_t\fR has three members that contain
-output data upon return from \fBwordsplit\fR or \fBwordsplit_len\fR,
-and a number of members that the caller can initialize on input in
-order to customize the function behavior. Each its member has a
-corresponding flag bit, which must be set in the \fIflags\fR argument
-in order to instruct the \fBwordsplit\fR function to use it.
-.SS OUTPUT
-.TP
-.BI size_t " ws_wordc"
-Number of words in \fIws_wordv\fR. Accessible upon successful return
-from \fBwordsplit\fR.
-.TP
-.BI "char ** " ws_wordv
-Array of resulting words. Accessible upon successful return
-from \fBwordsplit\fR.
-.TP
-.BI "size_t " ws_wordi
-Total number of words processed. This field is intended for use with
-.B WRDSF_INCREMENTAL
-flag. If that flag is not set, the following relation holds:
-.BR "ws_wordi == ws_wordc - ws_offs" .
-.TP
-.BI "int " ws_errno
-Error code, if the invocation of \fBwordsplit\fR or
-\fBwordsplit_len\fR failed. This is the same value as returned from
-the function in that case.
-.PP
-The caller should not attempt to free or reallocate \fIws_wordv\fR or
-any elements thereof, nor to modify \fIws_wordc\fR.
-.PP
-To store away the words for use after freeing \fIws\fR with
-.BR wordsplit_free ,
-the caller should use
-.BR wordsplit_getwords .
-It is more effective than copying the contents of
-.I ws_wordv
-manually.
-.SS INPUT
-.TP
-.BI "size_t " ws_offs
-If the
-.B WRDSF_DOOFFS
-flag is set, this member specifies the number of initial elements in
-.I ws_wordv
-to fill with NULLs. These elements are not counted in the returned
-.IR ws_wordc .
-.TP
-.BI "size_t " ws_maxwords
-Maximum number of words to return. For this field to take effect, the
-\fBWRDSO_MAXWORDS\fR option and \fBWRDSF_OPTIONS\fR flag must be set.
-For a detailed discussion, see the chapter
-.BR "LIMITING THE NUMBER OF WORDS" .
-.TP
-.BI "int " ws_flags
-Contains flags passed to wordsplit on entry. Can be used as a
-read-only member when using \fBwordsplit\fR in incremental mode or
-in a loop with
-.B WRDSF_REUSE
-flag set.
-.TP
-.BI "int " ws_options
-Additional options used when
-.B WRDSF_OPTIONS
-is set.
-.TP
-.BI "const char *" ws_delim
-Word delimiters. If initialized on input, the
-.B WRDSF_DELIM
-flag must be set. Otherwise, it is initialized on entry to
-.B wordsplit
-with the string \fB\(dq \\t\\n\(dq\fR.
-.TP
-.BI "const char *" ws_comment
-A zero-terminated string of characters that begin an inline comment.
-If initialized on input, the
-.B WRDSF_COMMENT
-flag must be set. By default, it's value is \fB\(dq#\(dq\fR.
-.TP
-.BI "const char *" ws_escape [2]
-Escape tables for unquoted words (\fBws_escape[0]\fR) and quoted
-strings (\fBws_escape[1]\fR). These are used to translate escape
-sequences (\fB\\\fIC\fR) into characters. Each table is a string
-consisting of even number of charactes. In each pair of characters,
-the first one is a character that can appear after backslash, and the
-following one is its representation. For example, the string
-\fB\(dqt\\tn\\n\(dq\fR translates \fB\\t\fR into horisontal
-tabulation character and \fB\\n\fR into newline.
-.B WRDSF_ESCAPE
-flag must be set if this member is initialized.
-.TP
-.BI "void (*" ws_alloc_die ") (wordsplit_t *)"
-This function is called when
-.B wordsplit
-is unable to allocate memory and the
-.B WRDSF_ENOMEMABRT
-flag was set. The default function prints a
-message on standard error and aborts. This member can be used
-to customize error handling. If initialized, the
-.B WRDSF_ALLOC_DIE
-flag must be set.
-.TP
-.BI "void (*" ws_error ") (const char *, ...)"
-Pointer to function used for error reporting. The invocation
-convention is the same as for
-.BR printf (3).
-The default function formats and prints the message on the standard
-error.
-
-If this member is initialized, the
-.B WRDSF_ERROR
-flag must be set.
-.TP
-.BI "void (*" ws_debug ") (const char *, ...)"
-Pointer to function used for debugging output. By default it points
-to the same function as
-.BR ws_error .
-If initialized, the
-.B WRDSF_DEBUG
-flag must be set.
-.TP
-.BR "const char **" ws_env
-A \fBNULL\fR-terminated array of environment variables. It is used
-during variable expansion. If set, the
-.B WRDSF_ENV
-flag must be set. Variable expansion is enabled only if either
-.B WRDSF_ENV
-or
-.B WRDSF_GETVAR
-(see below) is set, and
-.B WRDSF_NOVAR
-flag is not set.
-
-Each element of
-.I ws_env
-must have the form \fB\(dq\fINAME\fB=\fIVALUE\fR, where \fINAME\fR is
-the name of the variable, and \fIVALUE\fR is its value.
-Alternatively, if the \fBWRDSF_ENV_KV\fR flag is set, each variable is
-described by two elements of
-.IR ws_env :
-one containing variable name, and the next one with its
-value.
-.TP
-.BI "int (*" ws_getvar ") (char **ret, const char *var, size_t len, void *clos)"
-Points to the function that will be used during variable expansion to
-look up for the value of the environment variable named \fBvar\fR.
-This function is used if the variable expansion is enabled (i.e. the
-.B WRDSF_NOVAR
-flag is not set), and the \fBWRDSF_GETVAR\fR flag is set.
-
-If both
-.B WRDSF_ENV
-and
-.B WRDSF_GETVAR
-are set, the variable is first looked up in the
-.I ws_env
-array and, if not found there,
-.I ws_getvar
-is called.
-
-The name of the variable is specified by the first \fIlen\fR bytes of
-the string \fIvar\fR. The \fIclos\fR parameter supplies the
-user-specific data (see below the description of \fIws_closure\fR
-member) and the \fBret\fR parameter points to the memory location
-where output data is to be stored. On success, the function must
-store ther a pointer to the string with the value of the variable and
-return 0. On error, it must return one of the error codes described
-in the section
-.BR "ERROR CODES" .
-If \fIws_getvar\fR returns
-.BR WRDSE_USERERR ,
-it must store the pointer to the error description string in
-.BR *ret .
-In any case (whether returning \fB0\fR or \fBWRDSE_USERERR\fR) , the
-data returned in \fBret\fR must be allocated using
-.BR malloc (3).
-.TP
-.BI "void *" ws_closure
-Additional user-specific data passed as the last argument to
-.I ws_getvar
-or
-.I ws_command
-(see below). If defined, the
-.B WRDSF_CLOSURE
-flag must be set.
-.TP
-\fBint (*\fIws_command\fB)\
- (char **ret,\
- const char *cmd,\
- size_t len,\
- char **argv,\
- void *clos)\fR
-Pointer to the function that performs command substitution. It treats
-the first \fIlen\fR bytes of the string \fIcmd\fR as a command
-(whatever it means for the caller) and attempts to execute it. On
-success, a pointer to the string with the command output is stored
-in the memory location pointed to by \fBret\fR and \fB0\fR is
-returned. On error,
-the function must return one of the error codes described in the section
-.BR "ERROR CODES" .
-If \fIws_command\fR returns
-.BR WRDSE_USERERR ,
-it must store the pointer to the error description string in
-.BR *ret .
-In any case (whether returning \fB0\fR or \fBWRDSE_USERERR\fR) , the
-data returned in \fBret\fR must be allocated using
-.BR malloc (3).
-
-The parameter \fBargv\fR contains the command split into
-words using the same settings as the input \fIws\fR structure, with
-command substitution disabled.
-
-The \fIclos\fR parameter supplies user-specific data (see the
-description of \fIws_closure\fR member).
-.SH FLAGS
-The following macros are defined for use in the \fBflags\fR argument.
-.TP
-.B WRDSF_DEFFLAGS
-Default flags. This is a shortcut for:
-
-\fB(WRDSF_NOVAR |\
- WRDSF_NOCMD |\
- WRDSF_QUOTE |\
- WRDSF_SQUEEZE_DELIMS |\
- WRDSF_CESCAPES)\fR,
-
-i.e.: disable variable expansion and quote substituton, perform quote
-removal, treat any number of consequtive delimiters as a single
-delimiter, replace \fBC\fR escapes appearing in the input string with
-the corresponding characters.
-.TP
-.B WRDSF_APPEND
-Append the words found to the array resulting from a previous call to
-\fBwordsplit\fR.
-.TP
-.B WRDSF_DOOFFS
-Insert
-.I ws_offs
-initial
-.BR NULL s
-in the array
-.IR ws_wordv .
-These are not counted in the returned
-.IR ws_wordc .
-.TP
-.B WRDSF_NOCMD
-Don't do command substitution.
-.TP
-.B WRDSF_REUSE
-The parameter \fIws\fR resulted from a previous call to
-\fBwordsplit\fR, and \fBwordsplit_free\fR was not called. Reuse the
-allocated storage.
-.TP
-.B WRDSF_SHOWERR
-Print errors using
-.BR ws_error .
-.TP
-.B WRDSF_UNDEF
-Consider it an error if an undefined variable is expanded.
-.TP
-.B WRDSF_NOVAR
-Don't do variable expansion.
-.TP
-.B WRDSF_ENOMEMABRT
-Abort on
-.B ENOMEM
-error. By default, out of memory errors are treated as any other
-errors: the error is reported using \fIws_error\fR if the
-.B WRDSF_SHOWERR
-flag is set, and error code is returned. If this flag is set, the
-.B ws_alloc_die
-function is called instead. This function is not supposed to return.
-.TP
-.B WRDSF_WS
-Trim off any leading and trailind whitespace from the returned
-words. This flag is useful if the \fIws_delim\fR member does not
-contain whitespace characters.
-.TP
-.B WRDSF_SQUOTE
-Handle single quotes.
-.TP
-.B WRDSF_DQUOTE
-Handle double quotes.
-.TP
-.B WRDSF_QUOTE
-A shortcut for \fB(WRDSF_SQUOTE|WRDSF_DQUOTE)\fR.
-.TP
-.B WRDSF_SQUEEZE_DELIMS
-Replace each input sequence of repeated delimiters with a single
-delimiter.
-.TP
-.B WRDSF_RETURN_DELIMS
-Return delimiters.
-.TP
-.B WRDSF_SED_EXPR
-Treat
-.BR sed (1) expressions as words.
-.TP
-.B WRDSF_DELIM
-.I ws_delim
-member is initialized.
-.TP
-.B WRDSF_COMMENT
-.I ws_comment
-member is initialized.
-.TP
-.B WRDSF_ALLOC_DIE
-.I ws_alloc_die
-member is initialized.
-.TP
-.B WRDSF_ERROR
-.I ws_error
-member is initialized.
-.TP
-.B WRDSF_DEBUG
-.I ws_debug
-member is initialized.
-.TP
-.B WRDSF_ENV
-.I ws_env
-member is initialized.
-.TP
-.B WRDSF_GETVAR
-.I ws_getvar member is initialized.
-.TP
-.B WRDSF_SHOWDBG
-Enable debugging.
-.TP
-.B WRDSF_NOSPLIT
-Don't split input into words. This flag is is useful for side
-effects, e.g. to perform variable expansion within a string.
-.TP
-.B WRDSF_KEEPUNDEF
-Keep undefined variables in place, instead of expanding them to
-empty strings.
-.TP
-.B WRDSF_WARNUNDEF
-Warn about undefined variables.
-.TP
-.B WRDSF_CESCAPES
-Handle \fBC\fR-style escapes in the input string.
-.TP
-.B WRDSF_CLOSURE
-.I ws_closure
-is set.
-.TP
-.B WRDSF_ENV_KV
-Each two consecutive elements in the
-.I ws_env
-array describe a single variable:
-.IR ws_env [ n ]
-contains variable name, and
-.IR ws_env [ "n+1" ]
-contains its value.
-.TP
-.B WRDSF_ESCAPE
-.I ws_escape
-is set.
-.TP
-.B WRDSF_INCREMENTAL
-Incremental mode. Each subsequent call to \fBwordsplit\fR with
-\fBNULL\fR as its first argument parses the next word from the input.
-See the section
-.B INCREMENTAL MODE
-for a detailed discussion.
-.TP
-.B WRDSF_PATHEXPAND
-Perform pathname and tilde expansion. If this flag is set, the
-\fIws_options\fR member must also be initialized. See the
-subsection
-.B "Pathname expansion"
-for details.
-.TP
-.B WRDSF_OPTIONS
-The
-.I ws_options
-member is initialized.
-.SH OPTIONS
-The
-.I ws_options
-member is consulted if the
-.B WRDSF_OPTIONS
-flag is set. It contains a bitwise \fBOR\fR of one or more of the
-following options:
-.TP
-.B WRDSO_NULLGLOB
-Remove the words that produce empty string after pathname expansion.
-.TP
-.B WRDSO_FAILGLOB
-Output error message if pathname expansion produces empty string.
-.TP
-.B WRDSO_DOTGLOB
-During pathname expansion allow a leading period to be matched by
-metacharacters.
-.PP
-.TP
-.B WRDSO_BSKEEP_WORD
-Quote removal: when an unrecognized escape sequence is encountered in a word,
-preserve it on output. If that bit is not set, the backslash is
-removed from such sequences.
-.TP
-.B WRDSO_OESC_WORD
-Quote removal: handle octal escapes in words.
-.TP
-.B WRDSO_XESC_WORD
-Quote removal: handle hex escapes in words.
-.TP
-.B WRDSO_BSKEEP_QUOTE
-Quote removal: when an unrecognized escape sequence is encountered in
-a doubly-quoted string, preserve it on output. If that bit is not
-set, the backslash is removed from such sequences.
-.TP
-.B WRDSO_OESC_QUOTE
-Quote removal: handle octal escapes in doubly-quoted strings.
-.TP
-.B WRDSO_XESC_QUOTE
-Quote removal: handle hex escapes in doubly-quoted strings.
-.TP
-.B WRDSO_MAXWORDS
-The \fBws_maxwords\fR member is initialized. This is used to control
-the number of words returned by a call to \fBwordsplit\fR. For a
-detailed discussion, refer to the chapter
-.BR "LIMITING THE NUMBER OF WORDS" .
-.SH "ERROR CODES"
-.TP
-.BR WRDSE_OK ", " WRDSE_EOF
-Successful return.
-.TP
-.B WRDSE_QUOTE
-Missing closing quote. The \fIws_endp\fR points to the position in
-the input string where the error occurred.
-.TP
-.B WRDSE_NOSPACE
-Memory exhausted.
-.TP
-.B WRDSE_USAGE
-Invalid wordsplit usage.
-.TP
-.B WRDSE_CBRACE
-Unbalanced curly brace.
-.TP
-.B WRDSE_UNDEF
-Undefined variable. This error is returned only if the
-\fBWRDSF_UNDEF\fR flag is set.
-.TP
-.B WRDSE_NOINPUT
-Input exhausted. This is not acually an error. This code is returned
-if \fBwordsplit\fR (or \fBwordsplit_len\fR) is invoked in incremental
-mode and encounters end of input string. See the section
-.BR "INCREMENTAL MODE" .
-.TP
-.B WRDSE_PAREN
-Unbalanced parenthesis.
-.TP
-.B WRDSE_GLOBERR
-An error occurred during pattern matching.
-.TP
-.B WRDSE_USERERR
-User-defined error. Normally this error is returned by \fBws_getvar\fR or
-\fBws_command\fR. Use the function
-.B wordsplit_strerror
-to get textual description of the error.
-.SH "RETURN VALUE"
-Both
-.B wordsplit
-and
-.B wordsplit_len
-return \fB0\fR on success, and a non-zero error code on
-error (see the section
-.BR "ERROR CODES" ).
-.PP
-.B wordsplit_strerror
-returns a pointer to the constant string describing the last error
-condition that occurred in
-.IR ws .
-.SH EXAMPLE
-The short program below implements a function that parses the
-input string similarly to the shell. All expansions are performed.
-Default error reporting is used.
-.PP
-.EX
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <wordsplit.h>
-
-/* Run command from \fIstr\fR (\fIlen\fR bytes long) and store its
- output in \fIret\fR.
- \fIargv\fR and \fIclosure\fR are not used.
- Return wordsplit error code.
- */
-static int 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;
-
- /* Convert to a null-terminated string for \fBpopen\fR(3) */
- cmd = malloc(len + 1);
- if (!cmd)
- return WRDSE_NOSPACE;
- memcpy(cmd, str, len);
- cmd[len] = 0;
-
- fp = popen(cmd, "r");
- if (!fp) {
- char buf[128];
-
- snprintf(buf, sizeof buf, "can't run %s: %s",
- cmd, strerror(errno));
- *ret = strdup(buf);
- if (!*ret)
- return WRDSE_NOSPACE;
- else
- return WRDSE_USERERR;
- }
-
- /* Collect the output, reallocating \fIbuffer\fR as needed. */
- 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;
- }
-
- /* Tream off the trailing newline */
- if (buffer) {
- if (lastc == '\n')
- --buflen;
- buffer[buflen] = 0;
- }
-
- pclose(fp);
- free(cmd);
-
- /* Return the composed string. */
- *ret = buffer;
- return WRDSE_OK;
-}
-
-extern char **environ;
-
-/* Parse \fIs\fR much as shell does. Return array of words on
- succes, and NULL on error.
- */
-char **shell_parse(char *s)
-{
- wordsplit_t ws;
- size_t wc;
- char **wv;
- int rc;
-
- /* Initialize \fIws\fR */
- ws.ws_env = (const char **) environ;
- ws.ws_command = runcmd;
- /* Call \fBwordsplit\fR. Let it report errors, if any. */
- rc = wordsplit(s, &ws,
- WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS | WRDSF_PATHEXPAND
- | WRDSF_SHOWERR);
- if (rc == WRDSE_OK)
- /* Store away the resulting words on success. */
- wordsplit_getwords(&ws, &wc, &wv);
- else
- wv = NULL;
- wordsplit_free(&ws);
- return wv;
-}
-.EE
-.SH AUTHORS
-Sergey Poznyakoff
-.SH "BUG REPORTS"
-Report bugs to <gray+grecs@gnu.org.ua>.
-.SH COPYRIGHT
-Copyright \(co 2009-2018 Sergey Poznyakoff
-.br
-.na
-License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
-.br
-.ad
-This is free software: you are free to change and redistribute it.
-There is NO WARRANTY, to the extent permitted by law.
-.\" Local variables:
-.\" eval: (add-hook 'write-file-hooks 'time-stamp)
-.\" time-stamp-start: ".TH [A-Z_][A-Z0-9_]* [0-9] \""
-.\" time-stamp-format: "%:B %:d, %:y"
-.\" time-stamp-end: "\""
-.\" time-stamp-line-limit: 20
-.\" end:
-
diff --git a/include/Makefile.am b/include/Makefile.am
index 6a017a3..5934d40 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,5 +1,5 @@
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)
diff --git a/include/wordsplit.h b/include/wordsplit.h
deleted file mode 100644
index 3451979..0000000
--- a/include/wordsplit.h
+++ b/dev/null
@@ -1,306 +0,0 @@
-/* wordsplit - a word splitter
- Copyright (C) 2009-2019 Sergey Poznyakoff
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 3 of the License, or (at your
- option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef __WORDSPLIT_H
-#define __WORDSPLIT_H
-
-#include <stddef.h>
-
-typedef struct wordsplit wordsplit_t;
-
-/* Structure used to direct the splitting. Members marked with [Input]
- can be defined before calling wordsplit(), those marked with [Output]
- 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 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
-{
- 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. */
- int ws_flags; /* [Input] Flags passed to wordsplit. */
- 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
- out of memory. Must not return. */
- void (*ws_error) (const char *, ...)
- __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
- output. */
- const char **ws_env; /* [Input] (WRDSF_ENV, !WRDSF_NOVAR) Array of
- environment variables. */
-
- /* 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
- 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
- variable. Returns WRDSE_OK (0) on success,
- and an error code (see WRDSE_* defines below)
- 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
- 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
- location pointed to by RET the expansion of
- 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). */
- size_t ws_len; /* Length of ws_input. */
- size_t ws_endp; /* Points past the last processed byte in
- ws_input. */
- int ws_errno; /* [Output] Error code, if an error occurred. */
- 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. */
- char ws_sep[2]; /* Temporary storage used during splitting */
- int ws_lvl; /* Invocation nesting level. */
-};
-
-/* Initial size for ws_env, if allocated automatically */
-#define WORDSPLIT_ENV_INIT 16
-
-/* Wordsplit flags. */
-/* Append the words found to the array resulting from a previous
- call. */
-#define WRDSF_APPEND 0x00000001
-/* Insert ws_offs initial NULLs in the array ws_wordv.
- (These are not counted in the returned ws_wordc.) */
-#define WRDSF_DOOFFS 0x00000002
-/* Don't do command substitution. */
-#define WRDSF_NOCMD 0x00000004
-/* The parameter p resulted from a previous call to
- wordsplit(), and wordsplit_free() was not called. Reuse the
- allocated storage. */
-#define WRDSF_REUSE 0x00000008
-/* Print errors */
-#define WRDSF_SHOWERR 0x00000010
-/* Consider it an error if an undefined variable is expanded. */
-#define WRDSF_UNDEF 0x00000020
-/* Don't do variable expansion. */
-#define WRDSF_NOVAR 0x00000040
-/* Abort on ENOMEM error */
-#define WRDSF_ENOMEMABRT 0x00000080
-/* Trim off any leading and trailind whitespace */
-#define WRDSF_WS 0x00000100
-/* Handle single quotes */
-#define WRDSF_SQUOTE 0x00000200
-/* Handle double quotes */
-#define WRDSF_DQUOTE 0x00000400
-/* Handle single and double quotes */
-#define WRDSF_QUOTE (WRDSF_SQUOTE|WRDSF_DQUOTE)
-/* Replace each input sequence of repeated delimiters with a single
- delimiter */
-#define WRDSF_SQUEEZE_DELIMS 0x00000800
-/* Return delimiters */
-#define WRDSF_RETURN_DELIMS 0x00001000
-/* Treat sed expressions as words */
-#define WRDSF_SED_EXPR 0x00002000
-/* ws_delim field is initialized */
-#define WRDSF_DELIM 0x00004000
-/* ws_comment field is initialized */
-#define WRDSF_COMMENT 0x00008000
-/* ws_alloc_die field is initialized */
-#define WRDSF_ALLOC_DIE 0x00010000
-/* ws_error field is initialized */
-#define WRDSF_ERROR 0x00020000
-/* ws_debug field is initialized */
-#define WRDSF_DEBUG 0x00040000
-/* ws_env field is initialized */
-#define WRDSF_ENV 0x00080000
-/* ws_getvar field is initialized */
-#define WRDSF_GETVAR 0x00100000
-/* enable debugging */
-#define WRDSF_SHOWDBG 0x00200000
-/* Don't split input into words. Useful for side effects. */
-#define WRDSF_NOSPLIT 0x00400000
-/* Keep undefined variables in place, instead of expanding them to
- empty strings. */
-#define WRDSF_KEEPUNDEF 0x00800000
-/* Warn about undefined variables */
-#define WRDSF_WARNUNDEF 0x01000000
-/* Handle C escapes */
-#define WRDSF_CESCAPES 0x02000000
-/* ws_closure is set */
-#define WRDSF_CLOSURE 0x04000000
-/* ws_env is a Key/Value environment, i.e. the value of a variable is
- stored in the element that follows its name. */
-#define WRDSF_ENV_KV 0x08000000
-/* ws_escape is set */
-#define WRDSF_ESCAPE 0x10000000
-/* Incremental mode */
-#define WRDSF_INCREMENTAL 0x20000000
-/* Perform pathname and tilde expansion */
-#define WRDSF_PATHEXPAND 0x40000000
-/* ws_options is initialized */
-#define WRDSF_OPTIONS 0x80000000
-
-#define WRDSF_DEFFLAGS \
- (WRDSF_NOVAR | WRDSF_NOCMD | \
- WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS | WRDSF_CESCAPES)
-
-/* Remove the word that produces empty string after path expansion */
-#define WRDSO_NULLGLOB 0x00000001
-/* Print error message if path expansion produces empty string */
-#define WRDSO_FAILGLOB 0x00000002
-/* Allow a leading period to be matched by metacharacters. */
-#define WRDSO_DOTGLOB 0x00000004
-/* 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 */
-#define WRDSO_OESC_WORD 0x00000020
-/* 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
-
-/* Indices into ws_escape */
-#define WRDSX_WORD 0
-#define WRDSX_QUOTE 1
-
-/* Set escape option F in WS for words (Q==0) or quoted strings (Q==1) */
-#define WRDSO_ESC_SET(ws,q,f) ((ws)->ws_options |= ((f) << 4*(q)))
-/* Test WS for escape option F for words (Q==0) or quoted strings (Q==1) */
-#define WRDSO_ESC_TEST(ws,q,f) ((ws)->ws_options & ((f) << 4*(q)))
-
-#define WRDSE_OK 0
-#define WRDSE_EOF WRDSE_OK
-#define WRDSE_QUOTE 1
-#define WRDSE_NOSPACE 2
-#define WRDSE_USAGE 3
-#define WRDSE_CBRACE 4
-#define WRDSE_UNDEF 5
-#define WRDSE_NOINPUT 6
-#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_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);
-size_t wordsplit_c_quoted_length (const char *str, int quote_hex, int *quote);
-void wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex);
-
-void wordsplit_perror (wordsplit_t *ws);
-const char *wordsplit_strerror (wordsplit_t *ws);
-
-void wordsplit_clearerr (wordsplit_t *ws);
-
-#endif
diff --git a/src/Make-inst.am b/src/Make-inst.am
index a4b6aea..1eb04bb 100644
--- a/src/Make-inst.am
+++ b/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/src/Make-shared.am b/src/Make-shared.am
index 9a762a4..f080e46 100644
--- a/src/Make-shared.am
+++ b/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/src/Make-static.am b/src/Make-static.am
index 2688b40..1f4cd3e 100644
--- a/src/Make-static.am
+++ b/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/src/Make.am b/src/Make.am
index 9fa7688..5199991 100644
--- a/src/Make.am
+++ b/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
@@ -69,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/src/wordsplit.c b/src/wordsplit.c
deleted file mode 100644
index 9179a87..0000000
--- a/src/wordsplit.c
+++ b/dev/null
@@ -1,2892 +0,0 @@
-/* wordsplit - a word splitter
- Copyright (C) 2009-2019 Sergey Poznyakoff
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 3 of the License, or (at your
- option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <errno.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <pwd.h>
-#include <glob.h>
-#include <limits.h>
-
-#if ENABLE_NLS
-# include <gettext.h>
-#else
-# define gettext(msgid) msgid
-#endif
-#define _(msgid) gettext (msgid)
-#define N_(msgid) msgid
-
-#include <wordsplit.h>
-
-#define ISWS(c) ((c)==' '||(c)=='\t'||(c)=='\n')
-#define ISDELIM(ws,c) \
- (strchr ((ws)->ws_delim, (c)) != NULL)
-#define ISPUNCT(c) (strchr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",(c))!=NULL)
-#define ISUPPER(c) ('A' <= ((unsigned) (c)) && ((unsigned) (c)) <= 'Z')
-#define ISLOWER(c) ('a' <= ((unsigned) (c)) && ((unsigned) (c)) <= 'z')
-#define ISALPHA(c) (ISUPPER(c) || ISLOWER(c))
-#define ISDIGIT(c) ('0' <= ((unsigned) (c)) && ((unsigned) (c)) <= '9')
-#define ISXDIGIT(c) (strchr("abcdefABCDEF", c)!=NULL)
-#define ISALNUM(c) (ISALPHA(c) || ISDIGIT(c))
-#define ISPRINT(c) (' ' <= ((unsigned) (c)) && ((unsigned) (c)) <= 127)
-
-#define ISVARBEG(c) (ISALPHA(c) || c == '_')
-#define ISVARCHR(c) (ISALNUM(c) || c == '_')
-
-#define WSP_RETURN_DELIMS(wsp) \
- ((wsp)->ws_flags & WRDSF_RETURN_DELIMS || ((wsp)->ws_options & WRDSO_MAXWORDS))
-
-#define 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 ("%s", _("memory exhausted"));
- abort ();
-}
-
-static void
-_wsplt_error (const char *fmt, ...)
-{
- va_list ap;
-
- va_start (ap, fmt);
- vfprintf (stderr, fmt, ap);
- va_end (ap);
- fputc ('\n', stderr);
-}
-
-static void wordsplit_free_nodes (struct wordsplit *);
-
-static int
-_wsplt_seterr (struct wordsplit *wsp, int ec)
-{
- wsp->ws_errno = ec;
- if (wsp->ws_flags & WRDSF_SHOWERR)
- wordsplit_perror (wsp);
- return ec;
-}
-
-static int
-_wsplt_nomem (struct wordsplit *wsp)
-{
- errno = ENOMEM;
- wsp->ws_errno = WRDSE_NOSPACE;
- if (wsp->ws_flags & WRDSF_ENOMEMABRT)
- wsp->ws_alloc_die (wsp);
- if (wsp->ws_flags & WRDSF_SHOWERR)
- wordsplit_perror (wsp);
- if (!(wsp->ws_flags & WRDSF_REUSE))
- wordsplit_free (wsp);
- wordsplit_free_nodes (wsp);
- return wsp->ws_errno;
-}
-
-static 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 finalize)
-{
- int rc;
-
- wss->ws_delim = wsp->ws_delim;
- wss->ws_debug = wsp->ws_debug;
- wss->ws_error = wsp->ws_error;
- wss->ws_alloc_die = wsp->ws_alloc_die;
-
- if (!(flags & WRDSF_NOVAR))
- {
- wss->ws_env = wsp->ws_env;
- wss->ws_getvar = wsp->ws_getvar;
- flags |= wsp->ws_flags & (WRDSF_ENV | WRDSF_ENV_KV | WRDSF_GETVAR);
- }
- if (!(flags & WRDSF_NOCMD))
- {
- wss->ws_command = wsp->ws_command;
- }
-
- if ((flags & (WRDSF_NOVAR|WRDSF_NOCMD)) != (WRDSF_NOVAR|WRDSF_NOCMD))
- {
- wss->ws_closure = wsp->ws_closure;
- flags |= wsp->ws_flags & WRDSF_CLOSURE;
- }
-
- wss->ws_options = wsp->ws_options;
-
- flags |= WRDSF_DELIM
- | WRDSF_ALLOC_DIE
- | WRDSF_ERROR
- | WRDSF_DEBUG
- | (wsp->ws_flags & (WRDSF_SHOWDBG | WRDSF_SHOWERR | WRDSF_OPTIONS));
-
- rc = wordsplit_init (wss, str, len, flags);
- if (rc)
- return rc;
- wss->ws_lvl = wsp->ws_lvl + 1;
- rc = wordsplit_process_list (wss, 0);
- if (rc)
- {
- wordsplit_free_nodes (wss);
- return rc;
- }
- if (finalize)
- {
- rc = wordsplit_finish (wss);
- wordsplit_free_nodes (wss);
- }
- return rc;
-}
-
-static void
-_wsplt_seterr_sub (struct wordsplit *wsp, struct wordsplit *wss)
-{
- /* 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)
- {
- wsp->ws_usererr = wss->ws_usererr;
- 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
-wordsplit_init0 (struct wordsplit *wsp)
-{
- if (wsp->ws_flags & WRDSF_REUSE)
- {
- if (!(wsp->ws_flags & WRDSF_APPEND))
- wordsplit_free_words (wsp);
- wordsplit_clearerr (wsp);
- }
- else
- {
- wsp->ws_wordv = NULL;
- wsp->ws_wordc = 0;
- wsp->ws_wordn = 0;
- }
-
- wsp->ws_errno = 0;
-}
-
-char wordsplit_c_escape_tab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v";
-
-static int
-wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
- int flags)
-{
- wsp->ws_flags = flags;
-
- if (!(wsp->ws_flags & WRDSF_ALLOC_DIE))
- wsp->ws_alloc_die = _wsplt_alloc_die;
- if (!(wsp->ws_flags & WRDSF_ERROR))
- wsp->ws_error = _wsplt_error;
-
- if (!(wsp->ws_flags & WRDSF_NOVAR))
- {
- /* These will be initialized on first variable assignment */
- wsp->ws_envidx = wsp->ws_envsiz = 0;
- wsp->ws_envbuf = NULL;
- }
-
- if (!(wsp->ws_flags & WRDSF_NOCMD))
- {
- if (!wsp->ws_command)
- {
- _wsplt_seterr (wsp, WRDSE_USAGE);
- errno = EINVAL;
- return wsp->ws_errno;
- }
- }
-
- if (wsp->ws_flags & WRDSF_SHOWDBG)
- {
- if (!(wsp->ws_flags & WRDSF_DEBUG))
- {
- if (wsp->ws_flags & WRDSF_ERROR)
- wsp->ws_debug = wsp->ws_error;
- else if (wsp->ws_flags & WRDSF_SHOWERR)
- wsp->ws_debug = _wsplt_error;
- else
- wsp->ws_flags &= ~WRDSF_SHOWDBG;
- }
- }
-
- wsp->ws_input = input;
- wsp->ws_len = len;
-
- if (!(wsp->ws_flags & WRDSF_DOOFFS))
- wsp->ws_offs = 0;
-
- if (!(wsp->ws_flags & WRDSF_DELIM))
- wsp->ws_delim = " \t\n";
-
- wsp->ws_sep[0] = wsp->ws_delim[0];
- wsp->ws_sep[1] = 0;
-
- if (!(wsp->ws_flags & WRDSF_COMMENT))
- wsp->ws_comment = NULL;
-
- if (!(wsp->ws_flags & WRDSF_CLOSURE))
- wsp->ws_closure = NULL;
-
- if (!(wsp->ws_flags & WRDSF_OPTIONS))
- wsp->ws_options = 0;
-
- if (wsp->ws_flags & WRDSF_ESCAPE)
- {
- if (!wsp->ws_escape[WRDSX_WORD])
- wsp->ws_escape[WRDSX_WORD] = "";
- if (!wsp->ws_escape[WRDSX_QUOTE])
- wsp->ws_escape[WRDSX_QUOTE] = "";
- }
- else
- {
- if (wsp->ws_flags & WRDSF_CESCAPES)
- {
- wsp->ws_escape[WRDSX_WORD] = wordsplit_c_escape_tab;
- wsp->ws_escape[WRDSX_QUOTE] = wordsplit_c_escape_tab;
- wsp->ws_options |= WRDSO_OESC_QUOTE | WRDSO_OESC_WORD
- | WRDSO_XESC_QUOTE | WRDSO_XESC_WORD;
- }
- else
- {
- wsp->ws_escape[WRDSX_WORD] = "";
- wsp->ws_escape[WRDSX_QUOTE] = "\\\\\"\"";
- wsp->ws_options |= WRDSO_BSKEEP_QUOTE;
- }
- }
-
- 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);
-
- return 0;
-}
-
-static int
-alloc_space (struct wordsplit *wsp, size_t count)
-{
- size_t offs = (wsp->ws_flags & WRDSF_DOOFFS) ? wsp->ws_offs : 0;
- char **ptr;
- size_t newalloc;
-
- if (wsp->ws_wordv == NULL)
- {
- newalloc = offs + count > ALLOC_INIT ? count : ALLOC_INIT;
- ptr = calloc (newalloc, sizeof (ptr[0]));
- }
- else if (wsp->ws_wordn < offs + wsp->ws_wordc + count)
- {
- newalloc = offs + wsp->ws_wordc +
- (count > ALLOC_INCR ? count : ALLOC_INCR);
- ptr = realloc (wsp->ws_wordv, newalloc * sizeof (ptr[0]));
- }
- else
- return 0;
-
- if (ptr)
- {
- wsp->ws_wordn = newalloc;
- wsp->ws_wordv = ptr;
- }
- else
- return _wsplt_nomem (wsp);
- return 0;
-}
-
-
-/* Node state flags */
-#define _WSNF_NULL 0x01 /* null node (a noop) */
-#define _WSNF_WORD 0x02 /* node contains word in v.word */
-#define _WSNF_QUOTE 0x04 /* text is quoted */
-#define _WSNF_NOEXPAND 0x08 /* text is not subject to expansion */
-#define _WSNF_JOIN 0x10 /* node must be joined with the next node */
-#define _WSNF_SEXP 0x20 /* is a sed expression */
-#define _WSNF_DELIM 0x40 /* node is a delimiter */
-#define _WSNF_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 */
-
-struct wordsplit_node
-{
- struct wordsplit_node *prev; /* Previous element */
- struct wordsplit_node *next; /* Next element */
- int flags; /* Node flags */
- union
- {
- struct
- {
- size_t beg; /* Start of word in ws_input */
- size_t end; /* End of word in ws_input */
- } segm;
- char *word;
- } v;
-};
-
-static const char *
-wsnode_flagstr (int flags)
-{
- static char retbuf[7];
- char *p = retbuf;
-
- if (flags & _WSNF_WORD)
- *p++ = 'w';
- else if (flags & _WSNF_NULL)
- *p++ = 'n';
- else
- *p++ = '-';
- if (flags & _WSNF_QUOTE)
- *p++ = 'q';
- else
- *p++ = '-';
- if (flags & _WSNF_NOEXPAND)
- *p++ = 'E';
- else
- *p++ = '-';
- if (flags & _WSNF_JOIN)
- *p++ = 'j';
- else
- *p++ = '-';
- if (flags & _WSNF_SEXP)
- *p++ = 's';
- else
- *p++ = '-';
- if (flags & _WSNF_DELIM)
- *p++ = 'd';
- else
- *p++ = '-';
- *p = 0;
- return retbuf;
-}
-
-static const char *
-wsnode_ptr (struct wordsplit *wsp, struct wordsplit_node *p)
-{
- if (p->flags & _WSNF_NULL)
- return "";
- else if (p->flags & _WSNF_WORD)
- return p->v.word;
- else
- return wsp->ws_input + p->v.segm.beg;
-}
-
-static size_t
-wsnode_len (struct wordsplit_node *p)
-{
- if (p->flags & _WSNF_NULL)
- return 0;
- else if (p->flags & _WSNF_WORD)
- return strlen (p->v.word);
- else
- return p->v.segm.end - p->v.segm.beg;
-}
-
-static int
-wsnode_new (struct wordsplit *wsp, struct wordsplit_node **pnode)
-{
- struct wordsplit_node *node = calloc (1, sizeof (*node));
- if (!node)
- return _wsplt_nomem (wsp);
- *pnode = node;
- return 0;
-}
-
-static void
-wsnode_free (struct wordsplit_node *p)
-{
- if ((p->flags & (_WSNF_WORD|_WSNF_CONST)) == _WSNF_WORD)
- free (p->v.word);
- free (p);
-}
-
-static void
-wsnode_append (struct wordsplit *wsp, struct wordsplit_node *node)
-{
- node->next = NULL;
- node->prev = wsp->ws_tail;
- if (wsp->ws_tail)
- wsp->ws_tail->next = node;
- else
- wsp->ws_head = node;
- wsp->ws_tail = node;
-}
-
-static void
-wsnode_remove (struct wordsplit *wsp, struct wordsplit_node *node)
-{
- struct wordsplit_node *p;
-
- p = node->prev;
- if (p)
- {
- p->next = node->next;
- if (!node->next)
- p->flags &= ~_WSNF_JOIN;
- }
- else
- wsp->ws_head = node->next;
-
- p = node->next;
- if (p)
- p->prev = node->prev;
- else
- wsp->ws_tail = node->prev;
-
- node->next = node->prev = NULL;
-}
-
-static struct wordsplit_node *
-wsnode_tail (struct wordsplit_node *p)
-{
- while (p && p->next)
- p = p->next;
- return p;
-}
-
-static void
-wsnode_insert (struct wordsplit *wsp, struct wordsplit_node *node,
- struct wordsplit_node *anchor, int before)
-{
- if (!wsp->ws_head)
- {
- node->next = node->prev = NULL;
- wsp->ws_head = wsp->ws_tail = node;
- }
- else if (before)
- {
- if (anchor->prev)
- wsnode_insert (wsp, node, anchor->prev, 0);
- else
- {
- struct wordsplit_node *tail = wsnode_tail (node);
- node->prev = NULL;
- tail->next = anchor;
- anchor->prev = tail;
- wsp->ws_head = node;
- }
- }
- else
- {
- struct wordsplit_node *p;
- struct wordsplit_node *tail = wsnode_tail (node);
-
- p = anchor->next;
- if (p)
- p->prev = tail;
- else
- wsp->ws_tail = tail;
- tail->next = p;
- node->prev = anchor;
- anchor->next = node;
- }
-}
-
-static int
-wordsplit_add_segm (struct wordsplit *wsp, size_t beg, size_t end, int flg)
-{
- struct wordsplit_node *node;
- int rc;
-
- if (end == beg && !(flg & _WSNF_EMPTYOK))
- return 0;
- rc = wsnode_new (wsp, &node);
- if (rc)
- return rc;
- node->flags = flg & ~(_WSNF_WORD | _WSNF_EMPTYOK);
- node->v.segm.beg = beg;
- node->v.segm.end = end;
- wsnode_append (wsp, node);
- return 0;
-}
-
-static void
-wordsplit_free_nodes (struct wordsplit *wsp)
-{
- struct wordsplit_node *p;
-
- for (p = wsp->ws_head; p;)
- {
- struct wordsplit_node *next = p->next;
- wsnode_free (p);
- p = next;
- }
- wsp->ws_head = wsp->ws_tail = NULL;
-}
-
-static void
-wordsplit_dump_nodes (struct wordsplit *wsp)
-{
- struct wordsplit_node *p;
- int n = 0;
-
- for (p = wsp->ws_head, n = 0; p; p = p->next, n++)
- {
- if (p->flags & _WSNF_WORD)
- wsp->ws_debug ("(%02d) %4d: %p: %#04x (%s):%s;",
- wsp->ws_lvl,
- n, p, p->flags, wsnode_flagstr (p->flags), p->v.word);
- else
- wsp->ws_debug ("(%02d) %4d: %p: %#04x (%s):%.*s;",
- wsp->ws_lvl,
- n, p, p->flags, wsnode_flagstr (p->flags),
- (int) (p->v.segm.end - p->v.segm.beg),
- wsp->ws_input + p->v.segm.beg);
- }
-}
-
-static int
-coalesce_segment (struct wordsplit *wsp, struct wordsplit_node *node)
-{
- struct wordsplit_node *p, *end;
- size_t len = 0;
- char *buf, *cur;
- int stop;
-
- if (!(node->flags & _WSNF_JOIN))
- return 0;
-
- for (p = node; p && (p->flags & _WSNF_JOIN); p = p->next)
- {
- len += wsnode_len (p);
- }
- if (p)
- len += wsnode_len (p);
- end = p;
-
- buf = malloc (len + 1);
- if (!buf)
- return _wsplt_nomem (wsp);
- cur = buf;
-
- p = node;
- for (stop = 0; !stop;)
- {
- struct wordsplit_node *next = p->next;
- const char *str = wsnode_ptr (wsp, p);
- size_t slen = wsnode_len (p);
-
- memcpy (cur, str, slen);
- cur += slen;
- if (p != node)
- {
- node->flags |= p->flags & _WSNF_QUOTE;
- wsnode_remove (wsp, p);
- stop = p == end;
- wsnode_free (p);
- }
- p = next;
- }
-
- *cur = 0;
-
- node->flags &= ~_WSNF_JOIN;
-
- if (node->flags & _WSNF_WORD)
- free (node->v.word);
- else
- node->flags |= _WSNF_WORD;
- node->v.word = buf;
- return 0;
-}
-
-static void wordsplit_string_unquote_copy (struct wordsplit *ws, int inquote,
- char *dst, const char *src,
- size_t n);
-
-static int
-wsnode_quoteremoval (struct wordsplit *wsp)
-{
- struct wordsplit_node *p;
-
- for (p = wsp->ws_head; p; p = p->next)
- {
- const char *str = wsnode_ptr (wsp, p);
- size_t slen = wsnode_len (p);
- int unquote;
-
- if (wsp->ws_flags & WRDSF_QUOTE)
- unquote = !(p->flags & _WSNF_NOEXPAND);
- else
- unquote = 0;
-
- if (unquote)
- {
- if (!(p->flags & _WSNF_WORD))
- {
- char *newstr = malloc (slen + 1);
- if (!newstr)
- return _wsplt_nomem (wsp);
- memcpy (newstr, str, slen);
- newstr[slen] = 0;
- p->v.word = newstr;
- p->flags |= _WSNF_WORD;
- }
-
- wordsplit_string_unquote_copy (wsp, p->flags & _WSNF_QUOTE,
- p->v.word, str, slen);
- }
- }
- return 0;
-}
-
-static int
-wsnode_coalesce (struct wordsplit *wsp)
-{
- struct wordsplit_node *p;
-
- for (p = wsp->ws_head; p; p = p->next)
- {
- if (p->flags & _WSNF_JOIN)
- if (coalesce_segment (wsp, p))
- return 1;
- }
- return 0;
-}
-
-static int
-wsnode_tail_coalesce (struct wordsplit *wsp, struct wordsplit_node *p)
-{
- if (p->next)
- {
- struct wordsplit_node *np = p;
- while (np && np->next)
- {
- np->flags |= _WSNF_JOIN;
- np = np->next;
- }
- if (coalesce_segment (wsp, p))
- return 1;
- }
- return 0;
-}
-
-static size_t skip_delim (struct wordsplit *wsp);
-
-static int
-wordsplit_finish (struct wordsplit *wsp)
-{
- struct wordsplit_node *p;
- size_t n;
- int delim;
-
- /* Postprocess delimiters. It would be rather simple, if it weren't for
- the incremental operation.
-
- 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 wsp->ws_errno;
-
- while (wsp->ws_head)
- {
- 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. */
- 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,
- struct wordsplit_node **ptail,
- struct wordsplit_node *node,
- size_t beg, size_t len, int flg)
-{
- struct wordsplit_node *newnode;
-
- if (len == 0)
- return 0;
- if (wsnode_new (wsp, &newnode))
- return 1;
- wsnode_insert (wsp, newnode, *ptail, 0);
- if (node->flags & _WSNF_WORD)
- {
- const char *str = wsnode_ptr (wsp, node);
- char *newstr = malloc (len + 1);
- if (!newstr)
- return _wsplt_nomem (wsp);
- memcpy (newstr, str + beg, len);
- newstr[len] = 0;
- newnode->flags = _WSNF_WORD;
- newnode->v.word = newstr;
- }
- else
- {
- newnode->v.segm.beg = node->v.segm.beg + beg;
- newnode->v.segm.end = newnode->v.segm.beg + len;
- }
- newnode->flags |= flg;
- *ptail = newnode;
- return 0;
-}
-
-static int
-find_closing_paren (const char *str, size_t i, size_t len, size_t *poff,
- char const *paren)
-{
- enum { st_init, st_squote, st_dquote } state = st_init;
- size_t level = 1;
-
- for (; i < len; i++)
- {
- switch (state)
- {
- case st_init:
- switch (str[i])
- {
- default:
- if (str[i] == paren[0])
- {
- level++;
- break;
- }
- else if (str[i] == paren[1])
- {
- if (--level == 0)
- {
- *poff = i;
- return 0;
- }
- break;
- }
- break;
-
- case '"':
- state = st_dquote;
- break;
-
- case '\'':
- state = st_squote;
- break;
- }
- break;
-
- case st_squote:
- if (str[i] == '\'')
- state = st_init;
- break;
-
- case st_dquote:
- if (str[i] == '\\')
- i++;
- else if (str[i] == '"')
- state = st_init;
- break;
- }
- }
- return 1;
-}
-
-static char const *
-wsplt_env_find (struct wordsplit *wsp, const char *name, size_t len)
-{
- size_t i;
-
- if (!wsp->ws_env)
- return NULL;
- if (wsp->ws_flags & WRDSF_ENV_KV)
- {
- /* A key-value pair environment */
- for (i = 0; wsp->ws_env[i]; i++)
- {
- size_t elen = strlen (wsp->ws_env[i]);
- if (elen == len && memcmp (wsp->ws_env[i], name, elen) == 0)
- 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
- {
- /* Usual (A=B) environment. */
- for (i = 0; wsp->ws_env[i]; i++)
- {
- size_t j;
- const char *var = wsp->ws_env[i];
-
- for (j = 0; j < len; j++)
- if (name[j] != var[j])
- break;
- if (j == len && var[j] == '=')
- 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 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;
- char **newenv;
-
- if (!wsp->ws_envbuf)
- {
- if (wsp->ws_flags & WRDSF_ENV)
- {
- size_t i = 0, j;
-
- if (wsp->ws_env)
- {
- for (; wsp->ws_env[i]; i++)
- ;
- }
-
- sz = i + n + 1;
-
- newenv = calloc (sz, sizeof(newenv[0]));
- if (!newenv)
- return _wsplt_nomem (wsp);
-
- for (j = 0; j < i; j++)
- {
- newenv[j] = strdup (wsp->ws_env[j]);
- if (!newenv[j])
- {
- for (; j > 1; j--)
- free (newenv[j-1]);
- free (newenv);
- return _wsplt_nomem (wsp);
- }
- }
- newenv[j] = NULL;
-
- wsp->ws_envbuf = newenv;
- wsp->ws_envidx = i;
- wsp->ws_envsiz = sz;
- wsp->ws_env = (const char**) wsp->ws_envbuf;
- }
- else
- {
- newenv = calloc (WORDSPLIT_ENV_INIT, sizeof(newenv[0]));
- if (!newenv)
- return _wsplt_nomem (wsp);
- wsp->ws_envbuf = newenv;
- wsp->ws_envidx = 0;
- wsp->ws_envsiz = WORDSPLIT_ENV_INIT;
- wsp->ws_env = (const char**) wsp->ws_envbuf;
- wsp->ws_flags |= WRDSF_ENV;
- }
- }
- else
- {
- 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 */
- char *p = malloc (namelen + 1);
- if (!p)
- return _wsplt_nomem (wsp);
- memcpy (p, name, namelen);
- p[namelen] = 0;
-
- v = strdup (value);
- if (!v)
- {
- free (p);
- return _wsplt_nomem (wsp);
- }
- wsp->ws_env[wsp->ws_envidx++] = p;
- wsp->ws_env[wsp->ws_envidx++] = v;
- }
- else
- {
- v = malloc (namelen + strlen(value) + 2);
- if (!v)
- return _wsplt_nomem (wsp);
- memcpy (v, name, namelen);
- v[namelen++] = '=';
- strcpy(v + namelen, value);
- wsp->ws_env[wsp->ws_envidx++] = v;
- }
- wsp->ws_env[wsp->ws_envidx] = NULL;
- return WRDSE_OK;
-}
-
-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)
-{
- size_t i = 0;
- const char *defstr = NULL;
- char *value;
- 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++)
- if (!ISVARCHR (str[i]))
- break;
- *pend = str + i - 1;
- }
- 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 = 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);
- *pend = str + j;
- break;
- }
- else if (str[i] == '}')
- {
- defstr = NULL;
- *pend = str + i;
- break;
- }
- else if (strchr ("-+?=", str[i]))
- {
- size_t j;
-
- defstr = str + i;
- if (find_closing_paren (str, i, len, &j, "{}"))
- return _wsplt_seterr (wsp, 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
- {
- return expvar_recover (wsp, str, ptail, pend, flg);
- }
-
- /* Actually expand the variable */
- /* str - start of the variable name
- i - its length
- defstr - default replacement str */
-
- if (defstr && strchr("-+?=", defstr[0]) == 0)
- {
- rc = WRDSE_UNDEF;
- defstr = NULL;
- }
- else
- {
- if (is_param)
- {
- 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)
- {
- 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 || value[0] == 0)
- && defstr && defstr[-1] == ':')
- {
- free (value);
- rc = WRDSE_UNDEF;
- }
- }
-
- switch (rc)
- {
- case WRDSE_OK:
- if (defstr && *defstr == '+')
- {
- size_t size = *pend - ++defstr;
-
- rc = _wsplt_subsplit (wsp, &ws, defstr, size,
- WRDSF_NOSPLIT | WRDSF_WS | WRDSF_QUOTE |
- (wsp->ws_flags &
- (WRDSF_NOVAR | WRDSF_NOCMD)), 1);
- if (rc)
- return rc;
- free (value);
- value = ws.ws_wordv[0];
- ws.ws_wordv[0] = NULL;
- wordsplit_free (&ws);
- }
- break;
-
- case WRDSE_UNDEF:
- if (defstr)
- {
- size_t size;
- if (*defstr == '-' || *defstr == '=')
- {
- size = *pend - ++defstr;
-
- rc = _wsplt_subsplit (wsp, &ws, defstr, size,
- WRDSF_NOSPLIT | WRDSF_WS | WRDSF_QUOTE |
- (wsp->ws_flags &
- (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] == '=')
- {
- 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
- {
- if (*defstr == '?')
- {
- size = *pend - ++defstr;
- if (size == 0)
- wsp->ws_error (_("%.*s: variable null or not set"),
- (int) i, str);
- else
- {
- rc = _wsplt_subsplit (wsp, &ws, defstr, size,
- WRDSF_NOSPLIT | WRDSF_WS |
- WRDSF_QUOTE |
- (wsp->ws_flags &
- (WRDSF_NOVAR | WRDSF_NOCMD)),
- 1);
- if (rc == 0)
- wsp->ws_error ("%.*s: %s",
- (int) i, str, ws.ws_wordv[0]);
- else
- wsp->ws_error ("%.*s: %.*s",
- (int) i, str, (int) size, defstr);
- wordsplit_free (&ws);
- }
- }
- value = NULL;
- }
- }
- else if (wsp->ws_flags & WRDSF_UNDEF)
- {
- _wsplt_setctxerr (wsp, WRDSE_UNDEF, str, *pend - str + 1);
- return 1;
- }
- else
- {
- if (wsp->ws_flags & WRDSF_WARNUNDEF)
- wsp->ws_error (_("warning: undefined variable `%.*s'"),
- (int) i, str);
- if (wsp->ws_flags & WRDSF_KEEPUNDEF)
- value = NULL;
- else
- {
- value = strdup ("");
- if (!value)
- return _wsplt_nomem (wsp);
- }
- }
- break;
-
- case WRDSE_NOSPACE:
- return _wsplt_nomem (wsp);
-
- case WRDSE_USERERR:
- if (wsp->ws_errno == WRDSE_USERERR)
- free (wsp->ws_usererr);
- wsp->ws_usererr = value;
- /* fall through */
- default:
- _wsplt_seterr (wsp, rc);
- return 1;
- }
-
- if (value)
- {
- if (flg & _WSNF_QUOTE)
- {
- 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;
- }
- else if (*value == 0)
- {
- free (value);
- /* Empty string is a special case */
- if (wsnode_new (wsp, &newnode))
- return 1;
- wsnode_insert (wsp, newnode, *ptail, 0);
- *ptail = newnode;
- newnode->flags = _WSNF_NULL;
- }
- else
- {
- struct wordsplit ws;
- int rc;
-
- rc = _wsplt_subsplit (wsp, &ws, value, strlen (value),
- WRDSF_NOVAR | WRDSF_NOCMD |
- WRDSF_QUOTE
- | (WSP_RETURN_DELIMS (wsp) ? WRDSF_RETURN_DELIMS : 0) ,
- 0);
- free (value);
- if (rc)
- {
- _wsplt_seterr_sub (wsp, &ws);
- wordsplit_free (&ws);
- return 1;
- }
- wsnode_insert (wsp, ws.ws_head, *ptail, 0);
- *ptail = ws.ws_tail;
- ws.ws_head = ws.ws_tail = NULL;
- wordsplit_free (&ws);
- }
- }
- else if (wsp->ws_flags & WRDSF_KEEPUNDEF)
- {
- size_t size = *pend - start + 1;
-
- 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 = malloc (size + 1);
- if (!newnode->v.word)
- return _wsplt_nomem (wsp);
- memcpy (newnode->v.word, start, size);
- newnode->v.word[size] = 0;
- }
- else
- {
- if (wsnode_new (wsp, &newnode))
- return 1;
- wsnode_insert (wsp, newnode, *ptail, 0);
- *ptail = newnode;
- newnode->flags = _WSNF_NULL;
- }
- return 0;
-}
-
-static int
-begin_var_p (int c)
-{
- return memchr ("{#@*", c, 4) != NULL || ISVARBEG (c) || ISDIGIT (c);
-}
-
-static int
-node_expand (struct wordsplit *wsp, struct wordsplit_node *node,
- int (*beg_p) (int),
- int (*ws_exp_fn) (struct wordsplit *wsp,
- const char *str, size_t len,
- struct wordsplit_node **ptail,
- const char **pend,
- int flg))
-{
- const char *str = wsnode_ptr (wsp, node);
- size_t slen = wsnode_len (node);
- const char *end = str + slen;
- const char *p;
- size_t off = 0;
- struct wordsplit_node *tail = node;
-
- for (p = str; p < end; p++)
- {
- if (*p == '\\')
- {
- p++;
- continue;
- }
- if (*p == '$' && beg_p (p[1]))
- {
- size_t n = p - str;
-
- if (tail != node)
- tail->flags |= _WSNF_JOIN;
- if (node_split_prefix (wsp, &tail, node, off, n, _WSNF_JOIN))
- return 1;
- p++;
- if (ws_exp_fn (wsp, p, slen - n, &tail, &p,
- node->flags & (_WSNF_JOIN | _WSNF_QUOTE)))
- return 1;
- off += p - str + 1;
- str = p + 1;
- }
- }
- if (p > str)
- {
- if (tail != node)
- tail->flags |= _WSNF_JOIN;
- if (node_split_prefix (wsp, &tail, node, off, p - str,
- node->flags & (_WSNF_JOIN|_WSNF_QUOTE)))
- return 1;
- }
- if (tail != node)
- {
- wsnode_remove (wsp, node);
- wsnode_free (node);
- }
- return 0;
-}
-
-/* Remove NULL nodes from the list */
-static void
-wsnode_nullelim (struct wordsplit *wsp)
-{
- struct wordsplit_node *p;
-
- for (p = wsp->ws_head; p;)
- {
- struct wordsplit_node *next = p->next;
- if (p->flags & _WSNF_DELIM && p->prev)
- p->prev->flags &= ~_WSNF_JOIN;
- if (p->flags & _WSNF_NULL)
- {
- wsnode_remove (wsp, p);
- wsnode_free (p);
- }
- p = next;
- }
-}
-
-static int
-wordsplit_varexp (struct wordsplit *wsp)
-{
- struct wordsplit_node *p;
-
- for (p = wsp->ws_head; p;)
- {
- struct wordsplit_node *next = p->next;
- if (!(p->flags & (_WSNF_NOEXPAND|_WSNF_DELIM)))
- if (node_expand (wsp, p, begin_var_p, expvar))
- return 1;
- p = next;
- }
-
- wsnode_nullelim (wsp);
- return 0;
-}
-
-static int
-begin_cmd_p (int c)
-{
- return c == '(';
-}
-
-static int
-expcmd (struct wordsplit *wsp, const char *str, size_t len,
- struct wordsplit_node **ptail, const char **pend, int flg)
-{
- int rc;
- size_t j;
- char *value;
- struct wordsplit_node *newnode;
- struct wordsplit ws;
-
- str++;
- len--;
-
- if (find_closing_paren (str, 0, len, &j, "()"))
- {
- _wsplt_seterr (wsp, WRDSE_PAREN);
- return 1;
- }
-
- *pend = str + j;
- rc = _wsplt_subsplit (wsp, &ws, str, j, WRDSF_WS | WRDSF_QUOTE, 1);
- 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);
- wordsplit_free (&ws);
-
- if (rc == WRDSE_NOSPACE)
- return _wsplt_nomem (wsp);
- else if (rc)
- {
- if (rc == WRDSE_USERERR)
- {
- if (wsp->ws_errno == WRDSE_USERERR)
- free (wsp->ws_usererr);
- wsp->ws_usererr = value;
- }
- _wsplt_seterr (wsp, rc);
- return 1;
- }
-
- if (value)
- {
- if (flg & _WSNF_QUOTE)
- {
- 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;
- }
- else if (*value == 0)
- {
- free (value);
- /* Empty string is a special case */
- if (wsnode_new (wsp, &newnode))
- return 1;
- wsnode_insert (wsp, newnode, *ptail, 0);
- *ptail = newnode;
- newnode->flags = _WSNF_NULL;
- }
- else
- {
- struct wordsplit ws;
- int rc;
-
- rc = _wsplt_subsplit (wsp, &ws, value, strlen (value),
- WRDSF_NOVAR | WRDSF_NOCMD
- | WRDSF_WS | WRDSF_QUOTE
- | (WSP_RETURN_DELIMS (wsp) ? WRDSF_RETURN_DELIMS : 0),
- 0);
- free (value);
- if (rc)
- {
- _wsplt_seterr_sub (wsp, &ws);
- wordsplit_free (&ws);
- return 1;
- }
- wsnode_insert (wsp, ws.ws_head, *ptail, 0);
- *ptail = ws.ws_tail;
- ws.ws_head = ws.ws_tail = NULL;
- wordsplit_free (&ws);
- }
- }
- else
- {
- if (wsnode_new (wsp, &newnode))
- return 1;
- wsnode_insert (wsp, newnode, *ptail, 0);
- *ptail = newnode;
- newnode->flags = _WSNF_NULL;
- }
- return 0;
-}
-
-static int
-wordsplit_cmdexp (struct wordsplit *wsp)
-{
- struct wordsplit_node *p;
-
- for (p = wsp->ws_head; p;)
- {
- struct wordsplit_node *next = p->next;
- if (!(p->flags & _WSNF_NOEXPAND))
- if (node_expand (wsp, p, begin_cmd_p, expcmd))
- return 1;
- p = next;
- }
-
- wsnode_nullelim (wsp);
- return 0;
-}
-
-/* Strip off any leading and trailing whitespace. This function is called
- right after the initial scanning, therefore it assumes that every
- node in the list is a text reference node. */
-static int
-wordsplit_trimws (struct wordsplit *wsp)
-{
- struct wordsplit_node *p;
-
- for (p = wsp->ws_head; p; p = p->next)
- {
- size_t n;
-
- if (!(p->flags & _WSNF_QUOTE))
- {
- /* Skip leading whitespace: */
- for (n = p->v.segm.beg; n < p->v.segm.end && ISWS (wsp->ws_input[n]);
- n++)
- ;
- 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--);
- p->v.segm.end = n;
- if (p->v.segm.beg == p->v.segm.end)
- p->flags |= _WSNF_NULL;
- }
-
- wsnode_nullelim (wsp);
- return 0;
-}
-
-static int
-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;
-
- if (p->flags & _WSNF_QUOTE)
- continue;
-
- str = wsnode_ptr (wsp, p);
- if (str[0] == '~')
- {
- size_t i, size, dlen;
- size_t slen = wsnode_len (p);
- struct passwd *pw;
- char *newstr;
-
- for (i = 1; i < slen && str[i] != '/'; i++)
- ;
- if (i == slen)
- continue;
- if (i > 1)
- {
- if (i > usize)
- {
- char *p = realloc (uname, i);
- if (!p)
- {
- free (uname);
- return _wsplt_nomem (wsp);
- }
- uname = p;
- usize = i;
- }
- --i;
- memcpy (uname, str + 1, i);
- uname[i] = 0;
- pw = getpwnam (uname);
- }
- else
- pw = getpwuid (getuid ());
-
- if (!pw)
- continue;
-
- dlen = strlen (pw->pw_dir);
- size = slen - i + dlen;
- newstr = malloc (size);
- if (!newstr)
- {
- free (uname);
- return _wsplt_nomem (wsp);
- }
- --size;
-
- memcpy (newstr, pw->pw_dir, dlen);
- memcpy (newstr + dlen, str + i + 1, slen - i - 1);
- newstr[size] = 0;
- if (p->flags & _WSNF_WORD)
- free (p->v.word);
- p->v.word = newstr;
- p->flags |= _WSNF_WORD;
- }
- }
- free (uname);
- return 0;
-}
-
-static int
-isglob (const char *s, int l)
-{
- while (l--)
- {
- if (strchr ("*?[", *s++))
- return 1;
- }
- return 0;
-}
-
-static int
-wordsplit_pathexpand (struct wordsplit *wsp)
-{
- struct wordsplit_node *p, *next;
- char *pattern = NULL;
- size_t patsize = 0;
- size_t slen;
- int flags = 0;
-
-#ifdef GLOB_PERIOD
- if (wsp->ws_options & WRDSO_DOTGLOB)
- flags = GLOB_PERIOD;
-#endif
-
- for (p = wsp->ws_head; p; p = next)
- {
- const char *str;
-
- next = p->next;
-
- if (p->flags & _WSNF_QUOTE)
- continue;
-
- str = wsnode_ptr (wsp, p);
- slen = wsnode_len (p);
-
- if (isglob (str, slen))
- {
- int i;
- glob_t g;
- struct wordsplit_node *prev;
-
- if (slen + 1 > patsize)
- {
- char *p = realloc (pattern, slen + 1);
- if (!p)
- return _wsplt_nomem (wsp);
- pattern = p;
- patsize = slen + 1;
- }
- 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)
- {
- wsnode_remove (wsp, p);
- wsnode_free (p);
- }
- else if (wsp->ws_options & WRDSO_FAILGLOB)
- {
- char buf[128];
- if (wsp->ws_errno == WRDSE_USERERR)
- free (wsp->ws_usererr);
- snprintf (buf, sizeof (buf), _("no files match pattern %s"),
- pattern);
- free (pattern);
- wsp->ws_usererr = strdup (buf);
- if (!wsp->ws_usererr)
- return _wsplt_nomem (wsp);
- else
- return _wsplt_seterr (wsp, WRDSE_USERERR);
- }
- continue;
-
- default:
- free (pattern);
- return _wsplt_setctxerr (wsp, WRDSE_GLOBERR, pattern, slen);
- }
-
- prev = p;
- for (i = 0; i < g.gl_pathc; i++)
- {
- struct wordsplit_node *newnode;
- char *newstr;
-
- if (wsnode_new (wsp, &newnode))
- return 1;
- newstr = strdup (g.gl_pathv[i]);
- if (!newstr)
- return _wsplt_nomem (wsp);
- newnode->v.word = newstr;
- newnode->flags |= _WSNF_WORD|_WSNF_QUOTE;
- wsnode_insert (wsp, newnode, prev, 0);
- prev = newnode;
- }
- globfree (&g);
-
- wsnode_remove (wsp, p);
- wsnode_free (p);
- }
- }
- free (pattern);
- return 0;
-}
-
-static int
-skip_sed_expr (const char *command, size_t i, size_t len)
-{
- int state;
-
- do
- {
- int delim;
-
- if (command[i] == ';')
- i++;
- if (!(command[i] == 's' && i + 3 < len && ISPUNCT (command[i + 1])))
- break;
-
- delim = command[++i];
- state = 1;
- for (i++; i < len; i++)
- {
- if (state == 3)
- {
- if (command[i] == delim || !ISALNUM (command[i]))
- break;
- }
- else if (command[i] == '\\')
- i++;
- else if (command[i] == delim)
- state++;
- }
- }
- while (state == 3 && i < len && command[i] == ';');
- return i;
-}
-
-/* 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)
-{
- return return_delims ? wsp->ws_endp : wsp->ws_endp + 1;
-}
-
-static inline size_t
-skip_delim (struct wordsplit *wsp)
-{
- return skip_delim_internal (wsp, WSP_RETURN_DELIMS (wsp));
-}
-
-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
-#define _WRDS_OK 1
-#define _WRDS_ERR 2
-
-static int
-scan_qstring (struct wordsplit *wsp, size_t start, size_t *end)
-{
- size_t j;
- const char *command = wsp->ws_input;
- size_t len = wsp->ws_len;
- char q = command[start];
-
- for (j = start + 1; j < len && command[j] != q; j++)
- if (q == '"' && command[j] == '\\')
- j++;
- if (j < len && command[j] == q)
- {
- int flags = _WSNF_QUOTE | _WSNF_EMPTYOK;
- if (q == '\'')
- flags |= _WSNF_NOEXPAND;
- if (wordsplit_add_segm (wsp, start + 1, j, flags))
- return _WRDS_ERR;
- *end = j;
- }
- else
- {
- wsp->ws_endp = start;
- _wsplt_seterr (wsp, WRDSE_QUOTE);
- return _WRDS_ERR;
- }
- return 0;
-}
-
-static int
-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;
-
- if (i >= len)
- {
- wsp->ws_errno = WRDSE_EOF;
- return _WRDS_EOF;
- }
-
- start = i;
-
- if (wsp->ws_flags & WRDSF_SED_EXPR
- && command[i] == 's' && i + 3 < len && ISPUNCT (command[i + 1]))
- {
- flags = _WSNF_SEXP;
- i = skip_sed_expr (command, i, len);
- }
- else if (consume_all || !ISDELIM (wsp, command[i]))
- {
- while (i < len)
- {
- if (comment && strchr (comment, command[i]) != NULL)
- {
- size_t j;
- for (j = i + 1; j < len && command[j] != '\n'; j++)
- ;
- if (wordsplit_add_segm (wsp, start, i, 0))
- return _WRDS_ERR;
- wsp->ws_endp = j;
- return _WRDS_OK;
- }
-
- if (wsp->ws_flags & WRDSF_QUOTE)
- {
- if (command[i] == '\\')
- {
- if (++i == len)
- break;
- i++;
- continue;
- }
-
- if (((wsp->ws_flags & WRDSF_SQUOTE) && command[i] == '\'') ||
- ((wsp->ws_flags & WRDSF_DQUOTE) && command[i] == '"'))
- {
- if (join && wsp->ws_tail)
- wsp->ws_tail->flags |= _WSNF_JOIN;
- if (wordsplit_add_segm (wsp, start, i, _WSNF_JOIN))
- return _WRDS_ERR;
- if (scan_qstring (wsp, i, &i))
- return _WRDS_ERR;
- start = i + 1;
- join = 1;
- }
- }
-
- if (command[i] == '$')
- {
- 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)
- || (wsp->ws_options & WRDSO_NOCMDSPLIT))
- && command[i+1] == '('
- && find_closing_paren (command, i + 2, len, &i, "()") == 0)
- continue;
- }
-
- if (!consume_all && ISDELIM (wsp, command[i]))
- break;
- else
- i++;
- }
- }
- else if (WSP_RETURN_DELIMS (wsp))
- {
- i++;
- flags |= _WSNF_DELIM;
- }
- else if (!(wsp->ws_flags & WRDSF_SQUEEZE_DELIMS))
- flags |= _WSNF_EMPTYOK;
-
- if (join && i > start && wsp->ws_tail)
- wsp->ws_tail->flags |= _WSNF_JOIN;
- if (wordsplit_add_segm (wsp, start, i, flags))
- return _WRDS_ERR;
- 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;
-}
-
-static int
-xtonum (int *pval, const char *src, int base, int cnt)
-{
- int i, val;
-
- for (i = 0, val = 0; i < cnt; i++, src++)
- {
- int n = *(unsigned char *) src;
- if (n > 127 || (n = to_num (n)) >= base)
- break;
- val = val * base + n;
- }
- *pval = val;
- return i;
-}
-
-size_t
-wordsplit_c_quoted_length (const char *str, int quote_hex, int *quote)
-{
- size_t len = 0;
-
- *quote = 0;
- for (; *str; str++)
- {
- if (strchr (" \"", *str))
- *quote = 1;
-
- if (*str == ' ')
- len++;
- else if (*str == '"')
- len += 2;
- else if (*str != '\t' && *str != '\\' && ISPRINT (*str))
- len++;
- else if (quote_hex)
- len += 3;
- else
- {
- if (wordsplit_c_quote_char (*str))
- len += 2;
- else
- len += 4;
- }
- }
- return len;
-}
-
-static int
-wsplt_unquote_char (const char *transtab, int c)
-{
- while (*transtab && transtab[1])
- {
- if (*transtab++ == c)
- return *transtab;
- ++transtab;
- }
- return 0;
-}
-
-static int
-wsplt_quote_char (const char *transtab, int c)
-{
- for (; *transtab && transtab[1]; transtab += 2)
- {
- if (transtab[1] == c)
- return *transtab;
- }
- return 0;
-}
-
-int
-wordsplit_c_unquote_char (int c)
-{
- return wsplt_unquote_char (wordsplit_c_escape_tab, c);
-}
-
-int
-wordsplit_c_quote_char (int c)
-{
- return wsplt_quote_char (wordsplit_c_escape_tab, c);
-}
-
-void
-wordsplit_string_unquote_copy (struct wordsplit *ws, int inquote,
- char *dst, const char *src, size_t n)
-{
- int i = 0;
- int c;
-
- inquote = !!inquote;
- while (i < n)
- {
- if (src[i] == '\\')
- {
- ++i;
- if (WRDSO_ESC_TEST (ws, inquote, WRDSO_XESC)
- && (src[i] == 'x' || src[i] == 'X'))
- {
- if (n - i < 2)
- {
- *dst++ = '\\';
- *dst++ = src[i++];
- }
- else
- {
- int off = xtonum (&c, src + i + 1,
- 16, 2);
- if (off == 0)
- {
- *dst++ = '\\';
- *dst++ = src[i++];
- }
- else
- {
- *dst++ = c;
- i += off + 1;
- }
- }
- }
- else if (WRDSO_ESC_TEST (ws, inquote, WRDSO_OESC)
- && (unsigned char) src[i] < 128 && ISDIGIT (src[i]))
- {
- if (n - i < 1)
- {
- *dst++ = '\\';
- *dst++ = src[i++];
- }
- else
- {
- int off = xtonum (&c, src + i, 8, 3);
- if (off == 0)
- {
- *dst++ = '\\';
- *dst++ = src[i++];
- }
- else
- {
- *dst++ = c;
- i += off;
- }
- }
- }
- else if ((c = wsplt_unquote_char (ws->ws_escape[inquote], src[i])))
- {
- *dst++ = c;
- ++i;
- }
- else
- {
- if (WRDSO_ESC_TEST (ws, inquote, WRDSO_BSKEEP))
- *dst++ = '\\';
- *dst++ = src[i++];
- }
- }
- else
- *dst++ = src[i++];
- }
- *dst = 0;
-}
-
-void
-wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex)
-{
- for (; *src; src++)
- {
- if (*src == '"')
- {
- *dst++ = '\\';
- *dst++ = *src;
- }
- else if (*src != '\t' && *src != '\\' && ISPRINT (*src))
- *dst++ = *src;
- else
- {
- char tmp[4];
-
- if (quote_hex)
- {
- snprintf (tmp, sizeof tmp, "%%%02X", *(unsigned char *) src);
- memcpy (dst, tmp, 3);
- dst += 3;
- }
- else
- {
- int c = wordsplit_c_quote_char (*src);
- *dst++ = '\\';
- if (c)
- *dst++ = c;
- else
- {
- snprintf (tmp, sizeof tmp, "%03o", *(unsigned char *) src);
- memcpy (dst, tmp, 3);
- dst += 3;
- }
- }
- }
- }
-}
-
-
-/* This structure describes a single expansion phase */
-struct exptab
-{
- 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
-/* 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_("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_("coalesce list"), 0, EXPOPT_NEG|EXPOPT_COALESCE,
- NULL },
- { 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_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 single word */
- if (scan_word (wsp, start, 1) == _WRDS_ERR)
- return wsp->ws_errno;
- }
- else
- {
- int rc;
-
- while ((rc = scan_word (wsp, start, 0)) == _WRDS_OK)
- start = skip_delim (wsp);
- /* Make sure tail element is not joinable */
- if (wsp->ws_tail)
- wsp->ws_tail->flags &= ~_WSNF_JOIN;
- if (rc == _WRDS_ERR)
- return wsp->ws_errno;
- }
-
- if (wsp->ws_flags & WRDSF_SHOWDBG)
- {
- wsp->ws_debug ("(%02d) %s", wsp->ws_lvl, _("Initial list:"));
- wordsplit_dump_nodes (wsp);
- }
-
- for (p = exptab; p->descr; p++)
- {
- if (exptab_matches(p, wsp))
- {
- if (p->opt & EXPOPT_COALESCE)
- {
- if (wsnode_coalesce (wsp))
- break;
- if (wsp->ws_flags & WRDSF_SHOWDBG)
- {
- wsp->ws_debug ("(%02d) %s", wsp->ws_lvl,
- _("Coalesced list:"));
- wordsplit_dump_nodes (wsp);
- }
- }
- if (p->expansion)
- {
- if (p->expansion (wsp))
- break;
- if (wsp->ws_flags & WRDSF_SHOWDBG)
- {
- wsp->ws_debug ("(%02d) %s", wsp->ws_lvl, _(p->descr));
- wordsplit_dump_nodes (wsp);
- }
- }
- }
- }
-
- return wsp->ws_errno;
-}
-
-static int
-wordsplit_run (const char *command, size_t length, struct wordsplit *wsp,
- int flags, int lvl)
-{
- int rc;
- size_t start;
-
- /* Initialize error context early */
- wsp->ws_errctx = NULL;
- if (!command)
- {
- if (!(flags & WRDSF_INCREMENTAL))
- return _wsplt_seterr (wsp, WRDSE_USAGE);
-
- if (wsp->ws_head)
- return wordsplit_finish (wsp);
-
- start = skip_delim_real (wsp);
- if (wsp->ws_endp == wsp->ws_len)
- return _wsplt_seterr (wsp, WRDSE_NOINPUT);
-
- wsp->ws_flags |= WRDSF_REUSE;
- wordsplit_init0 (wsp);
- }
- else
- {
- start = 0;
- rc = wordsplit_init (wsp, command, length, flags);
- if (rc)
- return rc;
- wsp->ws_lvl = lvl;
- }
-
- rc = wordsplit_process_list (wsp, start);
- if (rc)
- return rc;
- return wordsplit_finish (wsp);
-}
-
-int
-wordsplit_len (const char *command, size_t length, struct wordsplit *wsp,
- int flags)
-{
- return wordsplit_run (command, length, wsp, flags, 0);
-}
-
-int
-wordsplit (const char *command, struct wordsplit *ws, int flags)
-{
- return wordsplit_len (command, command ? strlen (command) : 0, ws, flags);
-}
-
-void
-wordsplit_free_words (struct wordsplit *ws)
-{
- size_t i;
-
- for (i = 0; i < ws->ws_wordc; i++)
- {
- char *p = ws->ws_wordv[ws->ws_offs + i];
- if (p)
- {
- free (p);
- ws->ws_wordv[ws->ws_offs + i] = NULL;
- }
- }
- ws->ws_wordc = 0;
-}
-
-void
-wordsplit_free_envbuf (struct wordsplit *ws)
-{
- if (!(ws->ws_flags & WRDSF_ENV))
- return;
- if (ws->ws_envbuf)
- {
- size_t i;
-
- for (i = 0; ws->ws_envbuf[i]; i++)
- free (ws->ws_envbuf[i]);
- free (ws->ws_envbuf);
- ws->ws_envidx = ws->ws_envsiz = 0;
- ws->ws_envbuf = NULL;
- }
-}
-
-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);
-}
-
-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]));
- 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[] = {
- N_("no error"),
- N_("missing closing quote"),
- N_("memory exhausted"),
- N_("invalid wordsplit usage"),
- N_("unbalanced curly brace"),
- N_("undefined variable"),
- N_("input exhausted"),
- N_("unbalanced parenthesis"),
- N_("globbing error"),
- N_("user-defined error"),
- N_("invalid parameter number in assignment")
-};
-int _wordsplit_nerrs =
- sizeof (_wordsplit_errstr) / sizeof (_wordsplit_errstr[0]);
-
-const char *
-wordsplit_strerror (struct wordsplit *ws)
-{
- if (ws->ws_errno == WRDSE_USERERR)
- return ws->ws_usererr;
- if (ws->ws_errno < _wordsplit_nerrs)
- return _wordsplit_errstr[ws->ws_errno];
- return N_("unknown error");
-}
-
-void
-wordsplit_perror (struct wordsplit *wsp)
-{
- switch (wsp->ws_errno)
- {
- case WRDSE_QUOTE:
- wsp->ws_error (_("missing closing %c (start near #%lu)"),
- wsp->ws_input[wsp->ws_endp],
- (unsigned long) wsp->ws_endp);
- break;
-
- default:
- 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/tests/.gitignore b/tests/.gitignore
index d16cf06..8ddd703 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -11,3 +11,7 @@ package.m4
testsuite
testsuite.log
wsp
+wordsplit-version.h
+wspackage.m4
+wstest
+wstest.log
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 292619d..a8ca2d3 100644
--- a/tests/Makefile.am
+++ b/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
@@ -125,7 +125,6 @@ TESTSUITE_AT = \
strcat.at\
testsuite.at\
vercmp.at\
- wordsplit.at\
@GRECS_DISTCK_AT@
TESTSUITE = $(srcdir)/testsuite
@@ -139,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.
@@ -155,8 +154,7 @@ noinst_PROGRAMS = \
gcfenum\
gcfpeek\
gcfset\
- gcfver\
- wsp
+ gcfver
if GRECS_COND_JSON
noinst_PROGRAMS += json
@@ -165,5 +163,49 @@ endif
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/tests/testsuite.at b/tests/testsuite.at
index cb7f1a5..ee9ebb8 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -47,8 +47,6 @@ 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])
diff --git a/tests/wordsplit.at b/tests/wordsplit.at
deleted file mode 100644
index 7ecc016..0000000
--- a/tests/wordsplit.at
+++ b/dev/null
@@ -1,1030 +0,0 @@
-# This file is part of grecs -*- Autotest -*-
-# Copyright (C) 2014-2018 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_BANNER(Wordsplit)
-
-m4_pushdef([wspnum],[0])
-m4_pushdef([wspid])
-m4_pushdef([wspgroupnum])
-m4_pushdef([wspgroupname])
-
-m4_pushdef([genkw],[dnl
-m4_define([wspid],m4_format([wordsplit%03d wsp%03d],wspnum))dnl
-m4_if(wspgroupname,,,[m4_define([wspid],wspid[ ]dnl
-m4_format(wspgroupname[ ]wspgroupname[%03d],wspgroupnum))dnl
-m4_define([wspgroupnum],m4_incr(wspgroupnum))])dnl
-m4_define([wspnum],m4_incr(wspnum))dnl
-wspid])
-
-m4_pushdef([WSPGROUP],[
-m4_define([wspgroupname],$1)
-m4_define([wspgroupnum],0)])
-
-dnl ------------------------------------------------------------
-dnl TESTWSP([NAME], [KW = `'], [OPTS], [INPUT], [STDOUT = `'],
-dnl [STDERR = `'], [ENV], [PROLOGUE])
-dnl
-m4_pushdef([TESTWSP],[
-AT_SETUP([$1])
-AT_KEYWORDS([wordsplit wsp ]genkw[ $2])
-AT_CHECK([$8
-$7 wsp $3 <<'EOT'
-[$4]
-EOT
-],
-[0],
-[$5],
-[$6])
-AT_CLEANUP
-])
-
-dnl ------------------------------------------------------------
-dnl The first part reproduces legacy argcv tests
-dnl ------------------------------------------------------------
-
-TESTWSP([simple input],[wsp-simple],[],
-[1 2 3],
-[NF: 3
-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],[],
-[a "tab character"],
-[NF: 2
-0: a
-1: tab\tcharacter
-TOTAL: 2
-])
-
-WSPGROUP(wsp-escape)
-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],[],[],
-[\157\143\164\141\154\40 and \x20\x68\x65\x78],
-[NF: 3
-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()
-
-dnl ------------------------------------------------------------
-dnl Test worsplit-specific behavior
-dnl ------------------------------------------------------------
-TESTWSP([append],[wsp-append],[-append],
-[jeden dwa trzy
-cztery
-piec szesc],
-[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
-])
-
-TESTWSP([dooffs],[wsp-doofs ],[-dooffs jeden dwa trzy],
-[cztery piec],
-[NF: 2 (3)
-(0): jeden
-(1): dwa
-(2): trzy
-3: cztery
-4: piec
-TOTAL: 2
-])
-
-WSPGROUP(wsp-var)
-
-TESTWSP([variable substitutions: single var],[],[],
-[a $FOO test],
-[NF: 3
-0: a
-1: bar
-2: test
-TOTAL: 3
-],
-[],
-[FOO=bar])
-
-TESTWSP([variable substitutions: concatenated vars],[],
-[],
-[a $FOO${BAR}ent test],
-[NF: 3
-0: a
-1: stringent
-2: test
-TOTAL: 3
-],
-[],
-[FOO=str BAR=ing])
-
-TESTWSP([variable substitutions: field splitting],[],[],
-[a $FOO test],
-[NF: 4
-0: a
-1: variable
-2: substitution
-3: test
-TOTAL: 4
-],
-[],
-[FOO="variable substitution"])
-
-TESTWSP([variable substitutions: double-quoted variable],[],[],
-[a "$FOO" test],
-[NF: 3
-0: a
-1: "variable substitution"
-2: test
-TOTAL: 3
-],
-[],
-[FOO="variable substitution"])
-
-TESTWSP([variable substitutions: single-quoted variable],[],[],
-[a '$FOO' test],
-[NF: 3
-0: a
-1: $FOO
-2: test
-TOTAL: 3
-],
-[],
-[FOO="variable substitution"])
-
-TESTWSP([undefined variables 1],[],[],
-[a $FOO test a${FOO}b],
-[NF: 3
-0: a
-1: test
-2: ab
-TOTAL: 3
-],
-[],
-[unset FOO;])
-
-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],
-[$FOO],
-[NF: 0
-TOTAL: 0
-],
-[warning: undefined variable `FOO'
-],
-[unset FOO;])
-
-TESTWSP([bail out on undefined variables],[],[-undef],
-[$FOO],
-[],
-[undefined variable: FOO
-],
-[unset FOO;])
-
-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],
-[$FOO a$BAZ],
-[NF: 2
-0: bar
-1: aqux
-TOTAL: 2
-],
-[],
-[FOO=bar BAZ=qux])
-
-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 variable expansion],[],[-nosplit -novar],
-[a $FOO test],
-[NF: 1
-0: "a $FOO test\n"
-TOTAL: 1
-],
-[],
-[FOO="variable expansion"])
-
-TESTWSP([nosplit: empty expansion],[],[-nosplit -trimnl],
-[$FOO],
-[NF: 1
-0: ""
-TOTAL: 1
-],
-[],
-[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])
-
-TESTWSP([default value (:- null)],[],[],
-[${FOO:-bar}],
-[NF: 1
-0: bar
-TOTAL: 1
-],
-[],
-[FOO=])
-
-TESTWSP([default value (- null)],[],[],
-[${FOO-bar}],
-[NF: 0
-TOTAL: 0
-],
-[],
-[FOO=])
-
-TESTWSP([default value (- null, unset)],[],[],
-[${FOO-bar}],
-[NF: 1
-0: bar
-TOTAL: 1
-])
-
-TESTWSP([assign default values],[],[],
-[${FOO=bar}
-$FOO],
-[NF: 1
-0: bar
-TOTAL: 1
-NF: 1
-0: bar
-TOTAL: 1
-])
-
-TESTWSP([default error message (var defined)],[],[],
-[a ${FOO:?} test],
-[NF: 3
-0: a
-1: bar
-2: test
-TOTAL: 3
-],
-[],
-[FOO=bar])
-
-TESTWSP([default error message],[],[],
-[${FOO:?}],
-[NF: 0
-TOTAL: 0
-],
-[FOO: variable null or not set
-])
-
-TESTWSP([custom error message (defined)],[wsp-custom-err wsp-custom-err00],[],
-[a ${FOO:?please define it} test],
-[NF: 3
-0: a
-1: bar
-2: test
-TOTAL: 3
-],
-[],
-[FOO=bar])
-
-TESTWSP([custom error message],[wsp-custom-err wsp-custom-err01],[],
-[a ${FOO:?please define it} test],
-[NF: 2
-0: a
-1: test
-TOTAL: 2
-],
-[FOO: please define it
-])
-
-TESTWSP([alternate value (defined)],[wsp-alt wsp-alt00],[],
-[a ${FOO:+isset} test],
-[NF: 3
-0: a
-1: isset
-2: test
-TOTAL: 3
-],
-[],
-[FOO=bar])
-
-TESTWSP([alternate value],[wsp-alt wsp-alt01],[],
-[a ${FOO:+isset} test],
-[NF: 2
-0: a
-1: test
-TOTAL: 2
-],
-[],
-[unset FOO;])
-
-TESTWSP([getvar],[wsp-getvar],
-[foo=bar x=quux],
-[begin $foo $x end],
-[NF: 4
-0: begin
-1: bar
-2: quux
-3: end
-TOTAL: 4
-],
-[],
-[],
-[unset foo; unset x])
-
-TESTWSP([getvar and env],[wsp-getvar],
-[foo=bar x=quux y=xur],
-[begin $foo $TVAR $x $y end],
-[NF: 6
-0: begin
-1: bar
-2: 12
-3: quux
-4: zwar
-5: end
-TOTAL: 6
-],
-[],
-[TVAR=12 y=zwar],
-[unset foo; unset x])
-
-TESTWSP([getvar, alternate value],[wsp-getvar],
-[foo=bar],
-[a ${foo:+isset}],
-[NF: 2
-0: a
-1: isset
-TOTAL: 2
-])
-
-WSPGROUP()
-
-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 : -nows -trimnl],
-[semicolon: separated::list: of :words],
-[NF: 5
-0: semicolon
-1: " separated"
-2: list
-3: " of "
-4: words
-TOTAL: 5
-])
-
-TESTWSP([custom delimiters (no squeeze)],[],
-[-delim : -nows -nosqueeze_delims -trimnl],
-[semicolon: separated::list: of :words],
-[NF: 6
-0: semicolon
-1: " separated"
-2: ""
-3: list
-4: " of "
-5: words
-TOTAL: 6
-])
-
-TESTWSP([custom, with returned delimiters],[],
-[-delim : -nows -trimnl -return_delims],
-[semicolon: separated::list: of :words],
-[NF: 9
-0: semicolon
-1: :
-2: " separated"
-3: :
-4: list
-5: :
-6: " of "
-7: :
-8: words
-TOTAL: 9
-])
-
-TESTWSP([custom, with returned & squeezed delimiters],[],
-[-delim : -nows -trimnl -return_delims -nosqueeze_delims],
-[semicolon: separated::list: of :words],
-[NF: 10
-0: semicolon
-1: :
-2: " separated"
-3: :
-4: :
-5: list
-6: :
-7: " of "
-8: :
-9: words
-TOTAL: 10
-])
-
-WSPGROUP(wsp-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],
-[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],[-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],
-[( list items )],
-[NF: 4
-0: (
-1: list
-2: items
-3: )
-TOTAL: 4
-])
-
-TESTWSP([ws elimination + return delim],[wsp-ws-elim-ret],
-[-nodefault -novar -nocmd -delim ":," -return_delims -ws -dquote],
-["foo" : "bar", "quux" : "baaz" ],
-[NF: 7
-0: foo
-1: :
-2: bar
-3: ,
-4: quux
-5: :
-6: baaz
-TOTAL: 7
-])
-
-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],
-[t="":r],
-[NF: 3
-0: t=
-1: :
-2: r
-TOTAL: 3
-])
-
-TESTWSP([suppress ws trimming within quotes],
-[],
-[-default -delim , -ws -return_delims],
-[nocomponent,nonewline, formatfield="In message %{text}, "],
-[NF: 5
-0: nocomponent
-1: ,
-2: nonewline
-3: ,
-4: "formatfield=In message %{text}, "
-TOTAL: 5
-])
-
-TESTWSP([unescape],
-[wsp-unescape wsp-unescape-simple],
-[-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],
-[-nodefault -novar -nocmd -quote -escape-word '\\""' -escape-quote ':+0x:\\""'],
-[\Seen "quote \"" "bs \\" "3\x31 \101" 3\x31 \101],
-[NF: 6
-0: Seen
-1: "quote \""
-2: "bs \\"
-3: "31 A"
-4: 3x31
-5: 101
-TOTAL: 6
-])
-
-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],[],[-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],
-[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],
-[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 -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
-])
-
-TESTWSP([incremental nosplit],[],[-incremental -nosplit],
-[incremental "input test" line
-],
-[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: a
-2: b
-3: end
-TOTAL: 4
-])
-
-TESTWSP([quoted command substitution],[],[-cmd],
-[begin "$(words a b)" end],
-[NF: 3
-0: begin
-1: "a b"
-2: end
-TOTAL: 3
-])
-
-TESTWSP([coalesced command substitution],[],[-cmd],
-[begin($(words a b))end],
-[NF: 2
-0: begin(a
-1: b)end
-TOTAL: 2
-])
-
-TESTWSP([quoted coalesced command substitution],[],[-cmd],
-["begin($(words a b))end"],
-[NF: 1
-0: "begin(a b)end"
-TOTAL: 1
-])
-
-TESTWSP([variable and command substitution],[],[-cmd -var],
-[begin $X $(words $X $Y) end],
-[NF: 5
-0: begin
-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(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([
-mkdir dir
-> dir/1.c
-> dir/2.c
-> dir/3.b
-
-wsp -pathexpand<<'EOT'
-begin dir/*.c end
-EOT
-],
-[0],
-[NF: 4
-0: begin
-1: dir/1.c
-2: dir/2.c
-3: end
-TOTAL: 4
-])
-AT_CLEANUP
-
-AT_SETUP([pathname expansion: no match])
-AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-2])
-AT_CHECK([
-mkdir dir
-> dir/1.c
-> dir/2.b
-
-wsp -pathexpand<<'EOT'
-begin dir/*.d end
-EOT
-],
-[0],
-[NF: 3
-0: begin
-1: dir/*.d
-2: end
-TOTAL: 3
-])
-AT_CLEANUP
-
-AT_SETUP([pathname expansion: nullglob])
-AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-3])
-AT_CHECK([
-mkdir dir
-> dir/1.c
-> dir/2.b
-
-wsp -pathexpand -nullglob<<'EOT'
-begin dir/*.d end
-EOT
-],
-[0],
-[NF: 2
-0: begin
-1: end
-TOTAL: 2
-])
-AT_CLEANUP
-
-AT_SETUP([pathname expansion: failglob])
-AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-4])
-AT_CHECK([
-mkdir dir
-> dir/1.c
-> dir/2.b
-
-wsp -pathexpand -failglob<<'EOT'
-begin dir/*.d end
-EOT
-],
-[0],
-[],
-[no files match pattern dir/*.d
-])
-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])
-m4_popdef([genkw])
-m4_popdef([wspgroupnum])
-m4_popdef([wspgroupname])
-m4_popdef([WSPGROUP])
diff --git a/tests/wsp.c b/tests/wsp.c
deleted file mode 100644
index 958d01f..0000000
--- a/tests/wsp.c
+++ b/dev/null
@@ -1,756 +0,0 @@
-/* grecs - Gray's Extensible Configuration System
- Copyright (C) 2014-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 <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;
-
-/* 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;
-
-/* 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;
- }
- 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;
-
- 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 = NULL;
- if (grecs_asprintf (ret, &s, "unknown command: %s", argv[0]))
- return WRDSE_NOSPACE;
- else
- 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/wordsplit b/wordsplit
new file mode 160000
+Subproject d36275fe9adf1428fd2476defda9e1fcda56988

Return to:

Send suggestions and report system problems to the System administrator.