comparison kpathsea/expand.c @ 2999:faa5d0421460

[project @ 1997-05-23 03:02:09 by jwe]
author jwe
date Fri, 23 May 1997 03:02:36 +0000
parents
children 1f0b06020e36
comparison
equal deleted inserted replaced
2998:692ba9d441ec 2999:faa5d0421460
1 /* expand.c: general expansion. Some of this file (the brace-expansion
2 code from bash) is covered by the GPL; this is the only GPL-covered
3 code in kpathsea. The part of the file that I wrote (the first
4 couple of functions) is covered by the LGPL.
5
6 Copyright (C) 1993, 94, 95, 96, 97 Karl Berry.
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21
22 #include <kpathsea/config.h>
23
24 #include <kpathsea/c-pathch.h>
25 #include <kpathsea/expand.h>
26 #include <kpathsea/pathsearch.h>
27 #include <kpathsea/tilde.h>
28 #include <kpathsea/variable.h>
29
30
31 /* Do variable expansion first so ~${USER} works. (Besides, it's what the
32 shells do.) */
33
34 string
35 kpse_expand P1C(const_string, s)
36 {
37 string var_expansion = kpse_var_expand (s);
38 string tilde_expansion = kpse_tilde_expand (var_expansion);
39
40 /* `kpse_var_expand' always gives us new memory; `kpse_tilde_expand'
41 doesn't, necessarily. So be careful that we don't free what we are
42 about to return. */
43 if (tilde_expansion != var_expansion)
44 free (var_expansion);
45
46 return tilde_expansion;
47 }
48
49
50 static char **brace_expand P1H(const_string);
51 static void free_array P1H(char **);
52
53 /* Do brace expansion on ELT; then do variable and ~ expansion on each
54 element of the result; then do brace expansion again, in case a
55 variable definition contained braces (e.g., $TEXMF). Return a
56 string comprising all of the results separated by ENV_SEP_STRING. */
57
58 static string
59 kpse_brace_expand P1C(const_string, elt)
60 {
61 unsigned i;
62 string *expansions = brace_expand (elt);
63 string ret = xmalloc (1);
64 *ret = 0;
65
66 for (i = 0; expansions[i]; i++) {
67 /* Do $ and ~ expansion on each element. */
68 string x = kpse_expand (expansions[i]);
69 string save_ret = ret;
70 if (!STREQ (x, expansions[i])) {
71 /* If we did any expansions, do brace expansion again. Since
72 recursive variable definitions are not allowed, this recursion
73 must terminate. (In practice, it's unlikely there will ever be
74 more than one level of recursion.) */
75 string save_x = x;
76 x = kpse_brace_expand (x);
77 free (save_x);
78 }
79 ret = concat3 (ret, x, ENV_SEP_STRING);
80 free (save_ret);
81 free (x);
82 }
83
84 free_array (expansions);
85 ret[strlen (ret) - 1] = 0; /* waste the trailing null */
86 return ret;
87 }
88
89
90 /* Be careful to not waste all the memory we allocate for each element. */
91
92 string
93 kpse_path_expand P1C(const_string, path)
94 {
95 string elt;
96 /* Must do variable expansion first because if we have
97 foo = .:~
98 TEXINPUTS = $foo
99 we want to end up with TEXINPUTS = .:/home/karl.
100 Since kpse_path_element is not reentrant, we must get all
101 the path elements before we start the loop. */
102 string xpath = kpse_var_expand (path);
103 string ret = xmalloc (1);
104 *ret = 0;
105
106 for (elt = kpse_path_element (xpath); elt; elt = kpse_path_element (NULL)) {
107 string save_ret = ret;
108 /* Do brace expansion first, so tilde expansion happens in {~ka,~kb}. */
109 string expansion = kpse_brace_expand (elt);
110 ret = concat3 (ret, expansion, ENV_SEP_STRING);
111 free (expansion);
112 free (save_ret);
113 }
114
115 /* Waste the last byte by overwriting the trailing env_sep with a null. */
116 ret[strlen (ret) - 1] = 0;
117 free (xpath);
118
119 return ret;
120 }
121
122 /* braces.c -- code for doing word expansion in curly braces. Taken from
123 bash 1.14.5.
124
125 Copyright (C) 1987,1991 Free Software Foundation, Inc.
126
127 This program is free software; you can redistribute it and/or modify it
128 under the terms of the GNU General Public License as published by
129 the Free Software Foundation; either version 1, or (at your option)
130 any later version.
131
132 This program is distributed in the hope that it will be useful, but
133 WITHOUT ANY WARRANTY; without even the implied warranty of
134 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
135 General Public License for more details.
136
137 You should have received a copy of the GNU General Public License
138 along with this program; see the file COPYING. If not, write to the
139 Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
140 MA 02111-1307, USA. */
141
142
143 #define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
144 #define savestring xstrdup
145
146 /* Basic idea:
147
148 Segregate the text into 3 sections: preamble (stuff before an open brace),
149 postamble (stuff after the matching close brace) and amble (stuff after
150 preamble, and before postamble). Expand amble, and then tack on the
151 expansions to preamble. Expand postamble, and tack on the expansions to
152 the result so far.
153 */
154
155 /* The character which is used to separate arguments. */
156 static int brace_arg_separator = ',';
157
158 static int brace_gobbler P3H(const_string, int *, int);
159 static char **expand_amble P1H(const_string),
160 **array_concat P2H(string * , string *);
161
162 /* Return the length of ARRAY, a NULL terminated array of char *. */
163 static int
164 array_len P1C(char **, array)
165 {
166 register int i;
167 for (i = 0; array[i]; i++);
168 return (i);
169 }
170
171 /* Free the contents of ARRAY, a NULL terminated array of char *. */
172 static void
173 free_array P1C(char **, array)
174 {
175 register int i = 0;
176
177 if (!array) return;
178
179 while (array[i])
180 free (array[i++]);
181 free (array);
182 }
183
184 /* Allocate and return a new copy of ARRAY and its contents. */
185 static char **
186 copy_array P1C(char **, array)
187 {
188 register int i;
189 int len;
190 char **new_array;
191
192 len = array_len (array);
193
194 new_array = (char **)xmalloc ((len + 1) * sizeof (char *));
195 for (i = 0; array[i]; i++)
196 new_array[i] = savestring (array[i]);
197 new_array[i] = (char *)NULL;
198
199 return (new_array);
200 }
201
202
203 /* Return an array of strings; the brace expansion of TEXT. */
204 static char **
205 brace_expand P1C(const_string, text)
206 {
207 register int start;
208 char *preamble, *amble;
209 const_string postamble;
210 char **tack, **result;
211 int i, c;
212
213 /* Find the text of the preamble. */
214 i = 0;
215 c = brace_gobbler (text, &i, '{');
216
217 preamble = xmalloc (i + 1);
218 strncpy (preamble, text, i);
219 preamble[i] = 0;
220
221 result = xmalloc (2 * sizeof (char *));
222 result[0] = preamble;
223 result[1] = NULL;
224
225 /* Special case. If we never found an exciting character, then
226 the preamble is all of the text, so just return that. */
227 if (c != '{')
228 return (result);
229
230 /* Find the amble. This is the stuff inside this set of braces. */
231 start = ++i;
232 c = brace_gobbler (text, &i, '}');
233
234 /* What if there isn't a matching close brace? */
235 if (!c)
236 {
237 WARNING1 ("%s: Unmatched {", text);
238 free (preamble); /* Same as result[0]; see initialization. */
239 result[0] = savestring (text);
240 return (result);
241 }
242
243 amble = xmalloc (1 + (i - start));
244 strncpy (amble, &text[start], (i - start));
245 amble[i - start] = 0;
246
247 postamble = &text[i + 1];
248
249 tack = expand_amble (amble);
250 result = array_concat (result, tack);
251 free (amble);
252 free_array (tack);
253
254 tack = brace_expand (postamble);
255 result = array_concat (result, tack);
256 free_array (tack);
257
258 return (result);
259 }
260
261
262 /* Expand the text found inside of braces. We simply try to split the
263 text at BRACE_ARG_SEPARATORs into separate strings. We then brace
264 expand each slot which needs it, until there are no more slots which
265 need it. */
266 static char **
267 expand_amble P1C(const_string, text)
268 {
269 char **result, **partial;
270 char *tem;
271 int start, i, c;
272
273 result = NULL;
274
275 for (start = 0, i = 0, c = 1; c; start = ++i)
276 {
277 c = brace_gobbler (text, &i, brace_arg_separator);
278 tem = xmalloc (1 + (i - start));
279 strncpy (tem, &text[start], (i - start));
280 tem[i- start] = 0;
281
282 partial = brace_expand (tem);
283
284 if (!result)
285 result = partial;
286 else
287 {
288 register int lr = array_len (result);
289 register int lp = array_len (partial);
290 register int j;
291
292 result = xrealloc (result, (1 + lp + lr) * sizeof (char *));
293
294 for (j = 0; j < lp; j++)
295 result[lr + j] = partial[j];
296
297 result[lr + j] = NULL;
298 free (partial);
299 }
300 free (tem);
301 }
302 return (result);
303 }
304
305 /* Return a new array of strings which is the result of appending each
306 string in ARR2 to each string in ARR1. The resultant array is
307 len (arr1) * len (arr2) long. For convenience, ARR1 (and its contents)
308 are free ()'ed. ARR1 can be NULL, in that case, a new version of ARR2
309 is returned. */
310 static char **
311 array_concat P2C(string *, arr1, string *, arr2)
312 {
313 register int i, j, len, len1, len2;
314 register char **result;
315
316 if (!arr1)
317 return (copy_array (arr2));
318
319 if (!arr2)
320 return (copy_array (arr1));
321
322 len1 = array_len (arr1);
323 len2 = array_len (arr2);
324
325 result = xmalloc ((1 + (len1 * len2)) * sizeof (char *));
326
327 len = 0;
328 for (i = 0; i < len1; i++)
329 {
330 int strlen_1 = strlen (arr1[i]);
331
332 for (j = 0; j < len2; j++)
333 {
334 result[len] =
335 xmalloc (1 + strlen_1 + strlen (arr2[j]));
336 strcpy (result[len], arr1[i]);
337 strcpy (result[len] + strlen_1, arr2[j]);
338 len++;
339 }
340 free (arr1[i]);
341 }
342 free (arr1);
343
344 result[len] = NULL;
345 return (result);
346 }
347
348 /* Start at INDEX, and skip characters in TEXT. Set INDEX to the
349 index of the character matching SATISFY. This understands about
350 quoting. Return the character that caused us to stop searching;
351 this is either the same as SATISFY, or 0. */
352 static int
353 brace_gobbler P3C(const_string, text, int *, indx, int, satisfy)
354 {
355 register int i, c, quoted, level, pass_next;
356
357 level = quoted = pass_next = 0;
358
359 for (i = *indx; (c = text[i]); i++)
360 {
361 if (pass_next)
362 {
363 pass_next = 0;
364 continue;
365 }
366
367 /* A backslash escapes the next character. This allows backslash to
368 escape the quote character in a double-quoted string. */
369 if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
370 {
371 pass_next = 1;
372 continue;
373 }
374
375 if (quoted)
376 {
377 if (c == quoted)
378 quoted = 0;
379 continue;
380 }
381
382 if (c == '"' || c == '\'' || c == '`')
383 {
384 quoted = c;
385 continue;
386 }
387
388 if (c == satisfy && !level && !quoted)
389 {
390 /* We ignore an open brace surrounded by whitespace, and also
391 an open brace followed immediately by a close brace, that
392 was preceded with whitespace. */
393 if (c == '{' &&
394 ((!i || brace_whitespace (text[i - 1])) &&
395 (brace_whitespace (text[i + 1]) || text[i + 1] == '}')))
396 continue;
397 /* If this is being compiled as part of bash, ignore the `{'
398 in a `${}' construct */
399 if ((c != '{') || !i || (text[i - 1] != '$'))
400 break;
401 }
402
403 if (c == '{')
404 level++;
405 else if (c == '}' && level)
406 level--;
407 }
408
409 *indx = i;
410 return (c);
411 }
412
413 #if defined (TEST)
414 #include <stdio.h>
415
416 fatal_error (format, arg1, arg2)
417 char *format, *arg1, *arg2;
418 {
419 report_error (format, arg1, arg2);
420 exit (1);
421 }
422
423 report_error (format, arg1, arg2)
424 char *format, *arg1, *arg2;
425 {
426 fprintf (stderr, format, arg1, arg2);
427 fprintf (stderr, "\n");
428 }
429
430 main ()
431 {
432 char example[256];
433
434 for (;;)
435 {
436 char **result;
437 int i;
438
439 fprintf (stderr, "brace_expand> ");
440
441 if ((!fgets (example, 256, stdin)) ||
442 (strncmp (example, "quit", 4) == 0))
443 break;
444
445 if (strlen (example))
446 example[strlen (example) - 1] = 0;
447
448 result = brace_expand (example);
449
450 for (i = 0; result[i]; i++)
451 printf ("%s\n", result[i]);
452
453 free_array (result);
454 }
455 }
456
457 /*
458 * Local variables:
459 * test-compile-command: "gcc -g -DTEST -I.. -I. -o brace_expand braces.c -L. -lkpathsea"
460 * end:
461 */
462
463 #endif /* TEST */