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