aboutsummaryrefslogtreecommitdiff
path: root/src/wordsplit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/wordsplit.c')
-rw-r--r--src/wordsplit.c1646
1 files changed, 1284 insertions, 362 deletions
diff --git a/src/wordsplit.c b/src/wordsplit.c
index f4740bf..bad59b1 100644
--- a/src/wordsplit.c
+++ b/src/wordsplit.c
@@ -1,5 +1,5 @@
1/* wordsplit - a word splitter 1/* wordsplit - a word splitter
2 Copyright (C) 2009-2014 Sergey Poznyakoff 2 Copyright (C) 2009-2018 Sergey Poznyakoff
3 3
4 This program is free software; you can redistribute it and/or modify it 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 5 under the terms of the GNU General Public License as published by the
@@ -25,6 +25,8 @@
25#include <string.h> 25#include <string.h>
26#include <stdio.h> 26#include <stdio.h>
27#include <stdarg.h> 27#include <stdarg.h>
28#include <pwd.h>
29#include <glob.h>
28 30
29#if ENABLE_NLS 31#if ENABLE_NLS
30# include <gettext.h> 32# include <gettext.h>
@@ -48,17 +50,23 @@
48#define ISALNUM(c) (ISALPHA(c) || ISDIGIT(c)) 50#define ISALNUM(c) (ISALPHA(c) || ISDIGIT(c))
49#define ISPRINT(c) (' ' <= ((unsigned) (c)) && ((unsigned) (c)) <= 127) 51#define ISPRINT(c) (' ' <= ((unsigned) (c)) && ((unsigned) (c)) <= 127)
50 52
53#define ISVARBEG(c) (ISALPHA(c) || c == '_')
54#define ISVARCHR(c) (ISALNUM(c) || c == '_')
55
56#define WSP_RETURN_DELIMS(wsp) \
57 ((wsp)->ws_flags & WRDSF_RETURN_DELIMS || ((wsp)->ws_options & WRDSO_MAXWORDS))
58
51#define ALLOC_INIT 128 59#define ALLOC_INIT 128
52#define ALLOC_INCR 128 60#define ALLOC_INCR 128
53 61
54static void 62static void
55_wsplt_alloc_die (struct wordsplit *wsp) 63_wsplt_alloc_die (struct wordsplit *wsp)
56{ 64{
57 wsp->ws_error (_("memory exhausted")); 65 wsp->ws_error ("%s", _("memory exhausted"));
58 abort (); 66 abort ();
59} 67}
60 68
61static void 69static void
62_wsplt_error (const char *fmt, ...) 70_wsplt_error (const char *fmt, ...)
63{ 71{
64 va_list ap; 72 va_list ap;
@@ -72,6 +80,15 @@ _wsplt_error (const char *fmt, ...)
72static void wordsplit_free_nodes (struct wordsplit *); 80static void wordsplit_free_nodes (struct wordsplit *);
73 81
74static int 82static int
83_wsplt_seterr (struct wordsplit *wsp, int ec)
84{
85 wsp->ws_errno = ec;
86 if (wsp->ws_flags & WRDSF_SHOWERR)
87 wordsplit_perror (wsp);
88 return ec;
89}
90
91static int
75_wsplt_nomem (struct wordsplit *wsp) 92_wsplt_nomem (struct wordsplit *wsp)
76{ 93{
77 errno = ENOMEM; 94 errno = ENOMEM;
@@ -86,6 +103,84 @@ _wsplt_nomem (struct wordsplit *wsp)
86 return wsp->ws_errno; 103 return wsp->ws_errno;
87} 104}
88 105
106static int wordsplit_run (const char *command, size_t length,
107 struct wordsplit *wsp,
108 int flags, int lvl);
109
110static int wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
111 int flags);
112static int wordsplit_process_list (struct wordsplit *wsp, size_t start);
113static int wordsplit_finish (struct wordsplit *wsp);
114
115static int
116_wsplt_subsplit (struct wordsplit *wsp, struct wordsplit *wss,
117 char const *str, int len,
118 int flags, int finalize)
119{
120 int rc;
121
122 wss->ws_delim = wsp->ws_delim;
123 wss->ws_debug = wsp->ws_debug;
124 wss->ws_error = wsp->ws_error;
125 wss->ws_alloc_die = wsp->ws_alloc_die;
126
127 if (!(flags & WRDSF_NOVAR))
128 {
129 wss->ws_env = wsp->ws_env;
130 wss->ws_getvar = wsp->ws_getvar;
131 flags |= wsp->ws_flags & (WRDSF_ENV | WRDSF_ENV_KV | WRDSF_GETVAR);
132 }
133 if (!(flags & WRDSF_NOCMD))
134 {
135 wss->ws_command = wsp->ws_command;
136 }
137
138 if ((flags & (WRDSF_NOVAR|WRDSF_NOCMD)) != (WRDSF_NOVAR|WRDSF_NOCMD))
139 {
140 wss->ws_closure = wsp->ws_closure;
141 flags |= wsp->ws_flags & WRDSF_CLOSURE;
142 }
143
144 wss->ws_options = wsp->ws_options;
145
146 flags |= WRDSF_DELIM
147 | WRDSF_ALLOC_DIE
148 | WRDSF_ERROR
149 | WRDSF_DEBUG
150 | (wsp->ws_flags & (WRDSF_SHOWDBG | WRDSF_SHOWERR | WRDSF_OPTIONS));
151
152 rc = wordsplit_init (wss, str, len, flags);
153 if (rc)
154 return rc;
155 wss->ws_lvl = wsp->ws_lvl + 1;
156 rc = wordsplit_process_list (wss, 0);
157 if (rc)
158 {
159 wordsplit_free_nodes (wss);
160 return rc;
161 }
162 if (finalize)
163 {
164 rc = wordsplit_finish (wss);
165 wordsplit_free_nodes (wss);
166 }
167 return rc;
168}
169
170static void
171_wsplt_seterr_sub (struct wordsplit *wsp, struct wordsplit *wss)
172{
173 if (wsp->ws_errno == WRDSE_USERERR)
174 free (wsp->ws_usererr);
175 wsp->ws_errno = wss->ws_errno;
176 if (wss->ws_errno == WRDSE_USERERR)
177 {
178 wsp->ws_usererr = wss->ws_usererr;
179 wss->ws_errno = WRDSE_EOF;
180 wss->ws_usererr = NULL;
181 }
182}
183
89static void 184static void
90wordsplit_init0 (struct wordsplit *wsp) 185wordsplit_init0 (struct wordsplit *wsp)
91{ 186{
@@ -93,6 +188,7 @@ wordsplit_init0 (struct wordsplit *wsp)
93 { 188 {
94 if (!(wsp->ws_flags & WRDSF_APPEND)) 189 if (!(wsp->ws_flags & WRDSF_APPEND))
95 wordsplit_free_words (wsp); 190 wordsplit_free_words (wsp);
191 wordsplit_clearerr (wsp);
96 } 192 }
97 else 193 else
98 { 194 {
@@ -102,9 +198,10 @@ wordsplit_init0 (struct wordsplit *wsp)
102 } 198 }
103 199
104 wsp->ws_errno = 0; 200 wsp->ws_errno = 0;
105 wsp->ws_head = wsp->ws_tail = NULL;
106} 201}
107 202
203char wordsplit_c_escape_tab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v";
204
108static int 205static int
109wordsplit_init (struct wordsplit *wsp, const char *input, size_t len, 206wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
110 int flags) 207 int flags)
@@ -116,23 +213,21 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
116 if (!(wsp->ws_flags & WRDSF_ERROR)) 213 if (!(wsp->ws_flags & WRDSF_ERROR))
117 wsp->ws_error = _wsplt_error; 214 wsp->ws_error = _wsplt_error;
118 215
119 if (!(wsp->ws_flags & WRDSF_NOVAR) 216 if (!(wsp->ws_flags & WRDSF_NOVAR))
120 && !(wsp->ws_flags & (WRDSF_ENV | WRDSF_GETVAR)))
121 { 217 {
122 errno = EINVAL; 218 /* These will be initialized on first variable assignment */
123 wsp->ws_errno = WRDSE_USAGE; 219 wsp->ws_envidx = wsp->ws_envsiz = 0;
124 if (wsp->ws_flags & WRDSF_SHOWERR) 220 wsp->ws_envbuf = NULL;
125 wordsplit_perror (wsp);
126 return wsp->ws_errno;
127 } 221 }
128 222
129 if (!(wsp->ws_flags & WRDSF_NOCMD)) 223 if (!(wsp->ws_flags & WRDSF_NOCMD))
130 { 224 {
131 errno = EINVAL; 225 if (!wsp->ws_command)
132 wsp->ws_errno = WRDSE_NOSUPP; 226 {
133 if (wsp->ws_flags & WRDSF_SHOWERR) 227 _wsplt_seterr (wsp, WRDSE_USAGE);
134 wordsplit_perror (wsp); 228 errno = EINVAL;
135 return wsp->ws_errno; 229 return wsp->ws_errno;
230 }
136 } 231 }
137 232
138 if (wsp->ws_flags & WRDSF_SHOWDBG) 233 if (wsp->ws_flags & WRDSF_SHOWDBG)
@@ -163,10 +258,42 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
163 if (!(wsp->ws_flags & WRDSF_CLOSURE)) 258 if (!(wsp->ws_flags & WRDSF_CLOSURE))
164 wsp->ws_closure = NULL; 259 wsp->ws_closure = NULL;
165 260
261 if (!(wsp->ws_flags & WRDSF_OPTIONS))
262 wsp->ws_options = 0;
263
264 if (wsp->ws_flags & WRDSF_ESCAPE)
265 {
266 if (!wsp->ws_escape[WRDSX_WORD])
267 wsp->ws_escape[WRDSX_WORD] = "";
268 if (!wsp->ws_escape[WRDSX_QUOTE])
269 wsp->ws_escape[WRDSX_QUOTE] = "";
270 }
271 else
272 {
273 if (wsp->ws_flags & WRDSF_CESCAPES)
274 {
275 wsp->ws_escape[WRDSX_WORD] = wordsplit_c_escape_tab;
276 wsp->ws_escape[WRDSX_QUOTE] = wordsplit_c_escape_tab;
277 wsp->ws_options |= WRDSO_OESC_QUOTE | WRDSO_OESC_WORD
278 | WRDSO_XESC_QUOTE | WRDSO_XESC_WORD;
279 }
280 else
281 {
282 wsp->ws_escape[WRDSX_WORD] = "";
283 wsp->ws_escape[WRDSX_QUOTE] = "\\\\\"\"";