Imported from ../bash-2.05b.tar.gz.
[platform/upstream/bash.git] / make_cmd.c
index d17b4d8..1362e79 100644 (file)
@@ -1,13 +1,13 @@
 /* make_cmd.c -- Functions for making instances of the various
    parser constructs. */
 
-/* Copyright (C) 1989 Free Software Foundation, Inc.
+/* Copyright (C) 1989-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) any later
+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 ANY
@@ -17,48 +17,79 @@ for more details.
 
 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. */
+Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
 
 #include "config.h"
 
 #include <stdio.h>
 #include "bashtypes.h"
-#include <sys/file.h>
+#ifndef _MINIX
+#  include <sys/file.h>
+#endif
 #include "filecntl.h"
 #include "bashansi.h"
 #if defined (HAVE_UNISTD_H)
 #  include <unistd.h>
 #endif
 
+#include "syntax.h"
 #include "command.h"
 #include "general.h"
 #include "error.h"
 #include "flags.h"
 #include "make_cmd.h"
+#include "dispose_cmd.h"
 #include "variables.h"
 #include "subst.h"
 #include "input.h"
+#include "ocache.h"
 #include "externs.h"
 
 #if defined (JOB_CONTROL)
 #include "jobs.h"
 #endif
 
+#include "shmbutil.h"
+
 extern int line_number, current_command_line_count;
-extern int disallow_filename_globbing;
+extern int last_command_exit_value;
+
+/* Object caching */
+sh_obj_cache_t wdcache = {0, 0, 0};
+sh_obj_cache_t wlcache = {0, 0, 0};
+
+#define WDCACHESIZE    60
+#define WLCACHESIZE    60
+
+static COMMAND *make_for_or_select __P((enum command_type, WORD_DESC *, WORD_LIST *, COMMAND *));
+#if defined (ARITH_FOR_COMMAND)
+static WORD_LIST *make_arith_for_expr __P((char *));
+#endif
+static COMMAND *make_until_or_while __P((enum command_type, COMMAND *, COMMAND *));
+
+void
+cmd_init ()
+{
+  ocache_create (wdcache, WORD_DESC, WDCACHESIZE);
+  ocache_create (wlcache, WORD_LIST, WLCACHESIZE);
+}
 
 WORD_DESC *
 make_bare_word (string)
