]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/fc.def
Bash-4.2 patch 8
[thirdparty/bash.git] / builtins / fc.def
CommitLineData
726f6388
JA
1This file is fc.def, from which is created fc.c.
2It implements the builtin "fc" in Bash.
3
495aee44 4Copyright (C) 1987-2010 Free Software Foundation, Inc.
726f6388
JA
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
3185942a
JA
8Bash is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
726f6388 12
3185942a
JA
13Bash is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
726f6388 17
3185942a
JA
18You should have received a copy of the GNU General Public License
19along with Bash. If not, see <http://www.gnu.org/licenses/>.
726f6388
JA
20
21$PRODUCES fc.c
22
23$BUILTIN fc
24$FUNCTION fc_builtin
25$DEPENDS_ON HISTORY
3185942a
JA
26$SHORT_DOC fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command]
27Display or execute commands from the history list.
28
b72432fd 29fc is used to list or edit and re-execute commands from the history list.
726f6388
JA
30FIRST and LAST can be numbers specifying the range, or FIRST can be a
31string, which means the most recent command beginning with that
32string.
33
3185942a
JA
34Options:
35 -e ENAME select which editor to use. Default is FCEDIT, then EDITOR,
36 then vi
37 -l list lines instead of editing
38 -n omit line numbers when listing
39 -r reverse the order of the lines (newest listed first)
726f6388 40
3185942a 41With the `fc -s [pat=rep ...] [command]' format, COMMAND is
726f6388
JA
42re-executed after the substitution OLD=NEW is performed.
43
44A useful alias to use with this is r='fc -s', so that typing `r cc'
45runs the last command beginning with `cc' and typing `r' re-executes
46the last command.
3185942a
JA
47
48Exit Status:
49Returns success or status of executed command; non-zero if an error occurs.
726f6388
JA
50$END
51
ccc6cda3
JA
52#include <config.h>
53
726f6388 54#if defined (HISTORY)
cce855bc
JA
55#ifndef _MINIX
56# include <sys/param.h>
57#endif
d166f048 58#include "../bashtypes.h"
bb70624e 59#include "posixstat.h"
b80f6443 60#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
cce855bc
JA
61# include <sys/file.h>
62#endif
ccc6cda3
JA
63
64#if defined (HAVE_UNISTD_H)
65# include <unistd.h>
66#endif
67
68#include <stdio.h>
f73dda09 69#include <chartypes.h>
ccc6cda3
JA
70
71#include "../bashansi.h"
b80f6443 72#include "../bashintl.h"
726f6388 73#include <errno.h>
ccc6cda3
JA
74
75#include "../shell.h"
726f6388
JA
76#include "../builtins.h"
77#include "../flags.h"
726f6388 78#include "../bashhist.h"
bb70624e 79#include "maxpath.h"
726f6388
JA
80#include <readline/history.h>
81#include "bashgetopt.h"
ccc6cda3 82#include "common.h"
726f6388 83
726f6388
JA
84#if !defined (errno)
85extern int errno;
86#endif /* !errno */
87
495aee44 88extern int current_command_line_count, saved_command_line_count;
d166f048 89extern int literal_history;
95732b49 90extern int posixly_correct;
89a92869 91extern int subshell_environment, interactive_shell;
726f6388 92
f73dda09 93extern int unlink __P((const char *));
726f6388 94
28ef6c31 95extern FILE *sh_mktmpfp __P((char *, int, char **));
d166f048 96
726f6388
JA
97/* **************************************************************** */
98/* */
99/* The K*rn shell style fc command (Fix Command) */
100/* */
101/* **************************************************************** */
102
103/* fc builtin command (fix command) for Bash for those who
104 like K*rn-style history better than csh-style.
105
106 fc [-e ename] [-nlr] [first] [last]
107
108 FIRST and LAST can be numbers specifying the range, or FIRST can be
109 a string, which means the most recent command beginning with that
110 string.
111
112 -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
113 then the editor which corresponds to the current readline editing
114 mode, then vi.
115
116 -l means list lines instead of editing.
117 -n means no line numbers listed.
118 -r means reverse the order of the lines (making it newest listed first).
119
120 fc -e - [pat=rep ...] [command]
121 fc -s [pat=rep ...] [command]
122
123 Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
124*/
125
726f6388
JA
126/* Data structure describing a list of global replacements to perform. */
127typedef struct repl {
128 struct repl *next;
129 char *pat;
130 char *rep;
131} REPL;
132
726f6388
JA
133/* Accessors for HIST_ENTRY lists that are called HLIST. */
134#define histline(i) (hlist[(i)]->line)
135#define histdata(i) (hlist[(i)]->data)
136
137#define FREE_RLIST() \
138 do { \
139 for (rl = rlist; rl; ) { \
140 REPL *r; \
141 r = rl->next; \
142 if (rl->pat) \
143 free (rl->pat); \
144 if (rl->rep) \
145 free (rl->rep); \
146 free (rl); \
147 rl = r; \
148 } \
149 } while (0)
150
f73dda09
JA
151static char *fc_dosubs __P((char *, REPL *));
152static char *fc_gethist __P((char *, HIST_ENTRY **));
153static int fc_gethnum __P((char *, HIST_ENTRY **));
154static int fc_number __P((WORD_LIST *));
155static void fc_replhist __P((char *));
156#ifdef INCLUDE_UNUSED
157static char *fc_readline __P((FILE *));
158static void fc_addhist __P((char *));
159#endif
160
726f6388
JA
161/* String to execute on a file that we want to edit. */
162#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
95732b49
JA
163#if defined (STRICT_POSIX)
164# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}"
165#else
166# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}"
167#endif
726f6388
JA
168
169int
170fc_builtin (list)
171 WORD_LIST *list;
172{
173 register int i;
174 register char *sep;
175 int numbering, reverse, listing, execute;
89a92869 176 int histbeg, histend, last_hist, retval, opt, rh;
726f6388 177 FILE *stream;
ccc6cda3 178 REPL *rlist, *rl;
95732b49 179 char *ename, *command, *newcom, *fcedit;
726f6388 180 HIST_ENTRY **hlist;
28ef6c31 181 char *fn;
726f6388
JA
182
183 numbering = 1;
184 reverse = listing = execute = 0;
ccc6cda3 185 ename = (char *)NULL;
726f6388
JA
186
187 /* Parse out the options and set which of the two forms we're in. */
ccc6cda3
JA
188 reset_internal_getopt ();
189 lcurrent = list; /* XXX */
190 while (fc_number (loptend = lcurrent) == 0 &&
191 (opt = internal_getopt (list, ":e:lnrs")) != -1)
726f6388 192 {
ccc6cda3
JA
193 switch (opt)
194 {
195 case 'n':
196 numbering = 0;
197 break;
726f6388 198
ccc6cda3
JA
199 case 'l':
200 listing = 1;
201 break;
726f6388 202
ccc6cda3
JA
203 case 'r':
204 reverse = 1;
205 break;
206
207 case 's':
208 execute = 1;
209 break;
210
211 case 'e':
212 ename = list_optarg;
213 break;
214
215 default:
216 builtin_usage ();
217 return (EX_USAGE);
726f6388 218 }
726f6388
JA
219 }
220
ccc6cda3
JA
221 list = loptend;
222
726f6388
JA
223 if (ename && (*ename == '-') && (ename[1] == '\0'))
224 execute = 1;
225
226 /* The "execute" form of the command (re-run, with possible string
227 substitutions). */
228 if (execute)
229 {
ccc6cda3 230 rlist = (REPL *)NULL;
726f6388
JA
231 while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
232 {
233 *sep++ = '\0';
234 rl = (REPL *)xmalloc (sizeof (REPL));
235 rl->next = (REPL *)NULL;
236 rl->pat = savestring (list->word->word);
237 rl->rep = savestring (sep);
238
239 if (rlist == NULL)
240 rlist = rl;
241 else
242 {
243 rl->next = rlist;
244 rlist = rl;
245 }
246 list = list->next;
247 }
248
249 /* If we have a list of substitutions to do, then reverse it
250 to get the replacements in the proper order. */
251
7117c2d2 252 rlist = REVERSE_LIST (rlist, REPL *);
726f6388
JA
253
254 hlist = history_list ();
255
256 /* If we still have something in list, it is a command spec.
257 Otherwise, we use the most recent command in time. */
ccc6cda3 258 command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
726f6388
JA
259
260 if (command == NULL)
261 {
b80f6443 262 builtin_error (_("no command found"));
726f6388
JA
263 if (rlist)
264 FREE_RLIST ();
265
266 return (EXECUTION_FAILURE);
267 }
268
269 if (rlist)
270 {
271 newcom = fc_dosubs (command, rlist);
272 free (command);
273 FREE_RLIST ();
274 command = newcom;
275 }
276
ccc6cda3
JA
277 fprintf (stderr, "%s\n", command);
278 fc_replhist (command); /* replace `fc -s' with command */
89a92869
CR
279 /* Posix says that the re-executed commands should be entered into the
280 history. */
d166f048 281 return (parse_and_execute (command, "fc", SEVAL_NOHIST));
726f6388
JA
282 }
283
284 /* This is the second form of the command (the list-or-edit-and-rerun
285 form). */
286 hlist = history_list ();
287 if (hlist == 0)
288 return (EXECUTION_SUCCESS);
289 for (i = 0; hlist[i]; i++);
290
291 /* With the Bash implementation of history, the current command line
292 ("fc blah..." and so on) is already part of the history list by
293 the time we get to this point. This just skips over that command
294 and makes the last command that this deals with be the last command
d166f048
JA
295 the user entered before the fc. We need to check whether the
296 line was actually added (HISTIGNORE may have caused it to not be),
297 so we check hist_last_line_added. */
726f6388 298
89a92869
CR
299 /* Even though command substitution through parse_and_execute turns off
300 remember_on_history, command substitution in a shell when set -o history
301 has been enabled (interactive or not) should use it in the last_hist
302 calculation as if it were on. */
303 rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
304 last_hist = i - rh - hist_last_line_added;
726f6388 305
30d188c2 306 /* XXX */
495aee44 307 if (saved_command_line_count > 0 && i == last_hist && hlist[last_hist] == 0)
30d188c2
CR
308 while (last_hist >= 0 && hlist[last_hist] == 0)
309 last_hist--;
310 if (last_hist < 0)
311 {
312 sh_erange ((char *)NULL, _("history specification"));
313 return (EXECUTION_FAILURE);
314 }
315
726f6388
JA
316 if (list)
317 {
318 histbeg = fc_gethnum (list->word->word, hlist);
319 list = list->next;
320
321 if (list)
322 histend = fc_gethnum (list->word->word, hlist);
323 else
ccc6cda3 324 histend = listing ? last_hist : histbeg;
726f6388
JA
325 }
326 else
327 {
328 /* The default for listing is the last 16 history items. */
329 if (listing)
330 {
331 histend = last_hist;
95732b49 332 histbeg = histend - 16 + 1; /* +1 because loop below uses >= */
726f6388
JA
333 if (histbeg < 0)
334 histbeg = 0;
335 }
336 else
ccc6cda3
JA
337 /* For editing, it is the last history command. */
338 histbeg = histend = last_hist;
726f6388
JA
339 }
340
3185942a
JA
341 /* "When not listing, the fc command that caused the editing shall not be
342 entered into the history list." */
343 if (listing == 0 && hist_last_line_added)
344 {
345 bash_delete_last_history ();
346 /* If we're editing a single command -- the last command in the
347 history -- and we just removed the dummy command added by
348 edit_and_execute_command (), we need to check whether or not we
349 just removed the last command in the history and need to back
350 the pointer up. remember_on_history is off because we're running
351 in parse_and_execute(). */
352 if (histbeg == histend && histend == last_hist && hlist[last_hist] == 0)
353 last_hist = histbeg = --histend;
354 }
355
726f6388 356 /* We print error messages for line specifications out of range. */
7117c2d2 357 if ((histbeg < 0) || (histend < 0))
726f6388 358 {
b80f6443 359 sh_erange ((char *)NULL, _("history specification"));
726f6388
JA
360 return (EXECUTION_FAILURE);
361 }
362
363 if (histend < histbeg)
364 {
ccc6cda3 365 i = histend;
726f6388 366 histend = histbeg;
ccc6cda3
JA
367 histbeg = i;
368
726f6388
JA
369 reverse = 1;
370 }
371
372 if (listing)
373 stream = stdout;
374 else
375 {
376 numbering = 0;
28ef6c31 377 stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
ccc6cda3 378 if (stream == 0)
726f6388 379 {
b80f6443 380 builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
28ef6c31 381 FREE (fn);
726f6388
JA
382 return (EXECUTION_FAILURE);
383 }
384 }
385
ccc6cda3 386 for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
726f6388 387 {
ccc6cda3
JA
388 QUIT;
389 if (numbering)
390 fprintf (stream, "%d", i + history_base);
391 if (listing)
95732b49
JA
392 {
393 if (posixly_correct)
394 fputs ("\t", stream);
395 else
396 fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
397 }
ccc6cda3 398 fprintf (stream, "%s\n", histline (i));
726f6388
JA
399 }
400
401 if (listing)
3185942a 402 return (sh_chkwrite (EXECUTION_SUCCESS));
726f6388 403
3185942a
JA
404 fflush (stream);
405 if (ferror (stream))
406 {
407 sh_wrerror ();
408 fclose (stream);
409 return (EXECUTION_FAILURE);
410 }
726f6388
JA
411 fclose (stream);
412
413 /* Now edit the file of commands. */
414 if (ename)
415 {
416 command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
417 sprintf (command, "%s %s", ename, fn);
418 }
419 else
420 {
95732b49
JA
421 fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND;
422 command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn));
423 sprintf (command, "%s %s", fcedit, fn);
726f6388 424 }
d166f048 425 retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
ccc6cda3
JA
426 if (retval != EXECUTION_SUCCESS)
427 {
428 unlink (fn);
28ef6c31 429 free (fn);
ccc6cda3
JA
430 return (EXECUTION_FAILURE);
431 }
726f6388 432
d166f048
JA
433 /* Make sure parse_and_execute doesn't turn this off, even though a
434 call to parse_and_execute farther up the function call stack (e.g.,
435 if this is called by vi_edit_and_execute_command) may have already
436 called bash_history_disable. */
437 remember_on_history = 1;
726f6388 438
d166f048 439 /* Turn on the `v' flag while fc_execute_file runs so the commands
726f6388
JA
440 will be echoed as they are read by the parser. */
441 begin_unwind_frame ("fc builtin");
28ef6c31 442 add_unwind_protect ((Function *)xfree, fn);
726f6388
JA
443 add_unwind_protect (unlink, fn);
444 unwind_protect_int (echo_input_at_read);
445 echo_input_at_read = 1;
446
d166f048 447 retval = fc_execute_file (fn);
726f6388
JA
448
449 run_unwind_frame ("fc builtin");
450
451 return (retval);
452}
453
ccc6cda3
JA
454/* Return 1 if LIST->word->word is a legal number for fc's use. */
455static int
456fc_number (list)
457 WORD_LIST *list;
458{
459 char *s;
460
461 if (list == 0)
462 return 0;
463 s = list->word->word;
464 if (*s == '-')
465 s++;
7117c2d2 466 return (legal_number (s, (intmax_t *)NULL));
ccc6cda3
JA
467}
468
726f6388
JA
469/* Return an absolute index into HLIST which corresponds to COMMAND. If
470 COMMAND is a number, then it was specified in relative terms. If it
471 is a string, then it is the start of a command line present in HLIST. */
472static int
473fc_gethnum (command, hlist)
474 char *command;
475 HIST_ENTRY **hlist;
476{
89a92869 477 int sign, n, clen, rh;
495aee44 478 register int i, j;
726f6388
JA
479 register char *s;
480
3185942a 481 sign = 1;
726f6388
JA
482 /* Count history elements. */
483 for (i = 0; hlist[i]; i++);
484
485 /* With the Bash implementation of history, the current command line
486 ("fc blah..." and so on) is already part of the history list by
487 the time we get to this point. This just skips over that command
488 and makes the last command that this deals with be the last command
d166f048
JA
489 the user entered before the fc. We need to check whether the
490 line was actually added (HISTIGNORE may have caused it to not be),
3185942a
JA
491 so we check hist_last_line_added. This needs to agree with the
492 calculation of last_hist in fc_builtin above. */
89a92869
CR
493 /* Even though command substitution through parse_and_execute turns off
494 remember_on_history, command substitution in a shell when set -o history
495 has been enabled (interactive or not) should use it in the last_hist
496 calculation as if it were on. */
497 rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
495aee44 498 i -= rh + hist_last_line_added;
726f6388
JA
499
500 /* No specification defaults to most recent command. */
501 if (command == NULL)
502 return (i);
503
504 /* Otherwise, there is a specification. It can be a number relative to
505 the current position, or an absolute history number. */
506 s = command;
507
508 /* Handle possible leading minus sign. */
509 if (s && (*s == '-'))
510 {
511 sign = -1;
512 s++;
513 }
514
f73dda09 515 if (s && DIGIT(*s))
726f6388
JA
516 {
517 n = atoi (s);
518 n *= sign;
519
726f6388
JA
520 /* If the value is negative or zero, then it is an offset from
521 the current history item. */
522 if (n < 0)
7117c2d2
JA
523 {
524 n += i + 1;
525 return (n < 0 ? 0 : n);
526 }
726f6388
JA
527 else if (n == 0)
528 return (i);
529 else
7117c2d2
JA
530 {
531 n -= history_base;
532 return (i < n ? i : n);
533 }
726f6388
JA
534 }
535
536 clen = strlen (command);
537 for (j = i; j >= 0; j--)
538 {
539 if (STREQN (command, histline (j), clen))
540 return (j);
541 }
542 return (-1);
543}
544
545/* Locate the most recent history line which begins with
546 COMMAND in HLIST, and return a malloc()'ed copy of it. */
547static char *
548fc_gethist (command, hlist)
549 char *command;
550 HIST_ENTRY **hlist;
551{
552 int i;
553
95732b49 554 if (hlist == 0)
726f6388
JA
555 return ((char *)NULL);
556
557 i = fc_gethnum (command, hlist);
558
559 if (i >= 0)
560 return (savestring (histline (i)));
561 else
562 return ((char *)NULL);
563}
564
f73dda09 565#ifdef INCLUDE_UNUSED
726f6388
JA
566/* Read the edited history lines from STREAM and return them
567 one at a time. This can read unlimited length lines. The
568 caller should free the storage. */
569static char *
570fc_readline (stream)
571 FILE *stream;
572{
573 register int c;
574 int line_len = 0, lindex = 0;
575 char *line = (char *)NULL;
576
577 while ((c = getc (stream)) != EOF)
578 {
579 if ((lindex + 2) >= line_len)
f73dda09 580 line = (char *)xrealloc (line, (line_len += 128));
726f6388
JA
581
582 if (c == '\n')
583 {
584 line[lindex++] = '\n';
585 line[lindex++] = '\0';
586 return (line);
587 }
588 else
589 line[lindex++] = c;
590 }
591
592 if (!lindex)
593 {
594 if (line)
595 free (line);
596
597 return ((char *)NULL);
598 }
599
600 if (lindex + 2 >= line_len)
601 line = (char *)xrealloc (line, lindex + 3);
602
603 line[lindex++] = '\n'; /* Finish with newline if none in file */
604 line[lindex++] = '\0';
605 return (line);
606}
f73dda09 607#endif
726f6388
JA
608
609/* Perform the SUBS on COMMAND.
610 SUBS is a list of substitutions, and COMMAND is a simple string.
611 Return a pointer to a malloc'ed string which contains the substituted
612 command. */
613static char *
614fc_dosubs (command, subs)
615 char *command;
616 REPL *subs;
617{
ccc6cda3 618 register char *new, *t;
726f6388
JA
619 register REPL *r;
620
ccc6cda3 621 for (new = savestring (command), r = subs; r; r = r->next)
726f6388 622 {
ccc6cda3 623 t = strsub (new, r->pat, r->rep, 1);
726f6388
JA
624 free (new);
625 new = t;
626 }
627 return (new);
628}
629
726f6388
JA
630/* Use `command' to replace the last entry in the history list, which,
631 by this time, is `fc blah...'. The intent is that the new command
632 become the history entry, and that `fc' should never appear in the
633 history list. This way you can do `r' to your heart's content. */
634static void
635fc_replhist (command)
636 char *command;
637{
726f6388
JA
638 int n;
639
ccc6cda3 640 if (command == 0 || *command == '\0')
726f6388
JA
641 return;
642
726f6388 643 n = strlen (command);
726f6388
JA
644 if (command[n - 1] == '\n')
645 command[n - 1] = '\0';
646
647 if (command && *command)
648 {
3185942a 649 bash_delete_last_history ();
726f6388
JA
650 maybe_add_history (command); /* Obeys HISTCONTROL setting. */
651 }
652}
653
f73dda09 654#ifdef INCLUDE_UNUSED
726f6388
JA
655/* Add LINE to the history, after removing a single trailing newline. */
656static void
657fc_addhist (line)
658 char *line;
659{
660 register int n;
661
95732b49
JA
662 if (line == 0 || *line == 0)
663 return;
664
726f6388
JA
665 n = strlen (line);
666
667 if (line[n - 1] == '\n')
668 line[n - 1] = '\0';
669
670 if (line && *line)
95732b49 671 maybe_add_history (line); /* Obeys HISTCONTROL setting. */
726f6388 672}
f73dda09
JA
673#endif
674
726f6388 675#endif /* HISTORY */