Imported from ../bash-2.05a.tar.gz.
[platform/upstream/bash.git] / builtins / common.c
index 2936b88..19a76ea 100644 (file)
@@ -4,7 +4,7 @@
 
    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
    
    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>
 
 #if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
 #  include <unistd.h>
 #endif
 
 #include <stdio.h>
-#include <sys/types.h>
-#include "../posixstat.h"
+#include <chartypes.h>
+#include "../bashtypes.h"
+#include "posixstat.h"
 #include <signal.h>
 
+#include <errno.h>
+
 #if defined (PREFER_STDARG)
 #  include <stdarg.h>
 #else
 #include "../bashansi.h"
 
 #include "../shell.h"
-#include "../maxpath.h"
+#include "maxpath.h"
 #include "../flags.h"
 #include "../jobs.h"
 #include "../builtins.h"
 #include "../input.h"
 #include "../execute_cmd.h"
 #include "../trap.h"
-#include "hashcom.h"
 #include "bashgetopt.h"
 #include "common.h"
+#include "builtext.h"
 #include <tilde/tilde.h>
 
 #if defined (HISTORY)
 #  include "../bashhist.h"
 #endif
 
-extern int no_symbolic_links, interactive, interactive_shell;
+#if !defined (errno)
+extern int errno;   
+#endif /* !errno */
+
+extern int no_symbolic_links;
 extern int indirection_level, startup_state, subshell_environment;
 extern int line_number;
 extern int last_command_exit_value;
 extern int running_trap;
-extern int hashing_enabled;
-extern int variable_context;
 extern int posixly_correct;
 extern char *this_command_name, *shell_name;
-extern COMMAND *global_command;
-extern HASH_TABLE *hashed_filenames;
 extern char *bash_getcwd_errstr;
 
+/* Used by some builtins and the mainline code. */
+sh_builtin_func_t *last_shell_builtin = (sh_builtin_func_t *)NULL;
+sh_builtin_func_t *this_shell_builtin = (sh_builtin_func_t *)NULL;
+
 /* **************************************************************** */
 /*                                                                 */
 /*          Error reporting, usage, and option processing          */
@@ -310,17 +320,20 @@ set_dollar_vars_changed ()
 
 /* **************************************************************** */
 /*                                                                 */
-/*             Validating numeric input and arguments              */
+/*             Validating numeric input and arguments              */
 /*                                                                 */
 /* **************************************************************** */
 
 /* Read a numeric arg for this_command_name, the name of the shell builtin
    that wants it.  LIST is the word list that the arg is to come from.
    Accept only the numeric argument; report an error if other arguments
-   follow. */
-int
-get_numeric_arg (list)
+   follow.  If FATAL is true, call throw_to_top_level, which exits the
+   shell; if not, call jump_to_top_level (DISCARD), which aborts the
+   current command. */
+long
+get_numeric_arg (list, fatal)
      WORD_LIST *list;
+     int fatal;
 {
   long count = 1;
 
@@ -332,13 +345,38 @@ get_numeric_arg (list)
       if (!arg || (legal_number (arg, &count) == 0))
        {
          builtin_error ("bad non-numeric arg `%s'", list->word->word);
-         throw_to_top_level ();
+         if (fatal)
+           throw_to_top_level ();
+         else
+           jump_to_top_level (DISCARD);
        }
       no_args (list->next);
     }
+
   return (count);
 }
 
+/* Get an eight-bit status value from LIST */
+int
+get_exitstat (list)
+     WORD_LIST *list;
+{
+  int status;
+  long sval;
+  char *arg;
+
+  arg = list->word->word;
+  if (arg == 0 || legal_number (arg, &sval) == 0)
+    {
+      builtin_error ("bad non-numeric arg `%s'", list->word->word);
+      return 255;
+    }
+  no_args (list->next);
+
+  status = sval & 255;
+  return status;
+}
+
 /* Return the octal number parsed from STRING, or -1 to indicate
    that the string contained a bad number. */
 int
@@ -348,13 +386,15 @@ read_octal (string)
   int result, digits;
 
   result = digits = 0;
-  while (*string && *string >= '0' && *string < '8')
+  while (*string && ISOCTAL (*string))
     {
       digits++;
-      result = (result * 8) + *string++ - '0';
+      result = (result * 8) + (*string++ - '0');
+      if (result > 0777)
+       return -1;
     }
 
-  if (!digits || result > 0777 || *string)
+  if (digits == 0 || *string)
     result = -1;
 
   return (result);
@@ -362,80 +402,6 @@ read_octal (string)
 
 /* **************************************************************** */
 /*                                                                 */
