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 echo_input_at_read;
85 extern int current_command_line_count;
86 extern int literal_history;
87 extern int posixly_correct;
89 extern int unlink __P((const char *));
91 extern FILE *sh_mktmpfp __P((char *, int, char **));
92 extern int delete_last_history __P((void));
94 /* **************************************************************** */
96 /* The K*rn shell style fc command (Fix Command) */
98 /* **************************************************************** */
100 /* fc builtin command (fix command) for Bash for those who
101 like K*rn-style history better than csh-style.
103 fc [-e ename] [-nlr] [first] [last]
105 FIRST and LAST can be numbers specifying the range, or FIRST can be
106 a string, which means the most recent command beginning with that
109 -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
110 then the editor which corresponds to the current readline editing
113 -l means list lines instead of editing.
114 -n means no line numbers listed.
115 -r means reverse the order of the lines (making it newest listed first).
117 fc -e - [pat=rep ...] [command]
118 fc -s [pat=rep ...] [command]
120 Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
123 /* Data structure describing a list of global replacements to perform. */
124 typedef struct repl {
130 /* Accessors for HIST_ENTRY lists that are called HLIST. */
131 #define histline(i) (hlist[(i)]->line)
132 #define histdata(i) (hlist[(i)]->data)
134 #define FREE_RLIST() \
136 for (rl = rlist; rl; ) { \
148 static char *fc_dosubs __P((char *, REPL *));
149 static char *fc_gethist __P((char *, HIST_ENTRY **));
150 static int fc_gethnum __P((char *, HIST_ENTRY **));
151 static int fc_number __P((WORD_LIST *));
152 static void fc_replhist __P((char *));
153 #ifdef INCLUDE_UNUSED
154 static char *fc_readline __P((FILE *));
155 static void fc_addhist __P((char *));
158 /* String to execute on a file that we want to edit. */
159 #define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
160 #if defined (STRICT_POSIX)
161 # define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}"
163 # define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}"
172 int numbering, reverse, listing, execute;
173 int histbeg, histend, last_hist, retval, opt;
176 char *ename, *command, *newcom, *fcedit;
181 reverse = listing = execute = 0;
182 ename = (char *)NULL;
184 /* Parse out the options and set which of the two forms we're in. */
185 reset_internal_getopt ();
186 lcurrent = list; /* XXX */
187 while (fc_number (loptend = lcurrent) == 0 &&
188 (opt = internal_getopt (list, ":e:lnrs")) != -1)
220 if (ename && (*ename == '-') && (ename[1] == '\0'))
223 /* The "execute" form of the command (re-run, with possible string
227 rlist = (REPL *)NULL;
228 while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
231 rl = (REPL *)xmalloc (sizeof (REPL));
232 rl->next = (REPL *)NULL;
233 rl->pat = savestring (list->word->word);
234 rl->rep = savestring (sep);
246 /* If we have a list of substitutions to do, then reverse it
247 to get the replacements in the proper order. */
249 rlist = REVERSE_LIST (rlist, REPL *);
251 hlist = history_list ();
253 /* If we still have something in list, it is a command spec.
254 Otherwise, we use the most recent command in time. */
255 command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
259 builtin_error (_("no command found"));
263 return (EXECUTION_FAILURE);
268 newcom = fc_dosubs (command, rlist);
274 fprintf (stderr, "%s\n", command);
275 fc_replhist (command); /* replace `fc -s' with command */
276 return (parse_and_execute (command, "fc", SEVAL_NOHIST));
279 /* This is the second form of the command (the list-or-edit-and-rerun
281 hlist = history_list ();
283 return (EXECUTION_SUCCESS);
284 for (i = 0; hlist[i]; i++);
286 /* With the Bash implementation of history, the current command line
287 ("fc blah..." and so on) is already part of the history list by
288 the time we get to this point. This just skips over that command
289 and makes the last command that this deals with be the last command
290 the user entered before the fc. We need to check whether the
291 line was actually added (HISTIGNORE may have caused it to not be),
292 so we check hist_last_line_added. */
294 /* "When not listing, he fc command that caused the editing shall not be
295 entered into the history list." */
296 if (listing == 0 && hist_last_line_added)
297 delete_last_history ();
299 last_hist = i - 1 - hist_last_line_added;
303 histbeg = fc_gethnum (list->word->word, hlist);
307 histend = fc_gethnum (list->word->word, hlist);
309 histend = listing ? last_hist : histbeg;
313 /* The default for listing is the last 16 history items. */
317 histbeg = histend - 16 + 1; /* +1 because loop below uses >= */
322 /* For editing, it is the last history command. */
323 histbeg = histend = last_hist;
326 /* We print error messages for line specifications out of range. */
327 if ((histbeg < 0) || (histend < 0))
329 sh_erange ((char *)NULL, _("history specification"));
330 return (EXECUTION_FAILURE);
333 if (histend < histbeg)
347 stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
350 builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
352 return (EXECUTION_FAILURE);
356 for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
360 fprintf (stream, "%d", i + history_base);
364 fputs ("\t", stream);
366 fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
368 fprintf (stream, "%s\n", histline (i));
372 return (EXECUTION_SUCCESS);
376 /* Now edit the file of commands. */
379 command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
380 sprintf (command, "%s %s", ename, fn);
384 fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND;
385 command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn));
386 sprintf (command, "%s %s", fcedit, fn);
388 retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
389 if (retval != EXECUTION_SUCCESS)
393 return (EXECUTION_FAILURE);
396 /* Make sure parse_and_execute doesn't turn this off, even though a
397 call to parse_and_execute farther up the function call stack (e.g.,
398 if this is called by vi_edit_and_execute_command) may have already
399 called bash_history_disable. */
400 remember_on_history = 1;
402 /* Turn on the `v' flag while fc_execute_file runs so the commands
403 will be echoed as they are read by the parser. */
404 begin_unwind_frame ("fc builtin");
405 add_unwind_protect ((Function *)xfree, fn);
406 add_unwind_protect (unlink, fn);
407 unwind_protect_int (echo_input_at_read);
408 echo_input_at_read = 1;
410 retval = fc_execute_file (fn);
412 run_unwind_frame ("fc builtin");
417 /* Return 1 if LIST->word->word is a legal number for fc's use. */
426 s = list->word->word;
429 return (legal_number (s, (intmax_t *)NULL));
432 /* Return an absolute index into HLIST which corresponds to COMMAND. If
433 COMMAND is a number, then it was specified in relative terms. If it
434 is a string, then it is the start of a command line present in HLIST. */
436 fc_gethnum (command, hlist)
440 int sign = 1, n, clen;
444 /* Count history elements. */
445 for (i = 0; hlist[i]; i++);
447 /* With the Bash implementation of history, the current command line
448 ("fc blah..." and so on) is already part of the history list by
449 the time we get to this point. This just skips over that command
450 and makes the last command that this deals with be the last command
451 the user entered before the fc. We need to check whether the
452 line was actually added (HISTIGNORE may have caused it to not be),
453 so we check hist_last_line_added. */
454 i -= 1 + hist_last_line_added;
456 /* No specification defaults to most recent command. */
460 /* Otherwise, there is a specification. It can be a number relative to
461 the current position, or an absolute history number. */
464 /* Handle possible leading minus sign. */
465 if (s && (*s == '-'))
476 /* If the value is negative or zero, then it is an offset from
477 the current history item. */
481 return (n < 0 ? 0 : n);
488 return (i < n ? i : n);
492 clen = strlen (command);
493 for (j = i; j >= 0; j--)
495 if (STREQN (command, histline (j), clen))
501 /* Locate the most recent history line which begins with
502 COMMAND in HLIST, and return a malloc()'ed copy of it. */
504 fc_gethist (command, hlist)
511 return ((char *)NULL);
513 i = fc_gethnum (command, hlist);
516 return (savestring (histline (i)));
518 return ((char *)NULL);
521 #ifdef INCLUDE_UNUSED
522 /* Read the edited history lines from STREAM and return them
523 one at a time. This can read unlimited length lines. The
524 caller should free the storage. */
530 int line_len = 0, lindex = 0;
531 char *line = (char *)NULL;
533 while ((c = getc (stream)) != EOF)
535 if ((lindex + 2) >= line_len)
536 line = (char *)xrealloc (line, (line_len += 128));
540 line[lindex++] = '\n';
541 line[lindex++] = '\0';
553 return ((char *)NULL);
556 if (lindex + 2 >= line_len)
557 line = (char *)xrealloc (line, lindex + 3);
559 line[lindex++] = '\n'; /* Finish with newline if none in file */
560 line[lindex++] = '\0';
565 /* Perform the SUBS on COMMAND.
566 SUBS is a list of substitutions, and COMMAND is a simple string.
567 Return a pointer to a malloc'ed string which contains the substituted
570 fc_dosubs (command, subs)
574 register char *new, *t;
577 for (new = savestring (command), r = subs; r; r = r->next)
579 t = strsub (new, r->pat, r->rep, 1);
586 /* Use `command' to replace the last entry in the history list, which,
587 by this time, is `fc blah...'. The intent is that the new command
588 become the history entry, and that `fc' should never appear in the
589 history list. This way you can do `r' to your heart's content. */
591 fc_replhist (command)
596 if (command == 0 || *command == '\0')
599 n = strlen (command);
600 if (command[n - 1] == '\n')
601 command[n - 1] = '\0';
603 if (command && *command)
605 delete_last_history ();
606 maybe_add_history (command); /* Obeys HISTCONTROL setting. */
610 #ifdef INCLUDE_UNUSED
611 /* Add LINE to the history, after removing a single trailing newline. */
618 if (line == 0 || *line == 0)
623 if (line[n - 1] == '\n')
627 maybe_add_history (line); /* Obeys HISTCONTROL setting. */