Imported from ../bash-2.0.tar.gz.
[platform/upstream/bash.git] / make_cmd.c
index 85eb3d5..d17b4d8 100644 (file)
@@ -1,5 +1,5 @@
-/* make_cmd.c --
-   Functions for making instances of the various parser constructs. */
+/* make_cmd.c -- Functions for making instances of the various
+   parser constructs. */
 
 /* Copyright (C) 1989 Free Software Foundation, Inc.
 
@@ -19,17 +19,23 @@ 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. */
 
+#include "config.h"
+
 #include <stdio.h>
 #include "bashtypes.h"
 #include <sys/file.h>
 #include "filecntl.h"
 #include "bashansi.h"
-#include "config.h"
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
 #include "command.h"
 #include "general.h"
 #include "error.h"
 #include "flags.h"
 #include "make_cmd.h"
+#include "variables.h"
 #include "subst.h"
 #include "input.h"
 #include "externs.h"
@@ -42,47 +48,59 @@ extern int line_number, current_command_line_count;
 extern int disallow_filename_globbing;
 
 WORD_DESC *
-make_word (string)
+make_bare_word (string)
      char *string;
 {
   WORD_DESC *temp;
 
   temp = (WORD_DESC *)xmalloc (sizeof (WORD_DESC));
-  temp->word = savestring (string);
-  temp->quoted = temp->dollar_present = temp->assignment = 0;
-
-  while (*string)
+  if (*string)
+    temp->word = savestring (string);
+  else
     {
-      if (*string == '$') temp->dollar_present = 1;
-
-#ifdef OLDCODE
-      if (member (*string, "'`\\\""))
-       {
-         temp->quoted = 1;
-         if (*string == '\\')
-           string++;
-       }
-#else
-      switch (*string)
-       {
-         case '\\':
-           string++;
-           /*FALLTHROUGH*/
-         case '\'':
-         case '`':
-         case '"':
-           temp->quoted = 1;
-           break;
-       }
-#endif
-
-      if (*string)
-       (string++);
+      temp->word = xmalloc (1);
+      temp->word[0] = '\0';
     }
+
+  temp->flags = 0;
   return (temp);
 }
 
 WORD_DESC *
+make_word_flags (w, string)
+     WORD_DESC *w;
+     char *string;
+{
+  register char *s;
+
+  for (s = string; *s; s++)
+    switch (*s)
+      {
+       case '$':
+         w->flags |= W_HASDOLLAR;
+         break;
+       case '\\':
+         break;        /* continue the loop */
+       case '\'':
+       case '`':
+       case '"':
+         w->flags |= W_QUOTED;
+         break;
+      }
+  return (w);
+}
+
+WORD_DESC *
+make_word (string)
+     char *string;
+{
+  WORD_DESC *temp;
+
+  temp = make_bare_word (string);
+  return (make_word_flags (temp, string));
+}
+
+WORD_DESC *
 make_word_from_token (token)
      int token;
 {
@@ -112,24 +130,14 @@ add_string_to_list (string, list)
      char *string;
      WORD_LIST *list;
 {
-  WORD_LIST *temp = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
+  WORD_LIST *temp;
+
+  temp = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
   temp->word = make_word (string);
   temp->next = list;
   return (temp);
 }
 
-#if 0
-WORD_DESC *
-coerce_to_word (number)
-     int number;
-{
-  char string[24];
-
-  sprintf (string, "%d", number);
-  return (make_word (string));
-}
-#endif
-
 COMMAND *
 make_command (type, pointer)
      enum command_type type;
@@ -140,8 +148,7 @@ make_command (type, pointer)
   temp = (COMMAND *)xmalloc (sizeof (COMMAND));
   temp->type = type;
   temp->value.Simple = pointer;
-  temp->value.Simple->flags = 0;
-  temp->flags = 0;
+  temp->value.Simple->flags = temp->flags = 0;
   temp->redirects = (REDIRECT *)NULL;
   return (temp);
 }
@@ -160,44 +167,50 @@ command_connect (com1, com2, connector)
   return (make_command (cm_connection, (SIMPLE_COM *)temp));
 }
 
-COMMAND *
-make_for_command (name, map_list, action)
+static COMMAND *
+make_for_or_select (type, name, map_list, action)
+     enum command_type type;
      WORD_DESC *name;
      WORD_LIST *map_list;
      COMMAND *action;
 {
-  FOR_COM *temp = (FOR_COM *)xmalloc (sizeof (FOR_COM));
+  FOR_COM *temp;
 
+  temp = (FOR_COM *)xmalloc (sizeof (FOR_COM));
   temp->flags = 0;
   temp->name = name;
   temp->map_list = map_list;
   temp->action = action;
-  return (make_command (cm_for, (SIMPLE_COM *)temp));
+  return (make_command (type, (SIMPLE_COM *)temp));
 }
 
