diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-11-10 11:24:33 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-11-10 11:24:33 +0200 |
commit | 462c760d4605787a6f5baecc87dfee5e8ee5238b (patch) | |
tree | 1ba5325ed19cfbd38ab806f4615e198e418d0346 | |
parent | 2f1214a79a6befb629466c3e81a993123733a2fe (diff) | |
download | smap-462c760d4605787a6f5baecc87dfee5e8ee5238b.tar.gz smap-462c760d4605787a6f5baecc87dfee5e8ee5238b.tar.bz2 |
Pull wordsplit from grecs 3299cf1c.
* include/smap/wordsplit.h: New version.
* lib/wordsplit.c: New version.
* modules/ldap/ldap.c (getvar): Rewrite to match new prototype.
* src/cfg.c (wrdse_to_ex): Remove WRDSE_NOSUPP.
-rw-r--r-- | include/smap/wordsplit.h | 285 | ||||
-rw-r--r-- | lib/wordsplit.c | 3177 | ||||
-rw-r--r-- | modules/ldap/ldap.c | 33 | ||||
-rw-r--r-- | src/cfg.c | 2 |
4 files changed, 2307 insertions, 1190 deletions
diff --git a/include/smap/wordsplit.h b/include/smap/wordsplit.h index 3b27d25..d5775d1 100644 --- a/include/smap/wordsplit.h +++ b/include/smap/wordsplit.h @@ -1,5 +1,5 @@ /* wordsplit - a word splitter - Copyright (C) 2009-2010, 2014 Sergey Poznyakoff + Copyright (C) 2009-2016 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 @@ -14,131 +14,250 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef __SMAP_WORDSPLIT_H -#define __SMAP_WORDSPLIT_H +#ifndef __WORDSPLIT_H +#define __WORDSPLIT_H #include <stddef.h> -struct wordsplit { - size_t ws_wordc; - char **ws_wordv; - size_t ws_offs; - size_t ws_wordn; - int ws_flags; - const char *ws_delim; - const char *ws_comment; - void (*ws_alloc_die)(struct wordsplit *wsp); - void (*ws_error)(const char *, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); - void (*ws_debug)(const char *, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); - - const char **ws_env; - char *(*ws_getvar) (const char *, size_t, void *); - void *ws_closure; +typedef struct wordsplit wordsplit_t; + +/* Structure used to direct the splitting. Members marked with [Input] + can be defined before calling wordsplit(), those marked with [Output] + provide return values when the function returns. If neither mark is + used, the member is internal and must not be used by the caller. + + In the comments below, the + identifiers in parentheses indicate bits that must be set (or unset, if + starting with !) in 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 wordsplit(). */ +struct wordsplit +{ + size_t ws_wordc; /* [Output] Number of words in ws_wordv. */ + char **ws_wordv; /* [Output] Array of parsed out words. */ + size_t ws_offs; /* [Input] (WRDSF_DOOFFS) Number of initial + elements in ws_wordv to fill with NULLs. */ + size_t ws_wordn; /* Number of elements ws_wordv can accomodate. */ + int ws_flags; /* [Input] Flags passed to wordsplit. */ + int ws_options; /* [Input] (WRDSF_PATHEXPAND) + Additional options. */ + const char *ws_delim; /* [Input] (WRDSF_DELIM) Word delimiters. */ + const char *ws_comment; /* [Input] (WRDSF_COMMENT) Comment characters. */ + const char *ws_escape[2]; /* [Input] (WRDSF_ESCAPE) Characters to be escaped + with backslash. */ + void (*ws_alloc_die) (wordsplit_t *wsp); + /* [Input] (WRDSF_ALLOC_DIE) Function called when + out of memory. Must not return. */ + void (*ws_error) (const char *, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); + /* [Input] (WRDSF_ERROR) Function used for error + reporting */ + void (*ws_debug) (const char *, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); + /* [Input] (WRDSF_DEBUG) Function used for debug + output. */ + const char **ws_env; /* [Input] (WRDSF_ENV, !WRDSF_NOVAR) Array of + environment variables. */ + + 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] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up + the name VAR (LEN bytes long) in the table of + variables and if found returns in memory + location pointed to by RET the value of that + variable. Returns WRDSE_OK (0) on success, + and an error code (see WRDSE_* defines below) + on error. User-specific errors can be returned + by storing the error diagnostic string in RET + and returning WRDSE_USERERR. + Whatever is stored in RET, it must be allocated + using malloc(3). */ + void *ws_closure; /* [Input] (WRDSF_CLOSURE) Passed as the CLOS + argument to ws_getvar and ws_command. */ + int (*ws_command) (char **ret, const char *cmd, size_t len, char **argv, + void *clos); + /* [Input] (!WRDSF_NOCMD) Returns in the memory + location pointed to by RET the expansion of + the command CMD (LEN bytes nong). If WRDSF_ARGV + flag is set, ARGV contains CMD split out to + words. Otherwise ARGV is NULL. + + See ws_getvar for a discussion of possible + return values. */ - const char *ws_input; - size_t ws_len; - size_t ws_endp; - int ws_errno; - struct wordsplit_node *ws_head, *ws_tail; + const char *ws_input; /* Input string (the S argument to wordsplit. */ + size_t ws_len; /* Length of ws_input. */ + size_t ws_endp; /* Points past the last processed byte in + ws_input. */ + int ws_errno; /* [Output] Error code, if an error occurred. */ + char *ws_usererr; /* Points to textual description of + the error, if ws_errno is WRDSE_USERERR. Must + be allocated with malloc(3). */ + struct wordsplit_node *ws_head, *ws_tail; + /* Doubly-linked list of parsed out nodes. */ + int ws_lvl; /* Invocation nesting level. */ }; -/* Append the words found to the array resulting from a previous +/* Initial size for ws_env, if allocated automatically */ +#define WORDSPLIT_ENV_INIT 16 + +/* Wordsplit flags. */ +/* Append the words found to the array resulting from a previous call. */ -#define WRDSF_APPEND 0x0000001 -/* Insert we_offs initial NULLs in the array ws_wordv. +#define WRDSF_APPEND 0x00000001 +/* Insert ws_offs initial NULLs in the array ws_wordv. (These are not counted in the returned ws_wordc.) */ -#define WRDSF_DOOFFS 0x0000002 -/* Don't do command substitution. Reserved for future use. */ -#define WRDSF_NOCMD 0x0000004 +#define WRDSF_DOOFFS 0x00000002 +/* Don't do command substitution. */ +#define WRDSF_NOCMD 0x00000004 /* The parameter p resulted from a previous call to wordsplit(), and wordsplit_free() was not called. Reuse the allocated storage. */ -#define WRDSF_REUSE 0x0000008 +#define WRDSF_REUSE 0x00000008 /* Print errors */ -#define WRDSF_SHOWERR 0x0000010 -/* Consider it an error if an undefined shell variable - is expanded. */ -#define WRDSF_UNDEF 0x0000020 - +#define WRDSF_SHOWERR 0x00000010 +/* Consider it an error if an undefined variable is expanded. */ +#define WRDSF_UNDEF 0x00000020 /* Don't do variable expansion. */ -#define WRDSF_NOVAR 0x0000040 +#define WRDSF_NOVAR 0x00000040 /* Abort on ENOMEM error */ -#define WRDSF_ENOMEMABRT 0x0000080 +#define WRDSF_ENOMEMABRT 0x00000080 /* Trim off any leading and trailind whitespace */ -#define WRDSF_WS 0x0000100 -/* Handle quotes and escape directives */ -#define WRDSF_QUOTE 0x0000200 +#define WRDSF_WS 0x00000100 +/* Handle single quotes */ +#define WRDSF_SQUOTE 0x00000200 +/* Handle double quotes */ +#define WRDSF_DQUOTE 0x00000400 +/* Handle single and double quotes */ +#define WRDSF_QUOTE (WRDSF_SQUOTE|WRDSF_DQUOTE) /* Replace each input sequence of repeated delimiters with a single delimiter */ -#define WRDSF_SQUEEZE_DELIMS 0x0000400 +#define WRDSF_SQUEEZE_DELIMS 0x00000800 /* Return delimiters */ -#define WRDSF_RETURN_DELIMS 0x0000800 +#define WRDSF_RETURN_DELIMS 0x00001000 /* Treat sed expressions as words */ -#define WRDSF_SED_EXPR 0x0001000 +#define WRDSF_SED_EXPR 0x00002000 /* ws_delim field is initialized */ -#define WRDSF_DELIM 0x0002000 +#define WRDSF_DELIM 0x00004000 /* ws_comment field is initialized */ -#define WRDSF_COMMENT 0x0004000 +#define WRDSF_COMMENT 0x00008000 /* ws_alloc_die field is initialized */ -#define WRDSF_ALLOC_DIE 0x0008000 +#define WRDSF_ALLOC_DIE 0x00010000 /* ws_error field is initialized */ -#define WRDSF_ERROR 0x0010000 +#define WRDSF_ERROR 0x00020000 /* ws_debug field is initialized */ -#define WRDSF_DEBUG 0x0020000 +#define WRDSF_DEBUG 0x00040000 /* ws_env field is initialized */ -#define WRDSF_ENV 0x0040000 +#define WRDSF_ENV 0x00080000 /* ws_getvar field is initialized */ -#define WRDSF_GETVAR 0x0080000 +#define WRDSF_GETVAR 0x00100000 /* enable debugging */ -#define WRDSF_SHOWDBG 0x0100000 +#define WRDSF_SHOWDBG 0x00200000 /* Don't split input into words. Useful for side effects. */ -#define WRDSF_NOSPLIT 0x0200000 +#define WRDSF_NOSPLIT 0x00400000 /* Keep undefined variables in place, instead of expanding them to - empty string */ -#define WRDSF_KEEPUNDEF 0x0400000 + empty strings. */ +#define WRDSF_KEEPUNDEF 0x00800000 /* Warn about undefined variables */ -#define WRDSF_WARNUNDEF 0x0800000 +#define WRDSF_WARNUNDEF 0x01000000 /* Handle C escapes */ -#define WRDSF_CESCAPES 0x1000000 - +#define WRDSF_CESCAPES 0x02000000 /* ws_closure is set */ -#define WRDSF_CLOSURE 0x2000000 +#define WRDSF_CLOSURE 0x04000000 /* ws_env is a Key/Value environment, i.e. the value of a variable is stored in the element that follows its name. */ -#define WRDSF_ENV_KV 0x4000000 +#define WRDSF_ENV_KV 0x08000000 +/* ws_escape is set */ +#define WRDSF_ESCAPE 0x10000000 +/* Incremental mode */ +#define WRDSF_INCREMENTAL 0x20000000 +/* Perform pathname and tilde expansion */ +#define WRDSF_PATHEXPAND 0x40000000 +/* ws_options is initialized */ +#define WRDSF_OPTIONS 0x80000000 #define WRDSF_DEFFLAGS \ (WRDSF_NOVAR | WRDSF_NOCMD | \ WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS | WRDSF_CESCAPES) -#define WRDSE_EOF 0 +/* Remove the word that produces empty string after path expansion */ +#define WRDSO_NULLGLOB 0x00000001 +/* Print error message if path expansion produces empty string */ +#define WRDSO_FAILGLOB 0x00000002 +/* Allow a leading period to be matched by metacharacters. */ +#define WRDSO_DOTGLOB 0x00000004 +/* ws_command needs argv parameter */ +#define WRDSO_ARGV 0x00000008 +/* Keep backslash in unrecognized escape sequences in words */ +#define WRDSO_BSKEEP_WORD 0x00000010 +/* Handle octal escapes in words */ +#define WRDSO_OESC_WORD 0x00000020 +/* Handle hex escapes in words */ +#define WRDSO_XESC_WORD 0x00000040 + +/* Keep backslash in unrecognized escape sequences in quoted strings */ +#define WRDSO_BSKEEP_QUOTE 0x00000100 +/* Handle octal escapes in quoted strings */ +#define WRDSO_OESC_QUOTE 0x00000200 +/* Handle hex escapes in quoted strings */ +#define WRDSO_XESC_QUOTE 0x00000400 + +#define WRDSO_BSKEEP WRDSO_BSKEEP_WORD +#define WRDSO_OESC WRDSO_OESC_WORD +#define WRDSO_XESC WRDSO_XESC_WORD + +/* Indices into ws_escape */ +#define WRDSX_WORD 0 +#define WRDSX_QUOTE 1 + +/* Set escape option F in WS for words (Q==0) or quoted strings (Q==1) */ +#define WRDSO_ESC_SET(ws,q,f) ((ws)->ws_options |= ((f) << 4*(q))) +/* Test WS for escape option F for words (Q==0) or quoted strings (Q==1) */ +#define WRDSO_ESC_TEST(ws,q,f) ((ws)->ws_options & ((f) << 4*(q))) + +#define WRDSE_OK 0 +#define WRDSE_EOF WRDSE_OK #define WRDSE_QUOTE 1 #define WRDSE_NOSPACE 2 -#define WRDSE_NOSUPP 3 -#define WRDSE_USAGE 4 -#define WRDSE_CBRACE 5 -#define WRDSE_UNDEF 6 - -int wordsplit(const char *s, struct wordsplit *p, int flags); -int wordsplit_len(const char *s, size_t len, - struct wordsplit *p, int flags); -void wordsplit_free(struct wordsplit *p); -void wordsplit_free_words(struct wordsplit *ws); - -int wordsplit_c_unquote_char(int c); -int wordsplit_c_quote_char(int c); -size_t wordsplit_c_quoted_length(const char *str, int quote_hex, - int *quote); -void wordsplit_sh_unquote_copy(char *dst, const char *src, size_t n); -void wordsplit_c_unquote_copy(char *dst, const char *src, size_t n); -void wordsplit_c_quote_copy(char *dst, const char *src, int quote_hex); +#define WRDSE_USAGE 3 +#define WRDSE_CBRACE 4 +#define WRDSE_UNDEF 5 +#define WRDSE_NOINPUT 6 +#define WRDSE_PAREN 7 +#define WRDSE_GLOBERR 8 +#define WRDSE_USERERR 9 -int wordsplit_varnames(const char *input, char ***ret_names, int af); +int wordsplit (const char *s, wordsplit_t *ws, int flags); +int wordsplit_len (const char *s, size_t len, wordsplit_t *ws, int flags); +void wordsplit_free (wordsplit_t *ws); +void wordsplit_free_words (wordsplit_t *ws); +void wordsplit_free_envbuf (wordsplit_t *ws); +int wordsplit_get_words (wordsplit_t *ws, size_t *wordc, char ***wordv); + +static inline void wordsplit_getwords (wordsplit_t *ws, size_t *wordc, char ***wordv) + __attribute__ ((deprecated)); -void wordsplit_perror(struct wordsplit *ws); -const char *wordsplit_strerror(struct wordsplit *ws); +static inline void +wordsplit_getwords (wordsplit_t *ws, size_t *wordc, char ***wordv) +{ + wordsplit_get_words (ws, wordc, wordv); +} +int wordsplit_append (wordsplit_t *wsp, int argc, char **argv); + +int wordsplit_c_unquote_char (int c); +int wordsplit_c_quote_char (int c); +size_t wordsplit_c_quoted_length (const char *str, int quote_hex, int *quote); +void wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex); + +void wordsplit_perror (wordsplit_t *ws); +const char *wordsplit_strerror (wordsplit_t *ws); + +void wordsplit_clearerr (wordsplit_t *ws); + +int wordsplit_varnames(const char *input, char ***ret_names, int af); #endif diff --git a/lib/wordsplit.c b/lib/wordsplit.c index c4abc30..96e0f58 100644 --- a/lib/wordsplit.c +++ b/lib/wordsplit.c @@ -1,5 +1,5 @@ /* wordsplit - a word splitter - Copyright (C) 2009-2010, 2014 Sergey Poznyakoff + Copyright (C) 2009-2016 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 @@ -25,20 +25,22 @@ #include <string.h> #include <stdio.h> #include <stdarg.h> +#include <pwd.h> +#include <glob.h> -#include <smap/wordsplit.h> - -#ifdef HAVE_GETTEXT_H +#if ENABLE_NLS # include <gettext.h> #else -# define gettext(s) s +# define gettext(msgid) msgid #endif -#define _(msgid) gettext(msgid) +#define _(msgid) gettext (msgid) #define N_(msgid) msgid +#include <smap/wordsplit.h> + #define ISWS(c) ((c)==' '||(c)=='\t'||(c)=='\n') #define ISDELIM(ws,c) \ - (strchr ((ws)->ws_delim, (c)) != NULL) + (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') @@ -50,137 +52,251 @@ #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 wordsplit *wsp) +_wsplt_alloc_die (struct wordsplit *wsp) { - wsp->ws_error(_("memory exhausted")); - abort(); + wsp->ws_error ("%s", _("memory exhausted")); + abort (); } static void -_wsplt_error(const char *fmt, ...) +_wsplt_error (const char *fmt, ...) { - va_list ap; + va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputc('\n', stderr); + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + fputc ('\n', stderr); } -static void wordsplit_free_nodes(struct wordsplit *); +static void wordsplit_free_nodes (struct wordsplit *); static int -_wsplt_nomem(struct wordsplit *wsp) -{ - errno = ENOMEM; - wsp->ws_errno = WRDSE_NOSPACE; - if (wsp->ws_flags & WRDSF_ENOMEMABRT) - wsp->ws_alloc_die(wsp); - if (wsp->ws_flags & WRDSF_SHOWERR) - wordsplit_perror(wsp); - if (!(wsp->ws_flags & WRDSF_REUSE)) - wordsplit_free(wsp); - wordsplit_free_nodes(wsp); - return wsp->ws_errno; +_wsplt_seterr (struct wordsplit *wsp, int ec) +{ + wsp->ws_errno = ec; + if (wsp->ws_flags & WRDSF_SHOWERR) + wordsplit_perror (wsp); + return ec; +} + +static int +_wsplt_nomem (struct wordsplit *wsp) +{ + errno = ENOMEM; + wsp->ws_errno = WRDSE_NOSPACE; + if (wsp->ws_flags & WRDSF_ENOMEMABRT) + wsp->ws_alloc_die (wsp); + if (wsp->ws_flags & WRDSF_SHOWERR) + wordsplit_perror (wsp); + if (!(wsp->ws_flags & WRDSF_REUSE)) + wordsplit_free (wsp); + wordsplit_free_nodes (wsp); + return wsp->ws_errno; } +static int wordsplit_run (const char *command, size_t length, + struct wordsplit *wsp, + int flags, int lvl); + static int -wordsplit_init(struct wordsplit *wsp, const char *input, size_t len, - int flags) +_wsplt_subsplit (struct wordsplit *wsp, struct wordsplit *wss, + char const *str, int len, + int flags) { - wsp->ws_flags = 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 & WRDSF_NOVAR)) + { + wss->ws_env = wsp->ws_env; + wss->ws_getvar = wsp->ws_getvar; + flags |= wsp->ws_flags & (WRDSF_ENV | WRDSF_ENV_KV | WRDSF_GETVAR); + } + if (!(flags & WRDSF_NOCMD)) + { + wss->ws_command = wsp->ws_command; + } + + if ((flags & (WRDSF_NOVAR|WRDSF_NOCMD)) != (WRDSF_NOVAR|WRDSF_NOCMD)) + { + wss->ws_closure = wsp->ws_closure; + flags |= wsp->ws_flags & WRDSF_CLOSURE; + } + + wss->ws_options = wsp->ws_options; + + flags |= WRDSF_DELIM + | WRDSF_ALLOC_DIE + | WRDSF_ERROR + | WRDSF_DEBUG + | (wsp->ws_flags & (WRDSF_SHOWDBG | WRDSF_SHOWERR | WRDSF_OPTIONS)); + + return wordsplit_run (str, len, wss, flags, wsp->ws_lvl + 1); +} - if (!(wsp->ws_flags & WRDSF_ALLOC_DIE)) - wsp->ws_alloc_die = _wsplt_alloc_die; - if (!(wsp->ws_flags & WRDSF_ERROR)) - wsp->ws_error = _wsplt_error; +static void +_wsplt_seterr_sub (struct wordsplit *wsp, struct wordsplit *wss) +{ + if (wsp->ws_errno == WRDSE_USERERR) + free (wsp->ws_usererr); + wsp->ws_errno = wss->ws_errno; + if (wss->ws_errno == WRDSE_USERERR) + { + wsp->ws_usererr = wss->ws_usererr; + wss->ws_errno = WRDSE_EOF; + wss->ws_usererr = NULL; + } +} - if (!(wsp->ws_flags & WRDSF_NOVAR) - && !(wsp->ws_flags & (WRDSF_ENV | WRDSF_GETVAR))) { - errno = EINVAL; - wsp->ws_errno = WRDSE_USAGE; - if (wsp->ws_flags & WRDSF_SHOWERR) - wordsplit_perror(wsp); - return wsp->ws_errno; - } +static void +wordsplit_init0 (struct wordsplit *wsp) +{ + if (wsp->ws_flags & WRDSF_REUSE) + { + if (!(wsp->ws_flags & WRDSF_APPEND)) + wordsplit_free_words (wsp); + wordsplit_clearerr (wsp); + } + else + { + wsp->ws_wordv = NULL; + wsp->ws_wordc = 0; + wsp->ws_wordn = 0; + } + + wsp->ws_errno = 0; + wsp->ws_head = wsp->ws_tail = NULL; +} - if (!(wsp->ws_flags & WRDSF_NOCMD)) { - errno = EINVAL; - wsp->ws_errno = WRDSE_NOSUPP; - if (wsp->ws_flags & WRDSF_SHOWERR) - wordsplit_perror(wsp); - return wsp->ws_errno; +char wordsplit_c_escape_tab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v"; + +static int +wordsplit_init (struct wordsplit *wsp, const char *input, size_t len, + int flags) +{ + wsp->ws_flags = flags; + + if (!(wsp->ws_flags & WRDSF_ALLOC_DIE)) + wsp->ws_alloc_die = _wsplt_alloc_die; + if (!(wsp->ws_flags & WRDSF_ERROR)) + wsp->ws_error = _wsplt_error; + + if (!(wsp->ws_flags & WRDSF_NOVAR)) + { + /* These will be initialized on first variable assignment */ + wsp->ws_envidx = wsp->ws_envsiz = 0; + wsp->ws_envbuf = NULL; + } + + if (!(wsp->ws_flags & WRDSF_NOCMD)) + { + if (!wsp->ws_command) + { + _wsplt_seterr (wsp, WRDSE_USAGE); + errno = EINVAL; + return wsp->ws_errno; } - - if (wsp->ws_flags & WRDSF_SHOWDBG) { - if (!(wsp->ws_flags & WRDSF_DEBUG)) { - if (wsp->ws_flags & WRDSF_ERROR) - wsp->ws_debug = wsp->ws_error; - else if (wsp->ws_flags & WRDSF_SHOWERR) - wsp->ws_debug = _wsplt_error; - else - wsp->ws_flags &= ~WRDSF_SHOWDBG; - } + } + + if (wsp->ws_flags & WRDSF_SHOWDBG) + { + if (!(wsp->ws_flags & WRDSF_DEBUG)) + { + if (wsp->ws_flags & WRDSF_ERROR) + wsp->ws_debug = wsp->ws_error; + else if (wsp->ws_flags & WRDSF_SHOWERR) + wsp->ws_debug = _wsplt_error; + else + wsp->ws_flags &= ~WRDSF_SHOWDBG; } - - wsp->ws_input = input; - wsp->ws_len = len; - - if (!(wsp->ws_flags & WRDSF_DOOFFS)) - wsp->ws_offs = 0; - - if (!(wsp->ws_flags & WRDSF_DELIM)) - wsp->ws_delim = " \t\n"; - - if (!(wsp->ws_flags & WRDSF_COMMENT)) - wsp->ws_comment = NULL; - - if (wsp->ws_flags & WRDSF_REUSE) { - if (!(wsp->ws_flags & WRDSF_APPEND)) - wordsplit_free_words(wsp); - } else { - wsp->ws_wordv = NULL; - wsp->ws_wordc = 0; - wsp->ws_wordn = 0; + } + + wsp->ws_input = input; + wsp->ws_len = len; + + if (!(wsp->ws_flags & WRDSF_DOOFFS)) + wsp->ws_offs = 0; + + if (!(wsp->ws_flags & WRDSF_DELIM)) + wsp->ws_delim = " \t\n"; + + if (!(wsp->ws_flags & WRDSF_COMMENT)) + wsp->ws_comment = NULL; + + if (!(wsp->ws_flags & WRDSF_CLOSURE)) + wsp->ws_closure = NULL; + + if (!(wsp->ws_flags & WRDSF_OPTIONS)) + wsp->ws_options = 0; + + if (wsp->ws_flags & WRDSF_ESCAPE) + { + if (!wsp->ws_escape[WRDSX_WORD]) + wsp->ws_escape[WRDSX_WORD] = ""; + if (!wsp->ws_escape[WRDSX_QUOTE]) + wsp->ws_escape[WRDSX_QUOTE] = ""; + } + else + { + if (wsp->ws_flags & WRDSF_CESCAPES) + { + wsp->ws_escape[WRDSX_WORD] = wordsplit_c_escape_tab; + wsp->ws_escape[WRDSX_QUOTE] = wordsplit_c_escape_tab; + wsp->ws_options |= WRDSO_OESC_QUOTE | WRDSO_OESC_WORD + | WRDSO_XESC_QUOTE | WRDSO_XESC_WORD; + } + else + { + wsp->ws_escape[WRDSX_WORD] = ""; + wsp->ws_escape[WRDSX_QUOTE] = "\\\\\"\""; + wsp->ws_options |= WRDSO_BSKEEP_QUOTE; } + } + + wsp->ws_endp = 0; - if (!(wsp->ws_flags & WRDSF_CLOSURE)) - wsp->ws_closure = NULL; + wordsplit_init0 (wsp); - wsp->ws_endp = 0; - wsp->ws_errno = 0; - wsp->ws_head = wsp->ws_tail = NULL; - return 0; + return 0; } static int -alloc_space(struct wordsplit *wsp, size_t count) -{ - size_t offs = (wsp->ws_flags & WRDSF_DOOFFS) ? wsp->ws_offs : 0; - char **ptr; - size_t newalloc; - - if (wsp->ws_wordv == NULL) { - newalloc = offs + count > ALLOC_INIT ? count : ALLOC_INIT; - ptr = calloc(newalloc, sizeof(ptr[0])); - } else if (wsp->ws_wordn < offs + wsp->ws_wordc + count) { - newalloc = offs + wsp->ws_wordc + - count > ALLOC_INCR ? count : ALLOC_INCR; - ptr = realloc(wsp->ws_wordv, newalloc * sizeof(ptr[0])); - } else - return 0; - - if (ptr) { - wsp->ws_wordn = newalloc; - wsp->ws_wordv = ptr; - } else - return _wsplt_nomem(wsp); - return 0; +alloc_space (struct wordsplit *wsp, size_t count) +{ + size_t offs = (wsp->ws_flags & WRDSF_DOOFFS) ? wsp->ws_offs : 0; + char **ptr; + size_t newalloc; + + if (wsp->ws_wordv == NULL) + { + newalloc = offs + count > ALLOC_INIT ? count : ALLOC_INIT; + ptr = calloc (newalloc, sizeof (ptr[0])); + } + else if (wsp->ws_wordn < offs + wsp->ws_wordc + count) + { + newalloc = offs + wsp->ws_wordc + + (count > ALLOC_INCR ? count : ALLOC_INCR); + ptr = realloc (wsp->ws_wordv, newalloc * sizeof (ptr[0])); + } + else + return 0; + + if (ptr) + { + wsp->ws_wordn = newalloc; + wsp->ws_wordv = ptr; + } + else + return _wsplt_nomem (wsp); + return 0; } @@ -191,1201 +307,2078 @@ alloc_space(struct wordsplit *wsp, size_t count) #define _WSNF_NOEXPAND 0x08 /* text is not subject to expansion */ #define _WSNF_JOIN 0x10 /* node must be joined with the next node */ #define _WSNF_SEXP 0x20 /* is a sed expression */ +#define _WSNF_DELIM 0x40 /* node is a delimiter */ #define _WSNF_EMPTYOK 0x0100 /* special flag indicating that wordsplit_add_segm must add the segment even if it is empty */ -struct wordsplit_node { - struct wordsplit_node *prev; /* Previous element */ - struct wordsplit_node *next; /* Next element */ - int flags; /* Node flags */ - union { - struct { - size_t beg; /* Start of word in ws_input */ - size_t end; /* End of word in ws_input */ - } segm; - char *word; - } v; +struct wordsplit_node +{ + struct wordsplit_node *prev; /* Previous element */ + struct wordsplit_node *next; /* Next element */ + int flags; /* Node flags */ + union + { + struct + { + size_t beg; /* Start of word in ws_input */ + size_t end; /* End of word in ws_input */ + } segm; + char *word; + } v; }; static const char * -wsnode_flagstr(int flags) -{ - static char retbuf[6]; - 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++ = '-'; - *p = 0; - return retbuf; +wsnode_flagstr (int flags) +{ + static char retbuf[7]; + char *p = retbuf; + + if (flags & _WSNF_WORD) + *p++ = 'w'; + else if (flags & _WSNF_NULL) + *p++ = 'n'; + else + *p++ = '-'; + if (flags & _WSNF_QUOTE) + *p++ = 'q'; + else + *p++ = '-'; + if (flags & _WSNF_NOEXPAND) + *p++ = 'E'; + else + *p++ = '-'; + if (flags & _WSNF_JOIN) + *p++ = 'j'; + else + *p++ = '-'; + if (flags & _WSNF_SEXP) + *p++ = 's'; + else + *p++ = '-'; + if (flags & _WSNF_DELIM) + *p++ = 'd'; + else + *p++ = '-'; + *p = 0; + return retbuf; } static const char * -wsnode_ptr(struct wordsplit *wsp, struct wordsplit_node *p) +wsnode_ptr (struct wordsplit *wsp, struct wordsplit_node *p) { - if (p->flags & _WSNF_NULL) - return ""; - else if (p->flags & _WSNF_WORD) - return p->v.word; - else - return wsp->ws_input + p->v.segm.beg; + if (p->flags & _WSNF_NULL) + return ""; + else if (p->flags & _WSNF_WORD) + return p->v.word; + else + return wsp->ws_input + p->v.segm.beg; } static size_t -wsnode_len(struct wordsplit_node *p) +wsnode_len (struct wordsplit_node *p) { - if (p->flags & _WSNF_NULL) - return 0; - else if (p->flags & _WSNF_WORD) - return strlen(p->v.word); - else - return p->v.segm.end - p->v.segm.beg; + if (p->flags & _WSNF_NULL) + return 0; + else if (p->flags & _WSNF_WORD) + return strlen (p->v.word); + else + return p->v.segm.end - p->v.segm.beg; } static int -wsnode_new(struct wordsplit *wsp, struct wordsplit_node **pnode) +wsnode_new (struct wordsplit *wsp, struct wordsplit_node **pnode) { - struct wordsplit_node *node = calloc(1, sizeof(*node)); - if (!node) - return _wsplt_nomem(wsp); - *pnode = node; - return 0; + struct wordsplit_node *node = calloc (1, sizeof (*node)); + if (!node) + return _wsplt_nomem (wsp); + *pnode = node; + return 0; } static void -wsnode_free(struct wordsplit_node *p) +wsnode_free (struct wordsplit_node *p) { - if (p->flags & _WSNF_WORD) - free(p->v.word); - free(p); + if (p->flags & _WSNF_WORD) + free (p->v.word); + free (p); } static void -wsnode_append(struct wordsplit *wsp, struct wordsplit_node *node) -{ - node->next = NULL; - node->prev = wsp->ws_tail; - if (wsp->ws_tail) - wsp->ws_tail->next = node; - else - wsp->ws_head = node; - wsp->ws_tail = node; +wsnode_append (struct wordsplit *wsp, struct wordsplit_node *node) +{ + node->next = NULL; + node->prev = wsp->ws_tail; + if (wsp->ws_tail) + wsp->ws_tail->next = node; + else + wsp->ws_head = node; + wsp->ws_tail = node; } static void -wsnode_remove(struct wordsplit *wsp, struct wordsplit_node *node) +wsnode_remove (struct wordsplit *wsp, struct wordsplit_node *node) { - struct wordsplit_node *p; - - p = node->prev; - if (p) { - p->next = node->next; - if (!node->next) - p->flags &= ~_WSNF_JOIN; - } else - wsp->ws_head = node->next; - - p = node->next; - if (p) - p->prev = node->prev; - else - wsp->ws_tail = node->prev; - - node->next = node->prev = NULL; + struct wordsplit_node *p; + + p = node->prev; + if (p) + { + p->next = node->next; + if (!node->next) + p->flags &= ~_WSNF_JOIN; + } + else + wsp->ws_head = node->next; + + p = node->next; + if (p) + p->prev = node->prev; + else + wsp->ws_tail = node->prev; + + node->next = node->prev = NULL; } static void -wsnode_insert(struct wordsplit *wsp, struct wordsplit_node *node, - struct wordsplit_node *anchor, int before) -{ - if (!wsp->ws_head) { - node->next = node->prev = NULL; - wsp->ws_head = wsp->ws_tail = node; - } else if (before) { - if (anchor->prev) - wsnode_insert(wsp, node, anchor->prev, 0); - else { - node->prev = NULL; - node->next = anchor; - anchor->prev = node; - wsp->ws_head = node; - } - } else { - struct 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; +wsnode_insert (struct wordsplit *wsp, struct wordsplit_node *node, + struct wordsplit_node *anchor, int before) +{ + if (!wsp->ws_head) + { + node->next = node->prev = NULL; + wsp->ws_head = wsp->ws_tail = node; + } + else if (before) + { + if (anchor->prev) + wsnode_insert (wsp, node, anchor->prev, 0); + else + { + node->prev = NULL; + node->next = anchor; + anchor->prev = node; + wsp->ws_head = node; } + } + else + { + struct 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 -wordsplit_add_segm(struct wordsplit *wsp, size_t beg, size_t end, int flg) +wordsplit_add_segm (struct wordsplit *wsp, size_t beg, size_t end, int flg) { - struct wordsplit_node *node; - int rc; - - if (end == beg && !(flg & _WSNF_EMPTYOK)) - return 0; - rc = wsnode_new(wsp, &node); - if (rc) - return rc; - node->flags = flg & ~(_WSNF_WORD | _WSNF_EMPTYOK); - node->v.segm.beg = beg; - node->v.segm.end = end; - wsnode_append(wsp, node); - return 0; + struct wordsplit_node *node; + int rc; + + if (end == beg && !(flg & _WSNF_EMPTYOK)) + return 0; + rc = wsnode_new (wsp, &node); + if (rc) + return rc; + node->flags = flg & ~(_WSNF_WORD | _WSNF_EMPTYOK); + node->v.segm.beg = beg; + node->v.segm.end = end; + wsnode_append (wsp, node); + return 0; } static void -wordsplit_free_nodes(struct wordsplit *wsp) +wordsplit_free_nodes (struct wordsplit *wsp) { - struct wordsplit_node *p; - - for (p = wsp->ws_head; p;) { - struct wordsplit_node *next = p->next; - wsnode_free(p); - p = next; - } - wsp->ws_head = wsp->ws_tail = NULL; + struct wordsplit_node *p; + + for (p = wsp->ws_head; p;) + { + struct wordsplit_node *next = p->next; + wsnode_free (p); + p = next; + } + wsp->ws_head = wsp->ws_tail = NULL; } static void -wordsplit_dump_nodes(struct wordsplit *wsp) -{ - struct wordsplit_node *p; - int n = 0; - - for (p = wsp->ws_head, n = 0; p; p = p->next, n++) { - if (p->flags & _WSNF_WORD) - wsp->ws_debug("%4d: %p: %#04x (%s):%s;", - n, p, p->flags, - wsnode_flagstr(p->flags), p->v.word); - else - wsp->ws_debug("%4d: %p: %#04x (%s):%.*s;", - n, p, p->flags, - wsnode_flagstr(p->flags), - p->v.segm.end - p->v.segm.beg, - wsp->ws_input + p->v.segm.beg); - } +wordsplit_dump_nodes (struct wordsplit *wsp) +{ + s |