]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - builtins/fc.def
Imported from ../bash-3.2.tar.gz.
[thirdparty/bash.git] / builtins / fc.def
index e88ba122f534f35caf8d20f2c195de34eac09635..101eb008cbd46c7e21548f63f3465fb8c42156c4 100644 (file)
@@ -1,13 +1,13 @@
 This file is fc.def, from which is created fc.c.
 It implements the builtin "fc" in Bash.
 
-Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
+Copyright (C) 1987-2005 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,7 +17,7 @@ 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.
 
 $PRODUCES fc.c
 
@@ -25,14 +25,13 @@ $BUILTIN fc
 $FUNCTION fc_builtin
 $DEPENDS_ON HISTORY
 $SHORT_DOC fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [cmd]
-
+fc is used to list or edit and re-execute commands from the history list.
 FIRST and LAST can be numbers specifying the range, or FIRST can be a
 string, which means the most recent command beginning with that
 string.
 
    -e ENAME selects which editor to use.  Default is FCEDIT, then EDITOR,
-      then the editor which corresponds to the current readline editing
-      mode, then vi.
+      then vi.
 
    -l means list lines instead of editing.
    -n means no line numbers listed.
@@ -49,25 +48,31 @@ $END
 #include <config.h>
 
 #if defined (HISTORY)
-#include <sys/param.h>
+#ifndef _MINIX
+#  include <sys/param.h>
+#endif
 #include "../bashtypes.h"
-#include "../posixstat.h"
-#include <sys/file.h>
+#include "posixstat.h"
+#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
+#  include <sys/file.h>
+#endif
 
 #if defined (HAVE_UNISTD_H)
 #  include <unistd.h>
 #endif
 
 #include <stdio.h>
+#include <chartypes.h>
 
 #include "../bashansi.h"
+#include "../bashintl.h"
 #include <errno.h>
 
 #include "../shell.h"
 #include "../builtins.h"
 #include "../flags.h"
-#include "../maxpath.h"
 #include "../bashhist.h"
+#include "maxpath.h"
 #include <readline/history.h>
 #include "bashgetopt.h"
 #include "common.h"
@@ -76,13 +81,14 @@ $END
 extern int errno;
 #endif /* !errno */
 
-extern int echo_input_at_read;
 extern int current_command_line_count;
 extern int literal_history;
+extern int posixly_correct;
 
-extern int unlink ();
+extern int unlink __P((const char *));
 
-extern int fc_execute_file ();
+extern FILE *sh_mktmpfp __P((char *, int, char **));
+extern int delete_last_history __P((void));
 
 /* **************************************************************** */
 /*                                                                 */
@@ -113,10 +119,6 @@ extern int fc_execute_file ();
    Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
 */
 
-static char *fc_dosubs (), *fc_gethist (), *fc_readline ();
-static int fc_gethnum (), fc_number ();
-static void fc_replhist (), fc_addhist ();
-
 /* Data structure describing a list of global replacements to perform. */
 typedef struct repl {
   struct repl *next;
@@ -142,8 +144,23 @@ typedef struct repl {
                } \
        } while (0)
 
+static char *fc_dosubs __P((char *, REPL *));
+static char *fc_gethist __P((char *, HIST_ENTRY **));
+static int fc_gethnum __P((char *, HIST_ENTRY **));
+static int fc_number __P((WORD_LIST *));
+static void fc_replhist __P((char *));
+#ifdef INCLUDE_UNUSED
+static char *fc_readline __P((FILE *));
+static void fc_addhist __P((char *));
+#endif
+
 /* String to execute on a file that we want to edit. */
 #define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
+#if defined (STRICT_POSIX)
+#  define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}"
+#else
+#  define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}"
+#endif
 
 int
 fc_builtin (list)
@@ -152,12 +169,12 @@ fc_builtin (list)
   register int i;
   register char *sep;
   int numbering, reverse, listing, execute;
-  int histbeg, histend, last_hist, retval, first, opt;
+  int histbeg, histend, last_hist, retval, opt;
   FILE *stream;
   REPL *rlist, *rl;
-  char *ename, *command, *newcom, *line;
+  char *ename, *command, *newcom, *fcedit;
   HIST_ENTRY **hlist;
-  char fn[64];
+  char *fn;
 
   numbering = 1;
   reverse = listing = execute = 0;
@@ -228,8 +245,7 @@ fc_builtin (list)
       /* If we have a list of substitutions to do, then reverse it
         to get the replacements in the proper order. */
 
