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