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