Imported from ../bash-2.05.tar.gz.
[platform/upstream/bash.git] / braces.c
1 /* braces.c -- code for doing word expansion in curly braces. */
2
3 /* Copyright (C) 1987,1991 Free Software Foundation, Inc.
4
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
9    the Free Software Foundation; either version 2, or (at your option)
10    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
19    Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
20
21 /* Stuff in curly braces gets expanded before all other shell expansions. */
22
23 #include "config.h"
24
25 #if defined (BRACE_EXPANSION)
26
27 #if defined (HAVE_UNISTD_H)
28 #  ifdef _MINIX
29 #    include <sys/types.h>
30 #  endif
31 #  include <unistd.h>
32 #endif
33
34 #include "bashansi.h"
35
36 #if defined (SHELL)
37 #  include "shell.h"
38 #endif /* SHELL */
39
40 #include "general.h"
41 #define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
42
43 #if defined (SHELL)
44 extern char *extract_command_subst ();
45 #endif
46
47 /* Basic idea:
48
49    Segregate the text into 3 sections: preamble (stuff before an open brace),
50    postamble (stuff after the matching close brace) and amble (stuff after
51    preamble, and before postamble).  Expand amble, and then tack on the
52    expansions to preamble.  Expand postamble, and tack on the expansions to
53    the result so far.
54  */
55
56 /* The character which is used to separate arguments. */
57 int brace_arg_separator = ',';
58
59 static int brace_gobbler ();
60 static char **expand_amble (), **array_concat ();
61
62 /* Return an array of strings; the brace expansion of TEXT. */
63 char **
64 brace_expand (text)
65      char *text;
66 {
67   register int start;
68   char *preamble, *postamble, *amble;
69   char **tack, **result;
70   int i, j, c;
71
72   /* Find the text of the preamble. */
73   i = 0;
74   c = brace_gobbler (text, &i, '{');
75
76   preamble = (char *)xmalloc (i + 1);
77   strncpy (preamble, text, i);
78   preamble[i] = '\0';
79
80   result = (char **)xmalloc (2 * sizeof (char *));
81   result[0] = preamble;
82   result[1] = (char *)NULL;
83
84   /* Special case.  If we never found an exciting character, then
85      the preamble is all of the text, so just return that. */
86   if (c != '{')
87     return (result);
88
89   /* Find the amble.  This is the stuff inside this set of braces. */
90   start = ++i;
91   c = brace_gobbler (text, &i, '}');
92
93   /* What if there isn't a matching close brace? */
94   if (c == 0)
95     {
96 #if defined (NOTDEF)
97       /* Well, if we found an unquoted BRACE_ARG_SEPARATOR between START
98          and I, then this should be an error.  Otherwise, it isn't. */
99       for (j = start; j < i; j++)
100         {
101           if (text[j] == '\\')
102             {
103               j++;
104               continue;
105             }
106
107           if (text[j] == brace_arg_separator)
108             {
109               free_array (result);
110               report_error ("missing `}'");
111               throw_to_top_level ();
112             }
113         }
114 #endif
115       free (preamble);          /* Same as result[0]; see initialization. */
116       result[0] = savestring (text);
117       return (result);
118     }
119
120 #if defined (SHELL)
121   amble = substring (text, start, i);
122 #else
123   amble = (char *)xmalloc (1 + (i - start));
124   strncpy (amble, &text[start], (i - start));
125   amble[i - start] = '\0';
126 #endif
127
128 #if defined (SHELL)
129   /* If the amble does not contain an unquoted BRACE_ARG_SEPARATOR, then
130      just return without doing any expansion.  */
131   for (j = 0; amble[j]; j++)
132     {
133       if (amble[j] == '\\')
134         {
135           j++;
136           continue;
137         }
138       if (amble[j] == brace_arg_separator)
139         break;
140     }
141
142   if (!amble[j])
143     {
144       free (amble);
145       free (preamble);
146       result[0] = savestring (text);
147       return (result);
148     }
149 #endif /* SHELL */
150
151   postamble = &text[i + 1];
152
153   tack = expand_amble (amble);
154   result = array_concat (result, tack);
155   free (amble);
156   free_array (tack);
157
158   tack = brace_expand (postamble);
159   result = array_concat (result, tack);
160   free_array (tack);
161
162   return (result);
163 }
164
165 /* Expand the text found inside of braces.  We simply try to split the
166    text at BRACE_ARG_SEPARATORs into separate strings.  We then brace
167    expand each slot which needs it, until there are no more slots which
168    need it. */
169 static char **
170 expand_amble (text)
171      char *text;
172 {
173   char **result, **partial;
174   char *tem;
175   int start, i, c;
176
177   result = (char **)NULL;
178
179   for (start = 0, i = 0, c = 1; c; start = ++i)
180     {
181       c = brace_gobbler (text, &i, brace_arg_separator);
182 #if defined (SHELL)
183       tem = substring (text, start, i);
184 #else
185       tem = (char *)xmalloc (1 + (i - start));
186       strncpy (tem, &text[start], (i - start));
187       tem[i- start] = '\0';
188 #endif
189
190       partial = brace_expand (tem);
191
192       if (!result)
193         result = partial;
194       else
195         {
196           register int lr = array_len (result);
197           register int lp = array_len (partial);
198           register int j;
199
200           result = (char **)xrealloc (result, (1 + lp + lr) * sizeof (char *));
201
202           for (j = 0; j < lp; j++)
203             result[lr + j] = partial[j];
204
205           result[lr + j] = (char *)NULL;
206           free (partial);
207         }
208       free (tem);
209     }
210   return (result);
211 }
212
213 /* Start at INDEX, and skip characters in TEXT. Set INDEX to the
214    index of the character matching SATISFY.  This understands about
215    quoting.  Return the character that caused us to stop searching;
216    this is either the same as SATISFY, or 0. */
217 static int
218 brace_gobbler (text, indx, satisfy)
219      char *text;
220      int *indx;
221      int satisfy;
222 {
223   register int i, c, quoted, level, pass_next;
224 #if defined (SHELL)
225   int si;
226   char *t;
227 #endif
228
229   level = quoted = pass_next = 0;
230
231   for (i = *indx; c = text[i]; i++)
232     {
233       if (pass_next)
234         {
235           pass_next = 0;
236           continue;
237         }
238
239       /* A backslash escapes the next character.  This allows backslash to
240          escape the quote character in a double-quoted string. */
241       if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
242         {
243           pass_next = 1;
244           continue;
245         }
246
247       if (quoted)
248         {
249           if (c == quoted)
250             quoted = 0;
251           continue;
252         }
253
254       if (c == '"' || c == '\'' || c == '`')
255         {
256           quoted = c;
257           continue;
258         }
259
260 #if defined (SHELL)
261       /* Pass new-style command substitutions through unchanged. */
262       if (c == '$' && text[i+1] == '(')                 /* ) */
263         {
264           si = i + 2;
265           t = extract_command_subst (text, &si);
266           i = si;
267           free (t);
268           continue;
269         }
270 #endif
271
272       if (c == satisfy && level == 0 && quoted == 0)
273         {
274           /* We ignore an open brace surrounded by whitespace, and also
275              an open brace followed immediately by a close brace preceded
276              by whitespace.  */
277           if (c == '{' &&
278               ((!i || brace_whitespace (text[i - 1])) &&
279                (brace_whitespace (text[i + 1]) || text[i + 1] == '}')))
280             continue;
281 #if defined (SHELL)
282           /* If this is being compiled as part of bash, ignore the `{'
283              in a `${}' construct */
284           if ((c != '{') || i == 0 || (text[i - 1] != '$'))
285 #endif /* SHELL */
286             break;
287         }
288
289       if (c == '{')
290         level++;
291       else if (c == '}' && level)
292         level--;
293     }
294
295   *indx = i;
296   return (c);
297 }
298
299 /* Return a new array of strings which is the result of appending each
300    string in ARR2 to each string in ARR1.  The resultant array is
301    len (arr1) * len (arr2) long.  For convenience, ARR1 (and its contents)
302    are free ()'ed.  ARR1 can be NULL, in that case, a new version of ARR2
303    is returned. */
304 static char **
305 array_concat (arr1, arr2)
306      char **arr1, **arr2;
307 {
308   register int i, j, len, len1, len2;
309   register char **result;
310
311   if (arr1 == 0)
312     return (copy_array (arr2));
313
314   if (arr2 == 0)
315     return (copy_array (arr1));
316
317   len1 = array_len (arr1);
318   len2 = array_len (arr2);
319
320   result = (char **)xmalloc ((1 + (len1 * len2)) * sizeof (char *));
321
322   len = 0;
323   for (i = 0; i < len1; i++)
324     {
325       int strlen_1 = strlen (arr1[i]);
326
327       for (j = 0; j < len2; j++)
328         {
329           result[len] =
330             (char *)xmalloc (1 + strlen_1 + strlen (arr2[j]));
331           strcpy (result[len], arr1[i]);
332           strcpy (result[len] + strlen_1, arr2[j]);
333           len++;
334         }
335       free (arr1[i]);
336     }
337   free (arr1);
338
339   result[len] = (char *)NULL;
340   return (result);
341 }
342
343 #if defined (TEST)
344 #include <stdio.h>
345
346 fatal_error (format, arg1, arg2)
347      char *format, *arg1, *arg2;
348 {
349   report_error (format, arg1, arg2);
350   exit (1);
351 }
352
353 report_error (format, arg1, arg2)
354      char *format, *arg1, *arg2;
355 {
356   fprintf (stderr, format, arg1, arg2);
357   fprintf (stderr, "\n");
358 }
359
360 main ()
361 {
362   char example[256];
363
364   for (;;)
365     {
366       char **result;
367       int i;
368
369       fprintf (stderr, "brace_expand> ");
370
371       if ((!fgets (example, 256, stdin)) ||
372           (strncmp (example, "quit", 4) == 0))
373         break;
374
375       if (strlen (example))
376         example[strlen (example) - 1] = '\0';
377
378       result = brace_expand (example);
379
380       for (i = 0; result[i]; i++)
381         printf ("%s\n", result[i]);
382
383       free_array (result);
384     }
385 }
386 \f
387 /*
388  * Local variables:
389  * compile-command: "gcc -g -Bstatic -DTEST -o brace_expand braces.c general.o"
390  * end:
391  */
392
393 #endif /* TEST */
394 #endif /* BRACE_EXPANSION */