~ubuntu-branches/ubuntu/trusty/bash/trusty-security

« back to all changes in this revision

Viewing changes to braces.c

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2014-03-03 22:52:05 UTC
  • mfrom: (1.3.5) (2.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20140303225205-87ltrt5kspeq0g1b
Tags: 4.3-1ubuntu1
* Merge with Debian; remaining changes:
  - skel.bashrc:
    - Run lesspipe.
    - Enable ls aliases.
    - Set options in ll alias to -alF.
    - Define an alert alias.
    - Enabled colored grep aliases.
  - etc.bash.bashrc:
    - Add sudo hint.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* braces.c -- code for doing word expansion in curly braces. */
 
2
 
 
3
/* Copyright (C) 1987-2012 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
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation, either version 3 of the License, or
 
10
   (at your option) any later version.
 
11
 
 
12
   Bash is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
 
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 
19
*/
 
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 <errno.h>
 
35
 
 
36
#include "bashansi.h"
 
37
#include "bashintl.h"
 
38
 
 
39
#if defined (SHELL)
 
40
#  include "shell.h"
 
41
#endif /* SHELL */
 
42
 
 
43
#include "typemax.h"            /* INTMAX_MIN, INTMAX_MAX */
 
44
#include "general.h"
 
45
#include "shmbutil.h"
 
46
#include "chartypes.h"
 
47
 
 
48
#ifndef errno
 
49
extern int errno;
 
50
#endif
 
51
 
 
52
#define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
 
53
 
 
54
#define BRACE_SEQ_SPECIFIER     ".."
 
55
 
 
56
extern int asprintf __P((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
 
57
 
 
58
extern int last_command_exit_value;
 
59
 
 
60
/* Basic idea:
 
61
 
 
62
   Segregate the text into 3 sections: preamble (stuff before an open brace),
 
63
   postamble (stuff after the matching close brace) and amble (stuff after
 
64
   preamble, and before postamble).  Expand amble, and then tack on the
 
65
   expansions to preamble.  Expand postamble, and tack on the expansions to
 
66
   the result so far.
 
67
 */
 
68
 
 
69
/* The character which is used to separate arguments. */
 
70
static const int brace_arg_separator = ',';
 
71
 
 
72
#if defined (__P)
 
73
static int brace_gobbler __P((char *, size_t, int *, int));
 
74
static char **expand_amble __P((char *, size_t, int));
 
75
static char **expand_seqterm __P((char *, size_t));
 
76
static char **mkseq __P((intmax_t, intmax_t, intmax_t, int, int));
 
77
static char **array_concat __P((char **, char **));
 
78
#else
 
79
static int brace_gobbler ();
 
80
static char **expand_amble ();
 
81
static char **expand_seqterm ();
 
82
static char **mkseq();
 
83
static char **array_concat ();
 
84
#endif
 
85
 
 
86
#if 0
 
87
static void
 
88
dump_result (a)
 
89
     char **a;
 
90
{
 
91
  int i;
 
92
 
 
93
  for (i = 0; a[i]; i++)
 
94
    printf ("dump_result: a[%d] = -%s-\n", i, a[i]);
 
95
}
 
96
#endif
 
97
 
 
98
/* Return an array of strings; the brace expansion of TEXT. */
 
99
char **
 
100
brace_expand (text)
 
101
     char *text;
 
102
{
 
103
  register int start;
 
104
  size_t tlen;
 
105
  char *preamble, *postamble, *amble;
 
106
  size_t alen;
 
107
  char **tack, **result;
 
108
  int i, j, c, c1;
 
109
 
 
110
  DECLARE_MBSTATE;
 
111
 
 
112
  /* Find the text of the preamble. */
 
113
  tlen = strlen (text);
 
114
  i = 0;
 
115
#if defined (CSH_BRACE_COMPAT)
 
116
  c = brace_gobbler (text, tlen, &i, '{');      /* } */
 
117
#else
 
118
  /* Make sure that when we exit this loop, c == 0 or text[i] begins a
 
119
     valid brace expansion sequence. */
 
120
  do
 
121
    {
 
122
      c = brace_gobbler (text, tlen, &i, '{');  /* } */
 
123
      c1 = c;
 
124
      /* Verify that c begins a valid brace expansion word.  If it doesn't, we
 
125
         go on.  Loop stops when there are no more open braces in the word. */
 
126
      if (c)
 
127
        {
 
128
          start = j = i + 1;    /* { */
 
129
          c = brace_gobbler (text, tlen, &j, '}');
 
130
          if (c == 0)           /* it's not */
 
131
            {
 
132
              i++;
 
133
              c = c1;
 
134
              continue;
 
135
            }
 
136
          else                  /* it is */
 
137
            {
 
138
              c = c1;
 
139
              break;
 
140
            }
 
141
        }
 
142
      else
 
143
        break;
 
144
    }
 
145
  while (c);
 
146
#endif /* !CSH_BRACE_COMPAT */
 
147
 
 
148
  preamble = (char *)xmalloc (i + 1);
 
149
  if (i > 0)
 
150
    strncpy (preamble, text, i);
 
151
  preamble[i] = '\0';
 
152
 
 
153
  result = (char **)xmalloc (2 * sizeof (char *));
 
154
  result[0] = preamble;
 
155
  result[1] = (char *)NULL;
 
156
 
 
157
  /* Special case.  If we never found an exciting character, then
 
158
     the preamble is all of the text, so just return that. */
 
159
  if (c != '{')
 
160
    return (result);
 
161
 
 
162
  /* Find the amble.  This is the stuff inside this set of braces. */
 
163
  start = ++i;
 
164
  c = brace_gobbler (text, tlen, &i, '}');
 
165
 
 
166
  /* What if there isn't a matching close brace? */
 
167
  if (c == 0)
 
168
    {
 
169
#if defined (NOTDEF)
 
170
      /* Well, if we found an unquoted BRACE_ARG_SEPARATOR between START
 
171
         and I, then this should be an error.  Otherwise, it isn't. */
 
172
      j = start;
 
173
      while (j < i)
 
174
        {
 
175
          if (text[j] == '\\')
 
176
            {
 
177
              j++;
 
178
              ADVANCE_CHAR (text, tlen, j);
 
179
              continue;
 
180
            }
 
181
 
 
182
          if (text[j] == brace_arg_separator)
 
183
            {   /* { */
 
184
              strvec_dispose (result);
 
185
              last_command_exit_value = 1;
 
186
              report_error ("no closing `%c' in %s", '}', text);
 
187
              throw_to_top_level ();
 
188
            }
 
189
          ADVANCE_CHAR (text, tlen, j);
 
190
        }
 
191
#endif
 
192
      free (preamble);          /* Same as result[0]; see initialization. */
 
193
      result[0] = savestring (text);
 
194
      return (result);
 
195
    }
 
196
 
 
197
#if defined (SHELL)
 
198
  amble = substring (text, start, i);
 
199
  alen = i - start;
 
200
#else
 
201
  amble = (char *)xmalloc (1 + (i - start));
 
202
  strncpy (amble, &text[start], (i - start));
 
203
  alen = i - start;
 
204
  amble[alen] = '\0';
 
205
#endif
 
206
 
 
207
#if defined (SHELL)
 
208
  INITIALIZE_MBSTATE;
 
209
 
 
210
  /* If the amble does not contain an unquoted BRACE_ARG_SEPARATOR, then
 
211
     just return without doing any expansion.  */
 
212
  j = 0;
 
213
  while (amble[j])
 
214
    {
 
215
      if (amble[j] == '\\')
 
216
        {
 
217
          j++;
 
218
          ADVANCE_CHAR (amble, alen, j);
 
219
          continue;
 
220
        }
 
221
 
 
222
      if (amble[j] == brace_arg_separator)
 
223
        break;
 
224
 
 
225
      ADVANCE_CHAR (amble, alen, j);
 
226
    }
 
227
 
 
228
  if (amble[j] == 0)
 
229
    {
 
230
      tack = expand_seqterm (amble, alen);
 
231
      if (tack)
 
232
        goto add_tack;
 
233
      else if (text[i + 1])
 
234
        {
 
235
          /* If the sequence expansion fails (e.g., because the integers
 
236
             overflow), but there is more in the string, try and process
 
237
             the rest of the string, which may contain additional brace
 
238
             expansions.  Treat the unexpanded sequence term as a simple
 
239
             string (including the braces). */
 
240
          tack = strvec_create (2);
 
241
          tack[0] = savestring (text+start-1);
 
242
          tack[0][i-start+2] = '\0';
 
243
          tack[1] = (char *)0;
 
244
          goto add_tack;
 
245
        }
 
246
      else
 
247
        {
 
248
          free (amble);
 
249
          free (preamble);
 
250
          result[0] = savestring (text);
 
251
          return (result);
 
252
        }
 
253
    }
 
254
#endif /* SHELL */
 
255
 
 
256
  tack = expand_amble (amble, alen, 0);
 
257
add_tack:
 
258
  result = array_concat (result, tack);
 
259
  free (amble);
 
260
  if (tack != result)
 
261
    strvec_dispose (tack);
 
262
 
 
263
  postamble = text + i + 1;
 
264
 
 
265
  if (postamble && *postamble)
 
266
    {
 
267
      tack = brace_expand (postamble);
 
268
      result = array_concat (result, tack);
 
269
      if (tack != result)
 
270
        strvec_dispose (tack);
 
271
    }
 
272
 
 
273
  return (result);
 
274
}
 
275
 
 
276
/* Expand the text found inside of braces.  We simply try to split the
 
277
   text at BRACE_ARG_SEPARATORs into separate strings.  We then brace
 
278
   expand each slot which needs it, until there are no more slots which
 
279
   need it. */
 
280
static char **
 
281
expand_amble (text, tlen, flags)
 
282
     char *text;
 
283
     size_t tlen;
 
284
     int flags;
 
285
{
 
286
  char **result, **partial, **tresult;
 
287
  char *tem;
 
288
  int start, i, c;
 
289
 
 
290
  DECLARE_MBSTATE;
 
291
 
 
292
  result = (char **)NULL;
 
293
 
 
294
  start = i = 0;
 
295
  c = 1;
 
296
  while (c)
 
297
    {
 
298
      c = brace_gobbler (text, tlen, &i, brace_arg_separator);
 
299
#if defined (SHELL)
 
300
      tem = substring (text, start, i);
 
301
#else
 
302
      tem = (char *)xmalloc (1 + (i - start));
 
303
      strncpy (tem, &text[start], (i - start));
 
304
      tem[i- start] = '\0';
 
305
#endif
 
306
 
 
307
      partial = brace_expand (tem);
 
308
 
 
309
      if (!result)
 
310
        result = partial;
 
311
      else
 
312
        {
 
313
          register int lr, lp, j;
 
314
 
 
315
          lr = strvec_len (result);
 
316
          lp = strvec_len (partial);
 
317
 
 
318
          tresult = strvec_mresize (result, lp + lr + 1);
 
319
          if (tresult == 0)
 
320
            {
 
321
              internal_error (_("brace expansion: cannot allocate memory for %s"), tem);
 
322
              strvec_dispose (result);
 
323
              result = (char **)NULL;
 
324
              return result;
 
325
            }
 
326
          else
 
327
            result = tresult;
 
328
 
 
329
          for (j = 0; j < lp; j++)
 
330
            result[lr + j] = partial[j];
 
331
 
 
332
          result[lr + j] = (char *)NULL;
 
333
          free (partial);
 
334
        }
 
335
      free (tem);
 
336
      ADVANCE_CHAR (text, tlen, i);
 
337
      start = i;
 
338
    }
 
339
  return (result);
 
340
}
 
341
 
 
342
#define ST_BAD  0
 
343
#define ST_INT  1
 
344
#define ST_CHAR 2
 
345
#define ST_ZINT 3
 
346
 
 
347
#ifndef sh_imaxabs
 
348
#  define sh_imaxabs(x) (((x) >= 0) ? (x) : -(x))
 
349
#endif
 
350
 
 
351
/* Handle signed arithmetic overflow and underflow.  Have to do it this way
 
352
   to avoid compilers optimizing out simpler overflow checks. */
 
353
 
 
354
/* Make sure that a+b does not exceed MAXV or is smaller than MINV (if b < 0).
 
355
   Assumes that b > 0 if a > 0 and b < 0 if a < 0 */
 
356
#define ADDOVERFLOW(a,b,minv,maxv) \
 
357
        ((((a) > 0) && ((b) > ((maxv) - (a)))) || \
 
358
         (((a) < 0) && ((b) < ((minv) - (a)))))
 
359
 
 
360
/* Make sure that a-b is not smaller than MINV or exceeds MAXV (if b < 0).
 
361
   Assumes that b > 0 if a > 0 and b < 0 if a < 0 */
 
362
#define SUBOVERFLOW(a,b,minv,maxv) \
 
363
        ((((b) > 0) && ((a) < ((minv) + (b)))) || \
 
364
         (((b) < 0) && ((a) > ((maxv) + (b)))))
 
365
 
 
366
static char **
 
367
mkseq (start, end, incr, type, width)
 
368
     intmax_t start, end, incr;
 
369
     int type, width;
 
370
{
 
371
  intmax_t n, prevn;
 
372
  int i, j, nelem;
 
373
  char **result, *t;
 
374
 
 
375
  if (incr == 0)
 
376
    incr = 1;
 
377
 
 
378
  if (start > end && incr > 0)
 
379
    incr = -incr;
 
380
  else if (start < end && incr < 0)
 
381
    {
 
382
      if (incr == INTMAX_MIN)           /* Don't use -INTMAX_MIN */
 
383
        return ((char **)NULL);
 
384
      incr = -incr;
 
385
    }
 
386
 
 
387
  /* Check that end-start will not overflow INTMAX_MIN, INTMAX_MAX.  The +3
 
388
     and -2, not strictly necessary, are there because of the way the number
 
389
     of elements and value passed to strvec_create() are calculated below. */
 
390
  if (SUBOVERFLOW (end, start, INTMAX_MIN+3, INTMAX_MAX-2))
 
391
    return ((char **)NULL);
 
392
 
 
393
  prevn = sh_imaxabs (end - start);
 
394
  /* Need to check this way in case INT_MAX == INTMAX_MAX */
 
395
  if (INT_MAX == INTMAX_MAX && (ADDOVERFLOW (prevn, 2, INT_MIN, INT_MAX)))
 
396
    return ((char **)NULL);
 
397
  /* Make sure the assignment to nelem below doesn't end up <= 0 due to
 
398
     intmax_t overflow */
 
399
  else if (ADDOVERFLOW ((prevn/sh_imaxabs(incr)), 1, INTMAX_MIN, INTMAX_MAX))
 
400
    return ((char **)NULL);
 
401
 
 
402
  /* XXX - TOFIX: potentially allocating a lot of extra memory if
 
403
     imaxabs(incr) != 1 */
 
404
  /* Instead of a simple nelem = prevn + 1, something like:
 
405
        nelem = (prevn / imaxabs(incr)) + 1;
 
406
     would work */
 
407
  nelem = (prevn / sh_imaxabs(incr)) + 1;
 
408
  if (nelem > INT_MAX - 2)              /* Don't overflow int */
 
409
    return ((char **)NULL);
 
410
  result = strvec_mcreate (nelem + 1);
 
411
  if (result == 0)
 
412
    {
 
413
      internal_error (_("brace expansion: failed to allocate memory for %d elements"), nelem);
 
414
      return ((char **)NULL);
 
415
    }
 
416
 
 
417
  /* Make sure we go through the loop at least once, so {3..3} prints `3' */
 
418
  i = 0;
 
419
  n = start;
 
420
  do
 
421
    {
 
422
#if defined (SHELL)
 
423
      QUIT;             /* XXX - memory leak here */
 
424
#endif
 
425
      if (type == ST_INT)
 
426
        result[i++] = t = itos (n);
 
427
      else if (type == ST_ZINT)
 
428
        {
 
429
          int len, arg;
 
430
          arg = n;
 
431
          len = asprintf (&t, "%0*d", width, arg);
 
432
          result[i++] = t;
 
433
        }
 
434
      else
 
435
        {
 
436
          if (t = (char *)malloc (2))
 
437
            {
 
438
              t[0] = n;
 
439
              t[1] = '\0';
 
440
            }
 
441
          result[i++] = t;
 
442
        }
 
443
 
 
444
      /* We failed to allocate memory for this number, so we bail. */
 
445
      if (t == 0)
 
446
        {
 
447
          char *p, lbuf[INT_STRLEN_BOUND(intmax_t) + 1];
 
448
 
 
449
          /* Easier to do this than mess around with various intmax_t printf
 
450
             formats (%ld? %lld? %jd?) and PRIdMAX. */
 
451
          p = inttostr (n, lbuf, sizeof (lbuf));
 
452
          internal_error (_("brace expansion: failed to allocate memory for `%s'"), p);
 
453
          strvec_dispose (result);
 
454
          return ((char **)NULL);
 
455
        }
 
456
 
 
457
      /* Handle overflow and underflow of n+incr */
 
458
      if (ADDOVERFLOW (n, incr, INTMAX_MIN, INTMAX_MAX))
 
459
        break;
 
460
 
 
461
      n += incr;
 
462
 
 
463
      if ((incr < 0 && n < end) || (incr > 0 && n > end))
 
464
        break;
 
465
    }
 
466
  while (1);
 
467
 
 
468
  result[i] = (char *)0;
 
469
  return (result);
 
470
}
 
471
 
 
472
static char **
 
473
expand_seqterm (text, tlen)
 
474
     char *text;
 
475
     size_t tlen;
 
476
{
 
477
  char *t, *lhs, *rhs;
 
478
  int i, lhs_t, rhs_t, lhs_l, rhs_l, width;
 
479
  intmax_t lhs_v, rhs_v, incr;
 
480
  intmax_t tl, tr;
 
481
  char **result, *ep, *oep;
 
482
 
 
483
  t = strstr (text, BRACE_SEQ_SPECIFIER);
 
484
  if (t == 0)
 
485
    return ((char **)NULL);
 
486
 
 
487
  lhs_l = t - text;             /* index of start of BRACE_SEQ_SPECIFIER */
 
488
  lhs = substring (text, 0, lhs_l);
 
489
  rhs = substring (text, lhs_l + sizeof(BRACE_SEQ_SPECIFIER) - 1, tlen);
 
490
 
 
491
  if (lhs[0] == 0 || rhs[0] == 0)
 
492
    {
 
493
      free (lhs);
 
494
      free (rhs);
 
495
      return ((char **)NULL);
 
496
    }
 
497
 
 
498
  /* Now figure out whether LHS and RHS are integers or letters.  Both
 
499
     sides have to match. */
 
500
  lhs_t = (legal_number (lhs, &tl)) ? ST_INT :
 
501
                ((ISALPHA (lhs[0]) && lhs[1] == 0) ?  ST_CHAR : ST_BAD);
 
502
 
 
503
  /* Decide on rhs and whether or not it looks like the user specified
 
504
     an increment */
 
505
  ep = 0;
 
506
  if (ISDIGIT (rhs[0]) || ((rhs[0] == '+' || rhs[0] == '-') && ISDIGIT (rhs[1])))
 
507
    {
 
508
      rhs_t = ST_INT;
 
509
      errno = 0;
 
510
      tr = strtoimax (rhs, &ep, 10);
 
511
      if (errno == ERANGE || (ep && *ep != 0 && *ep != '.'))
 
512
        rhs_t = ST_BAD;                 /* invalid */
 
513
    }
 
514
  else if (ISALPHA (rhs[0]) && (rhs[1] == 0 || rhs[1] == '.'))
 
515
    {
 
516
      rhs_t = ST_CHAR;
 
517
      ep = rhs + 1;
 
518
    }
 
519
  else
 
520
    {
 
521
      rhs_t = ST_BAD;
 
522
      ep = 0;
 
523
    }
 
524
 
 
525
  incr = 1;
 
526
  if (rhs_t != ST_BAD)
 
527
    {
 
528
      oep = ep;
 
529
      errno = 0;
 
530
      if (ep && *ep == '.' && ep[1] == '.' && ep[2])
 
531
        incr = strtoimax (ep + 2, &ep, 10);
 
532
      if (*ep != 0 || errno == ERANGE)
 
533
        rhs_t = ST_BAD;                 /* invalid incr or overflow */
 
534
      tlen -= ep - oep;
 
535
    }
 
536
 
 
537
  if (lhs_t != rhs_t || lhs_t == ST_BAD || rhs_t == ST_BAD)
 
538
    {
 
539
      free (lhs);
 
540
      free (rhs);
 
541
      return ((char **)NULL);
 
542
    }
 
543
 
 
544
  /* OK, we have something.  It's either a sequence of integers, ascending
 
545
     or descending, or a sequence or letters, ditto.  Generate the sequence,
 
546
     put it into a string vector, and return it. */
 
547
  
 
548
  if (lhs_t == ST_CHAR)
 
549
    {
 
550
      lhs_v = (unsigned char)lhs[0];
 
551
      rhs_v = (unsigned char)rhs[0];
 
552
      width = 1;
 
553
    }
 
554
  else
 
555
    {
 
556
      lhs_v = tl;               /* integer truncation */
 
557
      rhs_v = tr;
 
558
 
 
559
      /* Decide whether or not the terms need zero-padding */
 
560
      rhs_l = tlen - lhs_l - sizeof (BRACE_SEQ_SPECIFIER) + 1;
 
561
      width = 0;
 
562
      if (lhs_l > 1 && lhs[0] == '0')
 
563
        width = lhs_l, lhs_t = ST_ZINT;
 
564
      if (lhs_l > 2 && lhs[0] == '-' && lhs[1] == '0')
 
565
        width = lhs_l, lhs_t = ST_ZINT;
 
566
      if (rhs_l > 1 && rhs[0] == '0' && width < rhs_l)
 
567
        width = rhs_l, lhs_t = ST_ZINT;
 
568
      if (rhs_l > 2 && rhs[0] == '-' && rhs[1] == '0' && width < rhs_l)
 
569
        width = rhs_l, lhs_t = ST_ZINT;
 
570
 
 
571
      if (width < lhs_l && lhs_t == ST_ZINT)
 
572
        width = lhs_l;
 
573
      if (width < rhs_l && lhs_t == ST_ZINT)
 
574
        width = rhs_l;
 
575
    }
 
576
 
 
577
  result = mkseq (lhs_v, rhs_v, incr, lhs_t, width);
 
578
 
 
579
  free (lhs);
 
580
  free (rhs);
 
581
 
 
582
  return (result);
 
583
}
 
584
 
 
585
/* Start at INDEX, and skip characters in TEXT. Set INDEX to the
 
586
   index of the character matching SATISFY.  This understands about
 
587
   quoting.  Return the character that caused us to stop searching;
 
588
   this is either the same as SATISFY, or 0. */
 
589
/* If SATISFY is `}', we are looking for a brace expression, so we
 
590
   should enforce the rules that govern valid brace expansions:
 
591
        1) to count as an arg separator, a comma or `..' has to be outside
 
592
           an inner set of braces.       
 
593
*/
 
594
static int
 
595
brace_gobbler (text, tlen, indx, satisfy)
 
596
     char *text;
 
597
     size_t tlen;
 
598
     int *indx;
 
599
     int satisfy;
 
600
{
 
601
  register int i, c, quoted, level, commas, pass_next;
 
602
#if defined (SHELL)
 
603
  int si;
 
604
  char *t;
 
605
#endif
 
606
  DECLARE_MBSTATE;
 
607
 
 
608
  level = quoted = pass_next = 0;
 
609
#if defined (CSH_BRACE_COMPAT)
 
610
  commas = 1;
 
611
#else
 
612
  commas = (satisfy == '}') ? 0 : 1;
 
613
#endif
 
614
 
 
615
  i = *indx;
 
616
  while (c = text[i])
 
617
    {
 
618
      if (pass_next)
 
619
        {
 
620
          pass_next = 0;
 
621
          ADVANCE_CHAR (text, tlen, i);
 
622
          continue;
 
623
        }
 
624
 
 
625
      /* A backslash escapes the next character.  This allows backslash to
 
626
         escape the quote character in a double-quoted string. */
 
627
      if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
 
628
        {
 
629
          pass_next = 1;
 
630
          i++;
 
631
          continue;
 
632
        }
 
633
 
 
634
#if defined (SHELL)
 
635
      /* If compiling for the shell, treat ${...} like \{...} */
 
636
      if (c == '$' && text[i+1] == '{' && quoted != '\'')               /* } */
 
637
        {
 
638
          pass_next = 1;
 
639
          i++;
 
640
          if (quoted == 0)
 
641
            level++;
 
642
          continue;
 
643
        }
 
644
#endif
 
645
 
 
646
      if (quoted)
 
647
        {
 
648
          if (c == quoted)
 
649
            quoted = 0;
 
650
#if defined (SHELL)
 
651
          /* The shell allows quoted command substitutions */
 
652
          if (quoted == '"' && c == '$' && text[i+1] == '(')    /*)*/
 
653
            goto comsub;
 
654
#endif
 
655
          ADVANCE_CHAR (text, tlen, i);
 
656
          continue;
 
657
        }
 
658
 
 
659
      if (c == '"' || c == '\'' || c == '`')
 
660
        {
 
661
          quoted = c;
 
662
          i++;
 
663
          continue;
 
664
        }
 
665
 
 
666
#if defined (SHELL)
 
667
      /* Pass new-style command and process substitutions through unchanged. */
 
668
      if ((c == '$' || c == '<' || c == '>') && text[i+1] == '(')                       /* ) */
 
669
        {
 
670
comsub:
 
671
          si = i + 2;
 
672
          t = extract_command_subst (text, &si, 0);
 
673
          i = si;
 
674
          free (t);
 
675
          i++;
 
676
          continue;
 
677
        }
 
678
#endif
 
679
 
 
680
      if (c == satisfy && level == 0 && quoted == 0 && commas > 0)
 
681
        {
 
682
          /* We ignore an open brace surrounded by whitespace, and also
 
683
             an open brace followed immediately by a close brace preceded
 
684
             by whitespace.  */
 
685
          if (c == '{' &&
 
686
              ((!i || brace_whitespace (text[i - 1])) &&
 
687
               (brace_whitespace (text[i + 1]) || text[i + 1] == '}')))
 
688
            {
 
689
              i++;
 
690
              continue;
 
691
            }
 
692
 
 
693
            break;
 
694
        }
 
695
 
 
696
      if (c == '{')
 
697
        level++;
 
698
      else if (c == '}' && level)
 
699
        level--;
 
700
#if !defined (CSH_BRACE_COMPAT)
 
701
      else if (satisfy == '}' && c == brace_arg_separator && level == 0)
 
702
        commas++;
 
703
      else if (satisfy == '}' && STREQN (text+i, BRACE_SEQ_SPECIFIER, 2) &&
 
704
                text[i+2] != satisfy && level == 0)
 
705
        commas++;
 
706
#endif
 
707
 
 
708
      ADVANCE_CHAR (text, tlen, i);
 
709
    }
 
710
 
 
711
  *indx = i;
 
712
  return (c);
 
713
}
 
714
 
 
715
/* Return 1 if ARR has any non-empty-string members.  Used to short-circuit
 
716
   in array_concat() below. */
 
717
static int
 
718
degenerate_array (arr)
 
719
     char **arr;
 
720
{
 
721
  register int i;
 
722
 
 
723
  for (i = 0; arr[i]; i++)
 
724
    if (arr[i][0] != '\0')
 
725
      return 0;
 
726
  return 1;
 
727
}
 
728
 
 
729
/* Return a new array of strings which is the result of appending each
 
730
   string in ARR2 to each string in ARR1.  The resultant array is
 
731
   len (arr1) * len (arr2) long.  For convenience, ARR1 (and its contents)
 
732
   are free ()'ed.  ARR1 can be NULL, in that case, a new version of ARR2
 
733
   is returned. */
 
734
static char **
 
735
array_concat (arr1, arr2)
 
736
     char **arr1, **arr2;
 
737
{
 
738
  register int i, j, len, len1, len2;
 
739
  register char **result;
 
740
 
 
741
  if (arr1 == 0)
 
742
    return (arr2);              /* XXX - see if we can get away without copying? */
 
743
 
 
744
  if (arr2 == 0)
 
745
    return (arr1);              /* XXX - caller expects us to free arr1 */
 
746
 
 
747
  /* We can only short-circuit if the array consists of a single null element;
 
748
     otherwise we need to replicate the contents of the other array and
 
749
     prefix (or append, below) an empty element to each one. */
 
750
  if (arr1[0] && arr1[0][0] == 0 && arr1[1] == 0)
 
751
    {
 
752
      strvec_dispose (arr1);
 
753
      return (arr2);            /* XXX - use flags to see if we can avoid copying here */
 
754
    }
 
755
 
 
756
  if (arr2[0] && arr2[0][0] == 0 && arr2[1] == 0)
 
757
    return (arr1);              /* XXX - rather than copying and freeing it */
 
758
 
 
759
  len1 = strvec_len (arr1);
 
760
  len2 = strvec_len (arr2);
 
761
 
 
762
  result = (char **)xmalloc ((1 + (len1 * len2)) * sizeof (char *));
 
763
 
 
764
  len = 0;
 
765
  for (i = 0; i < len1; i++)
 
766
    {
 
767
      int strlen_1 = strlen (arr1[i]);
 
768
 
 
769
      for (j = 0; j < len2; j++)
 
770
        {
 
771
          result[len] = (char *)xmalloc (1 + strlen_1 + strlen (arr2[j]));
 
772
          strcpy (result[len], arr1[i]);
 
773
          strcpy (result[len] + strlen_1, arr2[j]);
 
774
          len++;
 
775
        }
 
776
      free (arr1[i]);
 
777
    }
 
778
  free (arr1);
 
779
 
 
780
  result[len] = (char *)NULL;
 
781
  return (result);
 
782
}
 
783
 
 
784
#if defined (TEST)
 
785
#include <stdio.h>
 
786
 
 
787
fatal_error (format, arg1, arg2)
 
788
     char *format, *arg1, *arg2;
 
789
{
 
790
  report_error (format, arg1, arg2);
 
791
  exit (1);
 
792
}
 
793
 
 
794
report_error (format, arg1, arg2)
 
795
     char *format, *arg1, *arg2;
 
796
{
 
797
  fprintf (stderr, format, arg1, arg2);
 
798
  fprintf (stderr, "\n");
 
799
}
 
800
 
 
801
main ()
 
802
{
 
803
  char example[256];
 
804
 
 
805
  for (;;)
 
806
    {
 
807
      char **result;
 
808
      int i;
 
809
 
 
810
      fprintf (stderr, "brace_expand> ");
 
811
 
 
812
      if ((!fgets (example, 256, stdin)) ||
 
813
          (strncmp (example, "quit", 4) == 0))
 
814
        break;
 
815
 
 
816
      if (strlen (example))
 
817
        example[strlen (example) - 1] = '\0';
 
818
 
 
819
      result = brace_expand (example);
 
820
 
 
821
      for (i = 0; result[i]; i++)
 
822
        printf ("%s\n", result[i]);
 
823
 
 
824
      free_array (result);
 
825
    }
 
826
}
 
827
 
 
828
/*
 
829
 * Local variables:
 
830
 * compile-command: "gcc -g -Bstatic -DTEST -o brace_expand braces.c general.o"
 
831
 * end:
 
832
 */
 
833
 
 
834
#endif /* TEST */
 
835
#endif /* BRACE_EXPANSION */