]>
Commit | Line | Data |
---|---|---|
726f6388 JA |
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 | |
bb70624e | 9 | the Free Software Foundation; either version 2, or (at your option) |
726f6388 JA |
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 | |
bb70624e | 19 | Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ |
726f6388 | 20 | |
ccc6cda3 | 21 | /* Stuff in curly braces gets expanded before all other shell expansions. */ |
726f6388 | 22 | |
ccc6cda3 JA |
23 | #include "config.h" |
24 | ||
25 | #if defined (BRACE_EXPANSION) | |
26 | ||
27 | #if defined (HAVE_UNISTD_H) | |
cce855bc JA |
28 | # ifdef _MINIX |
29 | # include <sys/types.h> | |
30 | # endif | |
ccc6cda3 JA |
31 | # include <unistd.h> |
32 | #endif | |
726f6388 | 33 | |
d166f048 | 34 | #include "bashansi.h" |
726f6388 JA |
35 | |
36 | #if defined (SHELL) | |
ccc6cda3 | 37 | # include "shell.h" |
726f6388 JA |
38 | #endif /* SHELL */ |
39 | ||
40 | #include "general.h" | |
41 | #define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n') | |
42 | ||
d166f048 JA |
43 | #if defined (SHELL) |
44 | extern char *extract_command_subst (); | |
45 | #endif | |
46 | ||
726f6388 JA |
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; | |
ccc6cda3 | 70 | int i, j, c; |
726f6388 JA |
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; | |
ccc6cda3 | 83 | |
726f6388 JA |
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? */ | |
ccc6cda3 | 94 | if (c == 0) |
726f6388 JA |
95 | { |
96 | #if defined (NOTDEF) | |
726f6388 JA |
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); | |
ccc6cda3 | 110 | report_error ("missing `}'"); |
726f6388 JA |
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 | ||
bb70624e JA |
120 | #if defined (SHELL) |
121 | amble = substring (text, start, i); | |
122 | #else | |
726f6388 JA |
123 | amble = (char *)xmalloc (1 + (i - start)); |
124 | strncpy (amble, &text[start], (i - start)); | |
125 | amble[i - start] = '\0'; | |
bb70624e | 126 | #endif |
726f6388 JA |
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. */ | |
ccc6cda3 JA |
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 | } | |
726f6388 JA |
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); | |
bb70624e JA |
182 | #if defined (SHELL) |
183 | tem = substring (text, start, i); | |
184 | #else | |
726f6388 JA |
185 | tem = (char *)xmalloc (1 + (i - start)); |
186 | strncpy (tem, &text[start], (i - start)); | |
187 | tem[i- start] = '\0'; | |
bb70624e | 188 | #endif |
726f6388 JA |
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; | |
d166f048 JA |
224 | #if defined (SHELL) |
225 | int si; | |
226 | char *t; | |
227 | #endif | |
726f6388 JA |
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 | } | |
ccc6cda3 | 259 | |
d166f048 JA |
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 | ||
ccc6cda3 | 272 | if (c == satisfy && level == 0 && quoted == 0) |
726f6388 JA |
273 | { |
274 | /* We ignore an open brace surrounded by whitespace, and also | |
ccc6cda3 JA |
275 | an open brace followed immediately by a close brace preceded |
276 | by whitespace. */ | |
726f6388 JA |
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 */ | |
ccc6cda3 JA |
284 | if ((c != '{') || i == 0 || (text[i - 1] != '$')) |
285 | #endif /* SHELL */ | |
726f6388 JA |
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 | ||
ccc6cda3 | 311 | if (arr1 == 0) |
726f6388 JA |
312 | return (copy_array (arr2)); |
313 | ||
ccc6cda3 | 314 | if (arr2 == 0) |
726f6388 JA |
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 */ | |
ccc6cda3 | 394 | #endif /* BRACE_EXPANSION */ |