]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - builtins/fc.def
bash-5.1 distribution sources and documentation
[thirdparty/bash.git] / builtins / fc.def
index 62a28c4c5e136ed7886cc0bf4ecb96292116d4f2..467dbcbcc33a89b02e228dd442f5c221a02b22bf 100644 (file)
@@ -1,7 +1,7 @@
 This file is fc.def, from which is created fc.c.
 It implements the builtin "fc" in Bash.
 
-Copyright (C) 1987-2015 Free Software Foundation, Inc.
+Copyright (C) 1987-2020 Free Software Foundation, Inc.
 
 This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -86,9 +86,19 @@ $END
 extern int errno;
 #endif /* !errno */
 
-extern int unlink __P((const char *));
+#define HIST_INVALID INT_MIN
+#define HIST_ERANGE  INT_MIN+1
+#define HIST_NOTFOUND INT_MIN+2
 
-extern FILE *sh_mktmpfp __P((char *, int, char **));
+/* Values for the flags argument to fc_gethnum */
+#define HN_LISTING     0x01
+#define HN_FIRST       0x02
+
+extern int unlink PARAMS((const char *));
+
+extern FILE *sh_mktmpfp PARAMS((char *, int, char **));
+
+extern int suppress_debug_trap_verbose;
 
 /* **************************************************************** */
 /*                                                                 */
@@ -144,14 +154,14 @@ 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 *));
+static char *fc_dosubs PARAMS((char *, REPL *));
+static char *fc_gethist PARAMS((char *, HIST_ENTRY **, int));
+static int fc_gethnum PARAMS((char *, HIST_ENTRY **, int));
+static int fc_number PARAMS((WORD_LIST *));
+static void fc_replhist PARAMS((char *));
 #ifdef INCLUDE_UNUSED
-static char *fc_readline __P((FILE *));
-static void fc_addhist __P((char *));
+static char *fc_readline PARAMS((FILE *));
+static void fc_addhist PARAMS((char *));
 #endif
 
 static void
@@ -199,7 +209,7 @@ fc_builtin (list)
          break;
 
        case 'l':
-         listing = 1;
+         listing = HN_LISTING;         /* for fc_gethnum */
          break;
 
        case 'r':
@@ -258,7 +268,7 @@ fc_builtin (list)
 
       /* If we still have something in list, it is a command spec.
         Otherwise, we use the most recent command in time. */
-      command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
+      command = fc_gethist (list ? list->word->word : (char *)NULL, hlist, 0);
 
       if (command == NULL)
        {
@@ -319,18 +329,15 @@ fc_builtin (list)
     while (last_hist >= 0 && hlist[last_hist] == 0)
       last_hist--;
   if (last_hist < 0)
-    {
-      sh_erange ((char *)NULL, _("history specification"));
-      return (EXECUTION_FAILURE);
-    }
+    last_hist = 0;             /* per POSIX */
 
   if (list)
     {
-      histbeg = fc_gethnum (list->word->word, hlist);
+      histbeg = fc_gethnum (list->word->word, hlist, listing|HN_FIRST);
       list = list->next;
 
       if (list)
-       histend = fc_gethnum (list->word->word, hlist);
+       histend = fc_gethnum (list->word->word, hlist, listing);
       else if (histbeg == real_last)
        histend = listing ? real_last : histbeg;
       else
@@ -351,6 +358,28 @@ fc_builtin (list)
        histbeg = histend = last_hist;
     }
 
+  if (histbeg == HIST_INVALID || histend == HIST_INVALID)
+    {
+      sh_erange ((char *)NULL, _("history specification")); 
+      return (EXECUTION_FAILURE);
+    }
+  else if (histbeg == HIST_ERANGE || histend == HIST_ERANGE)
+    {
+      sh_erange ((char *)NULL, _("history specification"));
+      return (EXECUTION_FAILURE);
+    }
+  else if (histbeg == HIST_NOTFOUND || histend == HIST_NOTFOUND)
+    {
+      builtin_error (_("no command found"));
+      return (EXECUTION_FAILURE);
+    }
+
+  /* We don't throw an error for line specifications out of range, per POSIX */
+  if (histbeg < 0)
+    histbeg = 0;
+  if (histend < 0)
+    histend = 0;
+
   /* "When not listing, the fc command that caused the editing shall not be
      entered into the history list." */
   if (listing == 0 && hist_last_line_added)
@@ -364,14 +393,36 @@ fc_builtin (list)
         in parse_and_execute(). */
       if (histbeg == histend && histend == last_hist && hlist[last_hist] == 0)
        last_hist = histbeg = --histend;
+
+      if (hlist[last_hist] == 0)
+       last_hist--;
+      if (histend >= last_hist)
+       histend = last_hist;
+      else if (histbeg >= last_hist)
+       histbeg = last_hist;
     }
 