-#if defined (SELECT_COMMAND)
 COMMAND *
-make_select_command (name, map_list, action)
+make_for_command (name, map_list, action)
      WORD_DESC *name;
      WORD_LIST *map_list;
      COMMAND *action;
 {
-  SELECT_COM *temp = (SELECT_COM *)xmalloc (sizeof (SELECT_COM));
-
-  temp->flags = 0;
-  temp->name = name;
-  temp->map_list = map_list;
-  temp->action = action;
-  return (make_command (cm_select, (SIMPLE_COM *)temp));
+  return (make_for_or_select (cm_for, name, map_list, action));
 }
+
+COMMAND *
+make_select_command (name, map_list, action)
+     WORD_DESC *name;
+     WORD_LIST *map_list;
+     COMMAND *action;
+{
+#if defined (SELECT_COMMAND)
+  return (make_for_or_select (cm_select, name, map_list, action));
 #endif
+}
 
 COMMAND *
 make_group_command (command)
      COMMAND *command;
 {
-  GROUP_COM *temp = (GROUP_COM *)xmalloc (sizeof (GROUP_COM));
+  GROUP_COM *temp;
 
+  temp = (GROUP_COM *)xmalloc (sizeof (GROUP_COM));
   temp->command = command;
   return (make_command (cm_group, (SIMPLE_COM *)temp));
 }
@@ -245,9 +258,9 @@ make_if_command (test, true_case, false_case)
 }
 
 static COMMAND *
-make_until_or_while (test, action, which)
-     COMMAND *test, *action;
+make_until_or_while (which, test, action)
      enum command_type which;
+     COMMAND *test, *action;
 {
   WHILE_COM *temp;
 
@@ -262,31 +275,34 @@ COMMAND *
 make_while_command (test, action)
      COMMAND *test, *action;
 {
-  return (make_until_or_while (test, action, cm_while));
+  return (make_until_or_while (cm_while, test, action));
 }
 
 COMMAND *
 make_until_command (test, action)
      COMMAND *test, *action;
 {
-  return (make_until_or_while (test, action, cm_until));
+  return (make_until_or_while (cm_until, test, action));
 }
 
 COMMAND *
 make_bare_simple_command ()
 {
   COMMAND *command;
-  SIMPLE_COM *temp = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM));
+  SIMPLE_COM *temp;
+
+  command = (COMMAND *)xmalloc (sizeof (COMMAND));
+  command->value.Simple = temp = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM));
 
   temp->flags = 0;
   temp->line = line_number;
   temp->words = (WORD_LIST *)NULL;
   temp->redirects = (REDIRECT *)NULL;
-  command = (COMMAND *)xmalloc (sizeof (COMMAND));
+
   command->type = cm_simple;
   command->redirects = (REDIRECT *)NULL;
   command->flags = 0;
-  command->value.Simple = temp;
+
   return (command);
 }
 
@@ -302,7 +318,7 @@ make_simple_command (element, command)
      malloc doesn't return zeroed space. */
   if (!command)
     command = make_bare_simple_command ();
+
   if (element.word)
     {
       WORD_LIST *tw = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
@@ -324,127 +340,112 @@ make_simple_command (element, command)
   return (command);
 }
 
