]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/fc.def
Imported from ../bash-3.2.tar.gz.
[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 current_command_line_count;
85 extern int literal_history;
86 extern int posixly_correct;
87
88 extern int unlink __P((const char *));
89
90 extern FILE *sh_mktmpfp __P((char *, int, char **));
91 extern int delete_last_history __P((void));
92
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
122 /* Data structure describing a list of global replacements to perform. */
123 typedef struct repl {
124 struct repl *next;
125 char *pat;
126 char *rep;
127 } REPL;
128
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
147 static char *fc_dosubs __P((char *, REPL *));
148 static char *fc_gethist __P((char *, HIST_ENTRY **));
149 static int fc_gethnum __P((char *, HIST_ENTRY **));
150 static int fc_number __P((WORD_LIST *));
151 static void fc_replhist __P((char *));
152 #ifdef INCLUDE_UNUSED
153 static char *fc_readline __P((FILE *));
154 static void fc_addhist __P((char *));
155 #endif
156
157 /* String to execute on a file that we want to edit. */
158 #define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
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
164
165 int
166 fc_builtin (list)
167 WORD_LIST *list;
168 {
169 register int i;
170 register char *sep;
171 int numbering, reverse, listing, execute;
172 int histbeg, histend, last_hist, retval, opt;
173 FILE *stream;
174 REPL *rlist, *rl;
175 char *ename, *command, *newcom, *fcedit;
176 HIST_ENTRY **hlist;
177 char *fn;
178
179 numbering = 1;
180 reverse = listing = execute = 0;
181 ename = (char *)NULL;
182
183 /* Parse out the options and set which of the two forms we're in. */
184 reset_internal_getopt ();
185 lcurrent = list; /* XXX */
186 while (fc_number (loptend = lcurrent) == 0 &&
187 (opt = internal_getopt (list, ":e:lnrs")) != -1)
188 {
189 switch (opt)
190 {
191 case 'n':
192 numbering = 0;
193 break;
194
195 case 'l':
196 listing = 1;
197 break;
198
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);
214 }
215 }
216
217 list = loptend;
218
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 {
226 rlist = (REPL *)NULL;
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
248 rlist = REVERSE_LIST (rlist, REPL *);
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. */
254 command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
255
256 if (command == NULL)
257 {
258 builtin_error (_("no command found"));
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
273 fprintf (stderr, "%s\n", command);
274 fc_replhist (command); /* replace `fc -s' with command */
275 return (parse_and_execute (command, "fc", SEVAL_NOHIST));
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
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. */
292
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
298 last_hist = i - 1 - hist_last_line_added;
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
308 histend = listing ? last_hist : histbeg;
309 }
310 else
311 {
312 /* The default for listing is the last 16 history items. */
313 if (listing)
314 {
315 histend = last_hist;
316 histbeg = histend - 16 + 1; /* +1 because loop below uses >= */
317 if (histbeg < 0)
318 histbeg = 0;
319 }
320 else
321 /* For editing, it is the last history command. */
322 histbeg = histend = last_hist;
323 }
324
325 /* We print error messages for line specifications out of range. */
326 if ((histbeg < 0) || (histend < 0))
327 {
328 sh_erange ((char *)NULL, _("history specification"));
329 return (EXECUTION_FAILURE);
330 }
331
332 if (histend < histbeg)
333 {
334 i = histend;
335 histend = histbeg;
336 histbeg = i;
337
338 reverse = 1;
339 }
340
341 if (listing)
342 stream = stdout;
343 else
344 {
345 numbering = 0;
346 stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
347 if (stream == 0)
348 {
349 builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
350 FREE (fn);
351 return (EXECUTION_FAILURE);
352 }
353 }
354
355 for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
356 {
357 QUIT;
358 if (numbering)
359 fprintf (stream, "%d", i + history_base);
360 if (listing)
361 {
362 if (posixly_correct)
363 fputs ("\t", stream);
364 else
365 fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
366 }
367 fprintf (stream, "%s\n", histline (i));
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 {
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);
386 }
387 retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
388 if (retval != EXECUTION_SUCCESS)
389 {
390 unlink (fn);
391 free (fn);
392 return (EXECUTION_FAILURE);
393 }
394
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;
400
401 /* Turn on the `v' flag while fc_execute_file runs so the commands
402 will be echoed as they are read by the parser. */
403 begin_unwind_frame ("fc builtin");
404 add_unwind_protect ((Function *)xfree, fn);
405 add_unwind_protect (unlink, fn);
406 unwind_protect_int (echo_input_at_read);
407 echo_input_at_read = 1;
408
409 retval = fc_execute_file (fn);
410
411 run_unwind_frame ("fc builtin");
412
413 return (retval);
414 }
415
416 /* Return 1 if LIST->word->word is a legal number for fc's use. */
417 static int
418 fc_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++;
428 return (legal_number (s, (intmax_t *)NULL));
429 }
430
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. */
434 static int
435 fc_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
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;
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
470 if (s && DIGIT(*s))
471 {
472 n = atoi (s);
473 n *= sign;
474
475 /* If the value is negative or zero, then it is an offset from
476 the current history item. */
477 if (n < 0)
478 {
479 n += i + 1;
480 return (n < 0 ? 0 : n);
481 }
482 else if (n == 0)
483 return (i);
484 else
485 {
486 n -= history_base;
487 return (i < n ? i : n);
488 }
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. */
502 static char *
503 fc_gethist (command, hlist)
504 char *command;
505 HIST_ENTRY **hlist;
506 {
507 int i;
508
509 if (hlist == 0)
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
520 #ifdef INCLUDE_UNUSED
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. */
524 static char *
525 fc_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)
535 line = (char *)xrealloc (line, (line_len += 128));
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 }
562 #endif
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. */
568 static char *
569 fc_dosubs (command, subs)
570 char *command;
571 REPL *subs;
572 {
573 register char *new, *t;
574 register REPL *r;
575
576 for (new = savestring (command), r = subs; r; r = r->next)
577 {
578 t = strsub (new, r->pat, r->rep, 1);
579 free (new);
580 new = t;
581 }
582 return (new);
583 }
584
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. */
589 static void
590 fc_replhist (command)
591 char *command;
592 {
593 int n;
594
595 if (command == 0 || *command == '\0')
596 return;
597
598 n = strlen (command);
599 if (command[n - 1] == '\n')
600 command[n - 1] = '\0';
601
602 if (command && *command)
603 {
604 delete_last_history ();
605 maybe_add_history (command); /* Obeys HISTCONTROL setting. */
606 }
607 }
608
609 #ifdef INCLUDE_UNUSED
610 /* Add LINE to the history, after removing a single trailing newline. */
611 static void
612 fc_addhist (line)
613 char *line;
614 {
615 register int n;
616
617 if (line == 0 || *line == 0)
618 return;
619
620 n = strlen (line);
621
622 if (line[n - 1] == '\n')
623 line[n - 1] = '\0';
624
625 if (line && *line)
626 maybe_add_history (line); /* Obeys HISTCONTROL setting. */
627 }
628 #endif
629
630 #endif /* HISTORY */