-      if (rlist && rlist->next)
-       rlist = (REPL *)reverse_list ((GENERIC_LIST *) rlist);
+      rlist = REVERSE_LIST (rlist, REPL *);
 
       hlist = history_list ();
 
@@ -239,7 +255,7 @@ fc_builtin (list)
 
       if (command == NULL)
        {
-         builtin_error ("no command found");
+         builtin_error (_("no command found"));
          if (rlist)
            FREE_RLIST ();
 
@@ -274,6 +290,11 @@ fc_builtin (list)
      line was actually added (HISTIGNORE may have caused it to not be),
      so we check hist_last_line_added. */
 
+  /* "When not  listing, he fc command that caused the editing shall not be
+     entered into the history list." */
+  if (listing == 0 && hist_last_line_added)
+    delete_last_history ();
+
   last_hist = i - 1 - hist_last_line_added;
 
   if (list)
@@ -292,7 +313,7 @@ fc_builtin (list)
       if (listing)
        {
          histend = last_hist;
-         histbeg = histend - 16;
+         histbeg = histend - 16 + 1;   /* +1 because loop below uses >= */
          if (histbeg < 0)
            histbeg = 0;
        }
@@ -302,10 +323,9 @@ fc_builtin (list)
     }
 
   /* We print error messages for line specifications out of range. */
-  if ((histbeg < 0) || (histend < 0) ||
-      (histbeg > last_hist) || (histend > last_hist))
+  if ((histbeg < 0) || (histend < 0))
     {
-      builtin_error ("history specification out of range");
+      sh_erange ((char *)NULL, _("history specification"));
       return (EXECUTION_FAILURE);
     }
 
@@ -323,14 +343,11 @@ fc_builtin (list)
   else
     {
       numbering = 0;
-      /* XXX - this is raceable */
-      sprintf (fn, "/tmp/bash%d", (int)time ((time_t *) 0) + (int)getpid ());
-
-      stream = fopen (fn, "w");
-
+      stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
       if (stream == 0)
        {
-         builtin_error ("cannot open temp file %s", fn);
+         builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
+         FREE (fn);
          return (EXECUTION_FAILURE);
        }
     }
@@ -341,7 +358,12 @@ fc_builtin (list)
       if (numbering)
        fprintf (stream, "%d", i + history_base);
       if (listing)
-       fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
+       {
+         if (posixly_correct)
+           fputs ("\t", stream);
+         else
+           fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
+       }
       fprintf (stream, "%s\n", histline (i));
     }
 
@@ -358,78 +380,28 @@ fc_builtin (list)
     }
   else
     {
-      command = (char *)xmalloc (3 + strlen (FC_EDIT_COMMAND) + strlen (fn));
-      sprintf (command, "%s %s", FC_EDIT_COMMAND, fn);
+      fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND;
+      command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn));
+      sprintf (command, "%s %s", fcedit, fn);
     }
   retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
   if (retval != EXECUTION_SUCCESS)
     {
       unlink (fn);
+      free (fn);
       return (EXECUTION_FAILURE);
     }
 
-  /* Now reopen the file and execute the edited commands. */
-
-  stream = fopen (fn, "r");
-
-  if (stream == NULL)
-    {
-      builtin_error ("cannot reopen temp file %s", fn);
-      unlink (fn);
-      return (EXECUTION_FAILURE);
-    }
-
-  retval = EXECUTION_SUCCESS;
-  first = 1;
-
-#if 1
   /* Make sure parse_and_execute doesn't turn this off, even though a
      call to parse_and_execute farther up the function call stack (e.g.,
      if this is called by vi_edit_and_execute_command) may have already
      called bash_history_disable. */
   remember_on_history = 1;
-#else
-  /* First, write the commands to the history file.  This will not happen
-     when we call parse_and_execute, since parse_and_execute disables
-     the command line history while it executes. */
-
-  opt = current_command_line_count;
-  while ((line = fc_readline (stream)) != NULL)
-    {
-      if (line[0] == '\n')
-       {
-         free (line);
-         continue;             /* Skip blank lines. */
-       }
-
-      if (first)
-       {
-         first = 0;
-         /* If we retrieved only one command from the history file, but we
-            read multiple lines from the edited file, and literal_history
-            has been set by `shopt', we assume that it was a compound
-            command stored with embedded newlines.  In this case, we want
-            the history code to store it as one command again. */
-         if (literal_history && histbeg == histend)
-           current_command_line_count = 1;
-         fc_replhist (line);
-       }
-      else
-       {
-         if (literal_history && histbeg == histend)
-           current_command_line_count++;
-         fc_addhist (line);
-       }
-
-      free (line);
-    }
-  fclose (stream);
-  current_command_line_count = opt;
-#endif
 
   /* Turn on the `v' flag while fc_execute_file runs so the commands
      will be echoed as they are read by the parser. */
   begin_unwind_frame ("fc builtin");