-     char *string;
+     const char *string;
 {
   WORD_DESC *temp;
-
+#if 0
   temp = (WORD_DESC *)xmalloc (sizeof (WORD_DESC));
+#else
+  ocache_alloc (wdcache, WORD_DESC, temp);
+#endif
+
   if (*string)
     temp->word = savestring (string);
   else
     {
-      temp->word = xmalloc (1);
+      temp->word = (char *)xmalloc (1);
       temp->word[0] = '\0';
     }
 
@@ -69,13 +100,18 @@ make_bare_word (string)
 WORD_DESC *
 make_word_flags (w, string)
      WORD_DESC *w;
-     char *string;
+     const char *string;
 {
-  register char *s;
+  register int i;
+  size_t slen;
+  DECLARE_MBSTATE;
 
-  for (s = string; *s; s++)
-    switch (*s)
-      {
+  i = 0;
+  slen = strlen (string);
+  while (i < slen)
+    {
+      switch (string[i])
+       {
        case '$':
          w->flags |= W_HASDOLLAR;
          break;
@@ -86,13 +122,17 @@ make_word_flags (w, string)
        case '"':
          w->flags |= W_QUOTED;
          break;
-      }
+       }
+
+      ADVANCE_CHAR (string, slen, i);
+    }
+
   return (w);
 }
 
 WORD_DESC *
 make_word (string)
-     char *string;
+     const char *string;
 {
   WORD_DESC *temp;
 
@@ -113,28 +153,19 @@ make_word_from_token (token)
 }
 
 WORD_LIST *
-make_word_list (word, link)
+make_word_list (word, wlink)
      WORD_DESC *word;
-     WORD_LIST *link;
+     WORD_LIST *wlink;
 {
   WORD_LIST *temp;
 
+#if 0
   temp = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
+#else
+  ocache_alloc (wlcache, WORD_LIST, temp);
+#endif
   temp->word = word;
-  temp->next = link;
-  return (temp);
-}
-
-WORD_LIST *
-add_string_to_list (string, list)
-     char *string;
-     WORD_LIST *list;
-{
-  WORD_LIST *temp;
-
-  temp = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
-  temp->word = make_word (string);
-  temp->next = list;
+  temp->next = wlink;
   return (temp);
 }
 
@@ -201,9 +232,99 @@ make_select_command (name, map_list, action)
 {
 #if defined (SELECT_COMMAND)
   return (make_for_or_select (cm_select, name, map_list, action));
+#else
+  last_command_exit_value = 2;
+  return ((COMMAND *)NULL);
 #endif
 }
 
+#if defined (ARITH_FOR_COMMAND)
+static WORD_LIST *
+make_arith_for_expr (s)
+     char *s;
+{
+  WORD_LIST *result;
+
+  if (s == 0 || *s == '\0')
+    return ((WORD_LIST *)NULL);
+  result = make_word_list (make_word (s), (WORD_LIST *)NULL);
+  return result;
+}
+#endif
+
+COMMAND *
+make_arith_for_command (exprs, action, lineno)
+     WORD_LIST *exprs;
+     COMMAND *action;
+     int lineno;
+{
+#if defined (ARITH_FOR_COMMAND)
+  ARITH_FOR_COM *temp;
+  WORD_LIST *init, *test, *step;
+  char *s, *t, *start;
+  int nsemi;
+
+  init = test = step = (WORD_LIST *)NULL;
+  /* Parse the string into the three component sub-expressions. */
+  start = t = s = exprs->word->word;
+  for (nsemi = 0; ;)
+    {
+      /* skip whitespace at the start of each sub-expression. */
+      while (whitespace (*s))
+       s++;
+      start = s;
+      /* skip to the semicolon or EOS */
+      while (*s && *s != ';')
+       s++;
+
+      t = (s > start) ? substring (start, 0, s - start) : (char *)NULL;
+
+      nsemi++;
+      switch (nsemi)
+       {
+       case 1:
+         init = make_arith_for_expr (t);
+         break;
+       case 2:
+         test = make_arith_for_expr (t);
+         break;
+       case 3:
+         step = make_arith_for_expr (t);
+         break;
+       }
+
+      FREE (t);
+      if (*s == '\0')
+       break;
+      s++;     /* skip over semicolon */
+    }
+
+  if (nsemi != 3)
+    {
+      if (nsemi < 3)
+       parser_error (lineno, "syntax error: arithmetic expression required");
+      else
+       parser_error (lineno, "syntax error: `;' unexpected");
+      parser_error (lineno, "syntax error: `((%s))'", exprs->word->word);
+      last_command_exit_value = 2;
+      return ((COMMAND *)NULL);
+    }
+
+  temp = (ARITH_FOR_COM *)xmalloc (sizeof (ARITH_FOR_COM));
+  temp->flags = 0;
+  temp->line = lineno;
+  temp->init = init ? init : make_arith_for_expr ("1");
+  temp->test = test ? test : make_arith_for_expr ("1");
+  temp->step = step ? step : make_arith_for_expr ("1");
+  temp->action = action;
+
+  return (make_command (cm_arith_for, (SIMPLE_COM *)temp));
+#else
+  last_command_exit_value = 2;
+  return ((COMMAND *)NULL);
+#endif /* ARITH_FOR_COMMAND */
+}
+
 COMMAND *
 make_group_command (command)
      COMMAND *command;
@@ -286,6 +407,75 @@ make_until_command (test, action)
 }
 
 COMMAND *
