1 This file is fc.def, from which is created fc.c.
2 It implements the builtin "fc" in Bash.
4 Copyright (C) 1987-2005 Free Software Foundation, Inc.
6 This file is part of GNU Bash, the Bourne Again SHell.
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING. If not, write to the Free Software
20 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
27 $SHORT_DOC fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [cmd]
28 fc is used to list or edit and re-execute commands from the history list.
29 FIRST and LAST can be numbers specifying the range, or FIRST can be a
30 string, which means the most recent command beginning with that
33 -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
36 -l means list lines instead of editing.
37 -n means no line numbers listed.
38 -r means reverse the order of the lines (making it newest listed first).
40 With the `fc -s [pat=rep ...] [command]' format, the command is
41 re-executed after the substitution OLD=NEW is performed.
43 A useful alias to use with this is r='fc -s', so that typing `r cc'
44 runs the last command beginning with `cc' and typing `r' re-executes
52 # include <sys/param.h>
54 #include "../bashtypes.h"
55 #include "posixstat.h"
56 #if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
57 # include <sys/file.h>
60 #if defined (HAVE_UNISTD_H)
65 #include <chartypes.h>
67 #include "../bashansi.h"
68 #include "../bashintl.h"
72 #include "../builtins.h"
74 #include "../bashhist.h"
76 #include <readline/history.h>
77 #include "bashgetopt.h"
84 extern int current_command_line_count;
85 extern int literal_history;
86 extern int posixly_correct;
88 extern int unlink __P((const char *));
90 extern FILE *sh_mktmpfp __P((char *, int, char **));
91 extern int delete_last_history __P((void));
93 /* **************************************************************** */
95 /* The K*rn shell style fc command (Fix Command) */
97 /* **************************************************************** */
99 /* fc builtin command (fix command) for Bash for those who
100 like K*rn-style history better than csh-style.
102 fc [-e ename] [-nlr] [first] [last]
104 FIRST and LAST can be numbers specifying the range, or FIRST can be
105 a string, which means the most recent command beginning with that
108 -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
109 then the editor which corresponds to the current readline editing
112 -l means list lines instead of editing.
113 -n means no line numbers listed.
114 -r means reverse the order of the lines (making it newest listed first).
116 fc -e - [pat=rep ...] [command]
117 fc -s [pat=rep ...] [command]
119 Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
122 /* Data structure describing a list of global replacements to perform. */
123 typedef struct repl {
129 /* Accessors for HIST_ENTRY lists that are called HLIST. */
130 #define histline(i) (hlist[(i)]->line)
131 #define histdata(i) (hlist[(i)]->data)
133 #define FREE_RLIST() \
135 for (rl = rlist; rl; ) { \
147 static char *fc_dosubs __P((char *, REPL *));
148 static char *fc_gethist __P((char *, HIST_ENTRY **));
149 static int fc_gethnum __P((char *, HIST_ENTRY **));
150 static int fc_number __P((WORD_LIST *));
151 static void fc_replhist __P((char *));
152 #ifdef INCLUDE_UNUSED
153 static char *fc_readline __P((FILE *));
154 static void fc_addhist __P((char *));
157 /* String to execute on a file that we want to edit. */
158 #define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
159 #if defined (STRICT_POSIX)
160 # define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}"
162 # define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}"
171 int numbering, reverse, listing, execute;
172 int histbeg, histend, last_hist, retval, opt;
175 char *ename, *command, *newcom, *fcedit;
180 reverse = listing = execute = 0;
181 ename = (char *)NULL;
183 /* Parse out the options and set which of the two forms we're in. */
184 reset_internal_getopt ();
185 lcurrent = list; /* XXX */
186 while (fc_number (loptend = lcurrent) == 0 &&
187 (opt = internal_getopt (list, ":e:lnrs")) != -1)
219 if (ename && (*ename == '-') && (ename[1] == '\0'))
222 /* The "execute" form of the command (re-run, with possible string
226 rlist = (REPL *)NULL;
227 while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
230 rl = (REPL *)xmalloc (sizeof (REPL));
231 rl->next = (REPL *)NULL;
232 rl->pat = savestring (list->word->word);
233 rl->rep = savestring (sep);
245 /* If we have a list of substitutions to do, then reverse it
246 to get the replacements in the proper order. */
248 rlist = REVERSE_LIST (rlist, REPL *);
250 hlist = history_list ();
252 /* If we still have something in list, it is a command spec.
253 Otherwise, we use the most recent command in time. */
254 command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
258 builtin_error (_("no command found"));
262 return (EXECUTION_FAILURE);
267 newcom = fc_dosubs (command, rlist);
273 fprintf (stderr, "%s\n", command);
274 fc_replhist (command); /* replace `fc -s' with command */
275 return (parse_and_execute (command, "fc", SEVAL_NOHIST));
278 /* This is the second form of the command (the list-or-edit-and-rerun
280 hlist = history_list ();
282 return (EXECUTION_SUCCESS);
283 for (i = 0; hlist[i]; i++);
285 /* With the Bash implementation of history, the current command line
286 ("fc blah..." and so on) is already part of the history list by
287 the time we get to this point. This just skips over that command
288 and makes the last command that this deals with be the last command
289 the user entered before the fc. We need to check whether the
290 line was actually added (HISTIGNORE may have caused it to not be),
291 so we check hist_last_line_added. */
293 /* "When not listing, he fc command that caused the editing shall not be
294 entered into the history list." */
295 if (listing == 0 && hist_last_line_added)
296 delete_last_history ();
298 last_hist = i - 1 - hist_last_line_added;
302 histbeg = fc_gethnum (list->word->word, hlist);
306 histend = fc_gethnum (list->word->word, hlist);
308 histend = listing ? last_hist : histbeg;
312 /* The default for listing is the last 16 history items. */
316 histbeg = histend - 16 + 1; /* +1 because loop below uses >= */
321 /* For editing, it is the last history command. */
322 histbeg = histend = last_hist;
325 /* We print error messages for line specifications out of range. */
326 if ((histbeg < 0) || (histend < 0))
328 sh_erange ((char *)NULL, _("history specification"));
329 return (EXECUTION_FAILURE);
332 if (histend < histbeg)
346 stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
349 builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
351 return (EXECUTION_FAILURE);
355 for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
359 fprintf (stream, "%d", i + history_base);
363 fputs ("\t", stream);
365 fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
367 fprintf (stream, "%s\n", histline (i));
371 return (EXECUTION_SUCCESS);
375 /* Now edit the file of commands. */
378 command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
379 sprintf (command, "%s %s", ename, fn);
383 fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND;
384 command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn));
385 sprintf (command, "%s %s", fcedit, fn);
387 retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
388 if (retval != EXECUTION_SUCCESS)
392 return (EXECUTION_FAILURE);
395 /* Make sure parse_and_execute doesn't turn this off, even though a
396 call to parse_and_execute farther up the function call stack (e.g.,
397 if this is called by vi_edit_and_execute_command) may have already
398 called bash_history_disable. */
399 remember_on_history = 1;
401 /* Turn on the `v' flag while fc_execute_file runs so the commands
402 will be echoed as they are read by the parser. */
403 begin_unwind_frame ("fc builtin");
404 add_unwind_protect ((Function *)xfree, fn);
405 add_unwind_protect (unlink, fn);
406 unwind_protect_int (echo_input_at_read);
407 echo_input_at_read = 1;
409 retval = fc_execute_file (fn);
411 run_unwind_frame ("fc builtin");
416 /* Return 1 if LIST->word->word is a legal number for fc's use. */
425 s = list->word->word;
428 return (legal_number (s, (intmax_t *)NULL));
431 /* Return an absolute index into HLIST which corresponds to COMMAND. If
432 COMMAND is a number, then it was specified in relative terms. If it
433 is a string, then it is the start of a command line present in HLIST. */
435 fc_gethnum (command, hlist)
439 int sign = 1, n, clen;
443 /* Count history elements. */
444 for (i = 0; hlist[i]; i++);
446 /* With the Bash implementation of history, the current command line
447 ("fc blah..." and so on) is already part of the history list by
448 the time we get to this point. This just skips over that command
449 and makes the last command that this deals with be the last command
450 the user entered before the fc. We need to check whether the
451 line was actually added (HISTIGNORE may have caused it to not be),
452 so we check hist_last_line_added. */
453 i -= 1 + hist_last_line_added;
455 /* No specification defaults to most recent command. */
459 /* Otherwise, there is a specification. It can be a number relative to
460 the current position, or an absolute history number. */
463 /* Handle possible leading minus sign. */
464 if (s && (*s == '-'))
475 /* If the value is negative or zero, then it is an offset from
476 the current history item. */
480 return (n < 0 ? 0 : n);
487 return (i < n ? i : n);
491 clen = strlen (command);
492 for (j = i; j >= 0; j--)
494 if (STREQN (command, histline (j), clen))
500 /* Locate the most recent history line which begins with
501 COMMAND in HLIST, and return a malloc()'ed copy of it. */
503 fc_gethist (command, hlist)
510 return ((char *)NULL);
512 i = fc_gethnum (command, hlist);
515 return (savestring (histline (i)));
517 return ((char *)NULL);
520 #ifdef INCLUDE_UNUSED
521 /* Read the edited history lines from STREAM and return them
522 one at a time. This can read unlimited length lines. The
523 caller should free the storage. */
529 int line_len = 0, lindex = 0;
530 char *line = (char *)NULL;
532 while ((c = getc (stream)) != EOF)
534 if ((lindex + 2) >= line_len)
535 line = (char *)xrealloc (line, (line_len += 128));
539 line[lindex++] = '\n';
540 line[lindex++] = '\0';
552 return ((char *)NULL);
555 if (lindex + 2 >= line_len)
556 line = (char *)xrealloc (line, lindex + 3);
558 line[lindex++] = '\n'; /* Finish with newline if none in file */
559 line[lindex++] = '\0';
564 /* Perform the SUBS on COMMAND.
565 SUBS is a list of substitutions, and COMMAND is a simple string.
566 Return a pointer to a malloc'ed string which contains the substituted
569 fc_dosubs (command, subs)
573 register char *new, *t;
576 for (new = savestring (command), r = subs; r; r = r->next)
578 t = strsub (new, r->pat, r->rep, 1);
585 /* Use `command' to replace the last entry in the history list, which,
586 by this time, is `fc blah...'. The intent is that the new command
587 become the history entry, and that `fc' should never appear in the
588 history list. This way you can do `r' to your heart's content. */
590 fc_replhist (command)
595 if (command == 0 || *command == '\0')
598 n = strlen (command);
599 if (command[n - 1] == '\n')
600 command[n - 1] = '\0';
602 if (command && *command)
604 delete_last_history ();
605 maybe_add_history (command); /* Obeys HISTCONTROL setting. */
609 #ifdef INCLUDE_UNUSED
610 /* Add LINE to the history, after removing a single trailing newline. */
617 if (line == 0 || *line == 0)
622 if (line[n - 1] == '\n')
626 maybe_add_history (line); /* Obeys HISTCONTROL setting. */