+  add_unwind_protect ((Function *)xfree, fn);
   add_unwind_protect (unlink, fn);
   unwind_protect_int (echo_input_at_read);
   echo_input_at_read = 1;
@@ -453,7 +425,7 @@ fc_number (list)
   s = list->word->word;
   if (*s == '-')
     s++;
-  return (legal_number (s, (long *)NULL));
+  return (legal_number (s, (intmax_t *)NULL));
 }
 
 /* Return an absolute index into HLIST which corresponds to COMMAND.  If
@@ -495,24 +467,25 @@ fc_gethnum (command, hlist)
       s++;
     }
 
-  if (s && digit(*s))
+  if (s && DIGIT(*s))
     {
       n = atoi (s);
       n *= sign;
 
-      /* Anything specified greater than the last history element that we
-        deal with is an error. */
-      if (n > i + history_base)
-       return (-1);
-
       /* If the value is negative or zero, then it is an offset from
         the current history item. */
       if (n < 0)
-       return (i + n + 1);
+       {
+         n += i + 1;
+         return (n < 0 ? 0 : n);
+       }
       else if (n == 0)
        return (i);
       else
-       return (n - history_base);
+       {
+         n -= history_base;
+         return (i < n ? i : n);
+       }
     }
 
   clen = strlen (command);
@@ -533,7 +506,7 @@ fc_gethist (command, hlist)
 {
   int i;
 
-  if (!hlist)
+  if (hlist == 0)
     return ((char *)NULL);
 
   i = fc_gethnum (command, hlist);
@@ -544,6 +517,7 @@ fc_gethist (command, hlist)
     return ((char *)NULL);
 }
 
+#ifdef INCLUDE_UNUSED
 /* Read the edited history lines from STREAM and return them
    one at a time.  This can read unlimited length lines.  The
    caller should free the storage. */
@@ -558,7 +532,7 @@ fc_readline (stream)
   while ((c = getc (stream)) != EOF)
     {
       if ((lindex + 2) >= line_len)
-       line = (char *) xrealloc (line, (line_len += 128));
+       line = (char *)xrealloc (line, (line_len += 128));
 
       if (c == '\n')
        {
@@ -585,6 +559,7 @@ fc_readline (stream)
   line[lindex++] = '\0';
   return (line);
 }
+#endif
 
 /* Perform the SUBS on COMMAND.
    SUBS is a list of substitutions, and COMMAND is a simple string.
@@ -615,45 +590,23 @@ static void
 fc_replhist (command)
      char *command;
 {
-  register int i;
-  HIST_ENTRY **hlist, *histent, *discard;
   int n;
 
   if (command == 0 || *command == '\0')
     return;
 
-  hlist = history_list ();
-
-  if (hlist == NULL)
-    return;
-
-  for (i = 0; hlist[i]; i++);
-  i--;
-
-  /* History_get () takes a parameter that should be
-     offset by history_base. */
-
-  histent = history_get (history_base + i);    /* Don't free this */
-  if (histent == NULL)
-    return;
-
   n = strlen (command);
-
   if (command[n - 1] == '\n')
     command[n - 1] = '\0';
 
   if (command && *command)
     {
-      discard = remove_history (i);
-      if (discard)
-       {
-         FREE (discard->line);
-         free ((char *) discard);
-       }
+      delete_last_history ();
       maybe_add_history (command);     /* Obeys HISTCONTROL setting. */
     }
 }
 
+#ifdef INCLUDE_UNUSED
 /* Add LINE to the history, after removing a single trailing newline. */
 static void
 fc_addhist (line)
@@ -661,12 +614,17 @@ fc_addhist (line)
 {
   register int n;
 
+  if (line == 0 || *line == 0)
+    return;
+
   n = strlen (line);
 
   if (line[n - 1] == '\n')
     line[n - 1] = '\0';
 
   if (line && *line)
-    maybe_add_history (line);
+    maybe_add_history (line);          /* Obeys HISTCONTROL setting. */
 }
+#endif
+
 #endif /* HISTORY */