summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--.gitmodules3
-rw-r--r--configure.ac1
-rw-r--r--include/smap/.gitignore1
-rw-r--r--include/smap/Makefile.am2
-rw-r--r--include/smap/wordsplit.h263
-rw-r--r--lib/Makefile.am12
m---------lib/wordsplit0
-rw-r--r--lib/wordsplit.c2447
-rw-r--r--modules/echo/Makefile.am4
-rw-r--r--modules/guile/Makefile.am4
-rw-r--r--modules/ldap/Makefile.am4
-rw-r--r--modules/mailutils/Makefile.am4
-rw-r--r--modules/mysql/Makefile.am2
-rw-r--r--modules/postgres/Makefile.am2
-rw-r--r--modules/sed/Makefile.am2
-rw-r--r--src/Makefile.am6
16 files changed, 30 insertions, 2727 deletions
diff --git a/.gitmodules b/.gitmodules
index 7c369d4..50664b0 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
1[submodule "gint"] 1[submodule "gint"]
2 path = gint 2 path = gint
3 url = git://git.gnu.org.ua/gint.git 3 url = git://git.gnu.org.ua/gint.git
4[submodule "lib/wordsplit"]
5 path = lib/wordsplit
6 url = git://git.gnu.org.ua/wordsplit.git
diff --git a/configure.ac b/configure.ac
index 46774b2..387a8d1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -223,6 +223,7 @@ if test "$status_readline" != "no"; then
223 fi 223 fi
224fi 224fi
225 225
226AC_CONFIG_LINKS(include/smap/wordsplit.h:lib/wordsplit/wordsplit.h)
226 227
227AC_CONFIG_COMMANDS([status],[ 228AC_CONFIG_COMMANDS([status],[
228cat <<EOF 229cat <<EOF
diff --git a/include/smap/.gitignore b/include/smap/.gitignore
new file mode 100644
index 0000000..357781f
--- a/dev/null
+++ b/include/smap/.gitignore
@@ -0,0 +1 @@
wordsplit.h
diff --git a/include/smap/Makefile.am b/include/smap/Makefile.am
index 040c936..672b23a 100644
--- a/include/smap/Makefile.am
+++ b/include/smap/Makefile.am
@@ -15,7 +15,7 @@
15# along with Smap. If not, see <http://www.gnu.org/licenses/>. 15# along with Smap. If not, see <http://www.gnu.org/licenses/>.
16 16
17pkginclude_HEADERS = \ 17pkginclude_HEADERS = \
18 wordsplit.h\ 18 $(top_srcdir)/lib/wordsplit/wordsplit.h\
19 kwtab.h\ 19 kwtab.h\
20 module.h\ 20 module.h\
21 diag.h\ 21 diag.h\
diff --git a/include/smap/wordsplit.h b/include/smap/wordsplit.h
deleted file mode 100644
index d5775d1..0000000
--- a/include/smap/wordsplit.h
+++ b/dev/null
@@ -1,263 +0,0 @@
1/* wordsplit - a word splitter
2 Copyright (C) 2009-2016 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3 of the License, or (at your
7 option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#ifndef __WORDSPLIT_H
18#define __WORDSPLIT_H
19
20#include <stddef.h>
21
22typedef struct wordsplit wordsplit_t;
23
24/* Structure used to direct the splitting. Members marked with [Input]
25 can be defined before calling wordsplit(), those marked with [Output]
26 provide return values when the function returns. If neither mark is
27 used, the member is internal and must not be used by the caller.
28
29 In the comments below, the
30 identifiers in parentheses indicate bits that must be set (or unset, if
31 starting with !) in the ws_flags to initialize or use the given member.
32 If not redefined explicitly, most of them are set to some reasonable
33 default value upon entry to wordsplit(). */
34struct wordsplit
35{
36 size_t ws_wordc; /* [Output] Number of words in ws_wordv. */
37 char **ws_wordv; /* [Output] Array of parsed out words. */
38 size_t ws_offs; /* [Input] (WRDSF_DOOFFS) Number of initial
39 elements in ws_wordv to fill with NULLs. */
40 size_t ws_wordn; /* Number of elements ws_wordv can accomodate. */
41 int ws_flags; /* [Input] Flags passed to wordsplit. */
42 int ws_options; /* [Input] (WRDSF_PATHEXPAND)
43 Additional options. */
44 const char *ws_delim; /* [Input] (WRDSF_DELIM) Word delimiters. */
45 const char *ws_comment; /* [Input] (WRDSF_COMMENT) Comment characters. */
46 const char *ws_escape[2]; /* [Input] (WRDSF_ESCAPE) Characters to be escaped
47 with backslash. */
48 void (*ws_alloc_die) (wordsplit_t *wsp);
49 /* [Input] (WRDSF_ALLOC_DIE) Function called when
50 out of memory. Must not return. */
51 void (*ws_error) (const char *, ...)
52 __attribute__ ((__format__ (__printf__, 1, 2)));
53 /* [Input] (WRDSF_ERROR) Function used for error
54 reporting */
55 void (*ws_debug) (const char *, ...)
56 __attribute__ ((__format__ (__printf__, 1, 2)));
57 /* [Input] (WRDSF_DEBUG) Function used for debug
58 output. */
59 const char **ws_env; /* [Input] (WRDSF_ENV, !WRDSF_NOVAR) Array of
60 environment variables. */
61
62 char **ws_envbuf;
63 size_t ws_envidx;
64 size_t ws_envsiz;
65
66 int (*ws_getvar) (char **ret, const char *var, size_t len, void *clos);
67 /* [Input] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up
68 the name VAR (LEN bytes long) in the table of
69 variables and if found returns in memory
70 location pointed to by RET the value of that
71 variable. Returns WRDSE_OK (0) on success,
72 and an error code (see WRDSE_* defines below)
73 on error. User-specific errors can be returned
74 by storing the error diagnostic string in RET
75 and returning WRDSE_USERERR.
76 Whatever is stored in RET, it must be allocated
77 using malloc(3). */
78 void *ws_closure; /* [Input] (WRDSF_CLOSURE) Passed as the CLOS
79 argument to ws_getvar and ws_command. */
80 int (*ws_command) (char **ret, const char *cmd, size_t len, char **argv,
81 void *clos);
82 /* [Input] (!WRDSF_NOCMD) Returns in the memory
83 location pointed to by RET the expansion of
84 the command CMD (LEN bytes nong). If WRDSF_ARGV
85 flag is set, ARGV contains CMD split out to
86 words. Otherwise ARGV is NULL.
87
88 See ws_getvar for a discussion of possible
89 return values. */
90
91 const char *ws_input; /* Input string (the S argument to wordsplit. */
92 size_t ws_len; /* Length of ws_input. */
93 size_t ws_endp; /* Points past the last processed byte in
94 ws_input. */
95 int ws_errno; /* [Output] Error code, if an error occurred. */
96 char *ws_usererr; /* Points to textual description of
97 the error, if ws_errno is WRDSE_USERERR. Must
98 be allocated with malloc(3). */
99 struct wordsplit_node *ws_head, *ws_tail;
100 /* Doubly-linked list of parsed out nodes. */
101 int ws_lvl; /* Invocation nesting level. */
102};
103
104/* Initial size for ws_env, if allocated automatically */
105#define WORDSPLIT_ENV_INIT 16
106
107/* Wordsplit flags. */
108/* Append the words found to the array resulting from a previous
109 call. */
110#define WRDSF_APPEND 0x00000001
111/* Insert ws_offs initial NULLs in the array ws_wordv.
112 (These are not counted in the returned ws_wordc.) */
113#define WRDSF_DOOFFS 0x00000002
114/* Don't do command substitution. */
115#define WRDSF_NOCMD 0x00000004
116/* The parameter p resulted from a previous call to
117 wordsplit(), and wordsplit_free() was not called. Reuse the
118 allocated storage. */
119#define WRDSF_REUSE 0x00000008
120/* Print errors */
121#define WRDSF_SHOWERR 0x00000010
122/* Consider it an error if an undefined variable is expanded. */
123#define WRDSF_UNDEF 0x00000020
124/* Don't do variable expansion. */
125#define WRDSF_NOVAR 0x00000040
126/* Abort on ENOMEM error */
127#define WRDSF_ENOMEMABRT 0x00000080
128/* Trim off any leading and trailind whitespace */
129#define WRDSF_WS 0x00000100
130/* Handle single quotes */
131#define WRDSF_SQUOTE 0x00000200
132/* Handle double quotes */
133#define WRDSF_DQUOTE 0x00000400
134/* Handle single and double quotes */
135#define WRDSF_QUOTE (WRDSF_SQUOTE|WRDSF_DQUOTE)
136/* Replace each input sequence of repeated delimiters with a single
137 delimiter */
138#define WRDSF_SQUEEZE_DELIMS 0x00000800
139/* Return delimiters */
140#define WRDSF_RETURN_DELIMS 0x00001000
141/* Treat sed expressions as words */
142#define WRDSF_SED_EXPR 0x00002000
143/* ws_delim field is initialized */
144#define WRDSF_DELIM 0x00004000
145/* ws_comment field is initialized */
146#define WRDSF_COMMENT 0x00008000
147/* ws_alloc_die field is initialized */
148#define WRDSF_ALLOC_DIE 0x00010000
149/* ws_error field is initialized */
150#define WRDSF_ERROR 0x00020000
151/* ws_debug field is initialized */
152#define WRDSF_DEBUG 0x00040000
153/* ws_env field is initialized */
154#define WRDSF_ENV 0x00080000
155/* ws_getvar field is initialized */
156#define WRDSF_GETVAR 0x00100000
157/* enable debugging */
158#define WRDSF_SHOWDBG 0x00200000
159/* Don't split input into words. Useful for side effects. */
160#define WRDSF_NOSPLIT 0x00400000
161/* Keep undefined variables in place, instead of expanding them to
162 empty strings. */
163#define WRDSF_KEEPUNDEF 0x00800000
164/* Warn about undefined variables */
165#define WRDSF_WARNUNDEF 0x01000000
166/* Handle C escapes */
167#define WRDSF_CESCAPES 0x02000000
168/* ws_closure is set */
169#define WRDSF_CLOSURE 0x04000000
170/* ws_env is a Key/Value environment, i.e. the value of a variable is
171 stored in the element that follows its name. */
172#define WRDSF_ENV_KV 0x08000000
173/* ws_escape is set */
174#define WRDSF_ESCAPE 0x10000000
175/* Incremental mode */
176#define WRDSF_INCREMENTAL 0x20000000
177/* Perform pathname and tilde expansion */
178#define WRDSF_PATHEXPAND 0x40000000
179/* ws_options is initialized */
180#define WRDSF_OPTIONS 0x80000000
181
182 #define WRDSF_DEFFLAGS \
183 (WRDSF_NOVAR | WRDSF_NOCMD | \
184 WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS | WRDSF_CESCAPES)
185
186/* Remove the word that produces empty string after path expansion */
187#define WRDSO_NULLGLOB 0x00000001
188/* Print error message if path expansion produces empty string */
189#define WRDSO_FAILGLOB 0x00000002
190/* Allow a leading period to be matched by metacharacters. */
191#define WRDSO_DOTGLOB 0x00000004
192/* ws_command needs argv parameter */
193#define WRDSO_ARGV 0x00000008
194/* Keep backslash in unrecognized escape sequences in words */
195#define WRDSO_BSKEEP_WORD 0x00000010
196/* Handle octal escapes in words */
197#define WRDSO_OESC_WORD 0x00000020
198/* Handle hex escapes in words */
199#define WRDSO_XESC_WORD 0x00000040
200
201/* Keep backslash in unrecognized escape sequences in quoted strings */
202#define WRDSO_BSKEEP_QUOTE 0x00000100
203/* Handle octal escapes in quoted strings */
204#define WRDSO_OESC_QUOTE 0x00000200
205/* Handle hex escapes in quoted strings */
206#define WRDSO_XESC_QUOTE 0x00000400
207
208#define WRDSO_BSKEEP WRDSO_BSKEEP_WORD
209#define WRDSO_OESC WRDSO_OESC_WORD
210#define WRDSO_XESC WRDSO_XESC_WORD
211
212/* Indices into ws_escape */
213#define WRDSX_WORD 0
214#define WRDSX_QUOTE 1
215
216/* Set escape option F in WS for words (Q==0) or quoted strings (Q==1) */
217#define WRDSO_ESC_SET(ws,q,f) ((ws)->ws_options |= ((f) << 4*(q)))
218/* Test WS for escape option F for words (Q==0) or quoted strings (Q==1) */
219#define WRDSO_ESC_TEST(ws,q,f) ((ws)->ws_options & ((f) << 4*(q)))
220
221#define WRDSE_OK 0
222#define WRDSE_EOF WRDSE_OK
223#define WRDSE_QUOTE 1
224#define WRDSE_NOSPACE 2
225#define WRDSE_USAGE 3
226#define WRDSE_CBRACE 4
227#define WRDSE_UNDEF 5
228#define WRDSE_NOINPUT 6
229#define WRDSE_PAREN 7
230#define WRDSE_GLOBERR 8
231#define WRDSE_USERERR 9
232
233int wordsplit (const char *s, wordsplit_t *ws, int flags);
234int wordsplit_len (const char *s, size_t len, wordsplit_t *ws, int flags);
235void wordsplit_free (wordsplit_t *ws);
236void wordsplit_free_words (wordsplit_t *ws);
237void wordsplit_free_envbuf (wordsplit_t *ws);
238int wordsplit_get_words (wordsplit_t *ws, size_t *wordc, char ***wordv);
239
240static inline void wordsplit_getwords (wordsplit_t *ws, size_t *wordc, char ***wordv)
241 __attribute__ ((deprecated));
242
243static inline void
244wordsplit_getwords (wordsplit_t *ws, size_t *wordc, char ***wordv)
245{
246 wordsplit_get_words (ws, wordc, wordv);
247}
248
249int wordsplit_append (wordsplit_t *wsp, int argc, char **argv);
250
251int wordsplit_c_unquote_char (int c);
252int wordsplit_c_quote_char (int c);
253size_t wordsplit_c_quoted_length (const char *str, int quote_hex, int *quote);
254void wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex);
255
256void wordsplit_perror (wordsplit_t *ws);
257const char *wordsplit_strerror (wordsplit_t *ws);
258
259void wordsplit_clearerr (wordsplit_t *ws);
260
261int wordsplit_varnames(const char *input, char ***ret_names, int af);
262
263#endif
diff --git a/lib/Makefile.am b/lib/Makefile.am
index e5fc376..aa3ee22 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,5 +1,5 @@
1# This file is part of Smap. 1# This file is part of Smap.
2# Copyright (C) 2010, 2014 Sergey Poznyakoff 2# Copyright (C) 2010, 2014, 2019 Sergey Poznyakoff
3# 3#
4# Smap is free software; you can redistribute it and/or modify 4# Smap is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
@@ -35,9 +35,15 @@ libsmap_la_SOURCES = \
35 tracestr.c\ 35 tracestr.c\
36 url.c\ 36 url.c\
37 vasnprintf.c\ 37 vasnprintf.c\
38 wordsplit.c\
39 xscript.c 38 xscript.c
40 39
40nodist_libsmap_la_SOURCES = \
41 wordsplit.c\
42 wordsplit.h
43
44VPATH += $(srcdir)/wordsplit
45EXTRA_DIST = wordsplit/wordsplit.c wordsplit/wordsplit.h
46
41libsmap_la_LDFLAGS = -version-info 0:0:0 47libsmap_la_LDFLAGS = -version-info 0:0:0
42 48
43AM_CPPFLAGS = -I$(top_srcdir)/include 49AM_CPPFLAGS = -I$(top_srcdir)/include -I$(srcdir)/wordsplit
diff --git a/lib/wordsplit b/lib/wordsplit
new file mode 160000
Subproject 6ccb9ad200f6fa0b59a3d17e7e069badb2d39e5
diff --git a/lib/wordsplit.c b/lib/wordsplit.c
deleted file mode 100644
index 96e0f58..0000000
--- a/lib/wordsplit.c
+++ b/dev/null
@@ -1,2447 +0,0 @@
1/* wordsplit - a word splitter
2 Copyright (C) 2009-2016 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3 of the License, or (at your
7 option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20
21#include <errno.h>
22#include <ctype.h>
23#include <unistd.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdio.h>
27#include <stdarg.h>
28#include <pwd.h>
29#include <glob.h>
30
31#if ENABLE_NLS
32# include <gettext.h>
33#else
34# define gettext(msgid) msgid
35#endif
36#define _(msgid) gettext (msgid)
37#define N_(msgid) msgid
38
39#include <smap/wordsplit.h>
40
41#define ISWS(c) ((c)==' '||(c)=='\t'||(c)=='\n')
42#define ISDELIM(ws,c) \
43 (strchr ((ws)->ws_delim, (c)) != NULL)
44#define ISPUNCT(c) (strchr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",(c))!=NULL)
45#define ISUPPER(c) ('A' <= ((unsigned) (c)) && ((unsigned) (c)) <= 'Z')
46#define ISLOWER(c) ('a' <= ((unsigned) (c)) && ((unsigned) (c)) <= 'z')
47#define ISALPHA(c) (ISUPPER(c) || ISLOWER(c))
48#define ISDIGIT(c) ('0' <= ((unsigned) (c)) && ((unsigned) (c)) <= '9')
49#define ISXDIGIT(c) (strchr("abcdefABCDEF", c)!=NULL)
50#define ISALNUM(c) (ISALPHA(c) || ISDIGIT(c))
51#define ISPRINT(c) (' ' <= ((unsigned) (c)) && ((unsigned) (c)) <= 127)
52
53#define ISVARBEG(c) (ISALPHA(c) || c == '_')
54#define ISVARCHR(c) (ISALNUM(c) || c == '_')
55
56#define ALLOC_INIT 128
57#define ALLOC_INCR 128
58
59static void
60_wsplt_alloc_die (struct wordsplit *wsp)
61{
62 wsp->ws_error ("%s", _("memory exhausted"));
63 abort ();
64}
65
66static void
67_wsplt_error (const char *fmt, ...)
68{
69 va_list ap;
70
71 va_start (ap, fmt);
72 vfprintf (stderr, fmt, ap);
73 va_end (ap);
74 fputc ('\n', stderr);
75}
76
77static void wordsplit_free_nodes (struct wordsplit *);
78
79static int
80_wsplt_seterr (struct wordsplit *wsp, int ec)
81{
82 wsp->ws_errno = ec;
83 if (wsp->ws_flags & WRDSF_SHOWERR)
84 wordsplit_perror (wsp);
85 return ec;
86}
87
88static int
89_wsplt_nomem (struct wordsplit *wsp)
90{
91 errno = ENOMEM;
92 wsp->ws_errno = WRDSE_NOSPACE;
93 if (wsp->ws_flags & WRDSF_ENOMEMABRT)
94 wsp->ws_alloc_die (wsp);
95 if (wsp->ws_flags & WRDSF_SHOWERR)
96 wordsplit_perror (wsp);
97 if (!(wsp->ws_flags & WRDSF_REUSE))
98 wordsplit_free (wsp);
99 wordsplit_free_nodes (wsp);
100 return wsp->ws_errno;
101}
102
103static int wordsplit_run (const char *command, size_t length,
104 struct wordsplit *wsp,
105 int flags, int lvl);
106
107static int
108_wsplt_subsplit (struct wordsplit *wsp, struct wordsplit *wss,
109 char const *str, int len,
110 int flags)
111{
112 wss->ws_delim = wsp->ws_delim;
113 wss->ws_debug = wsp->ws_debug;
114 wss->ws_error = wsp->ws_error;
115 wss->ws_alloc_die = wsp->ws_alloc_die;
116
117 if (!(flags & WRDSF_NOVAR))
118 {
119 wss->ws_env = wsp->ws_env;
120 wss->ws_getvar = wsp->ws_getvar;
121 flags |= wsp->ws_flags & (WRDSF_ENV | WRDSF_ENV_KV | WRDSF_GETVAR);
122 }
123 if (!(flags & WRDSF_NOCMD))
124 {
125 wss->ws_command = wsp->ws_command;
126 }
127
128 if ((flags & (WRDSF_NOVAR|WRDSF_NOCMD)) != (WRDSF_NOVAR|WRDSF_NOCMD))
129 {
130 wss->ws_closure = wsp->ws_closure;
131 flags |= wsp->ws_flags & WRDSF_CLOSURE;
132 }
133
134 wss->ws_options = wsp->ws_options;
135
136 flags |= WRDSF_DELIM
137 | WRDSF_ALLOC_DIE
138 | WRDSF_ERROR
139 | WRDSF_DEBUG
140 | (wsp->ws_flags & (WRDSF_SHOWDBG | WRDSF_SHOWERR | WRDSF_OPTIONS));
141
142 return wordsplit_run (str, len, wss, flags, wsp->ws_lvl + 1);
143}
144
145static void
146_wsplt_seterr_sub (struct wordsplit *wsp, struct wordsplit *wss)
147{
148 if (wsp->ws_errno == WRDSE_USERERR)
149 free (wsp->ws_usererr);
150 wsp->ws_errno = wss->ws_errno;
151 if (wss->ws_errno == WRDSE_USERERR)
152 {
153 wsp->ws_usererr = wss->ws_usererr;
154 wss->ws_errno = WRDSE_EOF;
155 wss->ws_usererr = NULL;
156 }
157}
158
159static void
160wordsplit_init0 (struct wordsplit *wsp)
161{
162 if (wsp->ws_flags & WRDSF_REUSE)
163 {
164 if (!(wsp->ws_flags & WRDSF_APPEND))
165 wordsplit_free_words (wsp);
166 wordsplit_clearerr (wsp);
167 }
168 else
169 {
170 wsp->ws_wordv = NULL;
171 wsp->ws_wordc = 0;
172 wsp->ws_wordn = 0;
173 }
174
175 wsp->ws_errno = 0;
176 wsp->ws_head = wsp->ws_tail = NULL;
177}
178
179char wordsplit_c_escape_tab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v";
180
181static int
182wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
183 int flags)
184{
185 wsp->ws_flags = flags;
186
187 if (!(wsp->ws_flags & WRDSF_ALLOC_DIE))
188 wsp->ws_alloc_die = _wsplt_alloc_die;
189 if (!(wsp->ws_flags & WRDSF_ERROR))
190 wsp->ws_error = _wsplt_error;
191
192 if (!(wsp->ws_flags & WRDSF_NOVAR))
193 {
194 /* These will be initialized on first variable assignment */
195 wsp->ws_envidx = wsp->ws_envsiz = 0;
196 wsp->ws_envbuf = NULL;
197 }
198
199 if (!(wsp->ws_flags & WRDSF_NOCMD))
200 {
201 if (!wsp->ws_command)
202 {
203 _wsplt_seterr (wsp, WRDSE_USAGE);
204 errno = EINVAL;
205 return wsp->ws_errno;
206 }
207 }
208
209 if (wsp->ws_flags & WRDSF_SHOWDBG)
210 {
211 if (!(wsp->ws_flags & WRDSF_DEBUG))
212 {
213 if (wsp->ws_flags & WRDSF_ERROR)
214 wsp->ws_debug = wsp->ws_error;
215 else if (wsp->ws_flags & WRDSF_SHOWERR)
216 wsp->ws_debug = _wsplt_error;
217 else
218 wsp->ws_flags &= ~WRDSF_SHOWDBG;
219 }
220 }
221
222 wsp->ws_input = input;
223 wsp->ws_len = len;
224
225 if (!(wsp->ws_flags & WRDSF_DOOFFS))
226 wsp->ws_offs = 0;
227
228 if (!(wsp->ws_flags & WRDSF_DELIM))
229 wsp->ws_delim = " \t\n";
230
231 if (!(wsp->ws_flags & WRDSF_COMMENT))
232 wsp->ws_comment = NULL;
233
234 if (!(wsp->ws_flags & WRDSF_CLOSURE))
235 wsp->ws_closure = NULL;
236
237 if (!(wsp->ws_flags & WRDSF_OPTIONS))
238 wsp->ws_options = 0;
239
240 if (wsp->ws_flags & WRDSF_ESCAPE)
241 {
242 if (!wsp->ws_escape[WRDSX_WORD])
243 wsp->ws_escape[WRDSX_WORD] = "";
244 if (!wsp->ws_escape[WRDSX_QUOTE])
245 wsp->ws_escape[WRDSX_QUOTE] = "";
246 }
247 else
248 {
249 if (wsp->ws_flags & WRDSF_CESCAPES)
250 {
251 wsp->ws_escape[WRDSX_WORD] = wordsplit_c_escape_tab;
252 wsp->ws_escape[WRDSX_QUOTE] = wordsplit_c_escape_tab;
253 wsp->ws_options |= WRDSO_OESC_QUOTE | WRDSO_OESC_WORD
254 | WRDSO_XESC_QUOTE | WRDSO_XESC_WORD;
255 }
256 else
257 {
258 wsp->ws_escape[WRDSX_WORD] = "";
259 wsp->ws_escape[WRDSX_QUOTE] = "\\\\\"\"";
260 wsp->ws_options |= WRDSO_BSKEEP_QUOTE;
261 }
262 }
263
264 wsp->ws_endp = 0;
265
266 wordsplit_init0 (wsp);
267
268 return 0;
269}
270
271static int
272alloc_space (struct wordsplit *wsp, size_t count)
273{
274 size_t offs = (wsp->ws_flags & WRDSF_DOOFFS) ? wsp->ws_offs : 0;
275 char **ptr;
276 size_t newalloc;
277
278 if (wsp->ws_wordv == NULL)
279 {
280 newalloc = offs + count > ALLOC_INIT ? count : ALLOC_INIT;
281 ptr = calloc (newalloc, sizeof (ptr[0]));
282 }
283 else if (wsp->ws_wordn < offs + wsp->ws_wordc + count)
284 {
285 newalloc = offs + wsp->ws_wordc +
286 (count > ALLOC_INCR ? count : ALLOC_INCR);
287 ptr = realloc (wsp->ws_wordv, newalloc * sizeof (ptr[0]));
288 }
289 else
290 return 0;
291
292 if (ptr)
293 {
294 wsp->ws_wordn = newalloc;
295 wsp->ws_wordv = ptr;
296 }
297 else
298 return _wsplt_nomem (wsp);
299 return 0;
300}
301
302
303/* Node state flags */
304 #define _WSNF_NULL 0x01/* null node (a noop) */
305 #define _WSNF_WORD 0x02/* node contains word in v.word */
306 #define _WSNF_QUOTE 0x04/* text is quoted */
307 #define _WSNF_NOEXPAND 0x08/* text is not subject to expansion */
308 #define _WSNF_JOIN 0x10/* node must be joined with the next node */
309 #define _WSNF_SEXP 0x20/* is a sed expression */
310#define _WSNF_DELIM 0x40 /* node is a delimiter */
311
312 #define _WSNF_EMPTYOK 0x0100/* special flag indicating that
313 wordsplit_add_segm must add the
314 segment even if it is empty */
315
316struct wordsplit_node
317{
318 struct wordsplit_node *prev;/* Previous element */
319 struct wordsplit_node *next;/* Next element */
320 int flags; /* Node flags */
321 union
322 {
323 struct
324 {
325 size_t beg; /* Start of word in ws_input */
326 size_t end; /* End of word in ws_input */
327 } segm;
328 char *word;
329 } v;
330};
331
332static const char *
333wsnode_flagstr (int flags)
334{
335 static char retbuf[7];
336 char *p = retbuf;
337
338 if (flags & _WSNF_WORD)
339 *p++ = 'w';
340 else if (flags & _WSNF_NULL)
341 *p++ = 'n';
342 else
343 *p++ = '-';
344 if (flags & _WSNF_QUOTE)
345 *p++ = 'q';
346 else
347 *p++ = '-';
348 if (flags & _WSNF_NOEXPAND)
349 *p++ = 'E';
350 else
351 *p++ = '-';
352 if (flags & _WSNF_JOIN)
353 *p++ = 'j';
354 else
355 *p++ = '-';
356 if (flags & _WSNF_SEXP)
357 *p++ = 's';
358 else
359 *p++ = '-';
360 if (flags & _WSNF_DELIM)
361 *p++ = 'd';
362 else
363 *p++ = '-';
364 *p = 0;
365 return retbuf;
366}
367
368static const char *
369wsnode_ptr (struct wordsplit *wsp, struct wordsplit_node *p)
370{
371 if (p->flags & _WSNF_NULL)
372 return "";
373 else if (p->flags & _WSNF_WORD)
374 return p->v.word;
375 else
376 return wsp->ws_input + p->v.segm.beg;
377}
378
379static size_t
380wsnode_len (struct wordsplit_node *p)
381{
382 if (p->flags & _WSNF_NULL)
383 return 0;
384 else if (p->flags & _WSNF_WORD)
385 return strlen (p->v.word);
386 else
387 return p->v.segm.end - p->v.segm.beg;
388}
389
390static int
391wsnode_new (struct wordsplit *wsp, struct wordsplit_node **pnode)
392{
393 struct wordsplit_node *node = calloc (1, sizeof (*node));
394 if (!node)
395 return _wsplt_nomem (wsp);
396 *pnode = node;
397 return 0;
398}
399
400static void
401wsnode_free (struct wordsplit_node *p)
402{
403 if (p->flags & _WSNF_WORD)
404 free (p->v.word);
405 free (p);
406}
407
408static void
409wsnode_append (struct wordsplit *wsp, struct wordsplit_node *node)
410{
411 node->next = NULL;
412 node->prev = wsp->ws_tail;
413 if (wsp->ws_tail)
414 wsp->ws_tail->next = node;
415 else
416 wsp->ws_head = node;
417 wsp->ws_tail = node;
418}
419
420static void
421wsnode_remove (struct wordsplit *wsp, struct wordsplit_node *node)
422{
423 struct wordsplit_node *p;
424
425 p = node->prev;
426 if (p)
427 {
428 p->next = node->next;
429 if (!node->next)
430 p->flags &= ~_WSNF_JOIN;
431 }
432 else
433 wsp->ws_head = node->next;
434
435 p = node->next;
436 if (p)
437 p->prev = node->prev;
438 else
439 wsp->ws_tail = node->prev;
440
441 node->next = node->prev = NULL;
442}
443
444static void
445wsnode_insert (struct wordsplit *wsp, struct wordsplit_node *node,
446 struct wordsplit_node *anchor, int before)
447{
448 if (!wsp->ws_head)
449 {
450 node->next = node->prev = NULL;
451 wsp->ws_head = wsp->ws_tail = node;
452 }
453 else if (before)
454 {
455 if (anchor->prev)
456 wsnode_insert (wsp, node, anchor->prev, 0);
457 else
458 {
459 node->prev = NULL;
460 node->next = anchor;
461 anchor->prev = node;
462 wsp->ws_head = node;
463 }
464 }
465 else
466 {
467 struct wordsplit_node *p;
468
469 p = anchor->next;
470 if (p)
471 p->prev = node;
472 else
473 wsp->ws_tail = node;
474 node->next = p;
475 node->prev = anchor;
476 anchor->next = node;
477 }
478}
479
480static int
481wordsplit_add_segm (struct wordsplit *wsp, size_t beg, size_t end, int flg)
482{
483 struct wordsplit_node *node;
484 int rc;
485
486 if (end == beg && !(flg & _WSNF_EMPTYOK))
487 return 0;
488 rc = wsnode_new (wsp, &node);
489 if (rc)
490 return rc;
491 node->flags = flg & ~(_WSNF_WORD | _WSNF_EMPTYOK);
492 node->v.segm.beg = beg;
493 node->v.segm.end = end;
494 wsnode_append (wsp, node);
495 return 0;
496}
497
498static void
499wordsplit_free_nodes (struct wordsplit *wsp)
500{
501 struct wordsplit_node *p;
502
503 for (p = wsp->ws_head; p;)
504 {
505 struct wordsplit_node *next = p->next;
506 wsnode_free (p);
507 p = next;
508 }
509 wsp->ws_head = wsp->ws_tail = NULL;
510}
511
512static void
513wordsplit_dump_nodes (struct wordsplit *wsp)
514{
515 struct wordsplit_node *p;
516 int n = 0;
517
518 for (p = wsp->ws_head, n = 0; p; p = p->next, n++)
519 {
520 if (p->flags & _WSNF_WORD)
521 wsp->ws_debug ("(%02d) %4d: %p: %#04x (%s):%s;",
522 wsp->ws_lvl,
523 n, p, p->flags, wsnode_flagstr (p->flags), p->v.word);
524 else
525 wsp->ws_debug ("(%02d) %4d: %p: %#04x (%s):%.*s;",
526 wsp->ws_lvl,
527 n, p, p->flags, wsnode_flagstr (p->flags),
528 (int) (p->v.segm.end - p->v.segm.beg),
529 wsp->ws_input + p->v.segm.beg);
530 }
531}
532
533static int
534coalesce_segment (struct wordsplit *wsp, struct wordsplit_node *node)
535{
536 struct wordsplit_node *p, *end;
537 size_t len = 0;
538 char *buf, *cur;
539 int stop;
540
541 for (p = node; p && (p->flags & _WSNF_JOIN); p = p->next)
542 {
543 len += wsnode_len (p);
544 }
545 if (p)
546 len += wsnode_len (p);
547 end = p;
548
549 buf = malloc (len + 1);
550 if (!buf)
551 return _wsplt_nomem (wsp);
552 cur = buf;
553
554 p = node;
555 for (stop = 0; !stop;)
556 {
557 struct wordsplit_node *next = p->next;
558 const char *str = wsnode_ptr (wsp, p);
559 size_t slen = wsnode_len (p);
560
561 memcpy (cur, str, slen);
562 cur += slen;
563 if (p != node)
564 {
565 node->flags |= p->flags & _WSNF_QUOTE;
566 wsnode_remove (wsp, p);
567 stop = p == end;
568 wsnode_free (p);
569 }
570 p = next;
571 }
572
573 *cur = 0;
574
575 node->flags &= ~_WSNF_JOIN;
576
577 if (node->flags & _WSNF_WORD)
578 free (node->v.word);
579 else
580 node->flags |= _WSNF_WORD;
581 node->v.word = buf;
582 return 0;
583}
584
585static void wordsplit_string_unquote_copy (struct wordsplit *ws, int inquote,
586 char *dst, const char *src,
587 size_t n);
588
589static int
590wsnode_quoteremoval (struct wordsplit *wsp)
591{
592 struct wordsplit_node *p;
593
594 for (p = wsp->ws_head; p; p = p->next)
595 {
596 const char *str = wsnode_ptr (wsp, p);
597 size_t slen = wsnode_len (p);
598 int unquote;
599
600 if (wsp->ws_flags & WRDSF_QUOTE)
601 {
602 unquote = !(p->flags & _WSNF_NOEXPAND);
603 }
604 else
605 unquote = 0;
606
607 if (unquote)
608 {
609 if (!(p->flags & _WSNF_WORD))
610 {
611 char *newstr = malloc (slen + 1);
612 if (!newstr)
613 return _wsplt_nomem (wsp);
614 memcpy (newstr, str, slen);
615 newstr[slen] = 0;
616 p->v.word = newstr;
617 p->flags |= _WSNF_WORD;
618 }
619
620 wordsplit_string_unquote_copy (wsp, p->flags & _WSNF_QUOTE,
621 p->v.word, str, slen);
622 }
623 }
624 return 0;
625}
626
627static int
628wsnode_coalesce (struct wordsplit *wsp)
629{
630 struct wordsplit_node *p;
631
632 for (p = wsp->ws_head; p; p = p->next)
633 {
634 if (p->flags & _WSNF_JOIN)
635 if (coalesce_segment (wsp, p))
636 return 1;
637 }
638 return 0;
639}
640
641static int
642wordsplit_finish (struct wordsplit *wsp)
643{
644 struct wordsplit_node *p;
645 size_t n;
646
647 n = 0;
648
649 for (p = wsp->ws_head; p; p = p->next)
650 n++;
651
652 if (alloc_space (wsp, n + 1))
653 return 1;
654
655 for (p = wsp->ws_head; p; p = p->next)
656 {
657 const char *str = wsnode_ptr (wsp, p);
658 size_t slen = wsnode_len (p);
659 char *newstr = malloc (slen + 1);
660
661 /* Assign newstr first, even if it is NULL. This way
662 wordsplit_free will work even if we return
663 nomem later. */
664 wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = newstr;
665 if (!newstr)
666 return _wsplt_nomem (wsp);
667 memcpy (newstr, str, slen);
668 newstr[slen] = 0;
669
670 wsp->ws_wordc++;
671
672 }
673 wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = NULL;
674 return 0;
675}
676
677int
678wordsplit_append (wordsplit_t *wsp, int argc, char **argv)
679{
680 int rc;
681 size_t i;
682
683 rc = alloc_space (wsp, wsp->ws_wordc + argc + 1);
684 if (rc)
685 return rc;
686 for (i = 0; i < argc; i++)
687 {
688 char *newstr = strdup (argv[i]);
689 if (!newstr)
690 {
691 while (i > 0)
692 {
693 free (wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc + i - 1]);
694 wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc + i - 1] = NULL;
695 i--;
696 }
697 return _wsplt_nomem (wsp);
698 }
699 wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc + i] = newstr;
700 }
701 wsp->ws_wordc += i;
702 wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = NULL;
703 return 0;
704}
705
706/* Variable expansion */
707static int
708node_split_prefix (struct wordsplit *wsp,
709 struct wordsplit_node **ptail,
710 struct wordsplit_node *node,
711 size_t beg, size_t len, int flg)
712{
713 struct wordsplit_node *newnode;
714
715 if (len == 0)
716 return 0;
717 if (wsnode_new (wsp, &newnode))
718 return 1;
719 wsnode_insert (wsp, newnode, *ptail, 0);
720 if (node->flags & _WSNF_WORD)
721 {
722 const char *str = wsnode_ptr (wsp, node);
723 char *newstr = malloc (len + 1);
724 if (!newstr)
725 return _wsplt_nomem (wsp);
726 memcpy (newstr, str + beg, len);
727 newstr[len] = 0;
728 newnode->flags = _WSNF_WORD;
729 newnode->v.word = newstr;
730 }
731 else
732 {
733 newnode->v.segm.beg = node->v.segm.beg + beg;
734 newnode->v.segm.end = newnode->v.segm.beg + len;
735 }
736 newnode->flags |= flg;
737 *ptail = newnode;
738 return 0;
739}
740
741static int
742find_closing_paren (const char *str, size_t i, size_t len, size_t *poff,
743 char *paren)
744{
745 enum { st_init, st_squote, st_dquote } state = st_init;
746 size_t level = 1;
747
748 for (; i < len; i++)
749 {
750 switch (state)
751 {
752 case st_init:
753 switch (str[i])
754 {
755 default:
756 if (str[i] == paren[0])
757 {
758 level++;
759 break;
760 }
761 else if (str[i] == paren[1])
762 {
763 if (--level == 0)
764 {
765 *poff = i;
766 return 0;
767 }
768 break;
769 }
770 break;
771
772 case '"':
773 state = st_dquote;
774 break;
775
776 case '\'':
777 state = st_squote;
778 break;
779 }
780 break;
781
782 case st_squote:
783 if (str[i] == '\'')
784 state = st_init;
785 break;
786
787 case st_dquote:
788 if (str[i] == '\\')
789 i++;
790 else if (str[i] == '"')
791 state = st_init;
792 break;
793 }
794 }
795 return 1;
796}
797
798static int
799wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len,
800 char const **ret)
801{
802 size_t i;
803
804 if (!(wsp->ws_flags & WRDSF_ENV))
805 return WRDSE_UNDEF;
806
807 if (wsp->ws_flags & WRDSF_ENV_KV)
808 {
809 /* A key-value pair environment */
810 for (i = 0; wsp->ws_env[i]; i++)
811 {
812 size_t elen = strlen (wsp->ws_env[i]);
813 if (elen == len && memcmp (wsp->ws_env[i], name, elen) == 0)
814 {
815 *ret = wsp->ws_env[i + 1];
816 return WRDSE_OK;
817 }
818 /* Skip the value. Break the loop if it is NULL. */
819 i++;
820 if (wsp->ws_env[i] == NULL)
821 break;
822 }
823 }
824 else if (wsp->ws_env)
825 {
826 /* Usual (A=B) environment. */
827 for (i = 0; wsp->ws_env[i]; i++)
828 {
829 size_t j;
830 const char *var = wsp->ws_env[i];
831
832 for (j = 0; j < len; j++)
833 if (name[j] != var[j])
834 break;
835 if (j == len && var[j] == '=')
836 {
837 *ret = var + j + 1;
838 return WRDSE_OK;
839 }
840 }
841 }
842 return WRDSE_UNDEF;
843}
844
845static int
846wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
847 char *value)
848{
849 int n = (wsp->ws_flags & WRDSF_ENV_KV) ? 2 : 1;
850 char *v;
851
852 if (wsp->ws_envidx + n >= wsp->ws_envsiz)
853 {
854 size_t sz;
855 char **newenv;
856
857 if (!wsp->ws_envbuf)
858 {
859 if (wsp->ws_flags & WRDSF_ENV)
860 {
861 size_t i = 0, j;
862
863 if (wsp->ws_env)
864 {
865 for (; wsp->ws_env[i]; i++)
866 ;
867 }
868
869 sz = i + n + 1;
870
871 newenv = calloc (sz, sizeof(newenv[0]));
872 if (!newenv)
873 return _wsplt_nomem (wsp);
874
875 for (j = 0; j < i; j++)
876 {
877 newenv[j] = strdup (wsp->ws_env[j]);
878 if (!newenv[j])
879 {
880 for (; j > 1; j--)
881 free (newenv[j-1]);
882 free (newenv[j-1]);
883 return _wsplt_nomem (wsp);
884 }
885 }
886 newenv[j] = NULL;
887
888 wsp->ws_envbuf = newenv;
889 wsp->ws_envidx = i;
890 wsp->ws_envsiz = sz;
891 wsp->ws_env = (const char**) wsp->ws_envbuf;
892 }
893 else
894 {
895 newenv = calloc (WORDSPLIT_ENV_INIT, sizeof(newenv[0]));
896 if (!newenv)
897 return _wsplt_nomem (wsp);
898 wsp->ws_envbuf = newenv;
899 wsp->ws_envidx = 0;
900 wsp->ws_envsiz = WORDSPLIT_ENV_INIT;
901 wsp->ws_env = (const char**) wsp->ws_envbuf;
902 wsp->ws_flags |= WRDSF_ENV;
903 }
904 }
905 else
906 {
907 wsp->ws_envsiz *= 2;
908 newenv = realloc (wsp->ws_envbuf,
909 wsp->ws_envsiz * sizeof (wsp->ws_envbuf[0]));
910 if (!newenv)
911 return _wsplt_nomem (wsp);
912 wsp->ws_envbuf = newenv;
913 wsp->ws_env = (const char**) wsp->ws_envbuf;
914 }
915 }
916
917 if (wsp->ws_flags & WRDSF_ENV_KV)
918 {
919 /* A key-value pair environment */
920 char *p = malloc (namelen + 1);
921 if (!p)
922 return _wsplt_nomem (wsp);
923 memcpy (p, name, namelen);
924 p[namelen] = 0;
925
926 v = strdup (value);
927 if (!v)
928 {
929 free (p);
930 return _wsplt_nomem (wsp);
931 }
932 wsp->ws_env[wsp->ws_envidx++] = p;
933 wsp->ws_env[wsp->ws_envidx++] = v;
934 }
935 else
936 {
937 v = malloc (namelen + strlen(value) + 2);
938 if (!v)
939 return _wsplt_nomem (wsp);
940 memcpy (v, name, namelen);
941 v[namelen++] = '=';
942 strcpy(v + namelen, value);
943 wsp->ws_env[wsp->ws_envidx++] = v;
944 }
945 wsp->ws_env[wsp->ws_envidx++] = NULL;
946 return WRDSE_OK;
947}
948
949static int
950expvar (struct wordsplit *wsp, const char *str, size_t len,
951 struct wordsplit_node **ptail, const char **pend, int flg)
952{
953 size_t i = 0;
954 const char *defstr = NULL;
955 char *value;
956 const char *vptr;
957 struct wordsplit_node *newnode;
958 const char *start = str - 1;
959 int rc;
960 struct wordsplit ws;
961
962 if (ISVARBEG (str[0]))
963 {
964 for (i = 1; i < len; i++)
965 if (!ISVARCHR (str[i]))
966 break;
967 *pend = str + i - 1;
968 }
969 else if (str[0] == '{')
970 {
971 str++;
972 len--;
973 for (i = 1; i < len; i++)
974 {
975 if (str[i] == ':')
976 {
977 size_t j;
978
979 defstr = str + i + 1;
980 if (find_closing_paren (str, i + 1, len, &j, "{}"))
981 return _wsplt_seterr (wsp, WRDSE_CBRACE);
982 *pend = str + j;
983 break;
984 }
985 else if (str[i] == '}')
986 {
987 defstr = NULL;
988 *pend = str + i;
989 break;
990 }
991 else if (strchr ("-+?=", str[i]))
992 {
993 size_t j;
994
995 defstr = str + i;
996 if (find_closing_paren (str, i, len, &j, "{}"))
997 return _wsplt_seterr (wsp, WRDSE_CBRACE);
998 *pend = str + j;
999 break;
1000 }
1001 }
1002 if (i == len)
1003 return _wsplt_seterr (wsp, WRDSE_CBRACE);
1004 }
1005 else
1006 {
1007 if (wsnode_new (wsp, &newnode))
1008 return 1;
1009 wsnode_insert (wsp, newnode, *ptail, 0);
1010 *ptail = newnode;
1011 newnode->flags = _WSNF_WORD | flg;
1012 newnode->v.word = malloc (3);
1013 if (!newnode->v.word)
1014 return _wsplt_nomem (wsp);
1015 newnode->v.word[0] = '$';
1016 newnode->v.word[1] = str[0];
1017 newnode->v.word[2] = 0;
1018 *pend = str;
1019 return 0;
1020 }
1021
1022 /* Actually expand the variable */
1023 /* str - start of the variable name
1024 i - its length
1025 defstr - default replacement str */
1026
1027 if (defstr && strchr("-+?=", defstr[0]) == 0)
1028 {
1029 rc = WRDSE_UNDEF;
1030 defstr = NULL;
1031 }
1032 else
1033 {
1034 rc = wordsplit_find_env (wsp, str, i, &vptr);
1035 if (rc == WRDSE_OK)
1036 {
1037 value = strdup (vptr);
1038 if (!value)
1039 rc = WRDSE_NOSPACE;
1040 }
1041 else if (wsp->ws_flags & WRDSF_GETVAR)
1042 rc = wsp->ws_getvar (&value, str, i, wsp->ws_closure);
1043 else
1044 rc = WRDSE_UNDEF;
1045
1046 if (rc == WRDSE_OK
1047 && (!value || value[0] == 0)
1048 && defstr && defstr[-1] == ':')
1049 {
1050 free (value);
1051 rc = WRDSE_UNDEF;
1052 }
1053 }
1054
1055 switch (rc)
1056 {
1057 case WRDSE_OK:
1058 if (defstr && *defstr == '+')
1059 {
1060 size_t size = *pend - ++defstr;
1061
1062 rc = _wsplt_subsplit (wsp, &ws, defstr, size,
1063 WRDSF_NOSPLIT | WRDSF_WS | WRDSF_QUOTE |
1064 (wsp->ws_flags &
1065 (WRDSF_NOVAR | WRDSF_NOCMD)));
1066 if (rc)
1067 return rc;
1068 free (value);
1069 value = ws.ws_wordv[0];
1070 ws.ws_wordv[0] = NULL;
1071 wordsplit_free (&ws);
1072 }
1073 break;
1074
1075 case WRDSE_UNDEF:
1076 if (defstr)
1077 {
1078 size_t size;
1079 if (*defstr == '-' || *defstr == '=')
1080 {
1081 size = *pend - ++defstr;
1082
1083 rc = _wsplt_subsplit (wsp, &ws, defstr, size,
1084 WRDSF_NOSPLIT | WRDSF_WS | WRDSF_QUOTE |
1085 (wsp->ws_flags &
1086 (WRDSF_NOVAR | WRDSF_NOCMD)));
1087 if (rc)
1088 return rc;
1089
1090 value = ws.ws_wordv[0];
1091 ws.ws_wordv[0] = NULL;
1092 wordsplit_free (&ws);
1093
1094 if (defstr[-1] == '=')
1095 wsplt_assign_var (wsp, str, i, value);
1096 }
1097 else
1098 {
1099 if (*defstr == '?')
1100 {
1101 size = *pend - ++defstr;
1102 if (size == 0)
1103 wsp->ws_error (_("%.*s: variable null or not set"),
1104 (int) i, str);
1105 else
1106 {
1107 rc = _wsplt_subsplit (wsp, &ws, defstr, size,
1108 WRDSF_NOSPLIT | WRDSF_WS |
1109 WRDSF_QUOTE |
1110 (wsp->ws_flags &
1111 (WRDSF_NOVAR | WRDSF_NOCMD)));
1112 if (rc == 0)
1113 wsp->ws_error ("%.*s: %s",
1114 (int) i, str, ws.ws_wordv[0]);
1115 else
1116 wsp->ws_error ("%.*s: %.*s",
1117 (int) i, str, (int) size, defstr);
1118 wordsplit_free (&ws);
1119 }
1120 }
1121 value = NULL;
1122 }
1123 }
1124 else if (wsp->ws_flags & WRDSF_UNDEF)
1125 {
1126 _wsplt_seterr (wsp, WRDSE_UNDEF);
1127 return 1;
1128 }
1129 else
1130 {
1131 if (wsp->ws_flags & WRDSF_WARNUNDEF)
1132 wsp->ws_error (_("warning: undefined variable `%.*s'"),
1133 (int) i, str);
1134 if (wsp->ws_flags & WRDSF_KEEPUNDEF)
1135 value = NULL;
1136 else
1137 {
1138 value = strdup ("");
1139 if (!value)
1140 return _wsplt_nomem (wsp);
1141 }
1142 }
1143 break;
1144
1145 case WRDSE_NOSPACE:
1146 return _wsplt_nomem (wsp);
1147
1148 case WRDSE_USERERR:
1149 if (wsp->ws_errno == WRDSE_USERERR)
1150 free (wsp->ws_usererr);
1151 wsp->ws_usererr = value;
1152 /* fall through */
1153 default:
1154 _wsplt_seterr (wsp, rc);
1155 return 1;
1156 }
1157
1158 if (value)
1159 {
1160 if (flg & _WSNF_QUOTE)
1161 {
1162 if (wsnode_new (wsp, &newnode))
1163 return 1;
1164 wsnode_insert (wsp, newnode, *ptail, 0);
1165 *ptail = newnode;
1166 newnode->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg;
1167 newnode->v.word = value;
1168 }
1169 else if (*value == 0)
1170 {
1171 free (value);
1172 /* Empty string is a special case */
1173 if (wsnode_new (wsp, &newnode))
1174 return 1;
1175 wsnode_insert (wsp, newnode, *ptail, 0);
1176 *ptail = newnode;
1177 newnode->flags = _WSNF_NULL;
1178 }
1179 else
1180 {
1181 struct wordsplit ws;
1182 int i, rc;
1183
1184 rc = _wsplt_subsplit (wsp, &ws, value, strlen (value),
1185 WRDSF_NOVAR | WRDSF_NOCMD |
1186 WRDSF_QUOTE);
1187 free (value);
1188 if (rc)
1189 {
1190 _wsplt_seterr_sub (wsp, &ws);
1191 wordsplit_free (&ws);
1192 return 1;
1193 }
1194 for (i = 0; i < ws.ws_wordc; i++)
1195 {
1196 if (wsnode_new (wsp, &newnode))
1197 return 1;
1198 wsnode_insert (wsp, newnode, *ptail, 0);
1199 *ptail = newnode;
1200 newnode->flags = _WSNF_WORD |
1201 _WSNF_NOEXPAND |
1202 (i + 1 < ws.ws_wordc ? (flg & ~_WSNF_JOIN) : flg);
1203 newnode->v.word = strdup (ws.ws_wordv[i]);
1204 if (!newnode->v.word)
1205 return _wsplt_nomem (wsp);
1206 }
1207 wordsplit_free (&ws);
1208 }
1209 }
1210 else if (wsp->ws_flags & WRDSF_KEEPUNDEF)
1211 {
1212 size_t size = *pend - start + 1;
1213
1214 if (wsnode_new (wsp, &newnode))
1215 return 1;
1216 wsnode_insert (wsp, newnode, *ptail, 0);
1217 *ptail = newnode;
1218 newnode->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg;
1219 newnode->v.word = malloc (size + 1);
1220 if (!newnode->v.word)
1221 return _wsplt_nomem (wsp);
1222 memcpy (newnode->v.word, start, size);
1223 newnode->v.word[size] = 0;
1224 }
1225 else
1226 {
1227 if (wsnode_new (wsp, &newnode))
1228 return 1;
1229 wsnode_insert (wsp, newnode, *ptail, 0);
1230 *ptail = newnode;
1231 newnode->flags = _WSNF_NULL;
1232 }
1233 return 0;
1234}
1235
1236static int
1237begin_var_p (int c)
1238{
1239 return c == '{' || ISVARBEG (c);
1240}
1241
1242static int
1243node_expand (struct wordsplit *wsp, struct wordsplit_node *node,
1244 int (*beg_p) (int),
1245 int (*ws_exp_fn) (struct wordsplit *wsp,
1246 const char *str, size_t len,
1247 struct wordsplit_node **ptail,
1248 const char **pend,
1249 int flg))
1250{
1251 const char *str = wsnode_ptr (wsp, node);
1252 size_t slen = wsnode_len (node);
1253 const char *end = str + slen;
1254 const char *p;
1255 size_t off = 0;
1256 struct wordsplit_node *tail = node;
1257
1258 for (p = str; p < end; p++)
1259 {
1260 if (*p == '\\')
1261 {
1262 p++;
1263 continue;
1264 }
1265 if (*p == '$' && beg_p (p[1]))
1266 {
1267 size_t n = p - str;
1268
1269 if (tail != node)
1270 tail->flags |= _WSNF_JOIN;
1271 if (node_split_prefix (wsp, &tail, node, off, n, _WSNF_JOIN))
1272 return 1;
1273 p++;
1274 if (ws_exp_fn (wsp, p, slen - n, &tail, &p,
1275 node->flags & (_WSNF_JOIN | _WSNF_QUOTE)))
1276 return 1;
1277 off += p - str + 1;
1278 str = p + 1;
1279 }
1280 }
1281 if (p > str)
1282 {
1283 if (tail != node)
1284 tail->flags |= _WSNF_JOIN;
1285 if (node_split_prefix (wsp, &tail, node, off, p - str,
1286 node->flags & (_WSNF_JOIN|_WSNF_QUOTE)))
1287 return 1;
1288 }
1289 if (tail != node)
1290 {
1291 wsnode_remove (wsp, node);
1292 wsnode_free (node);
1293 }
1294 return 0;
1295}
1296
1297/* Remove NULL nodes from the list */
1298static void
1299wsnode_nullelim (struct wordsplit *wsp)
1300{
1301 struct wordsplit_node *p;
1302
1303 for (p = wsp->ws_head; p;)
1304 {
1305 struct wordsplit_node *next = p->next;
1306 if (p->flags & _WSNF_DELIM && p->prev)
1307 p->prev->flags &= ~_WSNF_JOIN;
1308 if (p->flags & _WSNF_NULL)
1309 {
1310 wsnode_remove (wsp, p);
1311 wsnode_free (p);
1312 }
1313 p = next;
1314 }
1315}
1316
1317static int
1318wordsplit_varexp (struct wordsplit *wsp)
1319{
1320 struct wordsplit_node *p;
1321
1322 for (p = wsp->ws_head; p;)
1323 {
1324 struct wordsplit_node *next = p->next;
1325 if (!(p->flags & _WSNF_NOEXPAND))
1326 if (node_expand (wsp, p, begin_var_p, expvar))
1327 return 1;
1328 p = next;
1329 }
1330
1331 wsnode_nullelim (wsp);
1332 return 0;
1333}
1334
1335static int
1336begin_cmd_p (int c)
1337{
1338 return c == '(';
1339}
1340
1341static int
1342expcmd (struct wordsplit *wsp, const char *str, size_t len,
1343 struct wordsplit_node **ptail, const char **pend, int flg)
1344{
1345 int rc;
1346 size_t j;
1347 char *value;
1348 struct wordsplit_node *newnode;
1349
1350 str++;
1351 len--;
1352
1353 if (find_closing_paren (str, 0, len, &j, "()"))
1354 {
1355 _wsplt_seterr (wsp, WRDSE_PAREN);
1356 return 1;
1357 }
1358
1359 *pend = str + j;
1360 if (wsp->ws_options & WRDSO_ARGV)
1361 {
1362 struct wordsplit ws;
1363
1364 rc = _wsplt_subsplit (wsp, &ws, str, j,
1365 WRDSF_WS | WRDSF_QUOTE);
1366 if (rc)
1367 {
1368 _wsplt_seterr_sub (wsp, &ws);
1369 wordsplit_free (&ws);
1370 return 1;
1371 }
1372 rc = wsp->ws_command (&value, str, j, ws.ws_wordv, wsp->ws_closure);
1373 wordsplit_free (&ws);
1374 }
1375 else
1376 rc = wsp->ws_command (&value, str, j, NULL, wsp->ws_closure);
1377
1378 if (rc == WRDSE_NOSPACE)
1379 return _wsplt_nomem (wsp);
1380 else if (rc)
1381 {
1382 if (rc == WRDSE_USERERR)
1383 {
1384 if (wsp->ws_errno == WRDSE_USERERR)
1385 free (wsp->ws_usererr);
1386 wsp->ws_usererr = value;
1387 }
1388 _wsplt_seterr (wsp, rc);
1389 return 1;
1390 }
1391
1392 if (value)
1393 {
1394 if (flg & _WSNF_QUOTE)
1395 {
1396 if (wsnode_new (wsp, &newnode))
1397 return 1;
1398 wsnode_insert (wsp, newnode, *ptail, 0);
1399 *ptail = newnode;
1400 newnode->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg;
1401 newnode->v.word = value;
1402 }
1403 else if (*value == 0)
1404 {
1405 free (value);
1406 /* Empty string is a special case */
1407 if (wsnode_new (wsp, &newnode))
1408 return 1;
1409 wsnode_insert (wsp, newnode, *ptail, 0);
1410 *ptail = newnode;
1411 newnode->flags = _WSNF_NULL;
1412 }
1413 else
1414 {
1415 struct wordsplit ws;
1416 int i, rc;
1417
1418 rc = _wsplt_subsplit (wsp, &ws, value, strlen (value),
1419 WRDSF_NOVAR | WRDSF_NOCMD |
1420 WRDSF_WS | WRDSF_QUOTE);
1421 free (value);
1422 if (rc)
1423 {
1424 _wsplt_seterr_sub (wsp, &ws);
1425 wordsplit_free (&ws);
1426 return 1;
1427 }
1428 for (i = 0; i < ws.ws_wordc; i++)
1429 {
1430 if (wsnode_new (wsp, &newnode))
1431 return 1;
1432 wsnode_insert (wsp, newnode, *ptail, 0);
1433 *ptail = newnode;
1434 newnode->flags = _WSNF_WORD |
1435 _WSNF_NOEXPAND |
1436 (i + 1 < ws.ws_wordc ? (flg & ~_WSNF_JOIN) : flg);
1437 newnode->v.word = strdup (ws.ws_wordv[i]);
1438 if (!newnode->v.word)
1439 return _wsplt_nomem (wsp);
1440 }
1441 wordsplit_free (&ws);
1442 }
1443 }
1444 else
1445 {
1446 if (wsnode_new (wsp, &newnode))
1447 return 1;
1448 wsnode_insert (wsp, newnode, *ptail, 0);
1449 *ptail = newnode;
1450 newnode->flags = _WSNF_NULL;
1451 }
1452 return 0;
1453}
1454
1455static int
1456wordsplit_cmdexp (struct wordsplit *wsp)
1457{
1458 struct wordsplit_node *p;
1459
1460 for (p = wsp->ws_head; p;)
1461 {
1462 struct wordsplit_node *next = p->next;
1463 if (!(p->flags & _WSNF_NOEXPAND))
1464 if (node_expand (wsp, p, begin_cmd_p, expcmd))
1465 return 1;
1466 p = next;
1467 }
1468
1469 wsnode_nullelim (wsp);
1470 return 0;
1471}
1472
1473/* Strip off any leading and trailing whitespace. This function is called
1474 right after the initial scanning, therefore it assumes that every
1475 node in the list is a text reference node. */
1476static int
1477wordsplit_trimws (struct wordsplit *wsp)
1478{
1479 struct wordsplit_node *p;
1480
1481 for (p = wsp->ws_head; p; p = p->next)
1482 {
1483 size_t n;
1484
1485 if (!(p->flags & _WSNF_QUOTE))
1486 {
1487 /* Skip leading whitespace: */
1488 for (n = p->v.segm.beg; n < p->v.segm.end && ISWS (wsp->ws_input[n]);
1489 n++)
1490 ;
1491 p->v.segm.beg = n;
1492 }
1493
1494 while (p->next && (p->flags & _WSNF_JOIN))
1495 p = p->next;
1496
1497 if (p->flags & _WSNF_QUOTE)
1498 continue;
1499
1500 /* Trim trailing whitespace */
1501 for (n = p->v.segm.end;
1502 n > p->v.segm.beg && ISWS (wsp->ws_input[n - 1]); n--);
1503 p->v.segm.end = n;
1504 if (p->v.segm.beg == p->v.segm.end)
1505 p->flags |= _WSNF_NULL;
1506 }
1507
1508 wsnode_nullelim (wsp);
1509 return 0;
1510}
1511
1512static int
1513wordsplit_tildexpand (struct wordsplit *wsp)
1514{
1515 struct wordsplit_node *p;
1516 char *uname = NULL;
1517 size_t usize = 0;
1518
1519 for (p = wsp->ws_head; p; p = p->next)
1520 {
1521 const char *str;
1522
1523 if (p->flags & _WSNF_QUOTE)
1524 continue;
1525
1526 str = wsnode_ptr (wsp, p);
1527 if (str[0] == '~')
1528 {
1529 size_t i, size, dlen;
1530 size_t slen = wsnode_len (p);
1531 struct passwd *pw;
1532 char *newstr;
1533
1534 for (i = 1; i < slen && str[i] != '/'; i++)
1535 ;
1536 if (i == slen)
1537 continue;
1538 if (i > 1)
1539 {
1540 if (i > usize)
1541 {
1542 char *p = realloc (uname, i);
1543 if (!p)
1544 {
1545 free (uname);
1546 return _wsplt_nomem (wsp);
1547 }
1548 uname = p;
1549 usize = i;
1550 }
1551 --i;
1552 memcpy (uname, str + 1, i);
1553 uname[i] = 0;
1554 pw = getpwnam (uname);
1555 }
1556 else
1557 pw = getpwuid (getuid ());
1558
1559 if (!pw)
1560 continue;
1561
1562 dlen = strlen (pw->pw_dir);
1563 size = slen - i + dlen;
1564 newstr = malloc (size);
1565 if (!newstr)
1566 {
1567 free (uname);
1568 return _wsplt_nomem (wsp);
1569 }
1570 --size;
1571
1572 memcpy (newstr, pw->pw_dir, dlen);
1573 memcpy (newstr + dlen, str + i + 1, slen - i - 1);
1574 newstr[size] = 0;
1575 if (p->flags & _WSNF_WORD)
1576 free (p->v.word);
1577 p->v.word = newstr;
1578 p->flags |= _WSNF_WORD;
1579 }
1580 }
1581 free (uname);
1582 return 0;
1583}
1584
1585static int
1586isglob (const char *s, int l)
1587{
1588 while (l--)
1589 {
1590 if (strchr ("*?[", *s++))
1591 return 1;
1592 }
1593 return 0;
1594}
1595
1596static int
1597wordsplit_pathexpand (struct wordsplit *wsp)
1598{
1599 struct wordsplit_node *p, *next;
1600 char *pattern = NULL;
1601 size_t patsize = 0;
1602 size_t slen;
1603 int flags = 0;
1604
1605#ifdef GLOB_PERIOD
1606 if (wsp->ws_options & WRDSO_DOTGLOB)
1607 flags = GLOB_PERIOD;
1608#endif
1609
1610 for (p = wsp->ws_head; p; p = next)
1611 {
1612 const char *str;
1613
1614 next = p->next;
1615
1616 if (p->flags & _WSNF_QUOTE)
1617 continue;
1618
1619 str = wsnode_ptr (wsp, p);
1620 slen = wsnode_len (p);
1621
1622 if (isglob (str, slen))
1623 {
1624 int i;
1625 glob_t g;
1626 struct wordsplit_node *prev;
1627
1628 if (slen + 1 > patsize)
1629 {
1630 char *p = realloc (pattern, slen + 1);
1631 if (!p)
1632 return _wsplt_nomem (wsp);
1633 pattern = p;
1634 patsize = slen + 1;
1635 }
1636 memcpy (pattern, str, slen);
1637 pattern[slen] = 0;
1638
1639 switch (glob (pattern, flags, NULL, &g))
1640 {
1641 case 0:
1642 break;
1643
1644 case GLOB_NOSPACE:
1645 free (pattern);
1646 return _wsplt_nomem (wsp);
1647
1648 case GLOB_NOMATCH:
1649 if (wsp->ws_options & WRDSO_NULLGLOB)
1650 {
1651 wsnode_remove (wsp, p);
1652 wsnode_free (p);
1653 }
1654 else if (wsp->ws_options & WRDSO_FAILGLOB)
1655 {
1656 char buf[128];
1657 if (wsp->ws_errno == WRDSE_USERERR)
1658 free (wsp->ws_usererr);
1659 snprintf (buf, sizeof (buf), _("no files match pattern %s"),
1660 pattern);
1661 free (pattern);
1662 wsp->ws_usererr = strdup (buf);
1663 if (!wsp->ws_usererr)
1664 return _wsplt_nomem (wsp);
1665 else
1666 return _wsplt_seterr (wsp, WRDSE_USERERR);
1667 }
1668 continue;
1669
1670 default:
1671 free (pattern);
1672 return _wsplt_seterr (wsp, WRDSE_GLOBERR);
1673 }
1674
1675 prev = p;
1676 for (i = 0; i < g.gl_pathc; i++)
1677 {
1678 struct wordsplit_node *newnode;
1679 char *newstr;
1680
1681 if (wsnode_new (wsp, &newnode))
1682 return 1;
1683 newstr = strdup (g.gl_pathv[i]);
1684 if (!newstr)
1685 return _wsplt_nomem (wsp);
1686 newnode->v.word = newstr;
1687 newnode->flags |= _WSNF_WORD|_WSNF_QUOTE;
1688 wsnode_insert (wsp, newnode, prev, 0);
1689 prev = newnode;
1690 }
1691 globfree (&g);
1692
1693 wsnode_remove (wsp, p);
1694 wsnode_free (p);
1695 }
1696 }
1697 free (pattern);
1698 return 0;
1699}
1700
1701static int
1702skip_sed_expr (const char *command, size_t i, size_t len)
1703{
1704 int state;
1705
1706 do
1707 {
1708 int delim;
1709
1710 if (command[i] == ';')
1711 i++;
1712 if (!(command[i] == 's' && i + 3 < len && ISPUNCT (command[i + 1])))
1713 break;
1714
1715 delim = command[++i];
1716 state = 1;
1717 for (i++; i < len; i++)
1718 {
1719 if (state == 3)
1720 {
1721 if (command[i] == delim || !ISALNUM (command[i]))
1722 break;
1723 }
1724 else if (command[i] == '\\')
1725 i++;
1726 else if (command[i] == delim)
1727 state++;
1728 }
1729 }
1730 while (state == 3 && i < len && command[i] == ';');
1731 return i;
1732}
1733
1734static size_t
1735skip_delim (struct wordsplit *wsp)
1736{
1737 size_t start = wsp->ws_endp;
1738 if (wsp->ws_flags & WRDSF_SQUEEZE_DELIMS)
1739 {
1740 if ((wsp->ws_flags & WRDSF_RETURN_DELIMS) &&
1741 ISDELIM (wsp, wsp->ws_input[start]))
1742 {
1743 int delim = wsp->ws_input[start];
1744 do
1745 start++;
1746 while (start < wsp->ws_len && delim == wsp->ws_input[start]);
1747 }
1748 else
1749 {
1750 do
1751 start++;
1752 while (start < wsp->ws_len && ISDELIM (wsp, wsp->ws_input[start]));
1753 }
1754 start--;
1755 }
1756
1757 if (!(wsp->ws_flags & WRDSF_RETURN_DELIMS))
1758 start++;
1759
1760 return start;
1761}
1762
1763#define _WRDS_EOF 0
1764#define _WRDS_OK 1
1765#define _WRDS_ERR 2
1766
1767static int
1768scan_qstring (struct wordsplit *wsp, size_t start, size_t * end)
1769{
1770 size_t j;
1771 const char *command = wsp->ws_input;
1772 size_t len = wsp->ws_len;
1773 char q = command[start];
1774
1775 for (j = start + 1; j < len && command[j] != q; j++)
1776 if (q == '"' && command[j] == '\\')
1777 j++;
1778 if (j < len && command[j] == q)
1779 {
1780 int flags = _WSNF_QUOTE | _WSNF_EMPTYOK;
1781 if (q == '\'')
1782 flags |= _WSNF_NOEXPAND;
1783 if (wordsplit_add_segm (wsp, start + 1, j, flags))
1784 return _WRDS_ERR;
1785 *end = j;
1786 }
1787 else
1788 {
1789 wsp->ws_endp = start;
1790 _wsplt_seterr (wsp, WRDSE_QUOTE);
1791 return _WRDS_ERR;
1792 }
1793 return 0;
1794}
1795
1796static int
1797scan_word (struct wordsplit *wsp, size_t start)
1798{
1799 size_t len = wsp->ws_len;
1800 const char *command = wsp->ws_input;
1801 const char *comment = wsp->ws_comment;
1802 int join = 0;
1803 int flags = 0;
1804
1805 size_t i = start;
1806
1807 if (i >= len)
1808 {
1809 wsp->ws_errno = WRDSE_EOF;
1810 return _WRDS_EOF;
1811 }
1812
1813 start = i;
1814
1815 if (wsp->ws_flags & WRDSF_SED_EXPR
1816 && command[i] == 's' && i + 3 < len && ISPUNCT (command[i + 1]))
1817 {
1818 flags = _WSNF_SEXP;
1819 i = skip_sed_expr (command, i, len);
1820 }
1821 else if (!ISDELIM (wsp, command[i]))
1822 {
1823 while (i < len)
1824 {
1825 if (comment && strchr (comment, command[i]) != NULL)
1826 {
1827 size_t j;
1828 for (j = i + 1; j < len && command[j] != '\n'; j++)
1829 ;
1830 if (wordsplit_add_segm (wsp, start, i, 0))
1831 return _WRDS_ERR;
1832 wsp->ws_endp = j;
1833 return _WRDS_OK;
1834 }
1835
1836 if (wsp->ws_flags & WRDSF_QUOTE)
1837 {
1838 if (command[i] == '\\')
1839 {
1840 if (++i == len)
1841 break;
1842 i++;
1843 continue;
1844 }
1845
1846 if (((wsp->ws_flags & WRDSF_SQUOTE) && command[i] == '\'') ||
1847 ((wsp->ws_flags & WRDSF_DQUOTE) && command[i] == '"'))
1848 {
1849 if (join && wsp->ws_tail)
1850 wsp->ws_tail->flags |= _WSNF_JOIN;
1851 if (wordsplit_add_segm (wsp, start, i, _WSNF_JOIN))
1852 return _WRDS_ERR;
1853 if (scan_qstring (wsp, i, &i))
1854 return _WRDS_ERR;
1855 start = i + 1;
1856 join = 1;
1857 }
1858 }
1859
1860 if (command[i] == '$')
1861 {
1862 if (!(wsp->ws_flags & WRDSF_NOVAR)
1863 && command[i+1] == '{'
1864 && find_closing_paren (command, i + 2, len, &i, "{}") == 0)
1865 continue;
1866 if (!(wsp->ws_flags & WRDSF_NOCMD)
1867 && command[i+1] == '('
1868 && find_closing_paren (command, i + 2, len, &i, "()") == 0)
1869 continue;
1870 }
1871
1872 if (ISDELIM (wsp, command[i]))
1873 break;
1874 else
1875 i++;
1876 }
1877 }
1878 else if (wsp->ws_flags & WRDSF_RETURN_DELIMS)
1879 {
1880 i++;
1881 flags |= _WSNF_DELIM;
1882 }
1883 else if (!(wsp->ws_flags & WRDSF_SQUEEZE_DELIMS))
1884 flags |= _WSNF_EMPTYOK;
1885
1886 if (join && i > start && wsp->ws_tail)
1887 wsp->ws_tail->flags |= _WSNF_JOIN;
1888 if (wordsplit_add_segm (wsp, start, i, flags))
1889 return _WRDS_ERR;
1890 wsp->ws_endp = i;
1891 if (wsp->ws_flags & WRDSF_INCREMENTAL)
1892 return _WRDS_EOF;
1893 return _WRDS_OK;
1894}
1895
1896#define to_num(c) \
1897 (ISDIGIT(c) ? c - '0' : (ISXDIGIT(c) ? toupper(c) - 'A' + 10 : 255 ))
1898
1899static int
1900xtonum (int *pval, const char *src, int base, int cnt)
1901{
1902 int i, val;
1903
1904 for (i = 0, val = 0; i < cnt; i++, src++)
1905 {
1906 int n = *(unsigned char *) src;
1907 if (n > 127 || (n = to_num (n)) >= base)
1908 break;
1909 val = val * base + n;
1910 }
1911 *pval = val;
1912 return i;
1913}
1914
1915size_t
1916wordsplit_c_quoted_length (const char *str, int quote_hex, int *quote)
1917{
1918 size_t len = 0;
1919
1920 *quote = 0;
1921 for (; *str; str++)
1922 {
1923 if (strchr (" \"", *str))
1924 *quote = 1;
1925
1926 if (*str == ' ')
1927 len++;
1928 else if (*str == '"')
1929 len += 2;
1930 else if (*str != '\t' && *str != '\\' && ISPRINT (*str))
1931 len++;
1932 else if (quote_hex)
1933 len += 3;
1934 else
1935 {
1936 if (wordsplit_c_quote_char (*str))
1937 len += 2;
1938 else
1939 len += 4;
1940 }
1941 }
1942 return len;
1943}
1944
1945int
1946wsplt_unquote_char (const char *transtab, int c)
1947{
1948 while (*transtab && transtab[1])
1949 {
1950 if (*transtab++ == c)
1951 return *transtab;
1952 ++transtab;
1953 }
1954 return 0;
1955}
1956
1957int
1958wsplt_quote_char (const char *transtab, int c)
1959{
1960 for (; *transtab && transtab[1]; transtab += 2)
1961 {
1962 if (transtab[1] == c)
1963 return *transtab;
1964 }
1965 return 0;
1966}
1967
1968int
1969wordsplit_c_unquote_char (int c)
1970{
1971 return wsplt_unquote_char (wordsplit_c_escape_tab, c);
1972}
1973
1974int
1975wordsplit_c_quote_char (int c)
1976{
1977 return wsplt_quote_char (wordsplit_c_escape_tab, c);
1978}
1979
1980void
1981wordsplit_string_unquote_copy (struct wordsplit *ws, int inquote,
1982 char *dst, const char *src, size_t n)
1983{
1984 int i = 0;
1985 int c;
1986
1987 inquote = !!inquote;
1988 while (i < n)
1989 {
1990 if (src[i] == '\\')
1991 {
1992 ++i;
1993 if (WRDSO_ESC_TEST (ws, inquote, WRDSO_XESC)
1994 && (src[i] == 'x' || src[i] == 'X'))
1995 {
1996 if (n - i < 2)
1997 {
1998 *dst++ = '\\';
1999 *dst++ = src[i++];
2000 }
2001 else
2002 {
2003 int off = xtonum (&c, src + i + 1,
2004 16, 2);
2005 if (off == 0)
2006 {
2007 *dst++ = '\\';
2008 *dst++ = src[i++];
2009 }
2010 else
2011 {
2012 *dst++ = c;
2013 i += off + 1;
2014 }
2015 }
2016 }
2017 else if (WRDSO_ESC_TEST (ws, inquote, WRDSO_OESC)
2018 && (unsigned char) src[i] < 128 && ISDIGIT (src[i]))
2019 {
2020 if (n - i < 1)
2021 {
2022 *dst++ = '\\';
2023 *dst++ = src[i++];
2024 }
2025 else
2026 {
2027 int off = xtonum (&c, src + i, 8, 3);
2028 if (off == 0)
2029 {
2030 *dst++ = '\\';
2031 *dst++ = src[i++];
2032 }
2033 else
2034 {
2035 *dst++ = c;
2036 i += off;
2037 }
2038 }
2039 }
2040 else if ((c = wsplt_unquote_char (ws->ws_escape[inquote], src[i])))
2041 {
2042 *dst++ = c;
2043 ++i;
2044 }
2045 else
2046 {
2047 if (WRDSO_ESC_TEST (ws, inquote, WRDSO_BSKEEP))
2048 *dst++ = '\\';
2049 *dst++ = src[i++];
2050 }
2051 }
2052 else
2053 *dst++ = src[i++];
2054 }
2055 *dst = 0;
2056}
2057
2058void
2059wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex)
2060{
2061 for (; *src; src++)
2062 {
2063 if (*src == '"')
2064 {
2065 *dst++ = '\\';
2066 *dst++ = *src;
2067 }
2068 else if (*src != '\t' && *src != '\\' && ISPRINT (*src))
2069 *dst++ = *src;
2070 else
2071 {
2072 char tmp[4];
2073
2074 if (quote_hex)
2075 {
2076 snprintf (tmp, sizeof tmp, "%%%02X", *(unsigned char *) src);
2077 memcpy (dst, tmp, 3);
2078 dst += 3;
2079 }
2080 else
2081 {
2082 int c = wordsplit_c_quote_char (*src);
2083 *dst++ = '\\';
2084 if (c)
2085 *dst++ = c;
2086 else
2087 {
2088 snprintf (tmp, sizeof tmp, "%03o", *(unsigned char *) src);
2089 memcpy (dst, tmp, 3);
2090 dst += 3;
2091 }
2092 }
2093 }
2094 }
2095}
2096
2097
2098/* This structure describes a single expansion phase */
2099struct exptab
2100{
2101 char *descr; /* Textual description (for debugging) */
2102 int flag; /* WRDSF_ bit that controls this phase */
2103 int opt; /* Entry-specific options (see EXPOPT_ flags below */
2104 int (*expansion) (struct wordsplit *wsp); /* expansion function */
2105};
2106
2107/* The following options control expansions: */
2108/* Normally the exptab entry is run if its flag bit is set in struct
2109 wordsplit. The EXPOPT_NEG option negates this test so that expansion
2110 is performed if its associated flag bit is not set in struct wordsplit. */
2111#define EXPOPT_NEG 0x01
2112/* Coalesce the input list before running the expansion. */
2113#define EXPOPT_COALESCE 0x02
2114
2115static struct exptab exptab[] = {
2116 { N_("WS trimming"), WRDSF_WS, 0,
2117 wordsplit_trimws },
2118 { N_("command substitution"), WRDSF_NOCMD, EXPOPT_NEG|EXPOPT_COALESCE,
2119 wordsplit_cmdexp },
2120 { N_("coalesce list"), 0, EXPOPT_NEG|EXPOPT_COALESCE,
2121 NULL },
2122 { N_("tilde expansion"), WRDSF_PATHEXPAND, 0,
2123 wordsplit_tildexpand },
2124 { N_("variable expansion"), WRDSF_NOVAR, EXPOPT_NEG,
2125 wordsplit_varexp },
2126 { N_("quote removal"), 0, EXPOPT_NEG,
2127 wsnode_quoteremoval },
2128 { N_("coalesce list"), 0, EXPOPT_NEG|EXPOPT_COALESCE,
2129 NULL },
2130 { N_("path expansion"), WRDSF_PATHEXPAND, 0,
2131 wordsplit_pathexpand },
2132 { NULL }
2133};
2134
2135static int
2136wordsplit_process_list (struct wordsplit *wsp, size_t start)
2137{
2138 struct exptab *p;
2139
2140 if (wsp->ws_flags & WRDSF_NOSPLIT)
2141 {
2142 /* Treat entire input as a quoted argument */
2143 if (wordsplit_add_segm (wsp, start, wsp->ws_len, _WSNF_QUOTE))
2144 return wsp->ws_errno;
2145 wsp->ws_endp = wsp->ws_len;
2146 }
2147 else
2148 {
2149 int rc;
2150
2151 while ((rc = scan_word (wsp, start)) == _WRDS_OK)
2152 start = skip_delim (wsp);
2153 /* Make sure tail element is not joinable */
2154 if (wsp->ws_tail)
2155 wsp->ws_tail->flags &= ~_WSNF_JOIN;
2156 if (rc == _WRDS_ERR)
2157 return wsp->ws_errno;
2158 }
2159
2160 if (wsp->ws_flags & WRDSF_SHOWDBG)
2161 {
2162 wsp->ws_debug ("(%02d) %s", wsp->ws_lvl, _("Initial list:"));
2163 wordsplit_dump_nodes (wsp);
2164 }
2165
2166 for (p = exptab; p->descr; p++)
2167 {
2168 if ((p->opt & EXPOPT_NEG)
2169 ? !(wsp->ws_flags & p->flag) : (wsp->ws_flags & p->flag))
2170 {
2171 if (p->opt & EXPOPT_COALESCE)
2172 {
2173 if (wsnode_coalesce (wsp))
2174 break;
2175 if (wsp->ws_flags & WRDSF_SHOWDBG)
2176 {
2177 wsp->ws_debug ("(%02d) %s", wsp->ws_lvl,
2178 _("Coalesced list:"));
2179 wordsplit_dump_nodes (wsp);
2180 }
2181 }
2182 if (p->expansion)
2183 {
2184 if (p->expansion (wsp))
2185 break;
2186 if (wsp->ws_flags & WRDSF_SHOWDBG)
2187 {
2188 wsp->ws_debug ("(%02d) %s", wsp->ws_lvl, _(p->descr));
2189 wordsplit_dump_nodes (wsp);
2190 }
2191 }
2192 }
2193 }
2194 return wsp->ws_errno;
2195}
2196
2197static int
2198wordsplit_run (const char *command, size_t length, struct wordsplit *wsp,
2199 int flags, int lvl)
2200{
2201 int rc;
2202 size_t start;
2203 const char *cmdptr;
2204 size_t cmdlen;
2205
2206 if (!command)
2207 {
2208 if (!(flags & WRDSF_INCREMENTAL))
2209 return EINVAL;
2210
2211 start = skip_delim (wsp);
2212 if (wsp->ws_endp == wsp->ws_len)
2213 return _wsplt_seterr (wsp, WRDSE_NOINPUT);
2214
2215 cmdptr = wsp->ws_input + wsp->ws_endp;
2216 cmdlen = wsp->ws_len - wsp->ws_endp;
2217 wsp->ws_flags |= WRDSF_REUSE;
2218 wordsplit_init0 (wsp);
2219 }
2220 else
2221 {
2222 cmdptr = command;
2223 cmdlen = length;
2224 start = 0;
2225 rc = wordsplit_init (wsp, cmdptr, cmdlen, flags);
2226 if (rc)
2227 return rc;
2228 wsp->ws_lvl = lvl;
2229 }
2230
2231 if (wsp->ws_flags & WRDSF_SHOWDBG)
2232 wsp->ws_debug (_("(%02d) Input:%.*s;"), wsp->ws_lvl, (int) cmdlen, cmdptr);
2233
2234 rc = wordsplit_process_list (wsp, start);
2235 if (rc == 0 && (flags & WRDSF_INCREMENTAL))
2236 {
2237 while (!wsp->ws_head && wsp->ws_endp < wsp->ws_len)
2238 {
2239 start = skip_delim (wsp);
2240 if (wsp->ws_flags & WRDSF_SHOWDBG)
2241 {
2242 cmdptr = wsp->ws_input + wsp->ws_endp;
2243 cmdlen = wsp->ws_len - wsp->ws_endp;
2244 wsp->ws_debug (_("(%02d) Restart:%.*s;"),
2245 wsp->ws_lvl, (int) cmdlen, cmdptr);
2246 }
2247 rc = wordsplit_process_list (wsp, start);
2248 if (rc)
2249 break;
2250 }
2251 }
2252 if (rc)
2253 {
2254 wordsplit_free_nodes (wsp);
2255 return rc;
2256 }
2257 wordsplit_finish (wsp);
2258 wordsplit_free_nodes (wsp);
2259 return wsp->ws_errno;
2260}
2261
2262int
2263wordsplit_len (const char *command, size_t length, struct wordsplit *wsp,
2264 int flags)
2265{
2266 return wordsplit_run (command, length, wsp, flags, 0);
2267}
2268
2269int
2270wordsplit (const char *command, struct wordsplit *ws, int flags)
2271{
2272 return wordsplit_len (command, command ? strlen (command) : 0, ws, flags);
2273}
2274
2275void
2276wordsplit_free_words (struct wordsplit *ws)
2277{
2278 size_t i;
2279
2280 for (i = 0; i < ws->ws_wordc; i++)
2281 {
2282 char *p = ws->ws_wordv[ws->ws_offs + i];
2283 if (p)
2284 {
2285 free (p);
2286 ws->ws_wordv[ws->ws_offs + i] = NULL;
2287 }
2288 }
2289 ws->ws_wordc = 0;
2290}
2291
2292void
2293wordsplit_free_envbuf (struct wordsplit *ws)
2294{
2295 if (ws->ws_flags & WRDSF_NOCMD)
2296 return;
2297 if (ws->ws_envbuf)
2298 {
2299 size_t i;
2300
2301 for (i = 0; ws->ws_envbuf[i]; i++)
2302 free (ws->ws_envbuf[i]);
2303 free (ws->ws_envbuf);
2304 ws->ws_envidx = ws->ws_envsiz = 0;
2305 ws->ws_envbuf = NULL;
2306 }
2307}
2308
2309void
2310wordsplit_clearerr (struct wordsplit *ws)
2311{
2312 if (ws->ws_errno == WRDSE_USERERR)
2313 free (ws->ws_usererr);
2314 ws->ws_usererr = NULL;
2315 ws->ws_errno = WRDSE_OK;
2316}
2317
2318void
2319wordsplit_free (struct wordsplit *ws)
2320{
2321 wordsplit_free_words (ws);
2322 free (ws->ws_wordv);
2323 ws->ws_wordv = NULL;
2324 wordsplit_free_envbuf (ws);
2325}
2326
2327int
2328wordsplit_get_words (struct wordsplit *ws, size_t *wordc, char ***wordv)
2329{
2330 char **p = realloc (ws->ws_wordv,
2331 (ws->ws_wordc + 1) * sizeof (ws->ws_wordv[0]));
2332 if (!p)
2333 return -1;
2334 *wordv = p;
2335 *wordc = ws->ws_wordc;
2336
2337 ws->ws_wordv = NULL;
2338 ws->ws_wordc = 0;
2339 ws->ws_wordn = 0;
2340
2341 return 0;
2342}
2343
2344const char *_wordsplit_errstr[] = {
2345 N_("no error"),
2346 N_("missing closing quote"),
2347 N_("memory exhausted"),
2348 N_("invalid wordsplit usage"),
2349 N_("unbalanced curly brace"),
2350 N_("undefined variable"),
2351 N_("input exhausted"),
2352 N_("unbalanced parenthesis"),
2353 N_("globbing error")
2354};
2355int _wordsplit_nerrs =
2356 sizeof (_wordsplit_errstr) / sizeof (_wordsplit_errstr[0]);
2357
2358const char *
2359wordsplit_strerror (struct wordsplit *ws)
2360{
2361 if (ws->ws_errno == WRDSE_USERERR)
2362 return ws->ws_usererr;
2363 if (ws->ws_errno < _wordsplit_nerrs)
2364 return _wordsplit_errstr[ws->ws_errno];
2365 return N_("unknown error");
2366}
2367
2368void
2369wordsplit_perror (struct wordsplit *wsp)
2370{
2371 switch (wsp->ws_errno)
2372 {
2373 case WRDSE_QUOTE:
2374 wsp->ws_error (_("missing closing %c (start near #%lu)"),
2375 wsp->ws_input[wsp->ws_endp],
2376 (unsigned long) wsp->ws_endp);
2377 break;
2378
2379 default:
2380 wsp->ws_error ("%s", wordsplit_strerror (wsp));
2381 }
2382}
2383
2384int
2385wordsplit_varnames(const char *input, char ***ret_names, int af)
2386{
2387 const char *p;
2388 size_t count = 0;
2389 char **names;
2390 size_t i = 0;
2391
2392 if (!input) {
2393 errno = EINVAL;
2394 return -1;
2395 }
2396
2397 for (p = input; *p; p++) {
2398 if (*p == '\\')
2399 ++p;
2400 else if (*p == '$')
2401 ++count;
2402 }
2403
2404 if (af && *ret_names) {
2405 names = *ret_names;
2406 for (i = 0; names[i]; i++)
2407 ;
2408 names = realloc(names, (i + count + 1) * sizeof(names));
2409 } else
2410 names = calloc(count + 1, sizeof(names[0]));
2411 if (!names)
2412 return -1;
2413 *ret_names = names;
2414
2415 for (p = input; *p; ) {
2416 if (*p == '\\')
2417 ++p;
2418 else if (*p == '$') {
2419 char const *kw;
2420 size_t len;
2421
2422 if (*++p == 0)
2423 break;
2424 else if (*p == '{') {
2425 kw = ++p;
2426 while (*p && !(*p == ':' || *p == '}'))
2427 ++p;
2428 } else if (ISVARBEG(*p)) {
2429 kw = p++;
2430 while (*p && ISVARCHR(*p))
2431 ++p;
2432 } else
2433 continue;
2434 len = p - kw;
2435 if (len) {
2436 if (!(names[i] = malloc(len + 1)))
2437 return 1;
2438 memcpy(names[i], kw, len);
2439 names[i][len] = 0;
2440 ++i;
2441 }
2442 } else
2443 ++p;
2444 }
2445 names[i] = NULL;
2446 return 0;
2447}
diff --git a/modules/echo/Makefile.am b/modules/echo/Makefile.am
index 335dcb3..80c0b51 100644
--- a/modules/echo/Makefile.am
+++ b/modules/echo/Makefile.am
@@ -1,5 +1,5 @@
1# This file is part of Smap. 1# This file is part of Smap.
2# Copyright (C) 2010, 2014 Sergey Poznyakoff 2# Copyright (C) 2010, 2014, 2019 Sergey Poznyakoff
3# 3#
4# Smap is free software; you can redistribute it and/or modify 4# Smap is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
@@ -21,4 +21,4 @@ mod_LTLIBRARIES=echo.la
21echo_la_SOURCES = echo.c 21echo_la_SOURCES = echo.c
22echo_la_LIBADD = ../../lib/libsmap.la 22echo_la_LIBADD = ../../lib/libsmap.la
23AM_LDFLAGS = -module -avoid-version -no-undefined 23AM_LDFLAGS = -module -avoid-version -no-undefined
24AM_CPPFLAGS = -I$(top_srcdir)/include 24AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
diff --git a/modules/guile/Makefile.am b/modules/guile/Makefile.am
index cca8d51..d197de8 100644
--- a/modules/guile/Makefile.am
+++ b/modules/guile/Makefile.am
@@ -1,5 +1,5 @@
1# This file is part of Smap. 1# This file is part of Smap.
2# Copyright (C) 2010, 2014 Sergey Poznyakoff 2# Copyright (C) 2010, 2014, 2019 Sergey Poznyakoff
3# 3#
4# Smap is free software; you can redistribute it and/or modify 4# Smap is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@ mod_LTLIBRARIES=guile.la
21guile_la_SOURCES = guile.c 21guile_la_SOURCES = guile.c
22guile_la_LIBADD = ../../lib/libsmap.la @GUILE_LIBS@ 22guile_la_LIBADD = ../../lib/libsmap.la @GUILE_LIBS@
23AM_LDFLAGS = -module -avoid-version -no-undefined 23AM_LDFLAGS = -module -avoid-version -no-undefined
24AM_CPPFLAGS = -I$(top_srcdir)/include @GUILE_INCLUDES@ 24AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include @GUILE_INCLUDES@
25 25
26SUFFIXES = 26SUFFIXES =
27BUILT_SOURCES = 27BUILT_SOURCES =
diff --git a/modules/ldap/Makefile.am b/modules/ldap/Makefile.am
index 4ffbf7b..9d528b3 100644
--- a/modules/ldap/Makefile.am
+++ b/modules/ldap/Makefile.am
@@ -1,5 +1,5 @@
1# This file is part of Smap. 1# This file is part of Smap.
2# Copyright (C) 2014 Sergey Poznyakoff 2# Copyright (C) 2014, 2019 Sergey Poznyakoff
3# 3#
4# Smap is free software; you can redistribute it and/or modify 4# Smap is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
@@ -20,4 +20,4 @@ mod_LTLIBRARIES=ldap.la
20ldap_la_SOURCES=ldap.c 20ldap_la_SOURCES=ldap.c
21ldap_la_LIBADD=-lldap 21ldap_la_LIBADD=-lldap
22AM_LDFLAGS = -module -avoid-version -no-undefined 22AM_LDFLAGS = -module -avoid-version -no-undefined
23AM_CPPFLAGS = -I$(top_srcdir)/include 23AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
diff --git a/modules/mailutils/Makefile.am b/modules/mailutils/Makefile.am
index 058ee03..3bcaff9 100644
--- a/modules/mailutils/Makefile.am
+++ b/modules/mailutils/Makefile.am
@@ -1,5 +1,5 @@
1# This file is part of Smap. 1# This file is part of Smap.
2# Copyright (C) 2010, 2014 Sergey Poznyakoff 2# Copyright (C) 2010, 2014, 2019 Sergey Poznyakoff
3# 3#
4# Smap is free software; you can redistribute it and/or modify 4# Smap is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
@@ -21,4 +21,4 @@ mod_LTLIBRARIES=mailutils.la
21mailutils_la_SOURCES = mailutils.c 21mailutils_la_SOURCES = mailutils.c
22mailutils_la_LIBADD = ../../lib/libsmap.la @MAILUTILS_LIBS@ 22mailutils_la_LIBADD = ../../lib/libsmap.la @MAILUTILS_LIBS@
23AM_LDFLAGS = -module -avoid-version -no-undefined 23AM_LDFLAGS = -module -avoid-version -no-undefined
24AM_CPPFLAGS = -I$(top_srcdir)/include @MAILUTILS_INCLUDES@ 24AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include @MAILUTILS_INCLUDES@
diff --git a/modules/mysql/Makefile.am b/modules/mysql/Makefile.am
index 9b3a904..d6d9dd5 100644
--- a/modules/mysql/Makefile.am
+++ b/modules/mysql/Makefile.am
@@ -22,4 +22,4 @@ mysql_la_SOURCES = mysql.c
22 22
23mysql_la_LIBADD = ../../lib/libsmap.la @MYSQL_LIBS@ 23mysql_la_LIBADD = ../../lib/libsmap.la @MYSQL_LIBS@
24AM_LDFLAGS = -module -avoid-version -no-undefined 24AM_LDFLAGS = -module -avoid-version -no-undefined
25AM_CPPFLAGS = -I$(top_srcdir)/include 25AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
diff --git a/modules/postgres/Makefile.am b/modules/postgres/Makefile.am
index 13e05eb..1fd7827 100644
--- a/modules/postgres/Makefile.am
+++ b/modules/postgres/Makefile.am
@@ -21,4 +21,4 @@ mod_LTLIBRARIES=postgres.la
21postgres_la_SOURCES = postgres.c 21postgres_la_SOURCES = postgres.c
22postgres_la_LIBADD = ../../lib/libsmap.la @POSTGRES_LIBS@ 22postgres_la_LIBADD = ../../lib/libsmap.la @POSTGRES_LIBS@
23AM_LDFLAGS = -module -avoid-version -no-undefined 23AM_LDFLAGS = -module -avoid-version -no-undefined
24AM_CPPFLAGS = -I$(top_srcdir)/include 24AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
diff --git a/modules/sed/Makefile.am b/modules/sed/Makefile.am
index 4531008..8bd4891 100644
--- a/modules/sed/Makefile.am
+++ b/modules/sed/Makefile.am
@@ -22,4 +22,4 @@ sed_la_SOURCES = sed.c transform.c
22sed_la_LIBADD = ../../lib/libsmap.la 22sed_la_LIBADD = ../../lib/libsmap.la
23noinst_HEADERS = transform.h 23noinst_HEADERS = transform.h
24AM_LDFLAGS = -module -avoid-version -no-undefined 24AM_LDFLAGS = -module -avoid-version -no-undefined
25AM_CPPFLAGS = -I$(top_srcdir)/include 25AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
diff --git a/src/Makefile.am b/src/Makefile.am
index 47a1382..c3dac14 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
1# This file is part of Smap. 1# This file is part of Smap.
2# Copyright (C) 2010, 2014 Sergey Poznyakoff 2# Copyright (C) 2010, 2014, 2019 Sergey Poznyakoff
3# 3#
4# Smap is free software; you can redistribute it and/or modify 4# Smap is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
@@ -43,7 +43,9 @@ SUFFIXES=.opt .c
43BUILT_SOURCES=cmdline.c smapccmd.c smapd.conf 43BUILT_SOURCES=cmdline.c smapccmd.c smapd.conf
44EXTRA_DIST=cmdline.opt cmdline.c smapccmd.opt smapccmd.c smapd.cfin getopt.m4 44EXTRA_DIST=cmdline.opt cmdline.c smapccmd.opt smapccmd.c smapd.cfin getopt.m4
45AM_CPPFLAGS =\ 45AM_CPPFLAGS =\
46 -I$(top_srcdir)/include @LTDLINCL@\ 46 -I$(top_srcdir)/include\
47 -I$(top_builddir)/include\
48 @LTDLINCL@\
47 -DSYSCONFDIR=\"$(sysconfdir)\"\ 49 -DSYSCONFDIR=\"$(sysconfdir)\"\
48 -DSMAP_MODDIR=\"$(SMAP_MODDIR)\" 50 -DSMAP_MODDIR=\"$(SMAP_MODDIR)\"
49CLEANFILES = smapd.conf 51CLEANFILES = smapd.conf

Return to:

Send suggestions and report system problems to the System administrator.