-  /* We print error messages for line specifications out of range. */
-  if ((histbeg < 0) || (histend < 0))
+  if (histbeg == HIST_INVALID || histend == HIST_INVALID)
+    {
+      sh_erange ((char *)NULL, _("history specification")); 
+      return (EXECUTION_FAILURE);
+    }
+  else if (histbeg == HIST_ERANGE || histend == HIST_ERANGE)
     {
       sh_erange ((char *)NULL, _("history specification"));
       return (EXECUTION_FAILURE);
     }
+  else if (histbeg == HIST_NOTFOUND || histend == HIST_NOTFOUND)
+    {
+      builtin_error (_("no command found"));
+      return (EXECUTION_FAILURE);
+    }
+
+  /* We don't throw an error for line specifications out of range, per POSIX */
+  if (histbeg < 0)
+    histbeg = 0;
+  if (histend < 0)
+    histend = 0;
 
   if (histend < histbeg)
     {
@@ -445,7 +496,7 @@ fc_builtin (list)
     }
 
 #if defined (READLINE)
-  /* If we're executing as part of a dispatched readline commnand like
+  /* If we're executing as part of a dispatched readline command like
      {emacs,vi}_edit_and_execute_command, the readline state will indicate it.
      We could remove the partial command from the history, but ksh93 doesn't
      so we stay compatible. */
@@ -463,7 +514,9 @@ fc_builtin (list)
   add_unwind_protect (xfree, fn);
   add_unwind_protect (unlink, fn);
   add_unwind_protect (set_verbose_flag, (char *)NULL);
+  unwind_protect_int (suppress_debug_trap_verbose);
   echo_input_at_read = 1;
+  suppress_debug_trap_verbose = 1;
 
   retval = fc_execute_file (fn);
   run_unwind_frame ("fc builtin");
@@ -488,16 +541,21 @@ fc_number (list)
 
 /* Return an absolute index into HLIST which corresponds to COMMAND.  If
    COMMAND is a number, then it was specified in relative terms.  If it
-   is a string, then it is the start of a command line present in HLIST. */
+   is a string, then it is the start of a command line present in HLIST.
+   MODE includes HN_LISTING if we are listing commands, and does not if we
+   are executing them. If MODE includes HN_FIRST we are looking for the
+   first history number specification. */
 static int
-fc_gethnum (command, hlist)
+fc_gethnum (command, hlist, mode)
      char *command;
      HIST_ENTRY **hlist;
+     int mode;
 {
   int sign, n, clen, rh;
-  register int i, j, last_hist, real_last;
+  register int i, j, last_hist, real_last, listing;
   register char *s;
 
+  listing = mode & HN_LISTING;
   sign = 1;
   /* Count history elements. */
   for (i = 0; hlist[i]; i++);
@@ -550,19 +608,33 @@ fc_gethnum (command, hlist)
       n = atoi (s);
       n *= sign;
 
+      /* We want to return something that is an offset to HISTORY_BASE. */
+
       /* If the value is negative or zero, then it is an offset from
         the current history item. */
+      /* We don't use HN_FIRST here, so we don't return different values
+        depending on whether we're looking for the first or last in a
+        pair of range arguments, but nobody else does, either. */
       if (n < 0)
        {
          n += i + 1;
          return (n < 0 ? 0 : n);
        }
       else if (n == 0)
-       return ((sign == -1) ? real_last : i);
+       return ((sign == -1) ? (listing ? real_last : HIST_INVALID) : i);
       else
        {
+         /* If we're out of range (greater than I (last history entry) or
+            less than HISTORY_BASE, we want to return different values
+            based on whether or not we are looking for the first or last
+            value in a desired range of history entries. */
          n -= history_base;
-         return (i < n ? i : n);
+         if (n < 0)
+           return (mode & HN_FIRST ? 0 : i);
+         else if (n >= i)
+           return (mode & HN_FIRST ? 0 : i);
+         else
+           return n;
        }
     }
 
@@ -572,22 +644,24 @@ fc_gethnum (command, hlist)
       if (STREQN (command, histline (j), clen))
        return (j);
     }
-  return (-1);
+  return (HIST_NOTFOUND);
 }
 
 /* Locate the most recent history line which begins with
-   COMMAND in HLIST, and return a malloc()'ed copy of it. */
+   COMMAND in HLIST, and return a malloc()'ed copy of it.
+   MODE is 1 if we are listing commands, 0 if we are executing them. */
 static char *
-fc_gethist (command, hlist)
+fc_gethist (command, hlist, mode)
      char *command;
      HIST_ENTRY **hlist;
+     int mode;
 {
   int i;
 
   if (hlist == 0)
     return ((char *)NULL);
 
-  i = fc_gethnum (command, hlist);
+  i = fc_gethnum (command, hlist, mode);
 
   if (i >= 0)
     return (savestring (histline (i)));