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
52 #include <sys/param.h>
53 #include "bashtypes.h"
54 #include "posixstat.h"
57 #if defined (HAVE_UNISTD_H)
63 #include "../bashansi.h"
67 #include "../builtins.h"
69 #include "../maxpath.h"
70 #include "../bashhist.h"
71 #include <readline/history.h>
72 #include "bashgetopt.h"
79 extern int echo_input_at_read;
83 /* **************************************************************** */
85 /* The K*rn shell style fc command (Fix Command) */
87 /* **************************************************************** */
89 /* fc builtin command (fix command) for Bash for those who
90 like K*rn-style history better than csh-style.
92 fc [-e ename] [-nlr] [first] [last]
94 FIRST and LAST can be numbers specifying the range, or FIRST can be
95 a string, which means the most recent command beginning with that
98 -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
99 then the editor which corresponds to the current readline editing
102 -l means list lines instead of editing.
103 -n means no line numbers listed.
104 -r means reverse the order of the lines (making it newest listed first).
106 fc -e - [pat=rep ...] [command]
107 fc -s [pat=rep ...] [command]
109 Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
112 static char *fc_dosubs (), *fc_gethist (), *fc_readline ();
113 static int fc_gethnum (), fc_number ();
114 static void fc_replhist (), fc_addhist ();
116 /* Data structure describing a list of global replacements to perform. */
117 typedef struct repl {
123 /* Accessors for HIST_ENTRY lists that are called HLIST. */
124 #define histline(i) (hlist[(i)]->line)
125 #define histdata(i) (hlist[(i)]->data)
127 #define FREE_RLIST() \
129 for (rl = rlist; rl; ) { \
141 /* String to execute on a file that we want to edit. */
142 #define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
150 int numbering, reverse, listing, execute;
151 int histbeg, histend, last_hist, retval, first, opt;
154 char *ename, *command, *newcom, *line;
159 reverse = listing = execute = 0;
160 ename = (char *)NULL;
162 /* Parse out the options and set which of the two forms we're in. */
163 reset_internal_getopt ();
164 lcurrent = list; /* XXX */
165 while (fc_number (loptend = lcurrent) == 0 &&
166 (opt = internal_getopt (list, ":e:lnrs")) != -1)
198 if (ename && (*ename == '-') && (ename[1] == '\0'))
201 /* The "execute" form of the command (re-run, with possible string
205 rlist = (REPL *)NULL;
206 while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
209 rl = (REPL *)xmalloc (sizeof (REPL));
210 rl->next = (REPL *)NULL;
211 rl->pat = savestring (list->word->word);
212 rl->rep = savestring (sep);
224 /* If we have a list of substitutions to do, then reverse it
225 to get the replacements in the proper order. */
227 if (rlist && rlist->next)
228 rlist = (REPL *)reverse_list ((GENERIC_LIST *) rlist);
230 hlist = history_list ();
232 /* If we still have something in list, it is a command spec.
233 Otherwise, we use the most recent command in time. */
234 command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
238 builtin_error ("no command found");
242 return (EXECUTION_FAILURE);
247 newcom = fc_dosubs (command, rlist);
253 fprintf (stderr, "%s\n", command);
254 fc_replhist (command); /* replace `fc -s' with command */
255 return (parse_and_execute (command, "fc", -1));
258 /* This is the second form of the command (the list-or-edit-and-rerun
260 hlist = history_list ();
262 return (EXECUTION_SUCCESS);
263 for (i = 0; hlist[i]; i++);
265 /* With the Bash implementation of history, the current command line
266 ("fc blah..." and so on) is already part of the history list by
267 the time we get to this point. This just skips over that command
268 and makes the last command that this deals with be the last command
269 the user entered before the fc. */
275 histbeg = fc_gethnum (list->word->word, hlist);
279 histend = fc_gethnum (list->word->word, hlist);
281 histend = listing ? last_hist : histbeg;
285 /* The default for listing is the last 16 history items. */
289 histbeg = histend - 16;
294 /* For editing, it is the last history command. */
295 histbeg = histend = last_hist;
298 /* We print error messages for line specifications out of range. */
299 if ((histbeg < 0) || (histend < 0) ||
300 (histbeg > last_hist) || (histend > last_hist))
302 builtin_error ("history specification out of range");
303 return (EXECUTION_FAILURE);
306 if (histend < histbeg)
320 sprintf (fn, "/tmp/bash%d", (int)time ((time_t *) 0) + (int)getpid ());
322 stream = fopen (fn, "w");
326 builtin_error ("cannot open temp file %s", fn);
327 return (EXECUTION_FAILURE);
331 for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
335 fprintf (stream, "%d", i + history_base);
337 fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
338 fprintf (stream, "%s\n", histline (i));
342 return (EXECUTION_SUCCESS);
346 /* Now edit the file of commands. */
349 command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
350 sprintf (command, "%s %s", ename, fn);
354 command = (char *)xmalloc (3 + strlen (FC_EDIT_COMMAND) + strlen (fn));
355 sprintf (command, "%s %s", FC_EDIT_COMMAND, fn);
357 retval = parse_and_execute (command, "fc", -1);
358 if (retval != EXECUTION_SUCCESS)
361 return (EXECUTION_FAILURE);
364 /* Now reopen the file and execute the edited commands. */
366 stream = fopen (fn, "r");
370 builtin_error ("cannot reopen temp file %s", fn);
372 return (EXECUTION_FAILURE);
375 retval = EXECUTION_SUCCESS;
378 /* First, write the commands to the history file. This will not happen
379 when we call parse_and_execute, since parse_and_execute disables
380 the command line history while it executes. */
382 while ((line = fc_readline (stream)) != NULL)
387 continue; /* Skip blank lines. */
402 /* Turn on the `v' flag while maybe_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 (unlink, fn);
406 unwind_protect_int (echo_input_at_read);
407 echo_input_at_read = 1;
409 retval = maybe_execute_file (fn, 0);
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, (long *)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. */
453 /* No specification defaults to most recent command. */
457 /* Otherwise, there is a specification. It can be a number relative to
458 the current position, or an absolute history number. */
461 /* Handle possible leading minus sign. */
462 if (s && (*s == '-'))
473 /* Anything specified greater than the last history element that we
474 deal with is an error. */
475 if (n > i + history_base)
478 /* If the value is negative or zero, then it is an offset from
479 the current history item. */
485 return (n - history_base);
488 clen = strlen (command);
489 for (j = i; j >= 0; j--)
491 if (STREQN (command, histline (j), clen))
497 /* Locate the most recent history line which begins with
498 COMMAND in HLIST, and return a malloc()'ed copy of it. */
500 fc_gethist (command, hlist)
507 return ((char *)NULL);
509 i = fc_gethnum (command, hlist);
512 return (savestring (histline (i)));
514 return ((char *)NULL);
517 /* Read the edited history lines from STREAM and return them
518 one at a time. This can read unlimited length lines. The
519 caller should free the storage. */
525 int line_len = 0, lindex = 0;
526 char *line = (char *)NULL;
528 while ((c = getc (stream)) != EOF)
530 if ((lindex + 2) >= line_len)
531 line = (char *) xrealloc (line, (line_len += 128));
535 line[lindex++] = '\n';
536 line[lindex++] = '\0';
548 return ((char *)NULL);
551 if (lindex + 2 >= line_len)
552 line = (char *)xrealloc (line, lindex + 3);
554 line[lindex++] = '\n'; /* Finish with newline if none in file */
555 line[lindex++] = '\0';
559 /* Perform the SUBS on COMMAND.
560 SUBS is a list of substitutions, and COMMAND is a simple string.
561 Return a pointer to a malloc'ed string which contains the substituted
564 fc_dosubs (command, subs)
568 register char *new, *t;
571 for (new = savestring (command), r = subs; r; r = r->next)
573 t = strsub (new, r->pat, r->rep, 1);
580 /* Use `command' to replace the last entry in the history list, which,
581 by this time, is `fc blah...'. The intent is that the new command
582 become the history entry, and that `fc' should never appear in the
583 history list. This way you can do `r' to your heart's content. */
585 fc_replhist (command)
589 HIST_ENTRY **hlist, *histent, *discard;
592 if (command == 0 || *command == '\0')
595 hlist = history_list ();
600 for (i = 0; hlist[i]; i++);
603 /* History_get () takes a parameter that should be
604 offset by history_base. */
606 histent = history_get (history_base + i); /* Don't free this */
610 n = strlen (command);
612 if (command[n - 1] == '\n')
613 command[n - 1] = '\0';
615 if (command && *command)
617 discard = remove_history (i);
620 FREE (discard->line);
621 free ((char *) discard);
623 maybe_add_history (command); /* Obeys HISTCONTROL setting. */
627 /* Add LINE to the history, after removing a single trailing newline. */
636 if (line[n - 1] == '\n')
640 maybe_add_history (line);