-#define POSIX_HERE_DOCUMENTS
+/* Because we are Bourne compatible, we read the input for this
+   << or <<- redirection now, from wherever input is coming from.
+   We store the input read into a WORD_DESC.  Replace the text of
+   the redirectee.word with the new input text.  If <<- is on,
+   then remove leading TABS from each line. */
 void
 make_here_document (temp)
      REDIRECT *temp;
 {
-  int kill_leading = 0;
+  int kill_leading, redir_len;
+  char *redir_word, *document, *full_line;
+  int document_index, document_size, delim_unquoted;
+
+  if (temp->instruction != r_deblank_reading_until &&
+      temp->instruction != r_reading_until)
+    {
+      internal_error ("make_here_document: bad instruction type %d", temp->instruction);
+      return;
+    }
+
+  kill_leading = temp->instruction == r_deblank_reading_until;
+
+  document = (char *)NULL;
+  document_index = document_size = 0;
+
+  /* Quote removal is the only expansion performed on the delimiter
+     for here documents, making it an extremely special case. */
+  redir_word = string_quote_removal (temp->redirectee.filename->word, 0);
+
+  /* redirection_expand will return NULL if the expansion results in
+     multiple words or no words.  Check for that here, and just abort
+     this here document if it does. */
+  if (redir_word)
+    redir_len = strlen (redir_word);
+  else
+    {
+      temp->here_doc_eof = xmalloc (1);
+      temp->here_doc_eof[0] = '\0';
+      goto document_done;
+    }
 
-  switch (temp->instruction)
+  free (temp->redirectee.filename->word);
+  temp->here_doc_eof = redir_word;
+
+  /* Read lines from wherever lines are coming from.
+     For each line read, if kill_leading, then kill the
+     leading tab characters.
+     If the line matches redir_word exactly, then we have
+     manufactured the document.  Otherwise, add the line to the
+     list of lines in the document. */
+
+  /* If the here-document delimiter was quoted, the lines should
+     be read verbatim from the input.  If it was not quoted, we
+     need to perform backslash-quoted newline removal. */
+  delim_unquoted = (temp->redirectee.filename->flags & W_QUOTED) == 0;
+  while (full_line = read_secondary_line (delim_unquoted))
     {
-      /* Because we are Bourne compatible, we read the input for this
-        << or <<- redirection now, from wherever input is coming from.
-        We store the input read into a WORD_DESC.  Replace the text of
-        the redirectee.word with the new input text.  If <<- is on,
-        then remove leading TABS from each line. */
-
-      case r_deblank_reading_until:    /* <<-foo */
-       kill_leading++;
-       /* FALLTHROUGH */
-      case r_reading_until:            /* <<foo */
+      register char *line;
+      int len;
+
+      line = full_line;
+      line_number++;
+
+      if (kill_leading && *line)
+        {
+         /* Hack:  To be compatible with some Bourne shells, we
+            check the word before stripping the whitespace.  This
+            is a hack, though. */
+         if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n')
+           goto document_done;
+
+         while (*line == '\t')
+           line++;
+       }
+
+      if (*line == 0)
+        continue;
+
+      if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n')
+       goto document_done;
+
+      len = strlen (line);
+      if (len + document_index >= document_size)
        {
-         char *redir_word;
-         int redir_len;
-         char *full_line;
-         char *document = (char *)NULL;
-         int document_index = 0, document_size = 0;
-
-#if !defined (POSIX_HERE_DOCUMENTS)
-         /* Because of Bourne shell semantics, we turn off globbing, but
-            only for this style of redirection.  I feel a little ill.  */
-         {
-           int old_value = disallow_filename_globbing;
-           disallow_filename_globbing = 1;
-
-           redir_word = redirection_expand (temp->redirectee.filename);
-
-           disallow_filename_globbing = old_value;
-         }
-#else /* POSIX_HERE_DOCUMENTS */
-         /* Quote removal is the only expansion performed on the delimiter
-            for here documents, making it an extremely special case.  I
-            still feel ill. */
-         redir_word = string_quote_removal (temp->redirectee.filename->word, 0);
-#endif /* POSIX_HERE_DOCUMENTS */
-
-         /* redirection_expand will return NULL if the expansion results in
-            multiple words or no words.  Check for that here, and just abort
-            this here document if it does. */
-         if (redir_word)
-           redir_len = strlen (redir_word);
-         else
-           {
-             temp->here_doc_eof = savestring ("");
-             goto document_done;
-           }
-
-         free (temp->redirectee.filename->word);
-         temp->here_doc_eof = redir_word;
-
-         /* Read lines from wherever lines are coming from.
-            For each line read, if kill_leading, then kill the
-            leading tab characters.
-            If the line matches redir_word exactly, then we have
-            manufactured the document.  Otherwise, add the line to the
-            list of lines in the document. */
-
-         /* If the here-document delimiter was quoted, the lines should
-            be read verbatim from the input.  If it was not quoted, we
-            need to perform backslash-quoted newline removal. */
-         while (full_line = read_secondary_line
-                (temp->redirectee.filename->quoted == 0))
-           {
-             register char *line = full_line;
-             int len;
-
-             line_number++;
-
-             if (kill_leading && *line)
-               {
-                 /* Hack:  To be compatible with some Bourne shells, we 
-                    check the word before stripping the whitespace.  This
-                    is a hack, though. */
-                 if (STREQN (line, redir_word, redir_len) &&
-                     line[redir_len] == '\n')
-                   goto document_done;
-
-                 while (*line == '\t')
-                   line++;
-               }
-
-             if (!*line)
-               continue;
-
-             if (STREQN (line, redir_word, redir_len) &&
-                 line[redir_len] == '\n')
-               goto document_done;
-
-             len = strlen (line);
-             if (len + document_index >= document_size)
-               {
-                 document_size = document_size ? 2 * (document_size + len)
-                                               : 1000; /* XXX */
-                 document = xrealloc (document, document_size);
-               }
-
-             /* len is guaranteed to be > 0 because of the check for line
-                being an empty string before the call to strlen. */
-             FASTCOPY (line, document + document_index, len);
-             document_index += len;
-           }
-
-  document_done:
-         if (document)
-           document[document_index] = '\0';
-         else
-           document = savestring ("");
-         temp->redirectee.filename->word = document;
+         document_size = document_size ? 2 * (document_size + len) : 1000;
+         document = xrealloc (document, document_size);
        }
+
+      /* len is guaranteed to be > 0 because of the check for line
+        being an empty string before the call to strlen. */
+      FASTCOPY (line, document + document_index, len);
+      document_index += len;
+    }
+
+document_done:
+  if (document)
+    document[document_index] = '\0';
+  else
+    {
+      document = xmalloc (1);
+      document[0] = '\0';
     }
+  temp->redirectee.filename->word = document;
 }
