author | Sergey Poznyakoff <gray@gnu.org> | 2019-07-11 08:29:34 (GMT) |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2019-07-11 08:29:34 (GMT) |
commit | 2ad00905cde7230317c27fcbb3c41969ca5b79ab (patch) (side-by-side diff) | |
tree | 5a159e95e5d9a649b189fc634832320010ec4657 | |
parent | 4ba3d95fe9bd9bb3b93be60a8ea89e381c5f88c0 (diff) | |
download | mailutils-2ad00905cde7230317c27fcbb3c41969ca5b79ab.tar.gz mailutils-2ad00905cde7230317c27fcbb3c41969ca5b79ab.tar.bz2 |
Pull wordsplit from submodule.
* .gitmodules: Add wordsplit.
* configure.ac: Version 3.7.90
* NEWS: Raise version number.
* include/mailutils/sys/Makefile.am: Include wordsplit.h from the
submodule.
* include/mailutils/sys/wordsplit.h: New file.
* include/mailutils/wordsplit.h: Rewrite as a wrapper over
mailutils/sys/wordsplit.h
* libmailutils/Makefile.am: Distribute files from wordsplit.
* libmailutils/string/Makefile.am: Add libmailutils/wordsplit to
the include path.
* libmailutils/string/wordsplit.c: Replace with a wrapper over
wordsplit/wordsplit.c
* libmailutils/tests/.gitignore: Update.
* libmailutils/tests/Makefile.am: Pull wordsplit testsuite from
the submodule.
* libmailutils/tests/wordsplit.at: Remove.
* libmailutils/tests/wsp.c: Remove.
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | include/mailutils/sys/Makefile.am | 3 | ||||
l--------- | include/mailutils/sys/wordsplit.h | 1 | ||||
-rw-r--r-- | include/mailutils/wordsplit.h | 358 | ||||
-rw-r--r-- | libmailutils/Makefile.am | 6 | ||||
-rw-r--r-- | libmailutils/string/Makefile.am | 6 | ||||
-rw-r--r-- | libmailutils/string/wordsplit.c | 2382 | ||||
-rw-r--r-- | libmailutils/tests/.gitignore | 1 | ||||
-rw-r--r-- | libmailutils/tests/Makefile.am | 35 | ||||
-rw-r--r-- | libmailutils/tests/wordsplit.at | 787 | ||||
-rw-r--r-- | libmailutils/tests/wsp.c | 654 | ||||
m--------- | libmailutils/wordsplit | 0 |
14 files changed, 164 insertions, 4078 deletions
diff --git a/.gitmodules b/.gitmodules index bdc2cb0..142e50c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "gnulib"] path = gnulib url = git://git.sv.gnu.org/gnulib.git +[submodule "libmailutils/wordsplit"] + path = libmailutils/wordsplit + url = git://git.gnu.org.ua/wordsplit.git @@ -4,6 +4,8 @@ See the end of file for copying conditions. Please send mailutils bug reports to <bug-mailutils@gnu.org>. +Version 3.7.90 (git) + Version 3.7 - 2019-06-21 * Support for the new mailbox format - dotmail diff --git a/configure.ac b/configure.ac index eb14361..c841acf 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ dnl You should have received a copy of the GNU General Public License along dnl with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. AC_PREREQ(2.63) -AC_INIT([GNU Mailutils], [3.7], [bug-mailutils@gnu.org], [mailutils], +AC_INIT([GNU Mailutils], [3.7.90], [bug-mailutils@gnu.org], [mailutils], [http://mailutils.org]) AC_CONFIG_SRCDIR([libmailutils/mailbox/mailbox.c]) AC_CONFIG_AUX_DIR([build-aux]) @@ -115,6 +115,8 @@ AC_CHECK_TYPE(iconv_t,:, # AC_CONFIG_LINKS(include/gettext.h:lib/gnu/gettext.h) +AC_CONFIG_LINKS(include/mailutils/sys/wordsplit.h:libmailutils/wordsplit/wordsplit.h) + AH_BOTTOM([ #define DEFAULT_TEXT_DOMAIN PACKAGE ]) diff --git a/include/mailutils/sys/Makefile.am b/include/mailutils/sys/Makefile.am index 7f31291..321c5f1 100644 --- a/include/mailutils/sys/Makefile.am +++ b/include/mailutils/sys/Makefile.am @@ -62,7 +62,8 @@ sysinclude_HEADERS = \ temp_file_stream.h\ tls-stream.h\ url.h\ - xscript-stream.h + xscript-stream.h\ + $(top_srcdir)/libmailutils/wordsplit/wordsplit.h BUILT_SOURCES = debcat.h diff --git a/include/mailutils/sys/wordsplit.h b/include/mailutils/sys/wordsplit.h new file mode 120000 index 0000000..5c46e03 --- a/dev/null +++ b/include/mailutils/sys/wordsplit.h @@ -0,0 +1 @@ +../../../libmailutils/wordsplit/wordsplit.h
\ No newline at end of file diff --git a/include/mailutils/wordsplit.h b/include/mailutils/wordsplit.h index d5631dd..203d924 100644 --- a/include/mailutils/wordsplit.h +++ b/include/mailutils/wordsplit.h @@ -1,261 +1,121 @@ -/* wordsplit - a word splitter - Copyright (C) 2009-2018 Sergey Poznyakoff +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999-2019 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 3 of the License, or (at your - option) any later version. + GNU Mailutils 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. - This program is distributed in the hope that it will be useful, + GNU Mailutils 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/>. */ + You should have received a copy of the GNU General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ + +/* This header converts wordsplit to mailutils namespace by prefixing each + exported identifier with mu_ (or MU_, for macros). + The canonical wordsplit.h header is located in mailutils/sys. +*/ #ifndef __MAILUTILS_WORDSPLIT_H #define __MAILUTILS_WORDSPLIT_H -#include <stddef.h> - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct mu_wordsplit mu_wordsplit_t; - -/* Structure used to direct the splitting. Members marked with [Input] - can be defined before calling mu_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 the ws_flags to initialize or use the given member. - If not redefined explicitly, most of them are set to some reasonable - default value upon entry to mu_wordsplit(). */ -struct mu_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] (MU_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 mu_wordsplit. */ - int ws_options; /* [Input] (MU_WRDSF_PATHEXPAND) - Additional options. */ - const char *ws_delim; /* [Input] (MU_WRDSF_DELIM) Word delimiters. */ - const char *ws_comment; /* [Input] (MU_WRDSF_COMMENT) Comment characters. */ - const char *ws_escape[2]; /* [Input] (MU_WRDSF_ESCAPE) Characters to be escaped - with backslash. */ - void (*ws_alloc_die) (mu_wordsplit_t *wsp); - /* [Input] (MU_WRDSF_ALLOC_DIE) Function called when - out of memory. Must not return. */ - void (*ws_error) (const char *, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); - /* [Input] (MU_WRDSF_ERROR) Function used for error - reporting */ - void (*ws_debug) (const char *, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); - /* [Input] (MU_WRDSF_DEBUG) Function used for debug - output. */ - const char **ws_env; /* [Input] (MU_WRDSF_ENV, !MU_WRDSF_NOVAR) Array of - environment variables. */ +# define wordsplit mu_wordsplit + +# define wordsplit_t mu_wordsplit_t + +# define wordsplit_len mu_wordsplit_len +# define wordsplit_free mu_wordsplit_free +# define wordsplit_free_words mu_wordsplit_free_words +# define wordsplit_free_envbuf mu_wordsplit_free_envbuf +# define wordsplit_free_parambuf mu_wordsplit_free_parambuf +# define wordsplit_getwords mu_wordsplit_getwords +# define wordsplit_get_words mu_wordsplit_get_words +# define wordsplit_append mu_wordsplit_append +# define wordsplit_c_unquote_char mu_wordsplit_c_unquote_char +# define wordsplit_c_quote_char mu_wordsplit_c_quote_char +# define wordsplit_c_quoted_length mu_wordsplit_c_quoted_length +# define wordsplit_c_quote_copy mu_wordsplit_c_quote_copy +# define wordsplit_perror mu_wordsplit_perror +# define wordsplit_strerror mu_wordsplit_strerror +# define wordsplit_clearerr mu_wordsplit_clearerr + +# include <mailutils/sys/wordsplit.h> + +# define MU_WORDSPLIT_ENV_INIT WORDSPLIT_ENV_INIT +# define MU_WRDSF_APPEND WRDSF_APPEND +# define MU_WRDSF_DOOFFS WRDSF_DOOFFS +# define MU_WRDSF_NOCMD WRDSF_NOCMD +# define MU_WRDSF_REUSE WRDSF_REUSE +# define MU_WRDSF_SHOWERR WRDSF_SHOWERR +# define MU_WRDSF_UNDEF WRDSF_UNDEF +# define MU_WRDSF_NOVAR WRDSF_NOVAR +# define MU_WRDSF_ENOMEMABRT WRDSF_ENOMEMABRT +# define MU_WRDSF_WS WRDSF_WS +# define MU_WRDSF_SQUOTE WRDSF_SQUOTE +# define MU_WRDSF_DQUOTE WRDSF_DQUOTE +# define MU_WRDSF_QUOTE WRDSF_QUOTE +# define MU_WRDSF_SQUEEZE_DELIMS WRDSF_SQUEEZE_DELIMS +# define MU_WRDSF_RETURN_DELIMS WRDSF_RETURN_DELIMS +# define MU_WRDSF_SED_EXPR WRDSF_SED_EXPR +# define MU_WRDSF_DELIM WRDSF_DELIM +# define MU_WRDSF_COMMENT WRDSF_COMMENT +# define MU_WRDSF_ALLOC_DIE WRDSF_ALLOC_DIE +# define MU_WRDSF_ERROR WRDSF_ERROR +# define MU_WRDSF_DEBUG WRDSF_DEBUG +# define MU_WRDSF_ENV WRDSF_ENV +# define MU_WRDSF_GETVAR WRDSF_GETVAR +# define MU_WRDSF_SHOWDBG WRDSF_SHOWDBG +# define MU_WRDSF_NOSPLIT WRDSF_NOSPLIT +# define MU_WRDSF_KEEPUNDEF WRDSF_KEEPUNDEF +# define MU_WRDSF_WARNUNDEF WRDSF_WARNUNDEF +# define MU_WRDSF_CESCAPES WRDSF_CESCAPES +# define MU_WRDSF_CLOSURE WRDSF_CLOSURE +# define MU_WRDSF_ENV_KV WRDSF_ENV_KV +# define MU_WRDSF_ESCAPE WRDSF_ESCAPE +# define MU_WRDSF_INCREMENTAL WRDSF_INCREMENTAL +# define MU_WRDSF_PATHEXPAND WRDSF_PATHEXPAND +# define MU_WRDSF_OPTIONS WRDSF_OPTIONS +# define MU_WRDSF_DEFFLAGS WRDSF_DEFFLAGS + +# define MU_WRDSO_NULLGLOB WRDSO_NULLGLOB +# define MU_WRDSO_FAILGLOB WRDSO_FAILGLOB +# define MU_WRDSO_DOTGLOB WRDSO_DOTGLOB +# define MU_WRDSO_GETVARPREF WRDSO_GETVARPREF +# define MU_WRDSO_BSKEEP_WORD WRDSO_BSKEEP_WORD +# define MU_WRDSO_OESC_WORD WRDSO_OESC_WORD +# define MU_WRDSO_XESC_WORD WRDSO_XESC_WORD +# define MU_WRDSO_MAXWORDS WRDSO_MAXWORDS +# define MU_WRDSO_BSKEEP_QUOTE WRDSO_BSKEEP_QUOTE +# define MU_WRDSO_OESC_QUOTE WRDSO_OESC_QUOTE +# define MU_WRDSO_XESC_QUOTE WRDSO_XESC_QUOTE +# define MU_WRDSO_NOVARSPLIT WRDSO_NOVARSPLIT +# define MU_WRDSO_NOCMDSPLIT WRDSO_NOCMDSPLIT +# define MU_WRDSO_PARAMV WRDSO_PARAMV +# define MU_WRDSO_PARAM_NEGIDX WRDSO_PARAM_NEGIDX +# define MU_WRDSO_BSKEEP WRDSO_BSKEEP +# define MU_WRDSO_OESC WRDSO_OESC +# define MU_WRDSO_XESC WRDSO_XESC + +# define MU_WRDSO_ESC_SET WRDSO_ESC_SET +# define MU_WRDSO_ESC_TEST WRDSO_ESC_TEST + +# define MU_WRDSX_WORD WRDSX_WORD +# define MU_WRDSX_QUOTE WRDSX_QUOTE + +# define MU_WRDSE_OK WRDSE_OK +# define MU_WRDSE_EOF WRDSE_EOF +# define MU_WRDSE_QUOTE WRDSE_QUOTE +# define MU_WRDSE_NOSPACE WRDSE_NOSPACE +# define MU_WRDSE_USAGE WRDSE_USAGE +# define MU_WRDSE_CBRACE WRDSE_CBRACE +# define MU_WRDSE_UNDEF WRDSE_UNDEF +# define MU_WRDSE_NOINPUT WRDSE_NOINPUT +# define MU_WRDSE_PAREN WRDSE_PAREN +# define MU_WRDSE_GLOBERR WRDSE_GLOBERR +# define MU_WRDSE_USERERR WRDSE_USERERR +# define MU_WRDSE_BADPARAM WRDSE_BADPARAM - char **ws_envbuf; - size_t ws_envidx; - size_t ws_envsiz; - - int (*ws_getvar) (char **ret, const char *var, size_t len, void *clos); - /* [Input] (MU_WRDSF_GETVAR, !MU_WRDSF_NOVAR) Looks up - the name VAR (LEN bytes long) in the table of - variables and, if found returns the value of - that variable in memory location pointed to - by RET . 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] (MU_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] (!MU_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 mu_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). */ - struct mu_wordsplit_node *ws_head, *ws_tail; - /* Doubly-linked list of parsed out nodes. */ - int ws_lvl; /* Invocation nesting level. */ -}; - -/* Initial size for ws_env, if allocated automatically */ -#define MU_WORDSPLIT_ENV_INIT 16 - -/* Mu_Wordsplit flags. */ -/* Append the words found to the array resulting from a previous - call. */ -#define MU_WRDSF_APPEND 0x00000001 -/* Insert ws_offs initial NULLs in the array ws_wordv. - (These are not counted in the returned ws_wordc.) */ -#define MU_WRDSF_DOOFFS 0x00000002 -/* Don't do command substitution. */ -#define MU_WRDSF_NOCMD 0x00000004 -/* The parameter p resulted from a previous call to - mu_wordsplit(), and mu_wordsplit_free() was not called. Reuse the - allocated storage. */ -#define MU_WRDSF_REUSE 0x00000008 -/* Print errors */ -#define MU_WRDSF_SHOWERR 0x00000010 -/* Consider it an error if an undefined variable is expanded. */ -#define MU_WRDSF_UNDEF 0x00000020 -/* Don't do variable expansion. */ -#define MU_WRDSF_NOVAR 0x00000040 -/* Abort on ENOMEM error */ -#define MU_WRDSF_ENOMEMABRT 0x00000080 -/* Trim off any leading and trailind whitespace */ -#define MU_WRDSF_WS 0x00000100 -/* Handle single quotes */ -#define MU_WRDSF_SQUOTE 0x00000200 -/* Handle double quotes */ -#define MU_WRDSF_DQUOTE 0x00000400 -/* Handle single and double quotes */ -#define MU_WRDSF_QUOTE (MU_WRDSF_SQUOTE|MU_WRDSF_DQUOTE) -/* Replace each input sequence of repeated delimiters with a single - delimiter */ -#define MU_WRDSF_SQUEEZE_DELIMS 0x00000800 -/* Return delimiters */ -#define MU_WRDSF_RETURN_DELIMS 0x00001000 -/* Treat sed expressions as words */ -#define MU_WRDSF_SED_EXPR 0x00002000 -/* ws_delim field is initialized */ -#define MU_WRDSF_DELIM 0x00004000 -/* ws_comment field is initialized */ -#define MU_WRDSF_COMMENT 0x00008000 -/* ws_alloc_die field is initialized */ -#define MU_WRDSF_ALLOC_DIE 0x00010000 -/* ws_error field is initialized */ -#define MU_WRDSF_ERROR 0x00020000 -/* ws_debug field is initialized */ -#define MU_WRDSF_DEBUG 0x00040000 -/* ws_env field is initialized */ -#define MU_WRDSF_ENV 0x00080000 -/* ws_getvar field is initialized */ -#define MU_WRDSF_GETVAR 0x00100000 -/* enable debugging */ -#define MU_WRDSF_SHOWDBG 0x00200000 -/* Don't split input into words. Useful for side effects. */ -#define MU_WRDSF_NOSPLIT 0x00400000 -/* Keep undefined variables in place, instead of expanding them to - empty strings. */ -#define MU_WRDSF_KEEPUNDEF 0x00800000 -/* Warn about undefined variables */ -#define MU_WRDSF_WARNUNDEF 0x01000000 -/* Handle C escapes */ -#define MU_WRDSF_CESCAPES 0x02000000 -/* ws_closure is set */ -#define MU_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 MU_WRDSF_ENV_KV 0x08000000 -/* ws_escape is set */ -#define MU_WRDSF_ESCAPE 0x10000000 -/* Incremental mode */ -#define MU_WRDSF_INCREMENTAL 0x20000000 -/* Perform pathname and tilde expansion */ -#define MU_WRDSF_PATHEXPAND 0x40000000 -/* ws_options is initialized */ -#define MU_WRDSF_OPTIONS 0x80000000 - -#define MU_WRDSF_DEFFLAGS \ - (MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | \ - MU_WRDSF_QUOTE | MU_WRDSF_SQUEEZE_DELIMS | MU_WRDSF_CESCAPES) - -/* Remove the word that produces empty string after path expansion */ -#define MU_WRDSO_NULLGLOB 0x00000001 -/* Print error message if path expansion produces empty string */ -#define MU_WRDSO_FAILGLOB 0x00000002 -/* Allow a leading period to be matched by metacharacters. */ -#define MU_WRDSO_DOTGLOB 0x00000004 -#if 0 -/* Unused */ -#define MU_WRDSO_ARGV 0x00000008 -#endif -/* Keep backslash in unrecognized escape sequences in words */ -#define MU_WRDSO_BSKEEP_WORD 0x00000010 -/* Handle octal escapes in words */ -#define MU_WRDSO_OESC_WORD 0x00000020 -/* Handle hex escapes in words */ -#define MU_WRDSO_XESC_WORD 0x00000040 - -/* Keep backslash in unrecognized escape sequences in quoted strings */ -#define MU_WRDSO_BSKEEP_QUOTE 0x00000100 -/* Handle octal escapes in quoted strings */ -#define MU_WRDSO_OESC_QUOTE 0x00000200 -/* Handle hex escapes in quoted strings */ -#define MU_WRDSO_XESC_QUOTE 0x00000400 - -#define MU_WRDSO_BSKEEP MU_WRDSO_BSKEEP_WORD -#define MU_WRDSO_OESC MU_WRDSO_OESC_WORD -#define MU_WRDSO_XESC MU_WRDSO_XESC_WORD - -/* Indices into ws_escape */ -#define MU_WRDSX_WORD 0 -#define MU_WRDSX_QUOTE 1 - -/* Set escape option F in WS for words (Q==0) or quoted strings (Q==1) */ -#define MU_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 MU_WRDSO_ESC_TEST(ws,q,f) ((ws)->ws_options & ((f) << 4*(q))) - -#define MU_WRDSE_OK 0 -#define MU_WRDSE_EOF MU_WRDSE_OK -#define MU_WRDSE_QUOTE 1 -#define MU_WRDSE_NOSPACE 2 -#define MU_WRDSE_USAGE 3 -#define MU_WRDSE_CBRACE 4 -#define MU_WRDSE_UNDEF 5 -#define MU_WRDSE_NOINPUT 6 -#define MU_WRDSE_PAREN 7 -#define MU_WRDSE_GLOBERR 8 -#define MU_WRDSE_USERERR 9 - -int mu_wordsplit (const char *s, mu_wordsplit_t *ws, int flags); -int mu_wordsplit_len (const char *s, size_t len, mu_wordsplit_t *ws, int flags); -void mu_wordsplit_free (mu_wordsplit_t *ws); -void mu_wordsplit_free_words (mu_wordsplit_t *ws); -void mu_wordsplit_free_envbuf (mu_wordsplit_t *ws); - -int mu_wordsplit_get_words (mu_wordsplit_t *ws, size_t *wordc, char ***wordv); -int mu_wordsplit_append (struct mu_wordsplit *wsp, int argc, char **argv); - -int mu_wordsplit_c_unquote_char (int c); -int mu_wordsplit_c_quote_char (int c); -size_t mu_wordsplit_c_quoted_length (const char *str, int quote_hex, int *quote); -void mu_wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex); - -void mu_wordsplit_perror (mu_wordsplit_t *ws); -const char *mu_wordsplit_strerror (mu_wordsplit_t *ws); - -void mu_wordsplit_clearerr (mu_wordsplit_t *ws); - -#ifdef __cplusplus -} -#endif - #endif diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am index 422d2c1..71bcda2 100644 --- a/libmailutils/Makefile.am +++ b/libmailutils/Makefile.am @@ -80,3 +80,9 @@ libmailutils_la_LIBADD = \ libmailutils_la_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ +EXTRA_DIST =\ + wordsplit/wordsplit.c\ + wordsplit/wordsplit.h\ + wordsplit/wordsplit.at\ + wordsplit/wsp.c + diff --git a/libmailutils/string/Makefile.am b/libmailutils/string/Makefile.am index 5cdd739..2455771 100644 --- a/libmailutils/string/Makefile.am +++ b/libmailutils/string/Makefile.am @@ -50,4 +50,8 @@ libstring_la_SOURCES = \ EXTRA_DIST=to_sn.c to_un.c -AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils -I${srcdir} +AM_CPPFLAGS = \ + @MU_LIB_COMMON_INCLUDES@\ + -I${srcdir}\ + -I${top_srcdir}/libmailutils\ + -I${top_srcdir}/libmailutils/wordsplit diff --git a/libmailutils/string/wordsplit.c b/libmailutils/string/wordsplit.c index 1f9b32a..dc3a04d 100644 --- a/libmailutils/string/wordsplit.c +++ b/libmailutils/string/wordsplit.c @@ -1,2382 +1,2 @@ -/* wordsplit - a word splitter - Copyright (C) 2009-2015 Sergey Poznyakoff - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 3 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program. If not, see <http://www.gnu.org/licenses/>. */ - -/* This module is shared with Grecs: http://puszcza.gnu.org.ua/projects/grecs. - The intent is to keep it as mu-independent as possible, so that the two - projects can be easily synchronized. Some time in the future I'll think - about providing a better way of synching, perhaps by integrating Grecs to - Mailutils as a submodule. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <errno.h> -#include <ctype.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <stdarg.h> -#include <pwd.h> -#include <glob.h> - -#include <mailutils/nls.h> #include <mailutils/wordsplit.h> - -#define ISWS(c) ((c)==' '||(c)=='\t'||(c)=='\n') -#define ISDELIM(ws,c) \ - (strchr ((ws)->ws_delim, (c)) != NULL) -#define ISPUNCT(c) (strchr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",(c))!=NULL) -#define ISUPPER(c) ('A' <= ((unsigned) (c)) && ((unsigned) (c)) <= 'Z') -#define ISLOWER(c) ('a' <= ((unsigned) (c)) && ((unsigned) (c)) <= 'z') -#define ISALPHA(c) (ISUPPER(c) || ISLOWER(c)) -#define ISDIGIT(c) ('0' <= ((unsigned) (c)) && ((unsigned) (c)) <= '9') -#define ISXDIGIT(c) (strchr("abcdefABCDEF", c)!=NULL) -#define ISALNUM(c) (ISALPHA(c) || ISDIGIT(c)) -#define ISPRINT(c) (' ' <= ((unsigned) (c)) && ((unsigned) (c)) <= 127) - -#define ISVARBEG(c) (ISALPHA(c) || c == '_') -#define ISVARCHR(c) (ISALNUM(c) || c == '_') - -#define ALLOC_INIT 128 -#define ALLOC_INCR 128 - -static void -_wsplt_alloc_die (struct mu_wordsplit *wsp) -{ - wsp->ws_error ("%s", _("memory exhausted")); - abort (); -} - -static void -_wsplt_error (const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - fputc ('\n', stderr); -} - -static void mu_wordsplit_free_nodes (struct mu_wordsplit *); - -static int -_wsplt_seterr (struct mu_wordsplit *wsp, int ec) -{ - wsp->ws_errno = ec; - if (wsp->ws_flags & MU_WRDSF_SHOWERR) - mu_wordsplit_perror (wsp); - return ec; -} - -static int -_wsplt_nomem (struct mu_wordsplit *wsp) -{ - errno = ENOMEM; - wsp->ws_errno = MU_WRDSE_NOSPACE; - if (wsp->ws_flags & MU_WRDSF_ENOMEMABRT) - wsp->ws_alloc_die (wsp); - if (wsp->ws_flags & MU_WRDSF_SHOWERR) - mu_wordsplit_perror (wsp); - if (!(wsp->ws_flags & MU_WRDSF_REUSE)) - mu_wordsplit_free (wsp); - mu_wordsplit_free_nodes (wsp); - return wsp->ws_errno; -} - -static int mu_wordsplit_run (const char *command, size_t length, - struct mu_wordsplit *wsp, - int flags, int lvl); - -static int -_wsplt_subsplit (struct mu_wordsplit *wsp, struct mu_wordsplit *wss, - char const *str, int len, - int flags) -{ - wss->ws_delim = wsp->ws_delim; - wss->ws_debug = wsp->ws_debug; - wss->ws_error = wsp->ws_error; - wss->ws_alloc_die = wsp->ws_alloc_die; - - if (!(flags & MU_WRDSF_NOVAR)) - { - wss->ws_env = wsp->ws_env; - wss->ws_getvar = wsp->ws_getvar; - flags |= wsp->ws_flags & (MU_WRDSF_ENV | MU_WRDSF_ENV_KV | MU_WRDSF_GETVAR); - } - if (!(flags & MU_WRDSF_NOCMD)) - { - wss->ws_command = wsp->ws_command; - } - - if ((flags & (MU_WRDSF_NOVAR|MU_WRDSF_NOCMD)) != (MU_WRDSF_NOVAR|MU_WRDSF_NOCMD)) - { - wss->ws_closure = wsp->ws_closure; - flags |= wsp->ws_flags & MU_WRDSF_CLOSURE; - } - - wss->ws_options = wsp->ws_options; - - flags |= MU_WRDSF_DELIM - | MU_WRDSF_ALLOC_DIE - | MU_WRDSF_ERROR - | MU_WRDSF_DEBUG - | (wsp->ws_flags & (MU_WRDSF_SHOWDBG | MU_WRDSF_SHOWERR | MU_WRDSF_OPTIONS)); - - return mu_wordsplit_run (str, len, wss, flags, wsp->ws_lvl + 1); -} - -static void -_wsplt_seterr_sub (struct mu_wordsplit *wsp, struct mu_wordsplit *wss) -{ - if (wsp->ws_errno == MU_WRDSE_USERERR) - free (wsp->ws_usererr); - wsp->ws_errno = wss->ws_errno; - if (wss->ws_errno == MU_WRDSE_USERERR) - { - wsp->ws_usererr = wss->ws_usererr; - wss->ws_errno = MU_WRDSE_EOF; - wss->ws_usererr = NULL; - } -} - -static void -mu_wordsplit_init0 (struct mu_wordsplit *wsp) -{ - if (wsp->ws_flags & MU_WRDSF_REUSE) - { - if (!(wsp->ws_flags & MU_WRDSF_APPEND)) - mu_wordsplit_free_words (wsp); - mu_wordsplit_clearerr (wsp); - } - else - { - wsp->ws_wordv = NULL; - wsp->ws_wordc = 0; - wsp->ws_wordn = 0; - } - - wsp->ws_errno = 0; - wsp->ws_head = wsp->ws_tail = NULL; -} - -char mu_wordsplit_c_escape_tab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v"; - -static int -mu_wordsplit_init (struct mu_wordsplit *wsp, const char *input, size_t len, - int flags) -{ - wsp->ws_flags = flags; - - if (!(wsp->ws_flags & MU_WRDSF_ALLOC_DIE)) - wsp->ws_alloc_die = _wsplt_alloc_die; - if (!(wsp->ws_flags & MU_WRDSF_ERROR)) - wsp->ws_error = _wsplt_error; - - if (!(wsp->ws_flags & MU_WRDSF_NOVAR)) - { - /* These will be initialized on first variable assignment */ - wsp->ws_envidx = wsp->ws_envsiz = 0; - wsp->ws_envbuf = NULL; - } - - if (!(wsp->ws_flags & MU_WRDSF_NOCMD)) - { - if (!wsp->ws_command) - { - _wsplt_seterr (wsp, MU_WRDSE_USAGE); - errno = EINVAL; - return wsp->ws_errno; - } - } - - if (wsp->ws_flags & MU_WRDSF_SHOWDBG) - { - if (!(wsp->ws_flags & MU_WRDSF_DEBUG)) - { - if (wsp->ws_flags & MU_WRDSF_ERROR) - wsp->ws_debug = wsp->ws_error; - else if (wsp->ws_flags & MU_WRDSF_SHOWERR) - wsp->ws_debug = _wsplt_error; - else - wsp->ws_flags &= ~MU_WRDSF_SHOWDBG; - } - } - - wsp->ws_input = input; - wsp->ws_len = len; - - if (!(wsp->ws_flags & MU_WRDSF_DOOFFS)) - wsp->ws_offs = 0; - - if (!(wsp->ws_flags & MU_WRDSF_DELIM)) - wsp->ws_delim = " \t\n"; - - if (!(wsp->ws_flags & MU_WRDSF_COMMENT)) - wsp->ws_comment = NULL; - - if (!(wsp->ws_flags & MU_WRDSF_CLOSURE)) - wsp->ws_closure = NULL; - - if (!(wsp->ws_flags & MU_WRDSF_OPTIONS)) - wsp->ws_options = 0; - - if (wsp->ws_flags & MU_WRDSF_ESCAPE) - { - if (!wsp->ws_escape[MU_WRDSX_WORD]) - wsp->ws_escape[MU_WRDSX_WORD] = ""; - if (!wsp->ws_escape[MU_WRDSX_QUOTE]) - wsp->ws_escape[MU_WRDSX_QUOTE] = ""; - } - else - { - if (wsp->ws_flags & MU_WRDSF_CESCAPES) - { - wsp->ws_escape[MU_WRDSX_WORD] = mu_wordsplit_c_escape_tab; - wsp->ws_escape[MU_WRDSX_QUOTE] = mu_wordsplit_c_escape_tab; - wsp->ws_options |= MU_WRDSO_OESC_QUOTE | MU_WRDSO_OESC_WORD - | MU_WRDSO_XESC_QUOTE | MU_WRDSO_XESC_WORD; - } - else - { - wsp->ws_escape[MU_WRDSX_WORD] = ""; - wsp->ws_escape[MU_WRDSX_QUOTE] = "\\\\\"\""; - wsp->ws_options |= MU_WRDSO_BSKEEP_QUOTE; - } - } - - wsp->ws_endp = 0; - - mu_wordsplit_init0 (wsp); - - return 0; -} - -static int -alloc_space (struct mu_wordsplit *wsp, size_t count) -{ - size_t offs = (wsp->ws_flags & MU_WRDSF_DOOFFS) ? wsp->ws_offs : 0; - char **ptr; - size_t newalloc; - - if (wsp->ws_wordv == NULL) - { - newalloc = offs + count > ALLOC_INIT ? count : ALLOC_INIT; - ptr = calloc (newalloc, sizeof (ptr[0])); - } - else if (wsp->ws_wordn < offs + wsp->ws_wordc + count) - { - newalloc = offs + wsp->ws_wordc + - (count > ALLOC_INCR ? count : ALLOC_INCR); - ptr = realloc (wsp->ws_wordv, newalloc * sizeof (ptr[0])); - } - else - return 0; - - if (ptr) - { - wsp->ws_wordn = newalloc; - wsp->ws_wordv = ptr; - } - else - return _wsplt_nomem (wsp); - return 0; -} - - -/* Node state flags */ -#define _WSNF_NULL 0x01 /* null node (a noop) */ -#define _WSNF_WORD 0x02 /* node contains word in v.word */ -#define _WSNF_QUOTE 0x04 /* text is quoted */ -#define _WSNF_NOEXPAND 0x08 /* text is not subject to expansion */ -#define _WSNF_JOIN 0x10 /* node must be joined with the next node */ -#define _WSNF_SEXP 0x20 /* is a sed expression */ -#define _WSNF_DELIM 0x40 /* node is a delimiter */ - -#define _WSNF_EMPTYOK 0x0100 /* special flag indicating that - mu_wordsplit_add_segm must add the - segment even if it is empty */ - -struct mu_wordsplit_node -{ - struct mu_wordsplit_node *prev; /* Previous element */ - struct mu_wordsplit_node *next; /* Next element */ - int flags; /* Node flags */ - union - { - struct - { - size_t beg; /* Start of word in ws_input */ - size_t end; /* End of word in ws_input */ - } segm; - char *word; - } v; -}; - -static const char * -wsnode_flagstr (int flags) -{ - static char retbuf[7]; - char *p = retbuf; - - if (flags & _WSNF_WORD) - *p++ = 'w'; - else if (flags & _WSNF_NULL) - *p++ = 'n'; - else - *p++ = '-'; - if (flags & _WSNF_QUOTE) - *p++ = 'q'; - else - *p++ = '-'; - if (flags & _WSNF_NOEXPAND) - *p++ = 'E'; - else - *p++ = '-'; - if (flags & _WSNF_JOIN) - *p++ = 'j'; - else - *p++ = '-'; - if (flags & _WSNF_SEXP) - *p++ = 's'; - else - *p++ = '-'; - if (flags & _WSNF_DELIM) - *p++ = 'd'; - else - *p++ = '-'; - *p = 0; - return retbuf; -} - -static const char * -wsnode_ptr (struct mu_wordsplit *wsp, struct mu_wordsplit_node *p) -{ - if (p->flags & _WSNF_NULL) - return ""; - else if (p->flags & _WSNF_WORD) - return p->v.word; - else - return wsp->ws_input + p->v.segm.beg; -} - -static size_t -wsnode_len (struct mu_wordsplit_node *p) -{ - if (p->flags & _WSNF_NULL) - return 0; - else if (p->flags & _WSNF_WORD) - return strlen (p->v.word); - else - return p->v.segm.end - p->v.segm.beg; -} - -static int -wsnode_new (struct mu_wordsplit *wsp, struct mu_wordsplit_node **pnode) -{ - struct mu_wordsplit_node *node = calloc (1, sizeof (*node)); - if (!node) - return _wsplt_nomem (wsp); - *pnode = node; - return 0; -} - -static void -wsnode_free (struct mu_wordsplit_node *p) -{ - if (p->flags & _WSNF_WORD) - free (p->v.word); - free (p); -} - -static void -wsnode_append (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node) -{ - node->next = NULL; - node->prev = wsp->ws_tail; - if (wsp->ws_tail) - wsp->ws_tail->next = node; - else - wsp->ws_head = node; - wsp->ws_tail = node; -} - -static void -wsnode_remove (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node) -{ - struct mu_wordsplit_node *p; - - p = node->prev; - if (p) - { - p->next = node->next; - if (!node->next) - p->flags &= ~_WSNF_JOIN; - } - else - wsp->ws_head = node->next; - - p = node->next; - if (p) - p->prev = node->prev; - else - wsp->ws_tail = node->prev; - - node->next = node->prev = NULL; -} - -static void -wsnode_insert (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node, - struct mu_wordsplit_node *anchor, int before) -{ - if (!wsp->ws_head) - { - node->next = node->prev = NULL; - wsp->ws_head = wsp->ws_tail = node; - } - else if (before) - { - if (anchor->prev) - wsnode_insert (wsp, node, anchor->prev, 0); - else - { - node->prev = NULL; - node->next = anchor; - anchor->prev = node; - wsp->ws_head = node; - } - } - else - { - struct mu_wordsplit_node *p; - - p = anchor->next; - if (p) - p->prev = node; - else - wsp->ws_tail = node; - node->next = p; - node->prev = anchor; - anchor->next = node; - } -} - -static int -mu_wordsplit_add_segm (struct mu_wordsplit *wsp, size_t beg, size_t end, int flg) -{ - struct mu_wordsplit_node *node; - int rc; - - if (end == beg && !(flg & _WSNF_EMPTYOK)) - return 0; - rc = wsnode_new (wsp, &node); - if (rc) - return rc; - node->flags = flg & ~(_WSNF_WORD | _WSNF_EMPTYOK); - node->v.segm.beg = beg; - node->v.segm.end = end; - wsnode_append (wsp, node); - return 0; -} - -static void -mu_wordsplit_free_nodes (struct mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p; - - for (p = wsp->ws_head; p;) - { - struct mu_wordsplit_node *next = p->next; - wsnode_free (p); - p = next; - } - wsp->ws_head = wsp->ws_tail = NULL; -} - -static void -mu_wordsplit_dump_nodes (struct mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p; - int n = 0; - - for (p = wsp->ws_head, n = 0; p; p = p->next, n++) - { - if (p->flags & _WSNF_WORD) - wsp->ws_debug ("(%02d) %4d: %p: %#04x (%s):%s;", - wsp->ws_lvl, - n, p, p->flags, wsnode_flagstr (p->flags), p->v.word); - else - wsp->ws_debug ("(%02d) %4d: %p: %#04x (%s):%.*s;", - wsp->ws_lvl, - n, p, p->flags, wsnode_flagstr (p->flags), - (int) (p->v.segm.end - p->v.segm.beg), - wsp->ws_input + p->v.segm.beg); - } -} - -static int -coalesce_segment (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node) -{ - struct mu_wordsplit_node *p, *end; - size_t len = 0; - char *buf, *cur; - int stop; - - for (p = node; p && (p->flags & _WSNF_JOIN); p = p->next) - { - len += wsnode_len (p); - } - if (p) - len += wsnode_len (p); - end = p; - - buf = malloc (len + 1); - if (!buf) - return _wsplt_nomem (wsp); - cur = buf; - - p = node; - for (stop = 0; !stop;) - { - struct mu_wordsplit_node *next = p->next; - const char *str = wsnode_ptr (wsp, p); - size_t slen = wsnode_len (p); - - memcpy (cur, str, slen); - cur += slen; - if (p != node) - { - node->flags |= p->flags & _WSNF_QUOTE; - wsnode_remove (wsp, p); - stop = p == end; - wsnode_free (p); - } - p = next; - } - - *cur = 0; - - node->flags &= ~_WSNF_JOIN; - - if (node->flags & _WSNF_WORD) - free (node->v.word); - else - node->flags |= _WSNF_WORD; - node->v.word = buf; - return 0; -} - -static void mu_wordsplit_string_unquote_copy (struct mu_wordsplit *ws, - int inquote, - char *dst, const char *src, - size_t n); - -static int -wsnode_quoteremoval (struct mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p; - - for (p = wsp->ws_head; p; p = p->next) - { - const char *str = wsnode_ptr (wsp, p); - size_t slen = wsnode_len (p); - int unquote; - - if (wsp->ws_flags & MU_WRDSF_QUOTE) - { - unquote = !(p->flags & _WSNF_NOEXPAND); - } - else - unquote = 0; - - if (unquote) - { - if (!(p->flags & _WSNF_WORD)) - { - char *newstr = malloc (slen + 1); - if (!newstr) - return _wsplt_nomem (wsp); - memcpy (newstr, str, slen); - newstr[slen] = 0; - p->v.word = newstr; - p->flags |= _WSNF_WORD; - } - - mu_wordsplit_string_unquote_copy (wsp, p->flags & _WSNF_QUOTE, - p->v.word, str, slen); - } - } - return 0; -} - -static int -wsnode_coalesce (struct mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p; - - for (p = wsp->ws_head; p; p = p->next) - { - if (p->flags & _WSNF_JOIN) - if (coalesce_segment (wsp, p)) - return 1; - } - return 0; -} - -static int -mu_wordsplit_finish (struct mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p; - size_t n; - - n = 0; - - for (p = wsp->ws_head; p; p = p->next) - n++; - - if (alloc_space (wsp, n + 1)) - return 1; - - for (p = wsp->ws_head; p; p = p->next) - { - const char *str = wsnode_ptr (wsp, p); - size_t slen = wsnode_len (p); - char *newstr = malloc (slen + 1); - - /* Assign newstr first, even if it is NULL. This way - mu_wordsplit_free will work even if we return - nomem later. */ - wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = newstr; - if (!newstr) - return _wsplt_nomem (wsp); - memcpy (newstr, str, slen); - newstr[slen] = 0; - - wsp->ws_wordc++; - - } - wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = NULL; - return 0; -} - -int -mu_wordsplit_append (struct mu_wordsplit *wsp, int argc, char **argv) -{ - int rc; - size_t i; - - rc = alloc_space (wsp, wsp->ws_wordc + argc + 1); - if (rc) - return rc; - for (i = 0; i < argc; i++) - { - char *newstr = strdup (argv[i]); - if (!newstr) - { - while (i > 0) - { - free (wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc + i - 1]); - wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc + i - 1] = NULL; - i--; - } - return _wsplt_nomem (wsp); - } - wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc + i] = newstr; - } - wsp->ws_wordc += i; - wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = NULL; - return 0; -} - -/* Variable expansion */ -static int -node_split_prefix (struct mu_wordsplit *wsp, - struct mu_wordsplit_node **ptail, - struct mu_wordsplit_node *node, - size_t beg, size_t len, int flg) -{ - struct mu_wordsplit_node *newnode; - - if (len == 0) - return 0; - if (wsnode_new (wsp, &newnode)) - return 1; - wsnode_insert (wsp, newnode, *ptail, 0); - if (node->flags & _WSNF_WORD) - { - const char *str = wsnode_ptr (wsp, node); - char *newstr = malloc (len + 1); - if (!newstr) - return _wsplt_nomem (wsp); - memcpy (newstr, str + beg, len); - newstr[len] = 0; - newnode->flags = _WSNF_WORD; - newnode->v.word = newstr; - } - else - { - newnode->v.segm.beg = node->v.segm.beg + beg; - newnode->v.segm.end = newnode->v.segm.beg + len; - } - newnode->flags |= flg; - *ptail = newnode; - return 0; -} - -static int -find_closing_paren (const char *str, size_t i, size_t len, size_t *poff, - char *paren) -{ - enum { st_init, st_squote, st_dquote } state = st_init; - size_t level = 1; - - for (; i < len; i++) - { - switch (state) - { - case st_init: - switch (str[i]) - { - default: - if (str[i] == paren[0]) - { - level++; - break; - } - else if (str[i] == paren[1]) - { - if (--level == 0) - { - *poff = i; - return 0; - } - break; - } - break; - - case '"': - state = st_dquote; - break; - - case '\'': - state = st_squote; - break; - } - break; - - case st_squote: - if (str[i] == '\'') - state = st_init; - break; - - case st_dquote: - if (str[i] == '\\') - i++; - else if (str[i] == '"') - state = st_init; - break; - } - } - return 1; -} - -static int -mu_wordsplit_find_env (struct mu_wordsplit *wsp, const char *name, size_t len, - char const **ret) -{ - size_t i; - - if (!(wsp->ws_flags & MU_WRDSF_ENV)) - return MU_WRDSE_UNDEF; - - if (wsp->ws_flags & MU_WRDSF_ENV_KV) - { - /* A key-value pair environment */ - for (i = 0; wsp->ws_env[i]; i++) - { - size_t elen = strlen (wsp->ws_env[i]); - if (elen == len && memcmp (wsp->ws_env[i], name, elen) == 0) - { - *ret = wsp->ws_env[i + 1]; - return MU_WRDSE_OK; - } - /* Skip the value. Break the loop if it is NULL. */ - i++; - if (wsp->ws_env[i] == NULL) - break; - } - } - else if (wsp->ws_env) - { - /* Usual (A=B) environment. */ - for (i = 0; wsp->ws_env[i]; i++) - { - size_t j; - const char *var = wsp->ws_env[i]; - - for (j = 0; j < len; j++) - if (name[j] != var[j]) - break; - if (j == len && var[j] == '=') - { - *ret = var + j + 1; - return MU_WRDSE_OK; - } - } - } - return MU_WRDSE_UNDEF; -} - -static int -wsplt_assign_var (struct mu_wordsplit *wsp, const char *name, size_t namelen, - char *value) -{ - int n = (wsp->ws_flags & MU_WRDSF_ENV_KV) ? 2 : 1; - char *v; - - if (wsp->ws_envidx + n >= wsp->ws_envsiz) - { - size_t sz; - char **newenv; - - if (!wsp->ws_envbuf) - { - if (wsp->ws_flags & MU_WRDSF_ENV) - { - size_t i = 0, j; - - if (wsp->ws_env) - { - for (; wsp->ws_env[i]; i++) - ; - } - - sz = i + n + 1; - - newenv = calloc (sz, sizeof(newenv[0])); - if (!newenv) - return _wsplt_nomem (wsp); - - for (j = 0; j < i; j++) - { - newenv[j] = strdup (wsp->ws_env[j]); - if (!newenv[j]) - { - for (; j > 1; j--) - free (newenv[j-1]); - free (newenv[j-1]); - return _wsplt_nomem (wsp); - } - } - newenv[j] = NULL; - - wsp->ws_envbuf = newenv; - wsp->ws_envidx = i; - wsp->ws_envsiz = sz; - wsp->ws_env = (const char**) wsp->ws_envbuf; - } - else - { - newenv = calloc (MU_WORDSPLIT_ENV_INIT, sizeof(newenv[0])); - if (!newenv) - return _wsplt_nomem (wsp); - wsp->ws_envbuf = newenv; - wsp->ws_envidx = 0; - wsp->ws_envsiz = MU_WORDSPLIT_ENV_INIT; - wsp->ws_env = (const char**) wsp->ws_envbuf; - wsp->ws_flags |= MU_WRDSF_ENV; - } - } - else - { - wsp->ws_envsiz *= 2; - newenv = realloc (wsp->ws_envbuf, - wsp->ws_envsiz * sizeof (wsp->ws_envbuf[0])); - if (!newenv) - return _wsplt_nomem (wsp); - wsp->ws_envbuf = newenv; - wsp->ws_env = (const char**) wsp->ws_envbuf; - } - } - - if (wsp->ws_flags & MU_WRDSF_ENV_KV) - { - /* A key-value pair environment */ - char *p = malloc (namelen + 1); - if (!p) - return _wsplt_nomem (wsp); - memcpy (p, name, namelen); - p[namelen] = 0; - - v = strdup (value); - if (!v) - { - free (p); - return _wsplt_nomem (wsp); - } - wsp->ws_env[wsp->ws_envidx++] = p; - wsp->ws_env[wsp->ws_envidx++] = v; - } - else - { - v = malloc (namelen + strlen(value) + 2); - if (!v) - return _wsplt_nomem (wsp); - memcpy (v, name, namelen); - v[namelen++] = '='; - strcpy(v + namelen, value); - wsp->ws_env[wsp->ws_envidx++] = v; - } - wsp->ws_env[wsp->ws_envidx++] = NULL; - return MU_WRDSE_OK; -} - -static int -expvar (struct mu_wordsplit *wsp, const char *str, size_t len, - struct mu_wordsplit_node **ptail, const char **pend, int flg) -{ - size_t i = 0; - const char *defstr = NULL; - char *value; - const char *vptr; - struct mu_wordsplit_node *newnode; - const char *start = str - 1; - int rc; - struct mu_wordsplit ws; - - if (ISVARBEG (str[0])) - { - for (i = 1; i < len; i++) - if (!ISVARCHR (str[i])) - break; - *pend = str + i - 1; - } - else if (str[0] == '{') - { - str++; - len--; - for (i = 1; i < len; i++) - { - if (str[i] == ':') - { - size_t j; - - defstr = str + i + 1; - if (find_closing_paren (str, i + 1, len, &j, "{}")) - return _wsplt_seterr (wsp, MU_WRDSE_CBRACE); - *pend = str + j; - break; - } - else if (str[i] == '}') - { - defstr = NULL; - *pend = str + i; - break; - } - else if (strchr ("-+?=", str[i])) - { - size_t j; - - defstr = str + i; - if (find_closing_paren (str, i, len, &j, "{}")) - return _wsplt_seterr (wsp, MU_WRDSE_CBRACE); - *pend = str + j; - break; - } - } - if (i == len) - return _wsplt_seterr (wsp, MU_WRDSE_CBRACE); - } - else - { - if (wsnode_new (wsp, &newnode)) - return 1; - wsnode_insert (wsp, newnode, *ptail, 0); - *ptail = newnode; - newnode->flags = _WSNF_WORD | flg; - newnode->v.word = malloc (3); - if (!newnode->v.word) - return _wsplt_nomem (wsp); - newnode->v.word[0] = '$'; - newnode->v.word[1] = str[0]; - newnode->v.word[2] = 0; - *pend = str; - return 0; - } - - /* Actually expand the variable */ - /* str - start of the variable name - i - its length - defstr - default replacement str */ - - if (defstr && strchr("-+?=", defstr[0]) == 0) - { - rc = MU_WRDSE_UNDEF; - defstr = NULL; - } - else - { - rc = mu_wordsplit_find_env (wsp, str, i, &vptr); - if (rc == MU_WRDSE_OK) - { - if (vptr) - { - value = strdup (vptr); - if (!value) - rc = MU_WRDSE_NOSPACE; - } - else - rc = MU_WRDSE_UNDEF; - } - else if (wsp->ws_flags & MU_WRDSF_GETVAR) - rc = wsp->ws_getvar (&value, str, i, wsp->ws_closure); - else - rc = MU_WRDSE_UNDEF; - - if (rc == MU_WRDSE_OK - && (!value || value[0] == 0) - && defstr && defstr[-1] == ':') - { - free (value); - rc = MU_WRDSE_UNDEF; - } - } - - switch (rc) - { - case MU_WRDSE_OK: - if (defstr && *defstr == '+') - { - size_t size = *pend - ++defstr; - - rc = _wsplt_subsplit (wsp, &ws, defstr, size, - MU_WRDSF_NOSPLIT | MU_WRDSF_WS | MU_WRDSF_QUOTE | - (wsp->ws_flags & - (MU_WRDSF_NOVAR | MU_WRDSF_NOCMD))); - if (rc) - return rc; - free (value); - value = ws.ws_wordv[0]; - ws.ws_wordv[0] = NULL; - mu_wordsplit_free (&ws); - } - break; - - case MU_WRDSE_UNDEF: - if (defstr) - { - size_t size; - if (*defstr == '-' || *defstr == '=') - { - size = *pend - ++defstr; - - rc = _wsplt_subsplit (wsp, &ws, defstr, size, - MU_WRDSF_NOSPLIT | MU_WRDSF_WS | MU_WRDSF_QUOTE | - (wsp->ws_flags & - (MU_WRDSF_NOVAR | MU_WRDSF_NOCMD))); - if (rc) - return rc; - - value = ws.ws_wordv[0]; - ws.ws_wordv[0] = NULL; - mu_wordsplit_free (&ws); - - if (defstr[-1] == '=') - wsplt_assign_var (wsp, str, i, value); - } - else - { - if (*defstr == '?') - { - size = *pend - ++defstr; - if (size == 0) - wsp->ws_error (_("%.*s: variable null or not set"), - (int) i, str); - else - { - rc = _wsplt_subsplit (wsp, &ws, defstr, size, - MU_WRDSF_NOSPLIT | MU_WRDSF_WS | - MU_WRDSF_QUOTE | - (wsp->ws_flags & - (MU_WRDSF_NOVAR | MU_WRDSF_NOCMD))); - 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); - mu_wordsplit_free (&ws); - } - } - value = NULL; - } - } - else if (wsp->ws_flags & MU_WRDSF_UNDEF) - { - _wsplt_seterr (wsp, MU_WRDSE_UNDEF); - return 1; - } - else - { - if (wsp->ws_flags & MU_WRDSF_WARNUNDEF) - wsp->ws_error (_("warning: undefined variable `%.*s'"), - (int) i, str); - if (wsp->ws_flags & MU_WRDSF_KEEPUNDEF) - value = NULL; - else - { - value = strdup (""); - if (!value) - return _wsplt_nomem (wsp); - } - } - break; - - case MU_WRDSE_NOSPACE: - return _wsplt_nomem (wsp); - - case MU_WRDSE_USERERR: - if (wsp->ws_errno == MU_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 mu_wordsplit ws; - int i, rc; - - rc = _wsplt_subsplit (wsp, &ws, value, strlen (value), - MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | - MU_WRDSF_QUOTE); - free (value); - if (rc) - { - _wsplt_seterr_sub (wsp, &ws); - mu_wordsplit_free (&ws); - return 1; - } - for (i = 0; i < ws.ws_wordc; i++) - { - if (wsnode_new (wsp, &newnode)) - return 1; - wsnode_insert (wsp, newnode, *ptail, 0); - *ptail = newnode; - newnode->flags = _WSNF_WORD | - _WSNF_NOEXPAND | - (i + 1 < ws.ws_wordc ? (flg & ~_WSNF_JOIN) : flg); - newnode->v.word = strdup (ws.ws_wordv[i]); - if (!newnode->v.word) - return _wsplt_nomem (wsp); - } - mu_wordsplit_free (&ws); - } - } - else if (wsp->ws_flags & MU_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 c == '{' || ISVARBEG (c); -} - -static int -node_expand (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node, - int (*beg_p) (int), - int (*ws_exp_fn) (struct mu_wordsplit *wsp, - const char *str, size_t len, - struct mu_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 mu_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 mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p; - - for (p = wsp->ws_head; p;) - { - struct mu_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 -mu_wordsplit_varexp (struct mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p; - - for (p = wsp->ws_head; p;) - { - struct mu_wordsplit_node *next = p->next; - if (!(p->flags & _WSNF_NOEXPAND)) - 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 mu_wordsplit *wsp, const char *str, size_t len, - struct mu_wordsplit_node **ptail, const char **pend, int flg) -{ - int rc; - size_t j; - char *value; - struct mu_wordsplit_node *newnode; - struct mu_wordsplit ws; - - str++; - len--; - - if (find_closing_paren (str, 0, len, &j, "()")) - { - _wsplt_seterr (wsp, MU_WRDSE_PAREN); - return 1; - } - - *pend = str + j; - - rc = _wsplt_subsplit (wsp, &ws, str, j, MU_WRDSF_WS | MU_WRDSF_QUOTE); - if (rc) - { - _wsplt_seterr_sub (wsp, &ws); - mu_wordsplit_free (&ws); - return 1; - } - rc = wsp->ws_command (&value, str, j, ws.ws_wordv, wsp->ws_closure); - mu_wordsplit_free (&ws); - - if (rc == MU_WRDSE_NOSPACE) - return _wsplt_nomem (wsp); - else if (rc) - { - if (rc == MU_WRDSE_USERERR) - { - if (wsp->ws_errno == MU_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 mu_wordsplit ws; - int i, rc; - - rc = _wsplt_subsplit (wsp, &ws, value, strlen (value), - MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | - MU_WRDSF_WS | MU_WRDSF_QUOTE); - free (value); - if (rc) - { - _wsplt_seterr_sub (wsp, &ws); - mu_wordsplit_free (&ws); - return 1; - } - for (i = 0; i < ws.ws_wordc; i++) - { - if (wsnode_new (wsp, &newnode)) - return 1; - wsnode_insert (wsp, newnode, *ptail, 0); - *ptail = newnode; - newnode->flags = _WSNF_WORD | - _WSNF_NOEXPAND | - (i + 1 < ws.ws_wordc ? (flg & ~_WSNF_JOIN) : flg); - newnode->v.word = strdup (ws.ws_wordv[i]); - if (!newnode->v.word) - return _wsplt_nomem (wsp); - } - mu_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 -mu_wordsplit_cmdexp (struct mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p; - - for (p = wsp->ws_head; p;) - { - struct mu_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 -mu_wordsplit_trimws (struct mu_wordsplit *wsp) -{ - struct mu_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 -mu_wordsplit_tildexpand (struct mu_wordsplit *wsp) -{ - struct mu_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 -mu_wordsplit_pathexpand (struct mu_wordsplit *wsp) -{ - struct mu_wordsplit_node *p, *next; - char *pattern = NULL; - size_t patsize = 0; - size_t slen; - int flags = 0; - -#ifdef GLOB_PERIOD - if (wsp->ws_options & MU_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 mu_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 & MU_WRDSO_NULLGLOB) - { - wsnode_remove (wsp, p); - wsnode_free (p); - } - else if (wsp->ws_options & MU_WRDSO_FAILGLOB) - { - char buf[128]; - if (wsp->ws_errno == MU_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, MU_WRDSE_USERERR); - } - continue; - - default: - free (pattern); - return _wsplt_seterr (wsp, MU_WRDSE_GLOBERR); - } - - prev = p; - for (i = 0; i < g.gl_pathc; i++) - { - struct mu_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; -} - -static size_t -skip_delim (struct mu_wordsplit *wsp) -{ - size_t start = wsp->ws_endp; - if (wsp->ws_flags & MU_WRDSF_SQUEEZE_DELIMS) - { - if ((wsp->ws_flags & MU_WRDSF_RETURN_DELIMS) && - ISDELIM (wsp, wsp->ws_input[start])) - { - int delim = wsp->ws_input[start]; - do - start++; - while (start < wsp->ws_len && delim == wsp->ws_input[start]); - } - else - { - do - start++; - while (start < wsp->ws_len && ISDELIM (wsp, wsp->ws_input[start])); - } - start--; - } - - if (!(wsp->ws_flags & MU_WRDSF_RETURN_DELIMS)) - start++; - - return start; -} - -#define _MU_WRDS_EOF 0 -#define _MU_WRDS_OK 1 -#define _MU_WRDS_ERR 2 - -static int -scan_qstring (struct mu_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 (mu_wordsplit_add_segm (wsp, start + 1, j, flags)) - return _MU_WRDS_ERR; - *end = j; - } - else - { - wsp->ws_endp = start; - _wsplt_seterr (wsp, MU_WRDSE_QUOTE); - return _MU_WRDS_ERR; - } - return 0; -} - -static int -scan_word (struct mu_wordsplit *wsp, size_t start) -{ - size_t len = wsp->ws_len; - const char *command = wsp->ws_input; - const char *comment = wsp->ws_comment; - int join = 0; - int flags = 0; - - size_t i = start; - - if (i >= len) - { - wsp->ws_errno = MU_WRDSE_EOF; - return _MU_WRDS_EOF; - } - - start = i; - - if (wsp->ws_flags & MU_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 (!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 (mu_wordsplit_add_segm (wsp, start, i, 0)) - return _MU_WRDS_ERR; - wsp->ws_endp = j; - return _MU_WRDS_OK; - } - - if (wsp->ws_flags & MU_WRDSF_QUOTE) - { - if (command[i] == '\\') - { - if (++i == len) - break; - i++; - continue; - } - - if (((wsp->ws_flags & MU_WRDSF_SQUOTE) && command[i] == '\'') || - ((wsp->ws_flags & MU_WRDSF_DQUOTE) && command[i] == '"')) - { - if (join && wsp->ws_tail) - wsp->ws_tail->flags |= _WSNF_JOIN; - if (mu_wordsplit_add_segm (wsp, start, i, _WSNF_JOIN)) - return _MU_WRDS_ERR; - if (scan_qstring (wsp, i, &i)) - return _MU_WRDS_ERR; - start = i + 1; - join = 1; - } - } - - if (command[i] == '$') - { - if (!(wsp->ws_flags & MU_WRDSF_NOVAR) - && command[i+1] == '{' - && find_closing_paren (command, i + 2, len, &i, "{}") == 0) - continue; - if (!(wsp->ws_flags & MU_WRDSF_NOCMD) - && command[i+1] == '(' - && find_closing_paren (command, i + 2, len, &i, "()") == 0) - continue; - } - - if (ISDELIM (wsp, command[i])) - break; - else - i++; - } - } - else if (wsp->ws_flags & MU_WRDSF_RETURN_DELIMS) - { - i++; - flags |= _WSNF_DELIM; - } - else if (!(wsp->ws_flags & MU_WRDSF_SQUEEZE_DELIMS)) - flags |= _WSNF_EMPTYOK; - - if (join && i > start && wsp->ws_tail) - wsp->ws_tail->flags |= _WSNF_JOIN; - if (mu_wordsplit_add_segm (wsp, start, i, flags)) - return _MU_WRDS_ERR; - wsp->ws_endp = i; - if (wsp->ws_flags & MU_WRDSF_INCREMENTAL) - return _MU_WRDS_EOF; - return _MU_WRDS_OK; -} - -#define to_num(c) \ - (ISDIGIT(c) ? c - '0' : (ISXDIGIT(c) ? toupper(c) - 'A' + 10 : 255 )) - -static int -xtonum (int *pval, const char *src, int base, int cnt) -{ - 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 -mu_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 (mu_wordsplit_c_quote_char (*str)) - len += 2; - else - len += 4; - } - } - return len; -} - -int -wsplt_unquote_char (const char *transtab, int c) -{ - while (*transtab && transtab[1]) - { - if (*transtab++ == c) - return *transtab; - ++transtab; - } - return 0; -} - -int -wsplt_quote_char (const char *transtab, int c) -{ - for (; *transtab && transtab[1]; transtab += 2) - { - if (transtab[1] == c) - return *transtab; - } - return 0; -} - -int -mu_wordsplit_c_unquote_char (int c) -{ - return wsplt_unquote_char (mu_wordsplit_c_escape_tab, c); -} - -int -mu_wordsplit_c_quote_char (int c) -{ - return wsplt_quote_char (mu_wordsplit_c_escape_tab, c); -} - -void -mu_wordsplit_string_unquote_copy (struct mu_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 (MU_WRDSO_ESC_TEST (ws, inquote, MU_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 (MU_WRDSO_ESC_TEST (ws, inquote, MU_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 (MU_WRDSO_ESC_TEST (ws, inquote, MU_WRDSO_BSKEEP)) - *dst++ = '\\'; - *dst++ = src[i++]; - } - } - else - *dst++ = src[i++]; - } - *dst = 0; -} - -void -mu_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 = mu_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 *descr; /* Textual description (for debugging) */ - int flag; /* MU_WRDSF_ bit that controls this phase */ - int opt; /* Entry-specific options (see EXPOPT_ flags below */ - int (*expansion) (struct mu_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 -/* Coalesce the input list before running the expansion. */ -#define EXPOPT_COALESCE 0x02 - -static struct exptab exptab[] = { - { N_("WS trimming"), MU_WRDSF_WS, 0, - mu_wordsplit_trimws }, - { N_("command substitution"), MU_WRDSF_NOCMD, EXPOPT_NEG|EXPOPT_COALESCE, - mu_wordsplit_cmdexp }, - { N_("coalesce list"), 0, EXPOPT_NEG|EXPOPT_COALESCE, - NULL }, - { N_("tilde expansion"), MU_WRDSF_PATHEXPAND, 0, - mu_wordsplit_tildexpand }, - { N_("variable expansion"), MU_WRDSF_NOVAR, EXPOPT_NEG, - mu_wordsplit_varexp }, - { N_("quote removal"), 0, EXPOPT_NEG, - wsnode_quoteremoval }, - { N_("coalesce list"), 0, EXPOPT_NEG|EXPOPT_COALESCE, - NULL }, - { N_("path expansion"), MU_WRDSF_PATHEXPAND, 0, - mu_wordsplit_pathexpand }, - { NULL } -}; - -static int -mu_wordsplit_process_list (struct mu_wordsplit *wsp, size_t start) -{ - struct exptab *p; - - if (wsp->ws_flags & MU_WRDSF_NOSPLIT) - { - /* Treat entire input as a quoted argument */ - if (mu_wordsplit_add_segm (wsp, start, wsp->ws_len, _WSNF_QUOTE)) - return wsp->ws_errno; - wsp->ws_endp = wsp->ws_len; - } - else - { - int rc; - - while ((rc = scan_word (wsp, start)) == _MU_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 == _MU_WRDS_ERR) - return wsp->ws_errno; - } - - if (wsp->ws_flags & MU_WRDSF_SHOWDBG) - { - wsp->ws_debug ("(%02d) %s", wsp->ws_lvl, _("Initial list:")); - mu_wordsplit_dump_nodes (wsp); - } - - for (p = exptab; p->descr; p++) - { - if ((p->opt & EXPOPT_NEG) - ? !(wsp->ws_flags & p->flag) : (wsp->ws_flags & p->flag)) - { - if (p->opt & EXPOPT_COALESCE) - { - if (wsnode_coalesce (wsp)) - break; - if (wsp->ws_flags & MU_WRDSF_SHOWDBG) - { - wsp->ws_debug ("(%02d) %s", wsp->ws_lvl, - _("Coalesced list:")); - mu_wordsplit_dump_nodes (wsp); - } - } - if (p->expansion) - { - if (p->expansion (wsp)) - break; - if (wsp->ws_flags & MU_WRDSF_SHOWDBG) - { - wsp->ws_debug ("(%02d) %s", wsp->ws_lvl, _(p->descr)); - mu_wordsplit_dump_nodes (wsp); - } - } - } - } - return wsp->ws_errno; -} - -static int -mu_wordsplit_run (const char *command, size_t length, struct mu_wordsplit *wsp, - int flags, int lvl) -{ - int rc; - size_t start; - const char *cmdptr; - size_t cmdlen; - - if (!command) - { - if (!(flags & MU_WRDSF_INCREMENTAL)) - return EINVAL; - - start = skip_delim (wsp); - if (wsp->ws_endp == wsp->ws_len) - return _wsplt_seterr (wsp, MU_WRDSE_NOINPUT); - - cmdptr = wsp->ws_input + wsp->ws_endp; - cmdlen = wsp->ws_len - wsp->ws_endp; - wsp->ws_flags |= MU_WRDSF_REUSE; - mu_wordsplit_init0 (wsp); - } - else - { - cmdptr = command; - cmdlen = length; - start = 0; - rc = mu_wordsplit_init (wsp, cmdptr, cmdlen, flags); - if (rc) - return rc; - wsp->ws_lvl = lvl; - } - - if (wsp->ws_flags & MU_WRDSF_SHOWDBG) - wsp->ws_debug (_("(%02d) Input:%.*s;"), wsp->ws_lvl, (int) cmdlen, cmdptr); - - rc = mu_wordsplit_process_list (wsp, start); - if (rc == 0 && (flags & MU_WRDSF_INCREMENTAL)) - { - while (!wsp->ws_head && wsp->ws_endp < wsp->ws_len) - { - start = skip_delim (wsp); - if (wsp->ws_flags & MU_WRDSF_SHOWDBG) - { - cmdptr = wsp->ws_input + wsp->ws_endp; - cmdlen = wsp->ws_len - wsp->ws_endp; - wsp->ws_debug (_("(%02d) Restart:%.*s;"), - wsp->ws_lvl, (int) cmdlen, cmdptr); - } - rc = mu_wordsplit_process_list (wsp, start); - if (rc) - break; - } - } - if (rc) - { - mu_wordsplit_free_nodes (wsp); - return rc; - } - mu_wordsplit_finish (wsp); - mu_wordsplit_free_nodes (wsp); - return wsp->ws_errno; -} - -int -mu_wordsplit_len (const char *command, size_t length, struct mu_wordsplit *wsp, - int flags) -{ - return mu_wordsplit_run (command, length, wsp, flags, 0); -} - -int -mu_wordsplit (const char *command, struct mu_wordsplit *ws, int flags) -{ - return mu_wordsplit_len (command, command ? strlen (command) : 0, ws, flags); -} - -void -mu_wordsplit_free_words (struct mu_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 -mu_wordsplit_free_envbuf (struct mu_wordsplit *ws) -{ - if (ws->ws_flags & MU_WRDSF_NOCMD) - 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 -mu_wordsplit_clearerr (struct mu_wordsplit *ws) -{ - if (ws->ws_errno == MU_WRDSE_USERERR) - free (ws->ws_usererr); - ws->ws_usererr = NULL; - ws->ws_errno = MU_WRDSE_OK; -} - -void -mu_wordsplit_free (struct mu_wordsplit *ws) -{ - mu_wordsplit_free_words (ws); - free (ws->ws_wordv); - ws->ws_wordv = NULL; - mu_wordsplit_free_envbuf (ws); -} - -int -mu_wordsplit_get_words (struct mu_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 *_mu_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") -}; -int _mu_wordsplit_nerrs = - sizeof (_mu_wordsplit_errstr) / sizeof (_mu_wordsplit_errstr[0]); - -const char * -mu_wordsplit_strerror (struct mu_wordsplit *ws) -{ - if (ws->ws_errno == MU_WRDSE_USERERR) - return ws->ws_usererr; - if (ws->ws_errno < _mu_wordsplit_nerrs) - return _mu_wordsplit_errstr[ws->ws_errno]; - return N_("unknown error"); -} - -void -mu_wordsplit_perror (struct mu_wordsplit *wsp) -{ - switch (wsp->ws_errno) - { - case MU_WRDSE_QUOTE: - wsp->ws_error (_("missing closing %c (start near #%lu)"), - wsp->ws_input[wsp->ws_endp], - (unsigned long) wsp->ws_endp); - break; - - default: - wsp->ws_error ("%s", mu_wordsplit_strerror (wsp)); - } -} - +#include "wordsplit/wordsplit.c" diff --git a/libmailutils/tests/.gitignore b/libmailutils/tests/.gitignore index d72fd78..3045b18 100644 --- a/libmailutils/tests/.gitignore +++ b/libmailutils/tests/.gitignore @@ -45,5 +45,6 @@ url-parse vexp wicket wordwrap +wordsplit-version.h wsp xscript diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am index 99b2341..bc839c3 100644 --- a/libmailutils/tests/Makefile.am +++ b/libmailutils/tests/Makefile.am @@ -38,7 +38,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac ## Non-installable programs ## -------------------------- ## -AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ +AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ noinst_LTLIBRARIES = libmu_tesh.la libmu_tesh_la_SOURCES = tesh.c tesh.h @@ -193,7 +193,6 @@ TESTSUITE_AT = \ url-comp.at\ xml.at\ wicket.at\ - wordsplit.at\ wordwrap00.at\ wordwrap01.at\ wordwrap02.at\ @@ -205,7 +204,11 @@ M4=m4 AUTOTEST = $(AUTOM4TE) --language=autotest $(TESTSUITE): package.m4 $(TESTSUITE_AT) $(top_srcdir)/testsuite/testsuite.inc - $(AM_V_GEN)$(AUTOTEST) -I $(srcdir) -I $(top_srcdir)/testsuite testsuite.at -o $@.tmp + $(AM_V_GEN)$(AUTOTEST) \ + -I $(srcdir)\ + -I $(top_srcdir)/testsuite\ + -I $(top_srcdir)/libmailutils/wordsplit\ + testsuite.at -o $@.tmp $(AM_V_at)mv $@.tmp $@ atconfig: $(top_builddir)/config.status @@ -214,11 +217,35 @@ atconfig: $(top_builddir)/config.status clean-local: @test ! -f $(TESTSUITE) || $(SHELL) $(TESTSUITE) --clean -check-local: atconfig atlocal $(TESTSUITE) +check-local: atconfig atlocal $(TESTSUITE) @$(SHELL) $(TESTSUITE) # Run the test suite on the *installed* tree. #installcheck-local: # $(SHELL) $(TESTSUITE) AUTOTEST_PATH=$(exec_prefix)/bin +# ########################### +# Wordsplit testsuite +# ########################### + +# The wordsplit-version.h header is to supply the version string to +# wsp and to force it to use the mailutils version of the wordsplit.h +# header. +EXTRA_DIST += wordsplit-version.h +$(srcdir)/wordsplit-version.h: $(top_srcdir)/configure.ac + $(AM_V_GEN){\ + if test -e $(top_srcdir)/libmailutils/wordsplit/.git; then \ + wsversion=$$(cd $(top_srcdir)/libmailutils/wordsplit; git describe); \ + else \ + wsversion="unknown"; \ + fi;\ + echo "#define WORDSPLIT_VERSION \"$wsversion\"";\ + echo '#include <mailutils/wordsplit.h>'; } \ + > $(srcdir)/wordsplit-version.h + +noinst_PROGRAMS += wsp +wsp_SOURCES = +nodist_wsp_SOURCES = wsp.c +wsp.o: $(srcdir)/wordsplit-version.h +VPATH += $(top_srcdir)/libmailutils/wordsplit diff --git a/libmailutils/tests/wordsplit.at b/libmailutils/tests/wordsplit.at deleted file mode 100644 index f695399..0000000 --- a/libmailutils/tests/wordsplit.at +++ b/dev/null @@ -1,787 +0,0 @@ -# This file is part of GNU Mailutils. -*- Autotest -*- -# Copyright (C) 2007-2019 Free Software Foundation, Inc. -# -# GNU Mailutils 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. -# -# GNU Mailutils 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 GNU Mailutils. 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]) -dnl -m4_pushdef([TESTWSP],[ -m4_pushdef([MU_TEST_GROUP],[Wordsplit]) -m4_pushdef([MU_TEST_KEYWORDS],[wordsplit wsp]) -m4_pushdef([MU_TEST_COMMAND],[$7 wsp $3]) -MU_GENERIC_TEST([$1],[genkw $2],[$4],[],[$5],[$6]) -m4_popdef([MU_TEST_COMMAND]) -m4_popdef([MU_TEST_KEYWORDS]) -m4_popdef([MU_TEST_GROUP]) -]) - -dnl ------------------------------------------------------------ -dnl The first part reproduces legacy argcv tests -dnl ------------------------------------------------------------ - -TESTWSP([simple input],[],[], -[1 2 3], -[NF: 3 -0: 1 -1: 2 -2: 3 -]) - -TESTWSP([quoted space],[],[], -[quoted\ space], -[NF: 1 -0: "quoted space" -]) - -TESTWSP([tab character],[],[], -[a "tab character"], -[NF: 2 -0: a -1: tab\tcharacter -]) - -WSPGROUP(wsp-escape) - -TESTWSP([octal and hex escapes],[],[], -[\157\143\164\141\154\40and\x20\x68\x65\x78], -[NF: 1 -0: "octal and hex" -]) - -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" -]) - -TESTWSP([escape representation],[],[], -[A\x3-\48\39], -[NF: 1 -0: A\003-\0048\0039 -]) - -WSPGROUP() - -dnl ------------------------------------------------------------ -dnl Test worsplit-specific behavior -dnl ------------------------------------------------------------ -TESTWSP([append],[],[append], -[jeden dwa trzy -cztery -piec szesc], -[NF: 3 -0: jeden -1: dwa -2: trzy -NF: 4 -0: jeden -1: dwa -2: trzy -3: cztery -NF: 6 -0: jeden -1: dwa -2: trzy -3: cztery -4: piec -5: szesc -]) - -TESTWSP([dooffs],[],[dooffs 3 jeden dwa trzy], -[cztery piec], -[NF: 2 (3) -(0): jeden -(1): dwa -(2): trzy -3: cztery -4: piec -]) - -WSPGROUP(wsp-var) - -TESTWSP([variable substitutions: single var],[],[], -[a $FOO test], -[NF: 3 -0: a -1: bar -2: test -], -[], -[FOO=bar]) - -TESTWSP([variable substitutions: concatenated vars],[],[], -[a $FOO${BAR}ent test], -[NF: 3 -0: a -1: stringent -2: test -], -[], -[FOO=str BAR=ing]) - -TESTWSP([variable substitutions: field splitting],[],[], -[a $FOO test], -[NF: 4 -0: a -1: variable -2: substitution -3: test -], -[], -[FOO="variable substitution"]) - -TESTWSP([variable substitutions: double-quoted variable],[],[], -[a "$FOO" test], -[NF: 3 -0: a -1: "variable substitution" -2: test -], -[], -[FOO="variable substitution"]) - -TESTWSP([variable substitutions: single-quoted variable],[],[], -[a '$FOO' test], -[NF: 3 -0: a -1: $FOO -2: test -], -[], -[FOO="variable substitution"]) - -TESTWSP([undefined variables 1],[],[], -[a $FOO test a${FOO}b], -[NF: 3 -0: a -1: test -2: ab -], -[], -[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 -], -[], -[unset FOO;]) - -TESTWSP([warn about undefined variables],[],[warnundef], -[$FOO], -[NF: 0 -], -[warning: undefined variable `FOO' -], -[unset FOO;]) - -TESTWSP([bail out on undefined variables],[],[undef], -[$FOO], -[], -[undefined variable -], -[unset FOO;]) - -TESTWSP([disable variable expansion],[],[novar], -[$FOO], -[NF: 1 -0: $FOO -], -[], -[FOO=bar]) - -TESTWSP([K/V environment],[],[env_kv], -[$FOO a$BAZ], -[NF: 2 -0: bar -1: aqux -], -[], -[FOO=bar BAZ=qux]) - -TESTWSP([nosplit with expansion],[],[nosplit], -[a $FOO test], -[NF: 1 -0: "a variable expansion test\n" -], -[], -[FOO="variable expansion"]) - -TESTWSP([nosplit without expansion],[],[nosplit novar], -[a $FOO test], -[NF: 1 -0: "a $FOO test\n" -], -[], -[FOO="variable expansion"]) - -TESTWSP([default value (defined)],[],[], -[${FOO:-bar}], -[NF: 1 -0: qux -], -[], -[FOO=qux]) - -TESTWSP([default value],[],[], -[${FOO:-bar}], -[NF: 1 -0: bar -]) - -TESTWSP([default value (defined)],[],[], -[${FOO:-bar}], -[NF: 1 -0: qux -], -[], -[FOO=qux]) - -TESTWSP([default value (:- null)],[],[], -[${FOO:-bar}], -[NF: 1 -0: bar -], -[], -[FOO=]) - -TESTWSP([default value (- null)],[],[], -[${FOO-bar}], -[NF: 0 -], -[], -[FOO=]) - -TESTWSP([default value (- null, unset)],[],[], -[${FOO-bar}], -[NF: 1 -0: bar -]) - -TESTWSP([assign default values],[],[], -[${FOO=bar} -$FOO], -[NF: 1 -0: bar -NF: 1 -0: bar -]) - -TESTWSP([default error message (var defined)],[],[], -[a ${FOO:?} test], -[NF: 3 -0: a -1: bar -2: test -], -[], -[FOO=bar]) - -TESTWSP([default error message],[],[], -[${FOO:?}], -[NF: 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 -], -[], -[FOO=bar]) - -TESTWSP([custom error message],[wsp-custom-err wsp-custom-err01],[], -[a ${FOO:?please define it} test], -[NF: 2 -0: a -1: test -], -[FOO: please define it -]) - -TESTWSP([alternate value (defined)],[wsp-alt wsp-alt00],[], -[a ${FOO:+isset} test], -[NF: 3 -0: a -1: isset -2: test -], -[], -[FOO=bar]) - -TESTWSP([alternate value],[wsp-alt wsp-alt01],[], -[a ${FOO:+isset} test], -[NF: 2 -0: a -1: test -], -[], -[unset FOO;]) - -TESTWSP([getvar],[wsp-getvar], -[foo=bar x=quux], -[begin $foo $x end], -[NF: 4 -0: begin -1: bar -2: quux -3: end -], -[], -[], -[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 -], -[], -[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 -]) - -WSPGROUP() - -TESTWSP([ignore quotes],[],[-quote], -["a text"], -[NF: 2 -0: "\"a" -1: "text\"" -]) - -WSPGROUP(wsp-delim) - -TESTWSP([custom delimiters (squeeze)],[],[delim : -ws trimnl], -[semicolon: separated::list: of :words], -[NF: 5 -0: semicolon -1: " separated" -2: list -3: " of " -4: words -]) - -TESTWSP([custom delimiters (no squeeze)],[],[delim : -ws -squeeze_delims trimnl], -[semicolon: separated::list: of :words], -[NF: 6 -0: semicolon -1: " separated" -2: "" -3: list -4: " of " -5: words -]) - -TESTWSP([custom, with returned delimiters],[],[delim : -ws trimnl return_delims], -[semicolon: separated::list: of :words], -[NF: 9 -0: semicolon -1: : -2: " separated" -3: : -4: list -5: : -6: " of " -7: : -8: words -]) - -TESTWSP([custom, with returned & squeezed delimiters],[],[delim : -ws trimnl return_delims -squeeze_delims], -[semicolon: separated::list: of :words], -[NF: 10 -0: semicolon -1: : -2: " separated" -3: : -4: : -5: list -6: : -7: " of " -8: : -9: words -]) - -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 -]) - -WSPGROUP() - -TESTWSP([C escapes on],[],[cescapes], -[a\ttab form\ffeed and new\nline], -[NF: 4 -0: a\ttab -1: form\ffeed -2: and -3: new\nline -]) - -TESTWSP([C escapes off],[],[-cescapes], -[a\ttab form\ffeed and new\nline], -[NF: 4 -0: attab -1: formffeed -2: and -3: newnline -]) - -TESTWSP([ws elimination],[],[delim ' ()' ws return_delims], -[( list items )], -[NF: 4 -0: ( -1: list -2: items -3: ) -]) - -TESTWSP([empty quotes],[],[delim : ws return_delims], -[t=""], -[NF: 1 -0: t= -]) - -TESTWSP([delimiter following empty quotes],[],[delim : ws return_delims], -[t="":r], -[NF: 3 -0: t= -1: : -2: r -]) - -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}, " -]) - -TESTWSP([unescape],[],[-default novar nocmd quote escape :+:'\\""'], -[\Seen "quote \"" "bs \\"], -[NF: 3 -0: \\Seen -1: "quote \"" -2: "bs \\" -]) - -TESTWSP([unescape: word/quote], -[wsp-unescape wsp-unescape-word], -[-default 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 -]) - -TESTWSP([dquote],[],[-default novar nocmd dquote], -[a "quoted example" isn't it], -[NF: 4 -0: a -1: "quoted example" -2: isn't -3: it -]) - -TESTWSP([squote],[],[-default novar nocmd squote], -[a 'quoted example' isn"t it], -[NF: 4 -0: a -1: "quoted example" -2: "isn\"t" -3: it -]) - -WSPGROUP(wsp-incr) - -TESTWSP([incremental],[],[incremental], -[incremental "input test" line - - -], -[NF: 1 -0: incremental -NF: 1 -0: "input test" -NF: 1 -0: line -], -[input exhausted -]) - -TESTWSP([incremental append],[],[incremental append], -[incremental "input test" line - - -], -[NF: 1 -0: incremental -NF: 2 -0: incremental -1: "input test" -NF: 3 -0: incremental -1: "input test" -2: line -], -[input exhausted -]) - -TESTWSP([incremental ws],[],[return_delims -squeeze_delims incremental ws], -[a list test - - -], -[NF: 1 -0: a -NF: 1 -0: list -NF: 1 -0: test -], -[input exhausted -]) - -TESTWSP([incremental nosplit],[],[incremental nosplit], -[incremental "input test" line -], -[NF: 1 -0: "incremental \"input test\" line" -], -[input exhausted -]) - -TESTWSP([simple command substitution],[],[-nocmd], -[begin $(words a b) end], -[NF: 4 -0: begin -1: a -2: b -3: end -]) - -TESTWSP([quoted command substitution],[],[-nocmd], -[begin "$(words a b)" end], -[NF: 3 -0: begin -1: "a b" -2: end -]) - -TESTWSP([coalesced command substitution],[],[-nocmd], -[begin($(words a b))end], -[NF: 2 -0: begin(a -1: b)end -]) - -TESTWSP([quoted coalesced command substitution],[],[-nocmd], -["begin($(words a b))end"], -[NF: 1 -0: "begin(a b)end" -]) - -TESTWSP([variable and command substitution],[],[-nocmd -novar], -[begin $X $(words $X $Y) end], -[NF: 5 -0: begin -1: a -2: a -3: b -4: end -],[],[X=a Y=b]) - -TESTWSP([variable expansion and command substitution in quotes],[],[-nocmd -novar], -["${BEGIN}($(words $X $Y))end"], -[NF: 1 -0: "begin(a b)end" -],[],[X=a Y=b BEGIN=begin]) - -TESTWSP([nested commands],[],[-nocmd -novar], -[$(words output $(words in$SUFFIX text) end)], -[NF: 4 -0: output -1: input -2: text -3: end -],[],[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 -]) -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 -]) -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 -]) -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],[],[-- extra arguments follow], -[some words and], -[NF: 6 -0: some -1: words -2: and -3: extra -4: arguments -5: follow -]) - -TESTWSP([append + dooffs + env],[], -[dooffs 2 preface words V=2 -- 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 -]) - - -m4_popdef([TESTWSP]) -m4_popdef([wspnum]) -m4_popdef([wspid]) -m4_popdef([genkw]) -m4_popdef([wspgroupnum]) -m4_popdef([wspgroupname]) -m4_popdef([WSPGROUP]) diff --git a/libmailutils/tests/wsp.c b/libmailutils/tests/wsp.c deleted file mode 100644 index cd158dc..0000000 --- a/libmailutils/tests/wsp.c +++ b/dev/null @@ -1,654 +0,0 @@ -/* GNU Mailutils -- a suite of utilities for electronic mail - Copyright (C) 2005-2019 Free Software Foundation, Inc. - - GNU Mailutils 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. - - GNU Mailutils 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 GNU Mailutils. 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 <mailutils/wordsplit.h> -#include <mailutils/alloc.h> -#include <mailutils/kwd.h> -#include <mailutils/errno.h> -#include <mailutils/error.h> -#include <mailutils/cstr.h> -#include <mailutils/io.h> - -extern char **environ; - -char *progname; - -struct mu_kwd bool_keytab[] = { - { "append", MU_WRDSF_APPEND }, - /*{ "reuse", MU_WRDSF_REUSE },*/ - { "undef", MU_WRDSF_UNDEF }, - { "novar", MU_WRDSF_NOVAR }, - { "nocmd", MU_WRDSF_NOCMD }, - { "ws", MU_WRDSF_WS }, - { "quote", MU_WRDSF_QUOTE }, - { "squote", MU_WRDSF_SQUOTE }, - { "dquote", MU_WRDSF_DQUOTE }, - { "squeeze_delims", MU_WRDSF_SQUEEZE_DELIMS }, - { "return_delims", MU_WRDSF_RETURN_DELIMS }, - { "sed", MU_WRDSF_SED_EXPR }, - { "debug", MU_WRDSF_SHOWDBG }, - { "nosplit", MU_WRDSF_NOSPLIT }, - { "keepundef", MU_WRDSF_KEEPUNDEF }, - { "warnundef", MU_WRDSF_WARNUNDEF }, - { "cescapes", MU_WRDSF_CESCAPES }, - { "default", MU_WRDSF_DEFFLAGS }, - { "env_kv", MU_WRDSF_ENV_KV }, - { "incremental", MU_WRDSF_INCREMENTAL }, - { "pathexpand", MU_WRDSF_PATHEXPAND }, - { NULL, 0 } -}; - -struct mu_kwd opt_keytab[] = { - { "nullglob", MU_WRDSO_NULLGLOB }, - { "failglob", MU_WRDSO_FAILGLOB }, - { "dotglob", MU_WRDSO_DOTGLOB }, - { NULL, 0 } -}; - -struct mu_kwd string_keytab[] = { - { "delim", MU_WRDSF_DELIM }, - { "comment", MU_WRDSF_COMMENT }, - { "escape", MU_WRDSF_ESCAPE }, - { NULL, 0 } -}; - -static void -help () -{ - size_t i; - - printf ("usage: %s [options] [VAR=VALUE...] [-- EXTRA...]\n", progname); - printf ("options are:\n"); - printf (" [-]trimnl\n"); - printf (" [-]plaintext\n"); - printf (" -env\n"); - printf (" env sys|none|null\n"); - putchar ('\n'); - for (i = 0; bool_keytab[i].name; i++) - printf (" [-]%s\n", bool_keytab[i].name); - putchar ('\n'); - for (i = 0; string_keytab[i].name; i++) - { - printf (" -%s\n", string_keytab[i].name); - printf (" %s ARG\n", string_keytab[i].name); - } - printf (" escape-word ARG\n"); - printf (" escape-quote ARG\n"); - putchar ('\n'); - for (i = 0; opt_keytab[i].name; i++) - { - printf (" [-]%s\n", opt_keytab[i].name); - } - putchar ('\n'); - printf (" -dooffs\n"); - printf (" dooffs COUNT ARGS...\n"); - exit (0); -} - -void -print_qword (const char *word, int plaintext) -{ - static char *qbuf = NULL; - static size_t qlen = 0; - int quote; - size_t size = mu_wordsplit_c_quoted_length (word, 0, "e); - - if (plaintext) - { - printf ("%s", word); - return; - } - - if (*word == 0) - quote = 1; - - if (size >= qlen) - { - qlen = size + 1; - qbuf = mu_realloc (qbuf, qlen); - } - mu_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 = mu_calloc (size, sizeof (newenv[0])); - - for (i = j = 0; environ[i]; i++) - { - size_t len = strcspn (environ[i], "="); - char *p = mu_alloc (len+1); - memcpy (p, environ[i], len); - p[len] = 0; - newenv[j++] = p; - p = mu_strdup (environ[i] + len + 1); - 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 MU_WRDSE_NOSPACE; - *ret = p; - return MU_WRDSE_OK; - } - } - return MU_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 MU_WRDSE_NOSPACE; - memcpy (*ret, str + alen, len); - (*ret)[len] = 0; - return MU_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 MU_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 MU_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 MU_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 MU_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; - - 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 (mu_asprintf (ret, "unknown command: %s", argv[0])) - return MU_WRDSE_NOSPACE; - else - return MU_WRDSE_USERERR; -} - -enum env_type - { - env_none, - env_null, - env_sys - }; - -struct mu_kwd env_keytab[] = { - { "none", env_none }, - { "null", env_null }, - { "sys", env_sys }, - { NULL } -}; - -static void -set_escape_string (mu_wordsplit_t *ws, int *wsflags, int q, const char *str) -{ - if (*str == ':') - { - while (*++str != ':') - { - int f; - switch (*str) - { - case '+': - f = MU_WRDSO_BSKEEP; - break; - - case '0': - f = MU_WRDSO_OESC; - break; - - case 'x': - f = MU_WRDSO_XESC; - break; - - default: - fprintf (stderr, "%s: invalid escape flag near %s\n", - progname, str); - abort (); - } - MU_WRDSO_ESC_SET (ws, q, f); - } - *wsflags |= MU_WRDSF_OPTIONS; - ++str; - } - ws->ws_escape[q] = str; -} - -int -main (int argc, char **argv) -{ - char buf[1024], *ptr, *saved_ptr; - int i, offarg = 0; - int trimnl_option = 0; - int plaintext_option = 0; - int wsflags = (MU_WRDSF_DEFFLAGS & ~MU_WRDSF_NOVAR) | - MU_WRDSF_ENOMEMABRT | - MU_WRDSF_SHOWERR; - mu_wordsplit_t ws; - int next_call = 0; - char *fenvbase[128]; - size_t fenvidx = 0; - size_t fenvmax = sizeof (fenvbase) / sizeof (fenvbase[0]); - int use_env = env_sys; - int appendc = 0; - char **appendv = NULL; - - progname = argv[0]; - - ws.ws_options = 0; - for (i = 1; i < argc; i++) - { - char *opt = argv[i]; - int negate; - int flag; - - if (opt[0] == '-') - { - if (opt[1] == '-' && opt[2] == 0) - { - appendc = argc - i - 1; - appendv = argv + i + 1; - break; - } - negate = 1; - opt++; - } - else if (opt[0] == '+') - { - negate = 0; - opt++; - } - else - negate = 0; - - if (strcmp (opt, "h") == 0 || - strcmp (opt, "help") == 0 || - strcmp (opt, "-help") == 0) - { - help (); - } - - if (strcmp (opt, "trimnl") == 0) - { - trimnl_option = !negate; - continue; - } - - if (strcmp (opt, "plaintext") == 0) - { - plaintext_option = !negate; - continue; - } - - if (strcmp (opt, "env") == 0) - { - if (negate) - use_env = env_none; - else - { - i++; - if (i == argc) - { - fprintf (stderr, "%s: missing argument for env\n", - progname); - exit (1); - } - - if (mu_kwd_xlat_name (env_keytab, argv[i], &use_env)) - { - fprintf (stderr, "%s: invalid argument for env\n", - progname); - exit (1); - } - } - continue; - } - - if (mu_kwd_xlat_name (bool_keytab, opt, &flag) == 0) - { - if (negate) - wsflags &= ~flag; - else - wsflags |= flag; - continue; - } - - if (mu_kwd_xlat_name (string_keytab, opt, &flag) == 0) - { - if (negate) - wsflags &= ~flag; - else - { - i++; - if (i == argc) - { - fprintf (stderr, "%s: missing argument for %s\n", - progname, opt); - exit (1); - } - - switch (flag) - { - case MU_WRDSF_DELIM: - ws.ws_delim = argv[i]; - break; - - case MU_WRDSF_COMMENT: - ws.ws_comment = argv[i]; - break; - - case MU_WRDSF_ESCAPE: - set_escape_string (&ws, &wsflags, 0, argv[i]); - set_escape_string (&ws, &wsflags, 1, argv[i]); - break; - } - - wsflags |= flag; - } - continue; - } - - if (strcmp (opt, "escape-word") == 0 - || strcmp (opt, "escape-quote") == 0) - { - int q = opt[7] == 'q'; - - i++; - if (i == argc) - { - fprintf (stderr, "%s: missing argument for %s\n", - progname, opt); - exit (1); - } - if (!(wsflags & MU_WRDSF_ESCAPE)) - { - wsflags |= MU_WRDSF_ESCAPE; - ws.ws_escape[!q] = NULL; - } - set_escape_string (&ws, &wsflags, q, argv[i]); - continue; - } - - if (strcmp (opt, "dooffs") == 0) - { - if (negate) - wsflags &= ~MU_WRDSF_DOOFFS; - else - { - char *p; - - i++; - - if (i == argc) - { - fprintf (stderr, "%s: missing arguments for %s\n", - progname, opt); - exit (1); - } - ws.ws_offs = strtoul (argv[i], &p, 10); - if (*p) - { - fprintf (stderr, "%s: invalid number: %s\n", - progname, argv[i]); - exit (1); - } - - i++; - if (i + ws.ws_offs > argc) - { - fprintf (stderr, "%s: not enough arguments for %s\n", - progname, opt); - exit (1); - } - offarg = i; - i += ws.ws_offs - 1; - wsflags |= MU_WRDSF_DOOFFS; - } - continue; - } - - if (mu_kwd_xlat_name (opt_keytab, opt, &flag) == 0) - { - wsflags |= MU_WRDSF_OPTIONS; - if (negate) - ws.ws_options &= ~flag; - else - ws.ws_options |= flag; - continue; - } - - if (strchr (opt, '=')) - { - if (fenvidx < fenvmax - 1) - { - fenvbase[fenvidx++] = opt; - continue; - } - else - { - fprintf (stderr, "%s: environment too big\n", progname); - exit (1); - } - } - - fprintf (stderr, "%s: unrecognized argument: %s\n", - progname, opt); - exit (1); - } - - if (fenvidx) - { - fenvbase[fenvidx] = NULL; - wsflags |= MU_WRDSF_GETVAR | MU_WRDSF_CLOSURE; - ws.ws_getvar = wsp_getvar; - ws.ws_closure = fenvbase; - } - - switch (use_env) - { - case env_null: - wsflags |= MU_WRDSF_ENV; - ws.ws_env = NULL; - break; - - case env_none: - break; - - case env_sys: - wsflags |= MU_WRDSF_ENV; - if (wsflags & MU_WRDSF_ENV_KV) - ws.ws_env = (const char **) make_env_kv (); - else - ws.ws_env = (const char **) environ; - break; - } - - if (!(wsflags & MU_WRDSF_NOCMD)) - ws.ws_command = wsp_runcmd; - - if (wsflags & MU_WRDSF_INCREMENTAL) - trimnl_option = 1; - - next_call = 0; - while ((ptr = fgets (buf, sizeof (buf), stdin))) - { - int rc; - size_t i; - - if (trimnl_option) - { - size_t len = strlen (ptr); - if (len && ptr[len-1] == '\n') - ptr[len-1] = 0; - } - - if (wsflags & MU_WRDSF_INCREMENTAL) - { - if (next_call) - { - if (*ptr == 0) - ptr = NULL; - else - free (saved_ptr); - } - else - next_call = 1; - if (ptr) - ptr = saved_ptr = mu_strdup (ptr); - } - - rc = mu_wordsplit (ptr, &ws, wsflags); - if (rc) - { - if (!(wsflags & MU_WRDSF_SHOWERR)) - mu_wordsplit_perror (&ws); - continue; - } - - if (offarg) - { - for (i = 0; i < ws.ws_offs; i++) - ws.ws_wordv[i] = argv[offarg + i]; - offarg = 0; - } - - if (appendc) - { - rc = mu_wordsplit_append (&ws, appendc, appendv); - if (rc) - { - if (!(wsflags & MU_WRDSF_SHOWERR)) - mu_wordsplit_perror (&ws); - continue; - } - } - - wsflags |= MU_WRDSF_REUSE | (ws.ws_flags & MU_WRDSF_ENV); - printf ("NF: %lu", (unsigned long) ws.ws_wordc); - if (wsflags & MU_WRDSF_DOOFFS) - printf (" (%lu)", (unsigned long) ws.ws_offs); - putchar ('\n'); - for (i = 0; i < ws.ws_offs; i++) - { - printf ("(%lu): ", (unsigned long) i); - print_qword (ws.ws_wordv[i], plaintext_option); - putchar ('\n'); - } - for (; i < ws.ws_offs + ws.ws_wordc; i++) - { - printf ("%lu: ", (unsigned long) i); - print_qword (ws.ws_wordv[i], plaintext_option); - putchar ('\n'); - } - } - return 0; -} diff --git a/libmailutils/wordsplit b/libmailutils/wordsplit new file mode 160000 +Subproject 6a7581f2e60a600a4915e4f55b74a15c8070197 |