+make_arith_command (exp)
+     WORD_LIST *exp;
+{
+#if defined (DPAREN_ARITHMETIC)
+  COMMAND *command;
+  ARITH_COM *temp;
+
+  command = (COMMAND *)xmalloc (sizeof (COMMAND));
+  command->value.Arith = temp = (ARITH_COM *)xmalloc (sizeof (ARITH_COM));
+
+  temp->flags = 0;
+  temp->line = line_number;
+  temp->exp = exp;
+
+  command->type = cm_arith;
+  command->redirects = (REDIRECT *)NULL;
+  command->flags = 0;
+
+  return (command);
+#else
+  last_command_exit_value = 2;
+  return ((COMMAND *)NULL);
+#endif
+}
+
+#if defined (COND_COMMAND)
+struct cond_com *
+make_cond_node (type, op, left, right)
+     int type;
+     WORD_DESC *op;
+     struct cond_com *left, *right;
+{
+  COND_COM *temp;
+
+  temp = (COND_COM *)xmalloc (sizeof (COND_COM));
+  temp->flags = 0;
+  temp->line = line_number;
+  temp->type = type;
+  temp->op = op;
+  temp->left = left;
+  temp->right = right;
+
+  return (temp);
+}
+#endif
+
+COMMAND *
+make_cond_command (cond_node)
+     COND_COM *cond_node;
+{
+#if defined (COND_COMMAND)
+  COMMAND *command;
+
+  command = (COMMAND *)xmalloc (sizeof (COMMAND));
+  command->value.Cond = cond_node;
+
+  command->type = cm_cond;
+  command->redirects = (REDIRECT *)NULL;
+  command->flags = 0;
+  command->line = cond_node ? cond_node->line : 0;
+
+  return (command);
+#else
+  last_command_exit_value = 2;
+  return ((COMMAND *)NULL);
+#endif
+}
+
+COMMAND *
 make_bare_simple_command ()
 {
   COMMAND *command;
@@ -320,12 +510,7 @@ make_simple_command (element, command)
     command = make_bare_simple_command ();
 
   if (element.word)
-    {
-      WORD_LIST *tw = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
-      tw->word = element.word;
-      tw->next = command->value.Simple->words;
-      command->value.Simple->words = tw;
-    }
+    command->value.Simple->words = make_word_list (element.word, command->value.Simple->words);
   else
     {
       REDIRECT *r = element.redirect;
@@ -376,7 +561,7 @@ make_here_document (temp)
     redir_len = strlen (redir_word);
   else
     {
-      temp->here_doc_eof = xmalloc (1);
+      temp->here_doc_eof = (char *)xmalloc (1);
       temp->here_doc_eof[0] = '\0';
       goto document_done;
     }
@@ -404,7 +589,7 @@ make_here_document (temp)
       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. */
@@ -416,7 +601,7 @@ make_here_document (temp)
        }
 
       if (*line == 0)
-        continue;
+       continue;
 
       if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n')
        goto document_done;
@@ -424,8 +609,8 @@ make_here_document (temp)
       len = strlen (line);
       if (len + document_index >= document_size)
        {
-         document_size = document_size ? 2 * (document_size + len) : 1000;
-         document = xrealloc (document, document_size);
+         document_size = document_size ? 2 * (document_size + len) : len + 2;
+         document = (char *)xrealloc (document, document_size);
        }
 
       /* len is guaranteed to be > 0 because of the check for line
@@ -439,7 +624,7 @@ document_done:
     document[document_index] = '\0';
   else
     {
-      document = xmalloc (1);
+      document = (char *)xmalloc (1);
       document[0] = '\0';
     }
   temp->redirectee.filename->word = document;
@@ -454,7 +639,12 @@ make_redirection (source, instruction, dest_and_filename)
      enum r_instruction instruction;
      REDIRECTEE dest_and_filename;
 {
-  REDIRECT *temp = (REDIRECT *)xmalloc (sizeof (REDIRECT));
+  REDIRECT *temp;
+  WORD_DESC *w;
+  int wlen;
+  intmax_t lfd;
+
+  temp = (REDIRECT *)xmalloc (sizeof (REDIRECT));
 
   /* First do the common cases. */
   temp->redirector = source;
@@ -466,37 +656,58 @@ make_redirection (source, instruction, dest_and_filename)
   switch (instruction)
     {
 
-    case r_output_direction:   /* >foo */
-    case r_output_force:       /* >| foo */
+    case r_output_direction:           /* >foo */
+    case r_output_force:               /* >| foo */
+    case r_err_and_out:                        /* command &>filename */
       temp->flags = O_TRUNC | O_WRONLY | O_CREAT;
       break;
 
-    case r_input_direction:    /* <foo */
-    case r_inputa_direction:   /* foo & makes this. */
-      temp->flags = O_RDONLY;
+    case r_appending_to:               /* >>foo */
+      temp->flags = O_APPEND | O_WRONLY | O_CREAT;
       break;
 
-    case r_appending_to:       /* >>foo */
-      temp->flags = O_APPEND | O_WRONLY | O_CREAT;
+    case r_input_direction:            /* <foo */
+    case r_inputa_direction:           /* foo & makes this. */
+      temp->flags = O_RDONLY;
       break;
 
-    case r_deblank_reading_until: /* <<-foo */
-    case r_reading_until:      /* << foo */
+    case r_input_output:               /* <>foo */
+      temp->flags = O_RDWR | O_CREAT;
       break;
 
+    case r_deblank_reading_until:      /* <<-foo */
+    case r_reading_until:              /* << foo */
+    case r_reading_string:             /* <<< foo */
     case r_close_this:                 /* <&- */
     case r_duplicating_input:          /* 1<&2 */
     case r_duplicating_output:         /* 1>&2 */
-    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;
+    /* the parser doesn't pass these. */
+    case r_move_input:                 /* 1<&2- */
+    case r_move_output:                        /* 1>&2- */
+    case r_move_input_word:            /* 1<&$foo- */
+    case r_move_output_word:           /* 1>&$foo- */
       break;
 
-    case r_input_output:
-      temp->flags = O_RDWR | O_CREAT;
+    /* The way the lexer works we have to do this here. */
+    case r_duplicating_input_word:     /* 1<&$foo */
+    case r_duplicating_output_word:    /* 1>&$foo */
+      w = dest_and_filename.filename;
+      wlen = strlen (w->word) - 1;
+      if (w->word[wlen] == '-')                /* Yuck */
+        {
+          w->word[wlen] = '\0';
+         if (all_digits (w->word) && legal_number (w->word, &lfd) && lfd == (int)lfd)
+           {
+             dispose_word (w);
+             temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input : r_move_output;
+             temp->redirectee.dest = lfd;
+           }
+         else
+           temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input_word : r_move_output_word;
+        }
+          
       break;
 
     default:
@@ -519,11 +730,23 @@ make_function_def (name, command, lineno, lstart)
   temp->command = command;
   temp->name = name;
   temp->line = lineno;
-  temp->ignore = 0;
+  temp->flags = 0;
   command->line = lstart;
   return (make_command (cm_function_def, (SIMPLE_COM *)temp));
 }
 
+COMMAND *
+make_subshell_command (command)
+     COMMAND *command;
+{
+  SUBSHELL_COM *temp;
+
+  temp = (SUBSHELL_COM *)xmalloc (sizeof (SUBSHELL_COM));
+  temp->command = command;
+  temp->flags = CMD_WANT_SUBSHELL;
+  return (make_command (cm_subshell, (SIMPLE_COM *)temp));
+}
+
 /* Reverse the word list and redirection list in the simple command
    has just been parsed.  It seems simpler to do this here the one
    time then by any other method that I can think of. */
@@ -532,7 +755,7 @@ clean_simple_command (command)
      COMMAND *command;
 {
   if (command->type != cm_simple)
-    programming_error ("clean_simple_command: bad command type `%d'", command->type);
+    command_error ("clean_simple_command", CMDERR_BADTYPE, command->type, 0);
   else
     {
       command->value.Simple->words =