-   
-/* Generate a REDIRECT from SOURCE, DEST, and INSTRUCTION. 
+
+/* Generate a REDIRECT from SOURCE, DEST, and INSTRUCTION.
    INSTRUCTION is the instruction type, SOURCE is a file descriptor,
    and DEST is a file descriptor or a WORD_DESC *. */
 REDIRECT *
@@ -483,13 +484,13 @@ make_redirection (source, instruction, dest_and_filename)
     case r_reading_until:      /* << foo */
       break;
 
+    case r_close_this:                 /* <&- */
     case r_duplicating_input:          /* 1<&2 */
     case r_duplicating_output:         /* 1>&2 */
-    case r_close_this:                 /* <&- */
     case r_duplicating_input_word:     /* 1<&$foo */
     case r_duplicating_output_word:    /* 1>&$foo */
       break;
-    
+
     case r_err_and_out:                /* command &>filename */
       temp->flags = O_TRUNC | O_WRONLY | O_CREAT;
       break;
@@ -499,8 +500,7 @@ make_redirection (source, instruction, dest_and_filename)
       break;
 
     default:
-      programming_error ("Redirection instruction from yyparse () '%d' is\n\
-out of range in make_redirection ().", instruction);
+      programming_error ("make_redirection: redirection instruction `%d' out of range", instruction);
       abort ();
       break;
     }
@@ -508,16 +508,19 @@ out of range in make_redirection ().", instruction);
 }
 
 COMMAND *
-make_function_def (name, command)
+make_function_def (name, command, lineno, lstart)
      WORD_DESC *name;
      COMMAND *command;
+     int lineno, lstart;
 {
   FUNCTION_DEF *temp;
 
   temp = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF));
   temp->command = command;
   temp->name = name;
-  command->line = line_number - current_command_line_count + 1;
+  temp->line = lineno;
+  temp->ignore = 0;
+  command->line = lstart;
   return (make_command (cm_function_def, (SIMPLE_COM *)temp));
 }
 
@@ -529,42 +532,18 @@ clean_simple_command (command)
      COMMAND *command;
 {
   if (command->type != cm_simple)
-    {
-      programming_error
-       ("clean_simple_command () got a command with type %d.", command->type);
-    }
+    programming_error ("clean_simple_command: bad command type `%d'", command->type);
   else
     {
       command->value.Simple->words =
        REVERSE_LIST (command->value.Simple->words, WORD_LIST *);
-      command->value.Simple->redirects = 
+      command->value.Simple->redirects =
        REVERSE_LIST (command->value.Simple->redirects, REDIRECT *);
     }
 
   return (command);
 }
 
-/* Cons up a new array of words.  The words are taken from LIST,
-   which is a WORD_LIST *.  Absolutely everything is malloc'ed,
-   so you should free everything in this array when you are done.
-   The array is NULL terminated. */
-char **
-make_word_array (list)
-     WORD_LIST *list;
-{
-  int count = list_length (list);
-  char **array = (char **)xmalloc ((1 + count) * sizeof (char *));
-
-  for (count = 0; list; count++)
-    {
-      array[count] = xmalloc (1 + strlen (list->word->word));
-      strcpy (array[count], list->word->word);
-      list = list->next;
-    }
-  array[count] = (char *)NULL;
-  return (array);
-}
-
 /* The Yacc grammar productions have a problem, in that they take a
    list followed by an ampersand (`&') and do a simple command connection,
    making the entire list effectively asynchronous, instead of just