blob: 4e0c08a795d9f13d0e853bc1a4f499a16324af76 [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));
Jari Aalto31859422009-01-12 13:36:28 +000066static char **mkseq __P((int, int, 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)
310 int start, end, incr, type, width;
Jari Aaltob80f6442004-07-27 13:29:18 +0000311{
Jari Aalto06285672006-10-10 14:15:34 +0000312 int n, i;
Jari Aaltob80f6442004-07-27 13:29:18 +0000313 char **result, *t;
314
315 n = abs (end - start) + 1;
316 result = strvec_create (n + 1);
317
Jari Aalto06285672006-10-10 14:15:34 +0000318 if (incr == 0)
319 incr = 1;
320
321 if (start > end && incr > 0)
322 incr = -incr;
323 else if (start < end && incr < 0)
324 incr = -incr;
Jari Aaltob80f6442004-07-27 13:29:18 +0000325
326 /* Make sure we go through the loop at least once, so {3..3} prints `3' */
327 i = 0;
328 n = start;
329 do
330 {
Jari Aalto06285672006-10-10 14:15:34 +0000331#if defined (SHELL)
332 QUIT; /* XXX - memory leak here */
333#endif
Jari Aaltob80f6442004-07-27 13:29:18 +0000334 if (type == ST_INT)
335 result[i++] = itos (n);
Jari Aalto31859422009-01-12 13:36:28 +0000336 else if (type == ST_ZINT)
337 {
338 int len;
339 len = asprintf (&t, "%0*d", width, n);
340 result[i++] = t;
341 }
Jari Aaltob80f6442004-07-27 13:29:18 +0000342 else
343 {
344 t = (char *)xmalloc (2);
345 t[0] = n;
346 t[1] = '\0';
347 result[i++] = t;
348 }
Jari Aaltob80f6442004-07-27 13:29:18 +0000349 n += incr;
Jari Aalto31859422009-01-12 13:36:28 +0000350 if ((incr < 0 && n < end) || (incr > 0 && n > end))
351 break;
Jari Aaltob80f6442004-07-27 13:29:18 +0000352 }
353 while (1);
354
355 result[i] = (char *)0;
356 return (result);
357}
358
359static char **
360expand_seqterm (text, tlen)
361 char *text;
362 size_t tlen;
363{
364 char *t, *lhs, *rhs;
Jari Aalto31859422009-01-12 13:36:28 +0000365 int i, lhs_t, rhs_t, lhs_v, rhs_v, incr, lhs_l, rhs_l, width;
Jari Aaltob80f6442004-07-27 13:29:18 +0000366 intmax_t tl, tr;
Jari Aalto31859422009-01-12 13:36:28 +0000367 char **result, *ep;
Jari Aaltob80f6442004-07-27 13:29:18 +0000368
369 t = strstr (text, BRACE_SEQ_SPECIFIER);
370 if (t == 0)
371 return ((char **)NULL);
372
Jari Aalto31859422009-01-12 13:36:28 +0000373 lhs_l = t - text; /* index of start of BRACE_SEQ_SPECIFIER */
374 lhs = substring (text, 0, lhs_l);
375 rhs = substring (text, lhs_l + sizeof(BRACE_SEQ_SPECIFIER) - 1, tlen);
Jari Aaltob80f6442004-07-27 13:29:18 +0000376
377 if (lhs[0] == 0 || rhs[0] == 0)
378 {
379 free (lhs);
380 free (rhs);
381 return ((char **)NULL);
382 }
383
384 /* Now figure out whether LHS and RHS are integers or letters. Both
385 sides have to match. */
386 lhs_t = (legal_number (lhs, &tl)) ? ST_INT :
387 ((ISALPHA (lhs[0]) && lhs[1] == 0) ? ST_CHAR : ST_BAD);
Jari Aalto31859422009-01-12 13:36:28 +0000388
389 /* Decide on rhs and whether or not it looks like the user specified
390 an increment */
391 ep = 0;
392 if (ISDIGIT (rhs[0]) || ((rhs[0] == '+' || rhs[0] == '-') && ISDIGIT (rhs[1])))
393 {
394 rhs_t = ST_INT;
395 tr = strtoimax (rhs, &ep, 10);
396 if (ep && *ep != 0 && *ep != '.')
397 rhs_t = ST_BAD; /* invalid */
398 }
399 else if (ISALPHA (rhs[0]) && (rhs[1] == 0 || rhs[1] == '.'))
400 {
401 rhs_t = ST_CHAR;
402 ep = rhs + 1;
403 }
404 else
405 {
406 rhs_t = ST_BAD;
407 ep = 0;
408 }
409
410 incr = 1;
411 if (rhs_t != ST_BAD)
412 {
413 if (ep && *ep == '.' && ep[1] == '.' && ep[2])
414 incr = strtoimax (ep + 2, &ep, 10);
415 if (*ep != 0)
416 rhs_t = ST_BAD; /* invalid incr */
417 }
Jari Aaltob80f6442004-07-27 13:29:18 +0000418
419 if (lhs_t != rhs_t || lhs_t == ST_BAD || rhs_t == ST_BAD)
420 {
421 free (lhs);
422 free (rhs);
423 return ((char **)NULL);
424 }
425
426 /* OK, we have something. It's either a sequence of integers, ascending
427 or descending, or a sequence or letters, ditto. Generate the sequence,
428 put it into a string vector, and return it. */
429
430 if (lhs_t == ST_CHAR)
431 {
Jari Aaltoeb873672004-11-09 21:37:25 +0000432 lhs_v = (unsigned char)lhs[0];
433 rhs_v = (unsigned char)rhs[0];
Jari Aalto31859422009-01-12 13:36:28 +0000434 width = 1;
Jari Aaltob80f6442004-07-27 13:29:18 +0000435 }
436 else
437 {
438 lhs_v = tl; /* integer truncation */
439 rhs_v = tr;
Jari Aalto31859422009-01-12 13:36:28 +0000440
441 /* Decide whether or not the terms need zero-padding */
442 rhs_l = tlen - lhs_l - sizeof (BRACE_SEQ_SPECIFIER) + 1;
443 width = 0;
444 if (lhs_l > 1 && lhs[0] == '0')
445 width = lhs_l, lhs_t = ST_ZINT;
446 if (lhs_l > 2 && lhs[0] == '-' && lhs[1] == '0')
447 width = lhs_l, lhs_t = ST_ZINT;
448 if (rhs_l > 1 && rhs[0] == '0' && width < rhs_l)
449 width = rhs_l, lhs_t = ST_ZINT;
450 if (rhs_l > 2 && rhs[0] == '-' && rhs[1] == '0' && width < rhs_l)
451 width = rhs_l, lhs_t = ST_ZINT;
Jari Aaltob80f6442004-07-27 13:29:18 +0000452 }
453
Jari Aalto31859422009-01-12 13:36:28 +0000454 result = mkseq (lhs_v, rhs_v, incr, lhs_t, width);
Jari Aaltob80f6442004-07-27 13:29:18 +0000455
456 free (lhs);
457 free (rhs);
458
459 return (result);
460}
461
Jari Aalto726f6381996-08-26 18:22:31 +0000462/* Start at INDEX, and skip characters in TEXT. Set INDEX to the
463 index of the character matching SATISFY. This understands about
464 quoting. Return the character that caused us to stop searching;
465 this is either the same as SATISFY, or 0. */
Jari Aalto06285672006-10-10 14:15:34 +0000466/* If SATISFY is `}', we are looking for a brace expression, so we
467 should enforce the rules that govern valid brace expansions:
468 1) to count as an arg separator, a comma or `..' has to be outside
469 an inner set of braces.
470*/
Jari Aalto726f6381996-08-26 18:22:31 +0000471static int
Jari Aalto7117c2d2002-07-17 14:10:11 +0000472brace_gobbler (text, tlen, indx, satisfy)
Jari Aalto726f6381996-08-26 18:22:31 +0000473 char *text;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000474 size_t tlen;
Jari Aalto726f6381996-08-26 18:22:31 +0000475 int *indx;
476 int satisfy;
477{
Jari Aalto06285672006-10-10 14:15:34 +0000478 register int i, c, quoted, level, commas, pass_next;
Jari Aaltod166f041997-06-05 14:59:13 +0000479#if defined (SHELL)
480 int si;
481 char *t;
482#endif
Jari Aalto7117c2d2002-07-17 14:10:11 +0000483 DECLARE_MBSTATE;
Jari Aalto726f6381996-08-26 18:22:31 +0000484
485 level = quoted = pass_next = 0;
Jari Aalto06285672006-10-10 14:15:34 +0000486#if defined (CSH_BRACE_COMPAT)
487 commas = 1;
488#else
489 commas = (satisfy == '}') ? 0 : 1;
490#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000491
Jari Aalto7117c2d2002-07-17 14:10:11 +0000492 i = *indx;
493 while (c = text[i])
Jari Aalto726f6381996-08-26 18:22:31 +0000494 {
495 if (pass_next)
496 {
497 pass_next = 0;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000498 ADVANCE_CHAR (text, tlen, i);
Jari Aalto726f6381996-08-26 18:22:31 +0000499 continue;
500 }
501
502 /* A backslash escapes the next character. This allows backslash to
503 escape the quote character in a double-quoted string. */
504 if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
Jari Aalto28ef6c32001-04-06 19:14:31 +0000505 {
506 pass_next = 1;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000507 i++;
Jari Aalto28ef6c32001-04-06 19:14:31 +0000508 continue;
509 }
Jari Aalto726f6381996-08-26 18:22:31 +0000510
Jari Aaltob80f6442004-07-27 13:29:18 +0000511#if defined (SHELL)
512 /* If compiling for the shell, treat ${...} like \{...} */
513 if (c == '$' && text[i+1] == '{' && quoted != '\'') /* } */
514 {
515 pass_next = 1;
516 i++;
Jari Aaltoeb873672004-11-09 21:37:25 +0000517 if (quoted == 0)
518 level++;
Jari Aaltob80f6442004-07-27 13:29:18 +0000519 continue;
520 }
521#endif
522
Jari Aalto726f6381996-08-26 18:22:31 +0000523 if (quoted)
524 {
525 if (c == quoted)
526 quoted = 0;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000527 ADVANCE_CHAR (text, tlen, i);
Jari Aalto726f6381996-08-26 18:22:31 +0000528 continue;
529 }
530
531 if (c == '"' || c == '\'' || c == '`')
532 {
533 quoted = c;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000534 i++;
Jari Aalto726f6381996-08-26 18:22:31 +0000535 continue;
536 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000537
Jari Aaltod166f041997-06-05 14:59:13 +0000538#if defined (SHELL)
Jari Aalto31859422009-01-12 13:36:28 +0000539 /* Pass new-style command and process substitutions through unchanged. */
540 if ((c == '$' || c == '<' || c == '>') && text[i+1] == '(') /* ) */
Jari Aaltod166f041997-06-05 14:59:13 +0000541 {
542 si = i + 2;
Jari Aalto31859422009-01-12 13:36:28 +0000543 t = extract_command_subst (text, &si, 0);
Jari Aaltod166f041997-06-05 14:59:13 +0000544 i = si;
545 free (t);
Jari Aalto7117c2d2002-07-17 14:10:11 +0000546 i++;
Jari Aaltod166f041997-06-05 14:59:13 +0000547 continue;
548 }
549#endif
550
Jari Aalto06285672006-10-10 14:15:34 +0000551 if (c == satisfy && level == 0 && quoted == 0 && commas > 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000552 {
553 /* We ignore an open brace surrounded by whitespace, and also
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000554 an open brace followed immediately by a close brace preceded
555 by whitespace. */
Jari Aalto726f6381996-08-26 18:22:31 +0000556 if (c == '{' &&
557 ((!i || brace_whitespace (text[i - 1])) &&
558 (brace_whitespace (text[i + 1]) || text[i + 1] == '}')))
Jari Aalto7117c2d2002-07-17 14:10:11 +0000559 {
560 i++;
561 continue;
562 }
Jari Aaltob80f6442004-07-27 13:29:18 +0000563
Jari Aalto726f6381996-08-26 18:22:31 +0000564 break;
565 }
566
567 if (c == '{')
568 level++;
569 else if (c == '}' && level)
570 level--;
Jari Aalto06285672006-10-10 14:15:34 +0000571#if !defined (CSH_BRACE_COMPAT)
572 else if (satisfy == '}' && c == brace_arg_separator && level == 0)
573 commas++;
574 else if (satisfy == '}' && STREQN (text+i, BRACE_SEQ_SPECIFIER, 2) &&
575 text[i+2] != satisfy && level == 0)
576 commas++;
577#endif
Jari Aalto7117c2d2002-07-17 14:10:11 +0000578
579 ADVANCE_CHAR (text, tlen, i);
Jari Aalto726f6381996-08-26 18:22:31 +0000580 }
581
582 *indx = i;
583 return (c);
584}
585
586/* Return a new array of strings which is the result of appending each
587 string in ARR2 to each string in ARR1. The resultant array is
588 len (arr1) * len (arr2) long. For convenience, ARR1 (and its contents)
589 are free ()'ed. ARR1 can be NULL, in that case, a new version of ARR2
590 is returned. */
591static char **
592array_concat (arr1, arr2)
593 char **arr1, **arr2;
594{
595 register int i, j, len, len1, len2;
596 register char **result;
597
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000598 if (arr1 == 0)
Jari Aalto7117c2d2002-07-17 14:10:11 +0000599 return (strvec_copy (arr2));
Jari Aalto726f6381996-08-26 18:22:31 +0000600
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000601 if (arr2 == 0)
Jari Aalto7117c2d2002-07-17 14:10:11 +0000602 return (strvec_copy (arr1));
Jari Aalto726f6381996-08-26 18:22:31 +0000603
Jari Aalto7117c2d2002-07-17 14:10:11 +0000604 len1 = strvec_len (arr1);
605 len2 = strvec_len (arr2);
Jari Aalto726f6381996-08-26 18:22:31 +0000606
607 result = (char **)xmalloc ((1 + (len1 * len2)) * sizeof (char *));
608
609 len = 0;
610 for (i = 0; i < len1; i++)
611 {
612 int strlen_1 = strlen (arr1[i]);
613
614 for (j = 0; j < len2; j++)
615 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000616 result[len] = (char *)xmalloc (1 + strlen_1 + strlen (arr2[j]));
Jari Aalto726f6381996-08-26 18:22:31 +0000617 strcpy (result[len], arr1[i]);
618 strcpy (result[len] + strlen_1, arr2[j]);
619 len++;
620 }
621 free (arr1[i]);
622 }
623 free (arr1);
624
625 result[len] = (char *)NULL;
626 return (result);
627}
628
629#if defined (TEST)
630#include <stdio.h>
631
632fatal_error (format, arg1, arg2)
633 char *format, *arg1, *arg2;
634{
635 report_error (format, arg1, arg2);
636 exit (1);
637}
638
639report_error (format, arg1, arg2)
640 char *format, *arg1, *arg2;
641{
642 fprintf (stderr, format, arg1, arg2);
643 fprintf (stderr, "\n");
644}
645
646main ()
647{
648 char example[256];
649
650 for (;;)
651 {
652 char **result;
653 int i;
654
655 fprintf (stderr, "brace_expand> ");
656
657 if ((!fgets (example, 256, stdin)) ||
658 (strncmp (example, "quit", 4) == 0))
659 break;
660
661 if (strlen (example))
662 example[strlen (example) - 1] = '\0';
663
664 result = brace_expand (example);
665
666 for (i = 0; result[i]; i++)
667 printf ("%s\n", result[i]);
668
669 free_array (result);
670 }
671}
672
673/*
674 * Local variables:
675 * compile-command: "gcc -g -Bstatic -DTEST -o brace_expand braces.c general.o"
676 * end:
677 */
678
679#endif /* TEST */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000680#endif /* BRACE_EXPANSION */