diff options
Diffstat (limited to 'src/wordsplit.c')
-rw-r--r-- | src/wordsplit.c | 1646 |
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 | ||
54 | static void | 62 | static 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 | ||
61 | static void | 69 | static 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, ...) | |||
72 | static void wordsplit_free_nodes (struct wordsplit *); | 80 | static void wordsplit_free_nodes (struct wordsplit *); |
73 | 81 | ||
74 | static int | 82 | static 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 | |||
91 | static 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 | ||
106 | static int wordsplit_run (const char *command, size_t length, | ||
107 | struct wordsplit *wsp, | ||
108 | int flags, int lvl); | ||
109 | |||
110 | static int wordsplit_init (struct wordsplit *wsp, const char *input, size_t len, | ||
111 | int flags); | ||
112 | static int wordsplit_process_list (struct wordsplit *wsp, size_t start); | ||
113 | static int wordsplit_finish (struct wordsplit *wsp); | ||
114 | |||
115 | static 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 | |||
170 | static 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 | |||
89 | static void | 184 | static void |
90 | wordsplit_init0 (struct wordsplit *wsp) | 185 | wordsplit_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 | ||
203 | char wordsplit_c_escape_tab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v"; | ||
204 | |||
108 | static int | 205 | static int |
109 | wordsplit_init (struct wordsplit *wsp, const char *input, size_t len, | 206 | wordsplit_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] = "\\\\\"\""; | ||