-/*                     Command name hashing                        */
-/*                                                                 */
-/* **************************************************************** */
-
-/* Return the full pathname that FILENAME hashes to.  If FILENAME
-   is hashed, but (data->flags & HASH_CHKDOT) is non-zero, check
-   ./FILENAME and return that if it is executable. */
-char *
-find_hashed_filename (filename)
-     char *filename;
-{
-  register BUCKET_CONTENTS *item;
-  char *path, *dotted_filename, *tail;
-  int same;
-
-  if (hashing_enabled == 0)
-    return ((char *)NULL);
-
-  item = find_hash_item (filename, hashed_filenames);
-
-  if (item == NULL)
-    return ((char *)NULL);
-
-  /* If this filename is hashed, but `.' comes before it in the path,
-     see if ./filename is executable.  If the hashed value is not an
-     absolute pathname, see if ./`hashed-value' exists. */
-  path = pathdata(item)->path;
-  if (pathdata(item)->flags & (HASH_CHKDOT|HASH_RELPATH))
-    {
-      tail = (pathdata(item)->flags & HASH_RELPATH) ? path : filename;
-      dotted_filename = xmalloc (3 + strlen (tail));
-      dotted_filename[0] = '.'; dotted_filename[1] = '/';
-      strcpy (dotted_filename + 2, tail);
-
-      if (executable_file (dotted_filename))
-       return (dotted_filename);
-
-      free (dotted_filename);
-
-#if 0
-      if (pathdata(item)->flags & HASH_RELPATH)
-       return ((char *)NULL);
-#endif
-
-      /* Watch out.  If this file was hashed to "./filename", and
-        "./filename" is not executable, then return NULL. */
-
-      /* Since we already know "./filename" is not executable, what
-        we're really interested in is whether or not the `path'
-        portion of the hashed filename is equivalent to the current
-        directory, but only if it starts with a `.'.  (This catches
-        ./. and so on.)  same_file () tests general Unix file
-        equivalence -- same device and inode. */
-      if (*path == '.')
-       {
-         same = 0;
-         tail = (char *)strrchr (path, '/');
-
-         if (tail)
-           {
-             *tail = '\0';
-             same = same_file (".", path, (struct stat *)NULL, (struct stat *)NULL);
-             *tail = '/';
-           }
-
-         return same ? (char *)NULL : path;
-       }
-    }
-
-  return (path);
-}
-
-/* **************************************************************** */
-/*                                                                 */
 /*          Manipulating the current working directory             */
 /*                                                                 */
 /* **************************************************************** */
