1 This file is fc.def, from which is created fc.c.
2 It implements the builtin "fc" in Bash.
4 Copyright (C) 1987, 1989, 1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
27 $SHORT_DOC fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [cmd]
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,
34 then the editor which corresponds to the current readline editing
37 -l means list lines instead of editing.
38 -n means no line numbers listed.
39 -r means reverse the order of the lines (making it newest listed first).
41 With the `fc -s [pat=rep ...] [command]' format, the command is
42 re-executed after the substitution OLD=NEW is performed.
44 A useful alias to use with this is r='fc -s', so that typing `r cc'
45 runs the last command beginning with `cc' and typing `r' re-executes
50 #include "../bashansi.h"
53 #include <sys/param.h>
54 #include <sys/types.h>
58 #include "../builtins.h"
60 #include "../maxpath.h"
61 #include "../bashhist.h"
62 #include <readline/history.h>
63 #include "bashgetopt.h"
65 /* Not all systems declare ERRNO in errno.h... and some systems #define it! */
70 extern int echo_input_at_read;
74 /* **************************************************************** */
76 /* The K*rn shell style fc command (Fix Command) */
78 /* **************************************************************** */
80 /* fc builtin command (fix command) for Bash for those who
81 like K*rn-style history better than csh-style.
83 fc [-e ename] [-nlr] [first] [last]
85 FIRST and LAST can be numbers specifying the range, or FIRST can be
86 a string, which means the most recent command beginning with that
89 -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
90 then the editor which corresponds to the current readline editing
93 -l means list lines instead of editing.
94 -n means no line numbers listed.
95 -r means reverse the order of the lines (making it newest listed first).
97 fc -e - [pat=rep ...] [command]
98 fc -s [pat=rep ...] [command]
100 Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
103 static char *fc_dosubs (), *fc_replace (), *fc_gethist (), *fc_readline ();
104 static int fc_gethnum ();
105 static void fc_replhist (), fc_addhist ();
107 /* Data structure describing a list of global replacements to perform. */
108 typedef struct repl {
114 #define USAGE "usage: fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [command]"
116 /* Accessors for HIST_ENTRY lists that are called HLIST. */
117 #define histline(i) (hlist[(i)]->line)
118 #define histdata(i) (hlist[(i)]->data)
120 #define FREE_RLIST() \
122 for (rl = rlist; rl; ) { \
134 /* String to execute on a file that we want to edit. */
135 #define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
143 int numbering, reverse, listing, execute;
144 int histbeg, histend, last_hist, retval, first, opt;
146 REPL *rlist = (REPL *) NULL, *rl;
147 char *ename = NULL, *command, *newcom, *line;
152 reverse = listing = execute = 0;
154 /* Parse out the options and set which of the two forms we're in. */
156 while (list && *list->word->word == '-')
158 register char *s = &((list->word->word)[1]);
187 builtin_error (USAGE);
190 ename = list->word->word;
194 builtin_error (USAGE);
201 if (ename && (*ename == '-') && (ename[1] == '\0'))
204 /* The "execute" form of the command (re-run, with possible string
208 while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
211 rl = (REPL *)xmalloc (sizeof (REPL));
212 rl->next = (REPL *)NULL;
213 rl->pat = savestring (list->word->word);
214 rl->rep = savestring (sep);
226 /* If we have a list of substitutions to do, then reverse it
227 to get the replacements in the proper order. */
229 if (rlist && rlist->next)
230 rlist = (REPL *) reverse_list ((GENERIC_LIST *) rlist);
232 hlist = history_list ();
234 /* If we still have something in list, it is a command spec.
235 Otherwise, we use the most recent command in time. */
237 command = fc_gethist (list->word->word, hlist);
239 command = fc_gethist ((char *) NULL, hlist);
243 builtin_error ("no command found");
247 return (EXECUTION_FAILURE);
252 newcom = fc_dosubs (command, rlist);
258 printf ("%s\n", command);
259 fc_replhist (command); /* replace `fc -e -' with command */
260 return (parse_and_execute (command, "fc", -1));
263 /* This is the second form of the command (the list-or-edit-and-rerun
265 hlist = history_list ();
267 return (EXECUTION_SUCCESS);
268 for (i = 0; hlist[i]; i++);
270 /* With the Bash implementation of history, the current command line
271 ("fc blah..." and so on) is already part of the history list by
272 the time we get to this point. This just skips over that command
273 and makes the last command that this deals with be the last command
274 the user entered before the fc. */
280 histbeg = fc_gethnum (list->word->word, hlist);
284 histend = fc_gethnum (list->word->word, hlist);
295 /* The default for listing is the last 16 history items. */
299 histbeg = histend - 16;
305 /* For editing, it is the last history command. */
306 histbeg = histend = last_hist;
310 /* We print error messages for line specifications out of range. */
311 if ((histbeg < 0) || (histend < 0) ||
312 (histbeg > last_hist) || (histend > last_hist))
314 builtin_error ("history specification out of range");
315 return (EXECUTION_FAILURE);
318 if (histend < histbeg)
332 sprintf (fn, "/tmp/bash%d", (int)time ((long *) 0) + (int)getpid ());
334 stream = fopen (fn, "w");
338 builtin_error ("cannot open temp file %s", fn);
339 return (EXECUTION_FAILURE);
345 for (i = histbeg; i <= histend; i++)
349 fprintf (stream, "%d", i + history_base);
351 fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
352 fprintf (stream, "%s\n", histline (i));
357 for (i = histend; i >= histbeg; i--)
361 fprintf (stream, "%d", i + history_base);
363 fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
364 fprintf (stream, "%s\n", histline (i));
369 return (EXECUTION_SUCCESS);
373 /* Now edit the file of commands. */
376 command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
377 sprintf (command, "%s %s", ename, fn);
381 command = (char *)xmalloc (3 + strlen (FC_EDIT_COMMAND) + strlen (fn));
382 sprintf (command, "%s %s", FC_EDIT_COMMAND, fn);
384 parse_and_execute (command, "fc", -1);
386 /* Now reopen the file and execute the edited commands. */
388 stream = fopen (fn, "r");
392 builtin_error ("cannot reopen temp file %s", fn);
394 return (EXECUTION_FAILURE);
397 retval = EXECUTION_SUCCESS;
400 /* First, write the commands to the history file. This will not happen
401 when we call parse_and_execute, since parse_and_execute disables
402 the command line history while it executes. */
404 while ((line = fc_readline (stream)) != NULL)
409 continue; /* Skip blank lines. */
424 /* Turn on the `v' flag while maybe_execute_file runs so the commands
425 will be echoed as they are read by the parser. */
426 begin_unwind_frame ("fc builtin");
427 add_unwind_protect (unlink, fn);
428 unwind_protect_int (echo_input_at_read);
429 echo_input_at_read = 1;
431 retval = maybe_execute_file (fn, 0);
433 run_unwind_frame ("fc builtin");
438 /* Return an absolute index into HLIST which corresponds to COMMAND. If
439 COMMAND is a number, then it was specified in relative terms. If it
440 is a string, then it is the start of a command line present in HLIST. */
442 fc_gethnum (command, hlist)
446 int sign = 1, n, clen;
450 /* Count history elements. */
451 for (i = 0; hlist[i]; i++);
453 /* With the Bash implementation of history, the current command line
454 ("fc blah..." and so on) is already part of the history list by
455 the time we get to this point. This just skips over that command
456 and makes the last command that this deals with be the last command
457 the user entered before the fc. */
460 /* No specification defaults to most recent command. */
464 /* Otherwise, there is a specification. It can be a number relative to
465 the current position, or an absolute history number. */
468 /* Handle possible leading minus sign. */
469 if (s && (*s == '-'))
480 /* Anything specified greater than the last history element that we
481 deal with is an error. */
482 if (n > i + history_base)
485 /* If the value is negative or zero, then it is an offset from
486 the current history item. */
492 return (n - history_base);
495 clen = strlen (command);
496 for (j = i; j >= 0; j--)
498 if (STREQN (command, histline (j), clen))
504 /* Locate the most recent history line which begins with
505 COMMAND in HLIST, and return a malloc()'ed copy of it. */
507 fc_gethist (command, hlist)
514 return ((char *)NULL);
516 i = fc_gethnum (command, hlist);
519 return (savestring (histline (i)));
521 return ((char *)NULL);
524 /* Read the edited history lines from STREAM and return them
525 one at a time. This can read unlimited length lines. The
526 caller should free the storage. */
532 int line_len = 0, lindex = 0;
533 char *line = (char *)NULL;
535 while ((c = getc (stream)) != EOF)
537 if ((lindex + 2) >= line_len)
538 line = (char *) xrealloc (line, (line_len += 128));
542 line[lindex++] = '\n';
543 line[lindex++] = '\0';
555 return ((char *)NULL);
558 if (lindex + 2 >= line_len)
559 line = (char *)xrealloc (line, lindex + 3);
561 line[lindex++] = '\n'; /* Finish with newline if none in file */
562 line[lindex++] = '\0';
566 /* Perform the SUBS on COMMAND.
567 SUBS is a list of substitutions, and COMMAND is a simple string.
568 Return a pointer to a malloc'ed string which contains the substituted
571 fc_dosubs (command, subs)
575 register char *new = savestring (command);
578 for (r = subs; r; r = r->next)
582 t = fc_replace (r->pat, r->rep, new);
589 /* Replace the occurrences of PAT with REP in COMMAND.
590 This returns a new string; the caller should free it. */
592 fc_replace (pat, rep, command)
593 char *pat, *rep, *command;
596 int patlen, replen, templen;
599 patlen = strlen (pat);
600 replen = strlen (rep);
602 temp = savestring (command);
603 templen = strlen (temp);
606 for (; (i + patlen) <= templen; i++)
608 if (STREQN (temp + i, pat, patlen))
610 new = (char *) xmalloc (1 + (replen - patlen) + templen);
612 strncpy (new, temp, i);
613 strncpy (new + i, rep, replen);
614 strncpy (new + i + replen,
615 temp + i + patlen, templen - (i + patlen));
616 new[templen + (replen - patlen)] = '\0'; /* just in case */
621 templen = strlen (temp);
627 /* Use `command' to replace the last entry in the history list, which,
628 by this time, is `fc blah...'. The intent is that the new command
629 become the history entry, and that `fc' should never appear in the
630 history list. This way you can do `r' to your heart's content. */
632 fc_replhist (command)
636 HIST_ENTRY **hlist, *histent, *discard;
640 if (!command || !*command)
643 hlist = history_list ();
648 for (i = 0; hlist[i]; i++);
651 /* History_get () takes a parameter that should be
652 offset by history_base. */
654 histent = history_get (history_base + i); /* Don't free this */
658 n = strlen (command);
660 if (command[n - 1] == '\n')
661 command[n - 1] = '\0';
663 if (command && *command)
665 discard = remove_history (i);
669 free (discard->line);
670 free ((char *) discard);
672 maybe_add_history (command); /* Obeys HISTCONTROL setting. */
676 /* Add LINE to the history, after removing a single trailing newline. */
685 if (line[n - 1] == '\n')
689 maybe_add_history (line);