blob: 25373974167d43d3b4144afc194cb54382f8f1ec [file] [log] [blame]
Jari Aalto726f6381996-08-26 18:22:31 +00001/* braces.c -- code for doing word expansion in curly braces. */
2
Jari Aaltob80f6442004-07-27 13:29:18 +00003/* Copyright (C) 1987-2003 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
7 Bash is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
Jari Aaltobb706242000-03-17 21:46:59 +00009 the Free Software Foundation; either version 2, or (at your option)
Jari Aalto726f6381996-08-26 18:22:31 +000010 any later version.
11
12 Bash is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Bash; see the file COPYING. If not, write to the Free
Jari Aaltobb706242000-03-17 21:46:59 +000019 Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
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 Aalto726f6381996-08-26 18:22:31 +000048/* Basic idea:
49
50 Segregate the text into 3 sections: preamble (stuff before an open brace),
51 postamble (stuff after the matching close brace) and amble (stuff after
52 preamble, and before postamble). Expand amble, and then tack on the
53 expansions to preamble. Expand postamble, and tack on the expansions to
54 the result so far.
55 */
56
57/* The character which is used to separate arguments. */
58int brace_arg_separator = ',';
59
Jari Aaltof73dda02001-11-13 17:56:06 +000060#if defined (__P)
Jari Aalto7117c2d2002-07-17 14:10:11 +000061static int brace_gobbler __P((char *, size_t, int *, int));
Jari Aaltob80f6442004-07-27 13:29:18 +000062static char **expand_amble __P((char *, size_t, int));
63static char **expand_seqterm __P((char *, size_t));
Jari Aalto06285672006-10-10 14:15:34 +000064static char **mkseq __P((int, int, int, int));
Jari Aaltof73dda02001-11-13 17:56:06 +000065static char **array_concat __P((char **, char **));
66#else
Jari Aalto726f6381996-08-26 18:22:31 +000067static int brace_gobbler ();
Jari Aaltof73dda02001-11-13 17:56:06 +000068static char **expand_amble ();
Jari Aaltob80f6442004-07-27 13:29:18 +000069static char **expand_seqterm ();
70static char **mkseq();
Jari Aaltof73dda02001-11-13 17:56:06 +000071static char **array_concat ();
72#endif
Jari Aalto726f6381996-08-26 18:22:31 +000073
Jari Aalto06285672006-10-10 14:15:34 +000074#if 0
75static void
76dump_result (a)
77 char **a;
78{
79 int i;
80
81 for (i = 0; a[i]; i++)
82 printf ("dump_result: a[%d] = -%s-\n", i, a[i]);
83}
84#endif
85
Jari Aalto726f6381996-08-26 18:22:31 +000086/* Return an array of strings; the brace expansion of TEXT. */
87char **
88brace_expand (text)
89 char *text;
90{
91 register int start;
Jari Aalto7117c2d2002-07-17 14:10:11 +000092 size_t tlen;
Jari Aalto726f6381996-08-26 18:22:31 +000093 char *preamble, *postamble, *amble;
Jari Aalto7117c2d2002-07-17 14:10:11 +000094 size_t alen;
Jari Aalto726f6381996-08-26 18:22:31 +000095 char **tack, **result;
Jari Aalto06285672006-10-10 14:15:34 +000096 int i, j, c, c1;
Jari Aalto726f6381996-08-26 18:22:31 +000097
Jari Aalto7117c2d2002-07-17 14:10:11 +000098 DECLARE_MBSTATE;
99
Jari Aalto726f6381996-08-26 18:22:31 +0000100 /* Find the text of the preamble. */
Jari Aalto7117c2d2002-07-17 14:10:11 +0000101 tlen = strlen (text);
Jari Aalto726f6381996-08-26 18:22:31 +0000102 i = 0;
Jari Aalto06285672006-10-10 14:15:34 +0000103#if defined (CSH_BRACE_COMPAT)
104 c = brace_gobbler (text, tlen, &i, '{'); /* } */
105#else
106 /* Make sure that when we exit this loop, c == 0 or text[i] begins a
107 valid brace expansion sequence. */
108 do
109 {
110 c = brace_gobbler (text, tlen, &i, '{'); /* } */
111 c1 = c;
112 /* Verify that c begins a valid brace expansion word. If it doesn't, we
113 go on. Loop stops when there are no more open braces in the word. */
114 if (c)
115 {
116 start = j = i + 1; /* { */
117 c = brace_gobbler (text, tlen, &j, '}');
118 if (c == 0) /* it's not */
119 {
120 i++;
121 c = c1;
122 continue;
123 }
124 else /* it is */
125 {
126 c = c1;
127 break;
128 }
129 }
130 else
131 break;
132 }
133 while (c);
134#endif /* !CSH_BRACE_COMPAT */
Jari Aalto726f6381996-08-26 18:22:31 +0000135
136 preamble = (char *)xmalloc (i + 1);
137 strncpy (preamble, text, i);
138 preamble[i] = '\0';
139
140 result = (char **)xmalloc (2 * sizeof (char *));
141 result[0] = preamble;
142 result[1] = (char *)NULL;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000143
Jari Aalto726f6381996-08-26 18:22:31 +0000144 /* Special case. If we never found an exciting character, then
145 the preamble is all of the text, so just return that. */
146 if (c != '{')
147 return (result);
148
149 /* Find the amble. This is the stuff inside this set of braces. */
150 start = ++i;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000151 c = brace_gobbler (text, tlen, &i, '}');
Jari Aalto726f6381996-08-26 18:22:31 +0000152
153 /* What if there isn't a matching close brace? */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000154 if (c == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000155 {
156#if defined (NOTDEF)
Jari Aalto726f6381996-08-26 18:22:31 +0000157 /* Well, if we found an unquoted BRACE_ARG_SEPARATOR between START
158 and I, then this should be an error. Otherwise, it isn't. */
Jari Aalto7117c2d2002-07-17 14:10:11 +0000159 j = start;
160 while (j < i)
Jari Aalto726f6381996-08-26 18:22:31 +0000161 {
162 if (text[j] == '\\')
163 {
164 j++;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000165 ADVANCE_CHAR (text, tlen, j);
Jari Aalto726f6381996-08-26 18:22:31 +0000166 continue;
167 }
168
169 if (text[j] == brace_arg_separator)
Jari Aaltob80f6442004-07-27 13:29:18 +0000170 { /* { */
Jari Aalto7117c2d2002-07-17 14:10:11 +0000171 strvec_dispose (result);
Jari Aaltob80f6442004-07-27 13:29:18 +0000172 report_error ("no closing `%c' in %s", '}', text);
Jari Aalto726f6381996-08-26 18:22:31 +0000173 throw_to_top_level ();
174 }
Jari Aalto7117c2d2002-07-17 14:10:11 +0000175 ADVANCE_CHAR (text, tlen, j);
Jari Aalto726f6381996-08-26 18:22:31 +0000176 }
177#endif
178 free (preamble); /* Same as result[0]; see initialization. */
179 result[0] = savestring (text);
180 return (result);
181 }
182
Jari Aaltobb706242000-03-17 21:46:59 +0000183#if defined (SHELL)
184 amble = substring (text, start, i);
Jari Aalto7117c2d2002-07-17 14:10:11 +0000185 alen = i - start;
Jari Aaltobb706242000-03-17 21:46:59 +0000186#else
Jari Aalto726f6381996-08-26 18:22:31 +0000187 amble = (char *)xmalloc (1 + (i - start));
188 strncpy (amble, &text[start], (i - start));
Jari Aalto7117c2d2002-07-17 14:10:11 +0000189 alen = i - start;
190 amble[alen] = '\0';
Jari Aaltobb706242000-03-17 21:46:59 +0000191#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000192
193#if defined (SHELL)
Jari Aalto7117c2d2002-07-17 14:10:11 +0000194 INITIALIZE_MBSTATE;
195
Jari Aalto726f6381996-08-26 18:22:31 +0000196 /* If the amble does not contain an unquoted BRACE_ARG_SEPARATOR, then
197 just return without doing any expansion. */
Jari Aalto7117c2d2002-07-17 14:10:11 +0000198 j = 0;
199 while (amble[j])
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000200 {
201 if (amble[j] == '\\')
202 {
203 j++;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000204 ADVANCE_CHAR (amble, alen, j);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000205 continue;
206 }
Jari Aalto7117c2d2002-07-17 14:10:11 +0000207
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000208 if (amble[j] == brace_arg_separator)
209 break;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000210
211 ADVANCE_CHAR (amble, alen, j);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000212 }
Jari Aalto726f6381996-08-26 18:22:31 +0000213
Jari Aaltob80f6442004-07-27 13:29:18 +0000214 if (amble[j] == 0)
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000215 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000216 tack = expand_seqterm (amble, alen);
217 if (tack)
218 goto add_tack;
219 else
220 {
221 free (amble);
222 free (preamble);
223 result[0] = savestring (text);
224 return (result);
225 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000226 }
Jari Aalto726f6381996-08-26 18:22:31 +0000227#endif /* SHELL */
228
Jari Aaltob80f6442004-07-27 13:29:18 +0000229 tack = expand_amble (amble, alen, 0);
230add_tack:
Jari Aalto726f6381996-08-26 18:22:31 +0000231 result = array_concat (result, tack);
232 free (amble);
Jari Aalto7117c2d2002-07-17 14:10:11 +0000233 strvec_dispose (tack);
Jari Aalto726f6381996-08-26 18:22:31 +0000234
Jari Aaltob80f6442004-07-27 13:29:18 +0000235 postamble = text + i + 1;
236
Jari Aalto726f6381996-08-26 18:22:31 +0000237 tack = brace_expand (postamble);
238 result = array_concat (result, tack);
Jari Aalto7117c2d2002-07-17 14:10:11 +0000239 strvec_dispose (tack);
Jari Aalto726f6381996-08-26 18:22:31 +0000240
241 return (result);
242}
243
244/* Expand the text found inside of braces. We simply try to split the
245 text at BRACE_ARG_SEPARATORs into separate strings. We then brace
246 expand each slot which needs it, until there are no more slots which
247 need it. */
248static char **
Jari Aaltob80f6442004-07-27 13:29:18 +0000249expand_amble (text, tlen, flags)
Jari Aalto726f6381996-08-26 18:22:31 +0000250 char *text;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000251 size_t tlen;
Jari Aaltob80f6442004-07-27 13:29:18 +0000252 int flags;
Jari Aalto726f6381996-08-26 18:22:31 +0000253{
254 char **result, **partial;
255 char *tem;
256 int start, i, c;
257
Jari Aalto7117c2d2002-07-17 14:10:11 +0000258 DECLARE_MBSTATE;
259
Jari Aalto726f6381996-08-26 18:22:31 +0000260 result = (char **)NULL;
261
Jari Aalto7117c2d2002-07-17 14:10:11 +0000262 start = i = 0;
263 c = 1;
264 while (c)
Jari Aalto726f6381996-08-26 18:22:31 +0000265 {
Jari Aalto7117c2d2002-07-17 14:10:11 +0000266 c = brace_gobbler (text, tlen, &i, brace_arg_separator);
Jari Aaltobb706242000-03-17 21:46:59 +0000267#if defined (SHELL)
268 tem = substring (text, start, i);
269#else
Jari Aalto726f6381996-08-26 18:22:31 +0000270 tem = (char *)xmalloc (1 + (i - start));
271 strncpy (tem, &text[start], (i - start));
272 tem[i- start] = '\0';
Jari Aaltobb706242000-03-17 21:46:59 +0000273#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000274
275 partial = brace_expand (tem);
276
277 if (!result)
278 result = partial;
279 else
280 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000281 register int lr, lp, j;
282
283 lr = strvec_len (result);
284 lp = strvec_len (partial);
Jari Aalto726f6381996-08-26 18:22:31 +0000285
Jari Aalto7117c2d2002-07-17 14:10:11 +0000286 result = strvec_resize (result, lp + lr + 1);
Jari Aalto726f6381996-08-26 18:22:31 +0000287
288 for (j = 0; j < lp; j++)
289 result[lr + j] = partial[j];
290
291 result[lr + j] = (char *)NULL;
292 free (partial);
293 }
294 free (tem);
Jari Aalto7117c2d2002-07-17 14:10:11 +0000295 ADVANCE_CHAR (text, tlen, i);
296 start = i;
Jari Aalto726f6381996-08-26 18:22:31 +0000297 }
298 return (result);
299}
300
Jari Aaltob80f6442004-07-27 13:29:18 +0000301#define ST_BAD 0
302#define ST_INT 1
303#define ST_CHAR 2
304
305static char **
Jari Aalto06285672006-10-10 14:15:34 +0000306mkseq (start, end, incr, type)
307 int start, end, incr, type;
Jari Aaltob80f6442004-07-27 13:29:18 +0000308{
Jari Aalto06285672006-10-10 14:15:34 +0000309 int n, i;
Jari Aaltob80f6442004-07-27 13:29:18 +0000310 char **result, *t;
311
312 n = abs (end - start) + 1;
313 result = strvec_create (n + 1);
314
Jari Aalto06285672006-10-10 14:15:34 +0000315 if (incr == 0)
316 incr = 1;
317
318 if (start > end && incr > 0)
319 incr = -incr;
320 else if (start < end && incr < 0)
321 incr = -incr;
Jari Aaltob80f6442004-07-27 13:29:18 +0000322
323 /* Make sure we go through the loop at least once, so {3..3} prints `3' */
324 i = 0;
325 n = start;
326 do
327 {
Jari Aalto06285672006-10-10 14:15:34 +0000328#if defined (SHELL)
329 QUIT; /* XXX - memory leak here */
330#endif
Jari Aaltob80f6442004-07-27 13:29:18 +0000331 if (type == ST_INT)
332 result[i++] = itos (n);
333 else
334 {
335 t = (char *)xmalloc (2);
336 t[0] = n;
337 t[1] = '\0';
338 result[i++] = t;
339 }
340 if (n == end)
341 break;
342 n += incr;
343 }
344 while (1);
345
346 result[i] = (char *)0;
347 return (result);
348}
349
350static char **
351expand_seqterm (text, tlen)
352 char *text;
353 size_t tlen;
354{
355 char *t, *lhs, *rhs;
356 int i, lhs_t, rhs_t, lhs_v, rhs_v;
357 intmax_t tl, tr;
358 char **result;
359
360 t = strstr (text, BRACE_SEQ_SPECIFIER);
361 if (t == 0)
362 return ((char **)NULL);
363
364 i = t - text; /* index of start of BRACE_SEQ_SPECIFIER */
365 lhs = substring (text, 0, i);
366 rhs = substring (text, i + sizeof(BRACE_SEQ_SPECIFIER) - 1, tlen);
367
368 if (lhs[0] == 0 || rhs[0] == 0)
369 {
370 free (lhs);
371 free (rhs);
372 return ((char **)NULL);
373 }
374
375 /* Now figure out whether LHS and RHS are integers or letters. Both
376 sides have to match. */
377 lhs_t = (legal_number (lhs, &tl)) ? ST_INT :
378 ((ISALPHA (lhs[0]) && lhs[1] == 0) ? ST_CHAR : ST_BAD);
379 rhs_t = (legal_number (rhs, &tr)) ? ST_INT :
380 ((ISALPHA (rhs[0]) && rhs[1] == 0) ? ST_CHAR : ST_BAD);
381
382 if (lhs_t != rhs_t || lhs_t == ST_BAD || rhs_t == ST_BAD)
383 {
384 free (lhs);
385 free (rhs);
386 return ((char **)NULL);
387 }
388
389 /* OK, we have something. It's either a sequence of integers, ascending
390 or descending, or a sequence or letters, ditto. Generate the sequence,
391 put it into a string vector, and return it. */
392
393 if (lhs_t == ST_CHAR)
394 {
Jari Aaltoeb873672004-11-09 21:37:25 +0000395 lhs_v = (unsigned char)lhs[0];
396 rhs_v = (unsigned char)rhs[0];
Jari Aaltob80f6442004-07-27 13:29:18 +0000397 }
398 else
399 {
400 lhs_v = tl; /* integer truncation */
401 rhs_v = tr;
402 }
403
Jari Aalto06285672006-10-10 14:15:34 +0000404 result = mkseq (lhs_v, rhs_v, 1, lhs_t);
Jari Aaltob80f6442004-07-27 13:29:18 +0000405
406 free (lhs);
407 free (rhs);
408
409 return (result);
410}
411
Jari Aalto726f6381996-08-26 18:22:31 +0000412/* Start at INDEX, and skip characters in TEXT. Set INDEX to the
413 index of the character matching SATISFY. This understands about
414 quoting. Return the character that caused us to stop searching;
415 this is either the same as SATISFY, or 0. */
Jari Aalto06285672006-10-10 14:15:34 +0000416/* If SATISFY is `}', we are looking for a brace expression, so we
417 should enforce the rules that govern valid brace expansions:
418 1) to count as an arg separator, a comma or `..' has to be outside
419 an inner set of braces.
420*/
Jari Aalto726f6381996-08-26 18:22:31 +0000421static int
Jari Aalto7117c2d2002-07-17 14:10:11 +0000422brace_gobbler (text, tlen, indx, satisfy)
Jari Aalto726f6381996-08-26 18:22:31 +0000423 char *text;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000424 size_t tlen;
Jari Aalto726f6381996-08-26 18:22:31 +0000425 int *indx;
426 int satisfy;
427{
Jari Aalto06285672006-10-10 14:15:34 +0000428 register int i, c, quoted, level, commas, pass_next;
Jari Aaltod166f041997-06-05 14:59:13 +0000429#if defined (SHELL)
430 int si;
431 char *t;
432#endif
Jari Aalto7117c2d2002-07-17 14:10:11 +0000433 DECLARE_MBSTATE;
Jari Aalto726f6381996-08-26 18:22:31 +0000434
435 level = quoted = pass_next = 0;
Jari Aalto06285672006-10-10 14:15:34 +0000436#if defined (CSH_BRACE_COMPAT)
437 commas = 1;
438#else
439 commas = (satisfy == '}') ? 0 : 1;
440#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000441
Jari Aalto7117c2d2002-07-17 14:10:11 +0000442 i = *indx;
443 while (c = text[i])
Jari Aalto726f6381996-08-26 18:22:31 +0000444 {
445 if (pass_next)
446 {
447 pass_next = 0;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000448 ADVANCE_CHAR (text, tlen, i);
Jari Aalto726f6381996-08-26 18:22:31 +0000449 continue;
450 }
451
452 /* A backslash escapes the next character. This allows backslash to
453 escape the quote character in a double-quoted string. */
454 if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
Jari Aalto28ef6c32001-04-06 19:14:31 +0000455 {
456 pass_next = 1;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000457 i++;
Jari Aalto28ef6c32001-04-06 19:14:31 +0000458 continue;
459 }
Jari Aalto726f6381996-08-26 18:22:31 +0000460
Jari Aaltob80f6442004-07-27 13:29:18 +0000461#if defined (SHELL)
462 /* If compiling for the shell, treat ${...} like \{...} */
463 if (c == '$' && text[i+1] == '{' && quoted != '\'') /* } */
464 {
465 pass_next = 1;
466 i++;
Jari Aaltoeb873672004-11-09 21:37:25 +0000467 if (quoted == 0)
468 level++;
Jari Aaltob80f6442004-07-27 13:29:18 +0000469 continue;
470 }
471#endif
472
Jari Aalto726f6381996-08-26 18:22:31 +0000473 if (quoted)
474 {
475 if (c == quoted)
476 quoted = 0;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000477 ADVANCE_CHAR (text, tlen, i);
Jari Aalto726f6381996-08-26 18:22:31 +0000478 continue;
479 }
480
481 if (c == '"' || c == '\'' || c == '`')
482 {
483 quoted = c;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000484 i++;
Jari Aalto726f6381996-08-26 18:22:31 +0000485 continue;
486 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000487
Jari Aaltod166f041997-06-05 14:59:13 +0000488#if defined (SHELL)
489 /* Pass new-style command substitutions through unchanged. */
490 if (c == '$' && text[i+1] == '(') /* ) */
491 {
492 si = i + 2;
493 t = extract_command_subst (text, &si);
494 i = si;
495 free (t);
Jari Aalto7117c2d2002-07-17 14:10:11 +0000496 i++;
Jari Aaltod166f041997-06-05 14:59:13 +0000497 continue;
498 }
499#endif
500
Jari Aalto06285672006-10-10 14:15:34 +0000501 if (c == satisfy && level == 0 && quoted == 0 && commas > 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000502 {
503 /* We ignore an open brace surrounded by whitespace, and also
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000504 an open brace followed immediately by a close brace preceded
505 by whitespace. */
Jari Aalto726f6381996-08-26 18:22:31 +0000506 if (c == '{' &&
507 ((!i || brace_whitespace (text[i - 1])) &&
508 (brace_whitespace (text[i + 1]) || text[i + 1] == '}')))
Jari Aalto7117c2d2002-07-17 14:10:11 +0000509 {
510 i++;
511 continue;
512 }
Jari Aaltob80f6442004-07-27 13:29:18 +0000513
Jari Aalto726f6381996-08-26 18:22:31 +0000514 break;
515 }
516
517 if (c == '{')
518 level++;
519 else if (c == '}' && level)
520 level--;
Jari Aalto06285672006-10-10 14:15:34 +0000521#if !defined (CSH_BRACE_COMPAT)
522 else if (satisfy == '}' && c == brace_arg_separator && level == 0)
523 commas++;
524 else if (satisfy == '}' && STREQN (text+i, BRACE_SEQ_SPECIFIER, 2) &&
525 text[i+2] != satisfy && level == 0)
526 commas++;
527#endif
Jari Aalto7117c2d2002-07-17 14:10:11 +0000528
529 ADVANCE_CHAR (text, tlen, i);
Jari Aalto726f6381996-08-26 18:22:31 +0000530 }
531
532 *indx = i;
533 return (c);
534}
535
536/* Return a new array of strings which is the result of appending each
537 string in ARR2 to each string in ARR1. The resultant array is
538 len (arr1) * len (arr2) long. For convenience, ARR1 (and its contents)
539 are free ()'ed. ARR1 can be NULL, in that case, a new version of ARR2
540 is returned. */
541static char **
542array_concat (arr1, arr2)
543 char **arr1, **arr2;
544{
545 register int i, j, len, len1, len2;
546 register char **result;
547
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000548 if (arr1 == 0)
Jari Aalto7117c2d2002-07-17 14:10:11 +0000549 return (strvec_copy (arr2));
Jari Aalto726f6381996-08-26 18:22:31 +0000550
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000551 if (arr2 == 0)
Jari Aalto7117c2d2002-07-17 14:10:11 +0000552 return (strvec_copy (arr1));
Jari Aalto726f6381996-08-26 18:22:31 +0000553
Jari Aalto7117c2d2002-07-17 14:10:11 +0000554 len1 = strvec_len (arr1);
555 len2 = strvec_len (arr2);
Jari Aalto726f6381996-08-26 18:22:31 +0000556
557 result = (char **)xmalloc ((1 + (len1 * len2)) * sizeof (char *));
558
559 len = 0;
560 for (i = 0; i < len1; i++)
561 {
562 int strlen_1 = strlen (arr1[i]);
563
564 for (j = 0; j < len2; j++)
565 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000566 result[len] = (char *)xmalloc (1 + strlen_1 + strlen (arr2[j]));
Jari Aalto726f6381996-08-26 18:22:31 +0000567 strcpy (result[len], arr1[i]);
568 strcpy (result[len] + strlen_1, arr2[j]);
569 len++;
570 }
571 free (arr1[i]);
572 }
573 free (arr1);
574
575 result[len] = (char *)NULL;
576 return (result);
577}
578
579#if defined (TEST)
580#include <stdio.h>
581
582fatal_error (format, arg1, arg2)
583 char *format, *arg1, *arg2;
584{
585 report_error (format, arg1, arg2);
586 exit (1);
587}
588
589report_error (format, arg1, arg2)
590 char *format, *arg1, *arg2;
591{
592 fprintf (stderr, format, arg1, arg2);
593 fprintf (stderr, "\n");
594}
595
596main ()
597{
598 char example[256];
599
600 for (;;)
601 {
602 char **result;
603 int i;
604
605 fprintf (stderr, "brace_expand> ");
606
607 if ((!fgets (example, 256, stdin)) ||
608 (strncmp (example, "quit", 4) == 0))
609 break;
610
611 if (strlen (example))
612 example[strlen (example) - 1] = '\0';
613
614 result = brace_expand (example);
615
616 for (i = 0; result[i]; i++)
617 printf ("%s\n", result[i]);
618
619 free_array (result);
620 }
621}
622
623/*
624 * Local variables:
625 * compile-command: "gcc -g -Bstatic -DTEST -o brace_expand braces.c general.o"
626 * end:
627 */
628
629#endif /* TEST */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000630#endif /* BRACE_EXPANSION */