Imported from ../bash-2.05b.tar.gz.
[platform/upstream/bash.git] / braces.c
index 2eb4de4..4f5b0f0 100644 (file)
--- a/braces.c
+++ b/braces.c
@@ -1,12 +1,12 @@
 /* braces.c -- code for doing word expansion in curly braces. */
 
-/* Copyright (C) 1987,1991 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
    Bash is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 1, or (at your option)
+   the Free Software Foundation; either version 2, or (at your option)
    any later version.
 
    Bash is distributed in the hope that it will be useful, but WITHOUT
 
    You should have received a copy of the GNU General Public License
    along with Bash; see the file COPYING.  If not, write to the Free
-   Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+   Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
 
-/* Stuff in curly braces gets expanded after variable and command
-   substitution, but before filename globbing.
+/* Stuff in curly braces gets expanded before all other shell expansions. */
 
-   (Actually, this should be true for the sake of efficiency, but it
-   isn't because of quoting hacks.  Once I rebuild quoting it will be
-   true. */
+#include "config.h"
 
-#if defined (HAVE_STRING_H)
-#  include <string.h>
-#else /* !HAVE_STRING_H */
-#  include <strings.h>
-#endif /* !HAVE_STRING_H */
+#if defined (BRACE_EXPANSION)
+
+#if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#include "bashansi.h"
 
 #if defined (SHELL)
-#include "shell.h"
+#  include "shell.h"
 #endif /* SHELL */
 
 #include "general.h"
+#include "shmbutil.h"
+
 #define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
 
 /* Basic idea:
 /* The character which is used to separate arguments. */
 int brace_arg_separator = ',';
 
+#if defined (__P)
+static int brace_gobbler __P((char *, size_t, int *, int));
+static char **expand_amble __P((char *, size_t));
+static char **array_concat __P((char **, char **));
+#else
 static int brace_gobbler ();
-static char **expand_amble (), **array_concat ();
+static char **expand_amble ();
+static char **array_concat ();
+#endif
 
 /* Return an array of strings; the brace expansion of TEXT. */
 char **
@@ -59,13 +70,18 @@ brace_expand (text)
      char *text;
 {
   register int start;
+  size_t tlen;
   char *preamble, *postamble, *amble;
+  size_t alen;
   char **tack, **result;
-  int i, c;
+  int i, j, c;
+
+  DECLARE_MBSTATE;
 
   /* Find the text of the preamble. */
+  tlen = strlen (text);
   i = 0;
-  c = brace_gobbler (text, &i, '{');
+  c = brace_gobbler (text, tlen, &i, '{');
 
   preamble = (char *)xmalloc (i + 1);
   strncpy (preamble, text, i);
@@ -74,7 +90,7 @@ brace_expand (text)
   result = (char **)xmalloc (2 * sizeof (char *));
   result[0] = preamble;
   result[1] = (char *)NULL;
-  
+
   /* Special case.  If we never found an exciting character, then
      the preamble is all of the text, so just return that. */
   if (c != '{')
@@ -82,30 +98,31 @@ brace_expand (text)
 
   /* Find the amble.  This is the stuff inside this set of braces. */
   start = ++i;
-  c = brace_gobbler (text, &i, '}');
+  c = brace_gobbler (text, tlen, &i, '}');
 
   /* What if there isn't a matching close brace? */
-  if (!c)
+  if (c == 0)
     {
 #if defined (NOTDEF)
-      register int j;
-
       /* Well, if we found an unquoted BRACE_ARG_SEPARATOR between START
         and I, then this should be an error.  Otherwise, it isn't. */
-      for (j = start; j < i; j++)
+      j = start;
+      while (j < i)
        {
          if (text[j] == '\\')
            {
              j++;
+             ADVANCE_CHAR (text, tlen, j);
              continue;
            }
 
          if (text[j] == brace_arg_separator)
            {
-             free_array (result);
-             report_error ("Missing `}'");
+             strvec_dispose (result);
+             report_error ("missing `}'");
              throw_to_top_level ();
            }
+         ADVANCE_CHAR (text, tlen, j);
        }
 #endif
       free (preamble);         /* Same as result[0]; see initialization. */
@@ -113,47 +130,56 @@ brace_expand (text)
       return (result);
     }
 
+#if defined (SHELL)
+  amble = substring (text, start, i);
+  alen = i - start;
+#else
   amble = (char *)xmalloc (1 + (i - start));
   strncpy (amble, &text[start], (i - start));
-  amble[i - start] = '\0';
+  alen = i - start;
+  amble[alen] = '\0';
+#endif
 
 #if defined (SHELL)
+  INITIALIZE_MBSTATE;
+
   /* If the amble does not contain an unquoted BRACE_ARG_SEPARATOR, then
      just return without doing any expansion.  */
-  {
-    register int j;
-
-    for (j = 0; amble[j]; j++)
-      {
-       if (amble[j] == '\\')
-         {
-           j++;
-           continue;
-         }
-       if (amble[j] == brace_arg_separator)
-         break;
-      }
-
-    if (!amble[j])
-      {
-       free (amble);
-       free (preamble);
-       result[0] = savestring (text);
-       return (result);
-      }
-  }
+  j = 0;
+  while (amble[j])
+    {
+      if (amble[j] == '\\')
+       {
+         j++;
+         ADVANCE_CHAR (amble, alen, j);
+         continue;
+       }
+
+      if (amble[j] == brace_arg_separator)
+       break;
+
+      ADVANCE_CHAR (amble, alen, j);
+    }
+
+  if (!amble[j])
+    {
+      free (amble);
+      free (preamble);
+      result[0] = savestring (text);
+      return (result);
+    }
 #endif /* SHELL */
 
   postamble = &text[i + 1];
 
-  tack = expand_amble (amble);
+  tack = expand_amble (amble, alen);
   result = array_concat (result, tack);
   free (amble);
-  free_array (tack);
+  strvec_dispose (tack);
 
   tack = brace_expand (postamble);
   result = array_concat (result, tack);
-  free_array (tack);
+  strvec_dispose (tack);
 
   return (result);
 }
@@ -163,21 +189,30 @@ brace_expand (text)
    expand each slot which needs it, until there are no more slots which
    need it. */
 static char **
-expand_amble (text)
+expand_amble (text, tlen)
      char *text;
+     size_t tlen;
 {
   char **result, **partial;
   char *tem;
   int start, i, c;
 
+  DECLARE_MBSTATE;
+
   result = (char **)NULL;
 
-  for (start = 0, i = 0, c = 1; c; start = ++i)
+  start = i = 0;
+  c = 1;
+  while (c)
     {
-      c = brace_gobbler (text, &i, brace_arg_separator);
+      c = brace_gobbler (text, tlen, &i, brace_arg_separator);
+#if defined (SHELL)
+      tem = substring (text, start, i);
+#else
       tem = (char *)xmalloc (1 + (i - start));
       strncpy (tem, &text[start], (i - start));
       tem[i- start] = '\0';
+#endif
 
       partial = brace_expand (tem);
 
@@ -185,11 +220,11 @@ expand_amble (text)
        result = partial;
       else
        {
-         register int lr = array_len (result);
-         register int lp = array_len (partial);
+         register int lr = strvec_len (result);
+         register int lp = strvec_len (partial);
          register int j;
 
-         result = (char **)xrealloc (result, (1 + lp + lr) * sizeof (char *));
+         result = strvec_resize (result, lp + lr + 1);
 
          for (j = 0; j < lp; j++)
            result[lr + j] = partial[j];
@@ -198,6 +233,8 @@ expand_amble (text)
          free (partial);
        }
       free (tem);
+      ADVANCE_CHAR (text, tlen, i);
+      start = i;
     }
   return (result);
 }
@@ -207,60 +244,85 @@ expand_amble (text)
    quoting.  Return the character that caused us to stop searching;
    this is either the same as SATISFY, or 0. */
 static int
-brace_gobbler (text, indx, satisfy)
+brace_gobbler (text, tlen, indx, satisfy)
      char *text;
+     size_t tlen;
      int *indx;
      int satisfy;
 {
   register int i, c, quoted, level, pass_next;
+#if defined (SHELL)
+  int si;
+  char *t;
+#endif
+  DECLARE_MBSTATE;
 
   level = quoted = pass_next = 0;
 
-  for (i = *indx; c = text[i]; i++)
+  i = *indx;
+  while (c = text[i])
     {
       if (pass_next)
        {
          pass_next = 0;
+         ADVANCE_CHAR (text, tlen, i);
          continue;
        }
 
       /* A backslash escapes the next character.  This allows backslash to
         escape the quote character in a double-quoted string. */
       if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
-        {
-          pass_next = 1;
-          continue;
-        }
+       {
+         pass_next = 1;
+         i++;
+         continue;
+       }
 
       if (quoted)
        {
          if (c == quoted)
            quoted = 0;
+         ADVANCE_CHAR (text, tlen, i);
          continue;
        }
 
       if (c == '"' || c == '\'' || c == '`')
        {
          quoted = c;
+         i++;
+         continue;
+       }
+
+#if defined (SHELL)
+      /* Pass new-style command substitutions through unchanged. */
+      if (c == '$' && text[i+1] == '(')                        /* ) */
+       {
+         si = i + 2;
+         t = extract_command_subst (text, &si);
+         i = si;
+         free (t);
+         i++;
          continue;
        }
-      
-      if (c == satisfy && !level && !quoted)
+#endif
+
+      if (c == satisfy && level == 0 && quoted == 0)
        {
          /* We ignore an open brace surrounded by whitespace, and also
-            an open brace followed immediately by a close brace, that
-            was preceded with whitespace.  */
+            an open brace followed immediately by a close brace preceded
+            by whitespace.  */
          if (c == '{' &&
              ((!i || brace_whitespace (text[i - 1])) &&
               (brace_whitespace (text[i + 1]) || text[i + 1] == '}')))
-           continue;
+           {
+             i++;
+             continue;
+           }
 #if defined (SHELL)
          /* If this is being compiled as part of bash, ignore the `{'
             in a `${}' construct */
-         if ((c != '{') || !i || (text[i - 1] != '$'))
-#else /* !SHELL */
-         if ((c != '{') || !i)
-#endif /* !SHELL */
+         if ((c != '{') || i == 0 || (text[i - 1] != '$'))
+#endif /* SHELL */
            break;
        }
 
@@ -268,6 +330,8 @@ brace_gobbler (text, indx, satisfy)
        level++;
       else if (c == '}' && level)
        level--;
+
+      ADVANCE_CHAR (text, tlen, i);
     }
 
   *indx = i;
@@ -286,14 +350,14 @@ array_concat (arr1, arr2)
   register int i, j, len, len1, len2;
   register char **result;
 
-  if (!arr1)
-    return (copy_array (arr2));
+  if (arr1 == 0)
+    return (strvec_copy (arr2));
 
-  if (!arr2)
-    return (copy_array (arr1));
+  if (arr2 == 0)
+    return (strvec_copy (arr1));
 
-  len1 = array_len (arr1);
-  len2 = array_len (arr2);
+  len1 = strvec_len (arr1);
+  len2 = strvec_len (arr2);
 
   result = (char **)xmalloc ((1 + (len1 * len2)) * sizeof (char *));
 
@@ -369,3 +433,4 @@ main ()
  */
 
 #endif /* TEST */
+#endif /* BRACE_EXPANSION */