blob: 2febed793e5882f2ce3c472a26de8b2a224d58f3 [file] [log] [blame]
Jari Aalto726f6381996-08-26 18:22:31 +00001/* braces.c -- code for doing word expansion in curly braces. */
2
Jari Aalto31859422009-01-12 13:36:28 +00003/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
Jari Aalto726f6381996-08-26 18:22:31 +00004
5 This file is part of GNU Bash, the Bourne Again SHell.
6
Jari Aalto31859422009-01-12 13:36:28 +00007 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
Jari Aalto726f6381996-08-26 18:22:31 +000011
Jari Aalto31859422009-01-12 13:36:28 +000012 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
Jari Aalto726f6381996-08-26 18:22:31 +000016
17 You should have received a copy of the GNU General Public License
Jari Aalto31859422009-01-12 13:36:28 +000018 along with Bash. If not, see <http://www.gnu.org/licenses/>.
19*/
Jari Aalto726f6381996-08-26 18:22:31 +000020
Jari Aaltoccc6cda1996-12-23 17:02:34 +000021/* Stuff in curly braces gets expanded before all other shell expansions. */
Jari Aalto726f6381996-08-26 18:22:31 +000022
Jari Aaltoccc6cda1996-12-23 17:02:34 +000023#include "config.h"
24
25#if defined (BRACE_EXPANSION)
26
27#if defined (HAVE_UNISTD_H)
Jari Aaltocce855b1998-04-17 19:52:44 +000028# ifdef _MINIX
29# include <sys/types.h>
30# endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +000031# include <unistd.h>
32#endif
Jari Aalto726f6381996-08-26 18:22:31 +000033
Jari Aaltod166f041997-06-05 14:59:13 +000034#include "bashansi.h"
Jari Aalto726f6381996-08-26 18:22:31 +000035
36#if defined (SHELL)
Jari Aaltoccc6cda1996-12-23 17:02:34 +000037# include "shell.h"
Jari Aalto726f6381996-08-26 18:22:31 +000038#endif /* SHELL */
39
40#include "general.h"
Jari Aalto7117c2d2002-07-17 14:10:11 +000041#include "shmbutil.h"
Jari Aaltob80f6442004-07-27 13:29:18 +000042#include "chartypes.h"
Jari Aalto7117c2d2002-07-17 14:10:11 +000043
Jari Aalto726f6381996-08-26 18:22:31 +000044#define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
45
Jari Aaltob80f6442004-07-27 13:29:18 +000046#define BRACE_SEQ_SPECIFIER ".."
47
Jari Aalto31859422009-01-12 13:36:28 +000048extern int asprintf __P((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
49
Jari Aalto726f6381996-08-26 18:22:31 +000050/* Basic idea:
51
52 Segregate the text into 3 sections: preamble (stuff before an open brace),
53 postamble (stuff after the matching close brace) and amble (stuff after
54 preamble, and before postamble). Expand amble, and then tack on the
55 expansions to preamble. Expand postamble, and tack on the expansions to
56 the result so far.
57 */
58
59/* The character which is used to separate arguments. */
Jari Aalto31859422009-01-12 13:36:28 +000060static const int brace_arg_separator = ',';
Jari Aalto726f6381996-08-26 18:22:31 +000061
Jari Aaltof73dda02001-11-13 17:56:06 +000062#if defined (__P)
Jari Aalto7117c2d2002-07-17 14:10:11 +000063static int brace_gobbler __P((char *, size_t, int *, int));
Jari Aaltob80f6442004-07-27 13:29:18 +000064static char **expand_amble __P((char *, size_t, int));
65static char **expand_seqterm __P((char *, size_t));
Chet Ramey495aee42011-11-22 19:11:26 -050066static char **mkseq __P((intmax_t, intmax_t, int, int, int));
Jari Aaltof73dda02001-11-13 17:56:06 +000067static char **array_concat __P((char **, char **));
68#else
Jari Aalto726f6381996-08-26 18:22:31 +000069static int brace_gobbler ();
Jari Aaltof73dda02001-11-13 17:56:06 +000070static char **expand_amble ();
Jari Aaltob80f6442004-07-27 13:29:18 +000071static char **expand_seqterm ();
72static char **mkseq();
Jari Aaltof73dda02001-11-13 17:56:06 +000073static char **array_concat ();
74#endif
Jari Aalto726f6381996-08-26 18:22:31 +000075
Jari Aalto06285672006-10-10 14:15:34 +000076#if 0
77static void
78dump_result (a)
79 char **a;
80{
81 int i;
82
83 for (i = 0; a[i]; i++)
84 printf ("dump_result: a[%d] = -%s-\n", i, a[i]);
85}
86#endif
87
Jari Aalto726f6381996-08-26 18:22:31 +000088/* Return an array of strings; the brace expansion of TEXT. */
89char **
90brace_expand (text)
91 char *text;
92{
93 register int start;
Jari Aalto7117c2d2002-07-17 14:10:11 +000094 size_t tlen;
Jari Aalto726f6381996-08-26 18:22:31 +000095 char *preamble, *postamble, *amble;
Jari Aalto7117c2d2002-07-17 14:10:11 +000096 size_t alen;
Jari Aalto726f6381996-08-26 18:22:31 +000097 char **tack, **result;
Jari Aalto06285672006-10-10 14:15:34 +000098 int i, j, c, c1;
Jari Aalto726f6381996-08-26 18:22:31 +000099
Jari Aalto7117c2d2002-07-17 14:10:11 +0000100 DECLARE_MBSTATE;
101
Jari Aalto726f6381996-08-26 18:22:31 +0000102 /* Find the text of the preamble. */
Jari Aalto7117c2d2002-07-17 14:10:11 +0000103 tlen = strlen (text);
Jari Aalto726f6381996-08-26 18:22:31 +0000104 i = 0;
Jari Aalto06285672006-10-10 14:15:34 +0000105#if defined (CSH_BRACE_COMPAT)
106 c = brace_gobbler (text, tlen, &i, '{'); /* } */
107#else
108 /* Make sure that when we exit this loop, c == 0 or text[i] begins a
109 valid brace expansion sequence. */
110 do
111 {
112 c = brace_gobbler (text, tlen, &i, '{'); /* } */
113 c1 = c;
114 /* Verify that c begins a valid brace expansion word. If it doesn't, we
115 go on. Loop stops when there are no more open braces in the word. */
116 if (c)
117 {
118 start = j = i + 1; /* { */
119 c = brace_gobbler (text, tlen, &j, '}');
120 if (c == 0) /* it's not */
121 {
122 i++;
123 c = c1;
124 continue;
125 }
126 else /* it is */
127 {
128 c = c1;
129 break;
130 }
131 }
132 else
133 break;
134 }
135 while (c);
136#endif /* !CSH_BRACE_COMPAT */
Jari Aalto726f6381996-08-26 18:22:31 +0000137
138 preamble = (char *)xmalloc (i + 1);
139 strncpy (preamble, text, i);
140 preamble[i] = '\0';
141
142 result = (char **)xmalloc (2 * sizeof (char *));
143 result[0] = preamble;
144 result[1] = (char *)NULL;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000145
Jari Aalto726f6381996-08-26 18:22:31 +0000146 /* Special case. If we never found an exciting character, then
147 the preamble is all of the text, so just return that. */
148 if (c != '{')
149 return (result);
150
151 /* Find the amble. This is the stuff inside this set of braces. */
152 start = ++i;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000153 c = brace_gobbler (text, tlen, &i, '}');
Jari Aalto726f6381996-08-26 18:22:31 +0000154
155 /* What if there isn't a matching close brace? */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000156 if (c == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000157 {
158#if defined (NOTDEF)
Jari Aalto726f6381996-08-26 18:22:31 +0000159 /* Well, if we found an unquoted BRACE_ARG_SEPARATOR between START
160 and I, then this should be an error. Otherwise, it isn't. */
Jari Aalto7117c2d2002-07-17 14:10:11 +0000161 j = start;
162 while (j < i)
Jari Aalto726f6381996-08-26 18:22:31 +0000163 {
164 if (text[j] == '\\')
165 {
166 j++;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000167 ADVANCE_CHAR (text, tlen, j);
Jari Aalto726f6381996-08-26 18:22:31 +0000168 continue;
169 }
170
171 if (text[j] == brace_arg_separator)
Jari Aaltob80f6442004-07-27 13:29:18 +0000172 { /* { */
Jari Aalto7117c2d2002-07-17 14:10:11 +0000173 strvec_dispose (result);
Jari Aaltob80f6442004-07-27 13:29:18 +0000174 report_error ("no closing `%c' in %s", '}', text);
Jari Aalto726f6381996-08-26 18:22:31 +0000175 throw_to_top_level ();
176 }
Jari Aalto7117c2d2002-07-17 14:10:11 +0000177 ADVANCE_CHAR (text, tlen, j);
Jari Aalto726f6381996-08-26 18:22:31 +0000178 }
179#endif
180 free (preamble); /* Same as result[0]; see initialization. */
181 result[0] = savestring (text);
182 return (result);
183 }
184
Jari Aaltobb706242000-03-17 21:46:59 +0000185#if defined (SHELL)
186 amble = substring (text, start, i);
Jari Aalto7117c2d2002-07-17 14:10:11 +0000187 alen = i - start;
Jari Aaltobb706242000-03-17 21:46:59 +0000188#else
Jari Aalto726f6381996-08-26 18:22:31 +0000189 amble = (char *)xmalloc (1 + (i - start));
190 strncpy (amble, &text[start], (i - start));
Jari Aalto7117c2d2002-07-17 14:10:11 +0000191 alen = i - start;
192 amble[alen] = '\0';
Jari Aaltobb706242000-03-17 21:46:59 +0000193#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000194
195#if defined (SHELL)
Jari Aalto7117c2d2002-07-17 14:10:11 +0000196 INITIALIZE_MBSTATE;
197
Jari Aalto726f6381996-08-26 18:22:31 +0000198 /* If the amble does not contain an unquoted BRACE_ARG_SEPARATOR, then
199 just return without doing any expansion. */
Jari Aalto7117c2d2002-07-17 14:10:11 +0000200 j = 0;
201 while (amble[j])
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000202 {
203 if (amble[j] == '\\')
204 {
205 j++;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000206 ADVANCE_CHAR (amble, alen, j);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000207 continue;
208 }
Jari Aalto7117c2d2002-07-17 14:10:11 +0000209
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000210 if (amble[j] == brace_arg_separator)
211 break;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000212
213 ADVANCE_CHAR (amble, alen, j);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000214 }
Jari Aalto726f6381996-08-26 18:22:31 +0000215
Jari Aaltob80f6442004-07-27 13:29:18 +0000216 if (amble[j] == 0)
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000217 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000218 tack = expand_seqterm (amble, alen);
219 if (tack)
220 goto add_tack;
221 else
222 {
223 free (amble);
224 free (preamble);
225 result[0] = savestring (text);
226 return (result);
227 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000228 }
Jari Aalto726f6381996-08-26 18:22:31 +0000229#endif /* SHELL */
230
Jari Aaltob80f6442004-07-27 13:29:18 +0000231 tack = expand_amble (amble, alen, 0);
232add_tack:
Jari Aalto726f6381996-08-26 18:22:31 +0000233 result = array_concat (result, tack);
234 free (amble);
Jari Aalto7117c2d2002-07-17 14:10:11 +0000235 strvec_dispose (tack);
Jari Aalto726f6381996-08-26 18:22:31 +0000236
Jari Aaltob80f6442004-07-27 13:29:18 +0000237 postamble = text + i + 1;
238
Jari Aalto726f6381996-08-26 18:22:31 +0000239 tack = brace_expand (postamble);
240 result = array_concat (result, tack);
Jari Aalto7117c2d2002-07-17 14:10:11 +0000241 strvec_dispose (tack);
Jari Aalto726f6381996-08-26 18:22:31 +0000242
243 return (result);
244}
245
246/* Expand the text found inside of braces. We simply try to split the
247 text at BRACE_ARG_SEPARATORs into separate strings. We then brace
248 expand each slot which needs it, until there are no more slots which
249 need it. */
250static char **
Jari Aaltob80f6442004-07-27 13:29:18 +0000251expand_amble (text, tlen, flags)
Jari Aalto726f6381996-08-26 18:22:31 +0000252 char *text;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000253 size_t tlen;
Jari Aaltob80f6442004-07-27 13:29:18 +0000254 int flags;
Jari Aalto726f6381996-08-26 18:22:31 +0000255{
256 char **result, **partial;
257 char *tem;
258 int start, i, c;
259
Jari Aalto7117c2d2002-07-17 14:10:11 +0000260 DECLARE_MBSTATE;
261
Jari Aalto726f6381996-08-26 18:22:31 +0000262 result = (char **)NULL;
263
Jari Aalto7117c2d2002-07-17 14:10:11 +0000264 start = i = 0;
265 c = 1;
266 while (c)
Jari Aalto726f6381996-08-26 18:22:31 +0000267 {
Jari Aalto7117c2d2002-07-17 14:10:11 +0000268 c = brace_gobbler (text, tlen, &i, brace_arg_separator);
Jari Aaltobb706242000-03-17 21:46:59 +0000269#if defined (SHELL)
270 tem = substring (text, start, i);
271#else
Jari Aalto726f6381996-08-26 18:22:31 +0000272 tem = (char *)xmalloc (1 + (i - start));
273 strncpy (tem, &text[start], (i - start));
274 tem[i- start] = '\0';
Jari Aaltobb706242000-03-17 21:46:59 +0000275#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000276
277 partial = brace_expand (tem);
278
279 if (!result)
280 result = partial;
281 else
282 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000283 register int lr, lp, j;
284
285 lr = strvec_len (result);
286 lp = strvec_len (partial);
Jari Aalto726f6381996-08-26 18:22:31 +0000287
Jari Aalto7117c2d2002-07-17 14:10:11 +0000288 result = strvec_resize (result, lp + lr + 1);
Jari Aalto726f6381996-08-26 18:22:31 +0000289
290 for (j = 0; j < lp; j++)
291 result[lr + j] = partial[j];
292
293 result[lr + j] = (char *)NULL;
294 free (partial);
295 }
296 free (tem);
Jari Aalto7117c2d2002-07-17 14:10:11 +0000297 ADVANCE_CHAR (text, tlen, i);
298 start = i;
Jari Aalto726f6381996-08-26 18:22:31 +0000299 }
300 return (result);
301}
302
Jari Aaltob80f6442004-07-27 13:29:18 +0000303#define ST_BAD 0
304#define ST_INT 1
305#define ST_CHAR 2
Jari Aalto31859422009-01-12 13:36:28 +0000306#define ST_ZINT 3
Jari Aaltob80f6442004-07-27 13:29:18 +0000307
308static char **
Jari Aalto31859422009-01-12 13:36:28 +0000309mkseq (start, end, incr, type, width)
Chet Ramey495aee42011-11-22 19:11:26 -0500310 intmax_t start, end;
311 int incr, type, width;
Jari Aaltob80f6442004-07-27 13:29:18 +0000312{
Chet Ramey495aee42011-11-22 19:11:26 -0500313 intmax_t n;
314 int i;
Jari Aaltob80f6442004-07-27 13:29:18 +0000315 char **result, *t;
316
Chet Ramey495aee42011-11-22 19:11:26 -0500317 i = abs (end - start) + 1;
318 result = strvec_create (i + 1);
Jari Aaltob80f6442004-07-27 13:29:18 +0000319
Jari Aalto06285672006-10-10 14:15:34 +0000320 if (incr == 0)
321 incr = 1;
322
323 if (start > end && incr > 0)
324 incr = -incr;
325 else if (start < end && incr < 0)
326 incr = -incr;
Jari Aaltob80f6442004-07-27 13:29:18 +0000327
328 /* Make sure we go through the loop at least once, so {3..3} prints `3' */
329 i = 0;
330 n = start;
331 do
332 {
Jari Aalto06285672006-10-10 14:15:34 +0000333#if defined (SHELL)
334 QUIT; /* XXX - memory leak here */
335#endif
Jari Aaltob80f6442004-07-27 13:29:18 +0000336 if (type == ST_INT)
337 result[i++] = itos (n);
Jari Aalto31859422009-01-12 13:36:28 +0000338 else if (type == ST_ZINT)
339 {
Chet Ramey495aee42011-11-22 19:11:26 -0500340 int len, arg;
341 arg = n;
342 len = asprintf (&t, "%0*d", width, arg);
Jari Aalto31859422009-01-12 13:36:28 +0000343 result[i++] = t;
344 }
Jari Aaltob80f6442004-07-27 13:29:18 +0000345 else
346 {
347 t = (char *)xmalloc (2);
348 t[0] = n;
349 t[1] = '\0';
350 result[i++] = t;
351 }
Jari Aaltob80f6442004-07-27 13:29:18 +0000352 n += incr;
Jari Aalto31859422009-01-12 13:36:28 +0000353 if ((incr < 0 && n < end) || (incr > 0 && n > end))
354 break;
Jari Aaltob80f6442004-07-27 13:29:18 +0000355 }
356 while (1);
357
358 result[i] = (char *)0;
359 return (result);
360}
361
362static char **
363expand_seqterm (text, tlen)
364 char *text;
365 size_t tlen;
366{
367 char *t, *lhs, *rhs;
Chet Ramey495aee42011-11-22 19:11:26 -0500368 int i, lhs_t, rhs_t, incr, lhs_l, rhs_l, width;
369 intmax_t lhs_v, rhs_v;
Jari Aaltob80f6442004-07-27 13:29:18 +0000370 intmax_t tl, tr;
Chet Ramey00018032011-11-21 20:51:19 -0500371 char **result, *ep, *oep;
Jari Aaltob80f6442004-07-27 13:29:18 +0000372
373 t = strstr (text, BRACE_SEQ_SPECIFIER);
374 if (t == 0)
375 return ((char **)NULL);
376
Jari Aalto31859422009-01-12 13:36:28 +0000377 lhs_l = t - text; /* index of start of BRACE_SEQ_SPECIFIER */
378 lhs = substring (text, 0, lhs_l);
379 rhs = substring (text, lhs_l + sizeof(BRACE_SEQ_SPECIFIER) - 1, tlen);
Jari Aaltob80f6442004-07-27 13:29:18 +0000380
381 if (lhs[0] == 0 || rhs[0] == 0)
382 {
383 free (lhs);
384 free (rhs);
385 return ((char **)NULL);
386 }
387
388 /* Now figure out whether LHS and RHS are integers or letters. Both
389 sides have to match. */
390 lhs_t = (legal_number (lhs, &tl)) ? ST_INT :
391 ((ISALPHA (lhs[0]) && lhs[1] == 0) ? ST_CHAR : ST_BAD);
Jari Aalto31859422009-01-12 13:36:28 +0000392
393 /* Decide on rhs and whether or not it looks like the user specified
394 an increment */
395 ep = 0;
396 if (ISDIGIT (rhs[0]) || ((rhs[0] == '+' || rhs[0] == '-') && ISDIGIT (rhs[1])))
397 {
398 rhs_t = ST_INT;
399 tr = strtoimax (rhs, &ep, 10);
400 if (ep && *ep != 0 && *ep != '.')
401 rhs_t = ST_BAD; /* invalid */
402 }
403 else if (ISALPHA (rhs[0]) && (rhs[1] == 0 || rhs[1] == '.'))
404 {
405 rhs_t = ST_CHAR;
406 ep = rhs + 1;
407 }
408 else
409 {
410 rhs_t = ST_BAD;
411 ep = 0;
412 }
413
414 incr = 1;
415 if (rhs_t != ST_BAD)
416 {
Chet Ramey00018032011-11-21 20:51:19 -0500417 oep = ep;
Jari Aalto31859422009-01-12 13:36:28 +0000418 if (ep && *ep == '.' && ep[1] == '.' && ep[2])
419 incr = strtoimax (ep + 2, &ep, 10);
420 if (*ep != 0)
421 rhs_t = ST_BAD; /* invalid incr */
Chet Ramey00018032011-11-21 20:51:19 -0500422 tlen -= ep - oep;
Jari Aalto31859422009-01-12 13:36:28 +0000423 }
Jari Aaltob80f6442004-07-27 13:29:18 +0000424
425 if (lhs_t != rhs_t || lhs_t == ST_BAD || rhs_t == ST_BAD)
426 {
427 free (lhs);
428 free (rhs);
429 return ((char **)NULL);
430 }
431
432 /* OK, we have something. It's either a sequence of integers, ascending
433 or descending, or a sequence or letters, ditto. Generate the sequence,
434 put it into a string vector, and return it. */
435
436 if (lhs_t == ST_CHAR)
437 {
Jari Aaltoeb873672004-11-09 21:37:25 +0000438 lhs_v = (unsigned char)lhs[0];
439 rhs_v = (unsigned char)rhs[0];
Jari Aalto31859422009-01-12 13:36:28 +0000440 width = 1;
Jari Aaltob80f6442004-07-27 13:29:18 +0000441 }
442 else
443 {
444 lhs_v = tl; /* integer truncation */
445 rhs_v = tr;
Jari Aalto31859422009-01-12 13:36:28 +0000446
447 /* Decide whether or not the terms need zero-padding */
448 rhs_l = tlen - lhs_l - sizeof (BRACE_SEQ_SPECIFIER) + 1;
449 width = 0;
450 if (lhs_l > 1 && lhs[0] == '0')
451 width = lhs_l, lhs_t = ST_ZINT;
452 if (lhs_l > 2 && lhs[0] == '-' && lhs[1] == '0')
453 width = lhs_l, lhs_t = ST_ZINT;
454 if (rhs_l > 1 && rhs[0] == '0' && width < rhs_l)
455 width = rhs_l, lhs_t = ST_ZINT;
456 if (rhs_l > 2 && rhs[0] == '-' && rhs[1] == '0' && width < rhs_l)
457 width = rhs_l, lhs_t = ST_ZINT;
Chet Ramey00018032011-11-21 20:51:19 -0500458
459 if (width < lhs_l && lhs_t == ST_ZINT)
460 width = lhs_l;
461 if (width < rhs_l && lhs_t == ST_ZINT)
462 width = rhs_l;
Jari Aaltob80f6442004-07-27 13:29:18 +0000463 }
464
Jari Aalto31859422009-01-12 13:36:28 +0000465 result = mkseq (lhs_v, rhs_v, incr, lhs_t, width);
Jari Aaltob80f6442004-07-27 13:29:18 +0000466
467 free (lhs);
468 free (rhs);
469
470 return (result);
471}
472
Jari Aalto726f6381996-08-26 18:22:31 +0000473/* Start at INDEX, and skip characters in TEXT. Set INDEX to the
474 index of the character matching SATISFY. This understands about
475 quoting. Return the character that caused us to stop searching;
476 this is either the same as SATISFY, or 0. */
Jari Aalto06285672006-10-10 14:15:34 +0000477/* If SATISFY is `}', we are looking for a brace expression, so we
478 should enforce the rules that govern valid brace expansions:
479 1) to count as an arg separator, a comma or `..' has to be outside
480 an inner set of braces.
481*/
Jari Aalto726f6381996-08-26 18:22:31 +0000482static int
Jari Aalto7117c2d2002-07-17 14:10:11 +0000483brace_gobbler (text, tlen, indx, satisfy)
Jari Aalto726f6381996-08-26 18:22:31 +0000484 char *text;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000485 size_t tlen;
Jari Aalto726f6381996-08-26 18:22:31 +0000486 int *indx;
487 int satisfy;
488{
Jari Aalto06285672006-10-10 14:15:34 +0000489 register int i, c, quoted, level, commas, pass_next;
Jari Aaltod166f041997-06-05 14:59:13 +0000490#if defined (SHELL)
491 int si;
492 char *t;
493#endif
Jari Aalto7117c2d2002-07-17 14:10:11 +0000494 DECLARE_MBSTATE;
Jari Aalto726f6381996-08-26 18:22:31 +0000495
496 level = quoted = pass_next = 0;
Jari Aalto06285672006-10-10 14:15:34 +0000497#if defined (CSH_BRACE_COMPAT)
498 commas = 1;
499#else
500 commas = (satisfy == '}') ? 0 : 1;
501#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000502
Jari Aalto7117c2d2002-07-17 14:10:11 +0000503 i = *indx;
504 while (c = text[i])
Jari Aalto726f6381996-08-26 18:22:31 +0000505 {
506 if (pass_next)
507 {
508 pass_next = 0;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000509 ADVANCE_CHAR (text, tlen, i);
Jari Aalto726f6381996-08-26 18:22:31 +0000510 continue;
511 }
512
513 /* A backslash escapes the next character. This allows backslash to
514 escape the quote character in a double-quoted string. */
515 if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
Jari Aalto28ef6c32001-04-06 19:14:31 +0000516 {
517 pass_next = 1;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000518 i++;
Jari Aalto28ef6c32001-04-06 19:14:31 +0000519 continue;
520 }
Jari Aalto726f6381996-08-26 18:22:31 +0000521
Jari Aaltob80f6442004-07-27 13:29:18 +0000522#if defined (SHELL)
523 /* If compiling for the shell, treat ${...} like \{...} */
524 if (c == '$' && text[i+1] == '{' && quoted != '\'') /* } */
525 {
526 pass_next = 1;
527 i++;
Jari Aaltoeb873672004-11-09 21:37:25 +0000528 if (quoted == 0)
529 level++;
Jari Aaltob80f6442004-07-27 13:29:18 +0000530 continue;
531 }
532#endif
533
Jari Aalto726f6381996-08-26 18:22:31 +0000534 if (quoted)
535 {
536 if (c == quoted)
537 quoted = 0;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000538 ADVANCE_CHAR (text, tlen, i);
Jari Aalto726f6381996-08-26 18:22:31 +0000539 continue;
540 }
541
542 if (c == '"' || c == '\'' || c == '`')
543 {
544 quoted = c;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000545 i++;
Jari Aalto726f6381996-08-26 18:22:31 +0000546 continue;
547 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000548
Jari Aaltod166f041997-06-05 14:59:13 +0000549#if defined (SHELL)
Jari Aalto31859422009-01-12 13:36:28 +0000550 /* Pass new-style command and process substitutions through unchanged. */
551 if ((c == '$' || c == '<' || c == '>') && text[i+1] == '(') /* ) */
Jari Aaltod166f041997-06-05 14:59:13 +0000552 {
553 si = i + 2;
Jari Aalto31859422009-01-12 13:36:28 +0000554 t = extract_command_subst (text, &si, 0);
Jari Aaltod166f041997-06-05 14:59:13 +0000555 i = si;
556 free (t);
Jari Aalto7117c2d2002-07-17 14:10:11 +0000557 i++;
Jari Aaltod166f041997-06-05 14:59:13 +0000558 continue;
559 }
560#endif
561
Jari Aalto06285672006-10-10 14:15:34 +0000562 if (c == satisfy && level == 0 && quoted == 0 && commas > 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000563 {
564 /* We ignore an open brace surrounded by whitespace, and also
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000565 an open brace followed immediately by a close brace preceded
566 by whitespace. */
Jari Aalto726f6381996-08-26 18:22:31 +0000567 if (c == '{' &&
568 ((!i || brace_whitespace (text[i - 1])) &&
569 (brace_whitespace (text[i + 1]) || text[i + 1] == '}')))
Jari Aalto7117c2d2002-07-17 14:10:11 +0000570 {
571 i++;
572 continue;
573 }
Jari Aaltob80f6442004-07-27 13:29:18 +0000574
Jari Aalto726f6381996-08-26 18:22:31 +0000575 break;
576 }
577
578 if (c == '{')
579 level++;
580 else if (c == '}' && level)
581 level--;
Jari Aalto06285672006-10-10 14:15:34 +0000582#if !defined (CSH_BRACE_COMPAT)
583 else if (satisfy == '}' && c == brace_arg_separator && level == 0)
584 commas++;
585 else if (satisfy == '}' && STREQN (text+i, BRACE_SEQ_SPECIFIER, 2) &&
586 text[i+2] != satisfy && level == 0)
587 commas++;
588#endif
Jari Aalto7117c2d2002-07-17 14:10:11 +0000589
590 ADVANCE_CHAR (text, tlen, i);
Jari Aalto726f6381996-08-26 18:22:31 +0000591 }
592
593 *indx = i;
594 return (c);
595}
596
597/* Return a new array of strings which is the result of appending each
598 string in ARR2 to each string in ARR1. The resultant array is
599 len (arr1) * len (arr2) long. For convenience, ARR1 (and its contents)
600 are free ()'ed. ARR1 can be NULL, in that case, a new version of ARR2
601 is returned. */
602static char **
603array_concat (arr1, arr2)
604 char **arr1, **arr2;
605{
606 register int i, j, len, len1, len2;
607 register char **result;
608
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000609 if (arr1 == 0)
Jari Aalto7117c2d2002-07-17 14:10:11 +0000610 return (strvec_copy (arr2));
Jari Aalto726f6381996-08-26 18:22:31 +0000611
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000612 if (arr2 == 0)
Jari Aalto7117c2d2002-07-17 14:10:11 +0000613 return (strvec_copy (arr1));
Jari Aalto726f6381996-08-26 18:22:31 +0000614
Jari Aalto7117c2d2002-07-17 14:10:11 +0000615 len1 = strvec_len (arr1);
616 len2 = strvec_len (arr2);
Jari Aalto726f6381996-08-26 18:22:31 +0000617
618 result = (char **)xmalloc ((1 + (len1 * len2)) * sizeof (char *));
619
620 len = 0;
621 for (i = 0; i < len1; i++)
622 {
623 int strlen_1 = strlen (arr1[i]);
624
625 for (j = 0; j < len2; j++)
626 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000627 result[len] = (char *)xmalloc (1 + strlen_1 + strlen (arr2[j]));
Jari Aalto726f6381996-08-26 18:22:31 +0000628 strcpy (result[len], arr1[i]);
629 strcpy (result[len] + strlen_1, arr2[j]);
630 len++;
631 }
632 free (arr1[i]);
633 }
634 free (arr1);
635
636 result[len] = (char *)NULL;
637 return (result);
638}
639
640#if defined (TEST)
641#include <stdio.h>
642
643fatal_error (format, arg1, arg2)
644 char *format, *arg1, *arg2;
645{
646 report_error (format, arg1, arg2);
647 exit (1);
648}
649
650report_error (format, arg1, arg2)
651 char *format, *arg1, *arg2;
652{
653 fprintf (stderr, format, arg1, arg2);
654 fprintf (stderr, "\n");
655}
656
657main ()
658{
659 char example[256];
660
661 for (;;)
662 {
663 char **result;
664 int i;
665
666 fprintf (stderr, "brace_expand> ");
667
668 if ((!fgets (example, 256, stdin)) ||
669 (strncmp (example, "quit", 4) == 0))
670 break;
671
672 if (strlen (example))
673 example[strlen (example) - 1] = '\0';
674
675 result = brace_expand (example);
676
677 for (i = 0; result[i]; i++)
678 printf ("%s\n", result[i]);
679
680 free_array (result);
681 }
682}
683
684/*
685 * Local variables:
686 * compile-command: "gcc -g -Bstatic -DTEST -o brace_expand braces.c general.o"
687 * end:
688 */
689
690#endif /* TEST */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000691#endif /* BRACE_EXPANSION */