@@ -460,16 +426,14 @@ get_working_directory (for_whom)
 
   if (the_current_working_directory == 0)
     {
-      the_current_working_directory = xmalloc (PATH_MAX);
+      the_current_working_directory = (char *)xmalloc (PATH_MAX);
       the_current_working_directory[0] = '\0';
       directory = getcwd (the_current_working_directory, PATH_MAX);
       if (directory == 0)
        {
-         fprintf (stderr, "%s: could not get current directory: %s\n",
+         fprintf (stderr, "%s: could not get current directory: %s: %s\n",
                   (for_whom && *for_whom) ? for_whom : get_name_for_error (),
-                  the_current_working_directory[0]
-                       ? the_current_working_directory
-                       : bash_getcwd_errstr);
+                  bash_getcwd_errstr, strerror (errno));
 
          free (the_current_working_directory);
          the_current_working_directory = (char *)NULL;
@@ -502,7 +466,7 @@ get_job_spec (list)
      WORD_LIST *list;
 {
   register char *word;
-  int job, substring;
+  int job, substring_search;
 
   if (list == 0)
     return (current_job);
@@ -515,13 +479,13 @@ get_job_spec (list)
   if (*word == '%')
     word++;
 
-  if (digit (*word) && all_digits (word))
+  if (DIGIT (*word) && all_digits (word))
     {
       job = atoi (word);
-      return (job - 1);
+      return (job >= job_slots ? NO_JOB : job - 1);
     }
 
-  substring = 0;
+  substring_search = 0;
   switch (*word)
     {
     case 0:
@@ -533,7 +497,7 @@ get_job_spec (list)
       return (previous_job);
 
     case '?':                  /* Substring search requested. */
-      substring++;
+      substring_search++;
       word++;
       /* FALLTHROUGH */
 
@@ -551,15 +515,17 @@ get_job_spec (list)
                p = jobs[i]->pipe;
                do
                  {
-                   if ((substring && strindex (p->command, word)) ||
+                   if ((substring_search && strindex (p->command, word)) ||
                        (STREQN (p->command, word, wl)))
-                     if (job != NO_JOB)
-                       {
-                         builtin_error ("ambigious job spec: %s", word);
-                         return (DUP_JOB);
-                       }
-                     else
-                       job = i;
+                     {
+                       if (job != NO_JOB)
+                         {
+                           builtin_error ("ambigious job spec: %s", word);
+                           return (DUP_JOB);
+                         }
+                       else
+                         job = i;
+                     }
 
                    p = p->next;
                  }
@@ -635,7 +601,13 @@ display_signal_list (list, forcecols)
              list = list->next;
              continue;
            }
+#if defined (JOB_CONTROL)
+         /* POSIX.2 says that `kill -l signum' prints the signal name without
+            the `SIG' prefix. */
+         printf ("%s\n", (this_shell_builtin == kill_builtin) ? name + 3 : name);
+#else
          printf ("%s\n", name);
+#endif
        }
       else
        {
@@ -705,33 +677,33 @@ builtin_address_internal (name, disabled_okay)
 }
 
 /* Return the pointer to the function implementing builtin command NAME. */
-Function *
+sh_builtin_func_t *
 find_shell_builtin (name)
      char *name;
 {
   current_builtin = builtin_address_internal (name, 0);
-  return (current_builtin ? current_builtin->function : (Function *)NULL);
+  return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
 }
 
 /* Return the address of builtin with NAME, whether it is enabled or not. */
-Function *
+sh_builtin_func_t *
 builtin_address (name)
      char *name;
 {
   current_builtin = builtin_address_internal (name, 1);
-  return (current_builtin ? current_builtin->function : (Function *)NULL);
+  return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
 }
 
 /* Return the function implementing the builtin NAME, but only if it is a
    POSIX.2 special builtin. */
-Function *
+sh_builtin_func_t *
 find_special_builtin (name)
      char *name;
 {
   current_builtin = builtin_address_internal (name, 0);
   return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ?
                        current_builtin->function :
-                       (Function *)NULL);
+                       (sh_builtin_func_t *)NULL);
 }
   
 static int
@@ -752,146 +724,5 @@ void
 initialize_shell_builtins ()
 {
   qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
-    shell_builtin_compare);
-}
-
-/* **************************************************************** */
-/*                                                                 */
-/*      Functions for quoting strings to be re-read as input       */
-/*                                                                 */
-/* **************************************************************** */
-
-/* Return a new string which is the single-quoted version of STRING.
-   Used by alias and trap, among others. */
-char *
-single_quote (string)
-     char *string;
-{
-  register int c;
-  char *result, *r, *s;
-
-  result = (char *)xmalloc (3 + (4 * strlen (string)));
-  r = result;
-  *r++ = '\'';
-
-  for (s = string; s && (c = *s); s++)
-    {
-      *r++ = c;
-
-      if (c == '\'')
-       {
-         *r++ = '\\';  /* insert escaped single quote */
-         *r++ = '\'';
-         *r++ = '\'';  /* start new quoted string */
-       }
-    }
-
-  *r++ = '\'';
-  *r = '\0';
-
-  return (result);
-}
-
-/* Quote STRING using double quotes.  Return a new string. */
-char *
-double_quote (string)
-     char *string;
-{
-  register int c;
-  char *result, *r, *s;
-
-  result = (char *)xmalloc (3 + (2 * strlen (string)));
-  r = result;
-  *r++ = '"';
-
-  for (s = string; s && (c = *s); s++)
-    {
-      switch (c)
-        {
-       case '"':
-       case '$':
-       case '`':
-       case '\\':
-         *r++ = '\\';
-       default:
-         *r++ = c;
-         break;
-        }
-    }
-
-  *r++ = '"';
-  *r = '\0';
-
-  return (result);
-}
-
-/* Quote special characters in STRING using backslashes.  Return a new
-   string. */
-char *
-backslash_quote (string)
-     char *string;
-{
-  int c;
-  char *result, *r, *s;
-
-  result = xmalloc (2 * strlen (string) + 1);
-
-  for (r = result, s = string; s && (c = *s); s++)
-    {
-      switch (c)
-       {
-       case ' ': case '\t': case '\n':         /* IFS white space */
-       case '\'': case '"': case '\\':         /* quoting chars */
-       case '|': case '&': case ';':           /* shell metacharacters */
-       case '(': case ')': case '<': case '>':
-       case '!': case '{': case '}':           /* reserved words */
-       case '*': case '[': case '?': case ']': /* globbing chars */
-       case '^':
-       case '$': case '`':                     /* expansion chars */
-         *r++ = '\\';
-         *r++ = c;
-         break;
-       case '#':                               /* comment char */
-         if (s == string)
-           *r++ = '\\';
-         /* FALLTHROUGH */
-       default:
-         *r++ = c;
-         break;
-       }
-    }
-
-  *r = '\0';
-  return (result);
-}
-
-int
-contains_shell_metas (string)
-     char *string;
-{
-  char *s;
-
-  for (s = string; s && *s; s++)
-    {
-      switch (*s)
-       {
-       case ' ': case '\t': case '\n':         /* IFS white space */
-       case '\'': case '"': case '\\':         /* quoting chars */
-       case '|': case '&': case ';':           /* shell metacharacters */
-       case '(': case ')': case '<': case '>':
-       case '!': case '{': case '}':           /* reserved words */
-       case '*': case '[': case '?': case ']': /* globbing chars */
-       case '^':
-       case '$': case '`':                     /* expansion chars */
-         return (1);
-       case '#':
-         if (s == string)                      /* comment char */
-           return (1);
-         /* FALLTHROUGH */
-       default:
-         break;
-       }
-    }
-
-  return (0);
+    (QSFUNC *)shell_builtin_compare);
 }