]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/fc.def
af9957968b26a7a555a4b56737db0ff138576770
[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, 1989, 1991 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
29 fc is used to list or edit and re-execute commands from the history list.
30 FIRST and LAST can be numbers specifying the range, or FIRST can be a
31 string, which means the most recent command beginning with that
32 string.
33
34 -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
35 then vi.
36
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).
40
41 With the `fc -s [pat=rep ...] [command]' format, the command is
42 re-executed after the substitution OLD=NEW is performed.
43
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
46 the last command.
47 $END
48
49 #include <config.h>
50
51 #if defined (HISTORY)
52 #ifndef _MINIX
53 # include <sys/param.h>
54 #endif
55 #include "../bashtypes.h"
56 #include "posixstat.h"
57 #ifndef _MINIX
58 # include <sys/file.h>
59 #endif
60
61 #if defined (HAVE_UNISTD_H)
62 # include <unistd.h>
63 #endif
64
65 #include <stdio.h>
66 #include <chartypes.h>
67
68 #include "../bashansi.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
88 extern int unlink __P((const char *));
89
90 extern FILE *sh_mktmpfp __P((char *, int, char **));
91
92 /* **************************************************************** */
93 /* */
94 /* The K*rn shell style fc command (Fix Command) */
95 /* */
96 /* **************************************************************** */
97
98 /* fc builtin command (fix command) for Bash for those who
99 like K*rn-style history better than csh-style.
100
101 fc [-e ename] [-nlr] [first] [last]
102
103 FIRST and LAST can be numbers specifying the range, or FIRST can be
104 a string, which means the most recent command beginning with that
105 string.
106
107 -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
108 then the editor which corresponds to the current readline editing
109 mode, then vi.
110
111 -l means list lines instead of editing.
112 -n means no line numbers listed.
113 -r means reverse the order of the lines (making it newest listed first).
114
115 fc -e - [pat=rep ...] [command]
116 fc -s [pat=rep ...] [command]
117
118 Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
119 */
120
121 /* Data structure describing a list of global replacements to perform. */
122 typedef struct repl {
123 struct repl *next;
124 char *pat;
125 char *rep;
126 } REPL;
127
128 /* Accessors for HIST_ENTRY lists that are called HLIST. */
129 #define histline(i) (hlist[(i)]->line)
130 #define histdata(i) (hlist[(i)]->data)
131
132 #define FREE_RLIST() \
133 do { \
134 for (rl = rlist; rl; ) { \
135 REPL *r; \
136 r = rl->next; \
137 if (rl->pat) \
138 free (rl->pat); \
139 if (rl->rep) \
140 free (rl->rep); \
141 free (rl); \
142 rl = r; \
143 } \
144 } while (0)
145
146 static char *fc_dosubs __P((char *, REPL *));
147 static char *fc_gethist __P((char *, HIST_ENTRY **));
148 static int fc_gethnum __P((char *, HIST_ENTRY **));
149 static int fc_number __P((WORD_LIST *));
150 static void fc_replhist __P((char *));
151 #ifdef INCLUDE_UNUSED
152 static char *fc_readline __P((FILE *));
153 static void fc_addhist __P((char *));
154 #endif
155
156 /* String to execute on a file that we want to edit. */
157 #define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
158
159 int
160 fc_builtin (list)
161 WORD_LIST *list;
162 {
163 register int i;
164 register char *sep;
165 int numbering, reverse, listing, execute;
166 int histbeg, histend, last_hist, retval, opt;
167 FILE *stream;
168 REPL *rlist, *rl;
169 char *ename, *command, *newcom;
170 HIST_ENTRY **hlist;
171 char *fn;
172
173 numbering = 1;
174 reverse = listing = execute = 0;
175 ename = (char *)NULL;
176
177 /* Parse out the options and set which of the two forms we're in. */
178 reset_internal_getopt ();
179 lcurrent = list; /* XXX */
180 while (fc_number (loptend = lcurrent) == 0 &&
181 (opt = internal_getopt (list, ":e:lnrs")) != -1)
182 {
183 switch (opt)
184 {
185 case 'n':
186 numbering = 0;
187 break;
188
189 case 'l':
190 listing = 1;
191 break;
192
193 case 'r':
194 reverse = 1;
195 break;
196
197 case 's':
198 execute = 1;
199 break;
200
201 case 'e':
202 ename = list_optarg;
203 break;
204
205 default:
206 builtin_usage ();
207 return (EX_USAGE);
208 }
209 }
210
211 list = loptend;
212
213 if (ename && (*ename == '-') && (ename[1] == '\0'))
214 execute = 1;
215
216 /* The "execute" form of the command (re-run, with possible string
217 substitutions). */
218 if (execute)
219 {
220 rlist = (REPL *)NULL;
221 while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
222 {
223 *sep++ = '\0';
224 rl = (REPL *)xmalloc (sizeof (REPL));
225 rl->next = (REPL *)NULL;
226 rl->pat = savestring (list->word->word);
227 rl->rep = savestring (sep);
228
229 if (rlist == NULL)
230 rlist = rl;
231 else
232 {
233 rl->next = rlist;
234 rlist = rl;
235 }
236 list = list->next;
237 }
238
239 /* If we have a list of substitutions to do, then reverse it
240 to get the replacements in the proper order. */
241
242 if (rlist && rlist->next)
243 rlist = (REPL *)reverse_list ((GENERIC_LIST *) rlist);
244
245 hlist = history_list ();
246
247 /* If we still have something in list, it is a command spec.
248 Otherwise, we use the most recent command in time. */
249 command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
250
251 if (command == NULL)
252 {
253 builtin_error ("no command found");
254 if (rlist)
255 FREE_RLIST ();
256
257 return (EXECUTION_FAILURE);
258 }
259
260 if (rlist)
261 {
262 newcom = fc_dosubs (command, rlist);
263 free (command);
264 FREE_RLIST ();
265 command = newcom;
266 }
267
268 fprintf (stderr, "%s\n", command);
269 fc_replhist (command); /* replace `fc -s' with command */
270 return (parse_and_execute (command, "fc", SEVAL_NOHIST));
271 }
272
273 /* This is the second form of the command (the list-or-edit-and-rerun
274 form). */
275 hlist = history_list ();
276 if (hlist == 0)
277 return (EXECUTION_SUCCESS);
278 for (i = 0; hlist[i]; i++);
279
280 /* With the Bash implementation of history, the current command line
281 ("fc blah..." and so on) is already part of the history list by
282 the time we get to this point. This just skips over that command
283 and makes the last command that this deals with be the last command
284 the user entered before the fc. We need to check whether the
285 line was actually added (HISTIGNORE may have caused it to not be),
286 so we check hist_last_line_added. */
287
288 last_hist = i - 1 - hist_last_line_added;
289
290 if (list)
291 {
292 histbeg = fc_gethnum (list->word->word, hlist);
293 list = list->next;
294
295 if (list)
296 histend = fc_gethnum (list->word->word, hlist);
297 else
298 histend = listing ? last_hist : histbeg;
299 }
300 else
301 {
302 /* The default for listing is the last 16 history items. */
303 if (listing)
304 {
305 histend = last_hist;
306 histbeg = histend - 16;
307 if (histbeg < 0)
308 histbeg = 0;
309 }
310 else
311 /* For editing, it is the last history command. */
312 histbeg = histend = last_hist;
313 }
314
315 /* We print error messages for line specifications out of range. */
316 if ((histbeg < 0) || (histend < 0) ||
317 (histbeg > last_hist) || (histend > last_hist))
318 {
319 builtin_error ("history specification out of range");
320 return (EXECUTION_FAILURE);
321 }
322
323 if (histend < histbeg)
324 {
325 i = histend;
326 histend = histbeg;
327 histbeg = i;
328
329 reverse = 1;
330 }
331
332 if (listing)
333 stream = stdout;
334 else
335 {
336 numbering = 0;
337 stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
338 if (stream == 0)
339 {
340 builtin_error ("cannot open temp file %s", fn ? fn : "");
341 FREE (fn);
342 return (EXECUTION_FAILURE);
343 }
344 }
345
346 for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
347 {
348 QUIT;
349 if (numbering)
350 fprintf (stream, "%d", i + history_base);
351 if (listing)
352 fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
353 fprintf (stream, "%s\n", histline (i));
354 }
355
356 if (listing)
357 return (EXECUTION_SUCCESS);
358
359 fclose (stream);
360
361 /* Now edit the file of commands. */
362 if (ename)
363 {
364 command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
365 sprintf (command, "%s %s", ename, fn);
366 }
367 else
368 {
369 command = (char *)xmalloc (3 + strlen (FC_EDIT_COMMAND) + strlen (fn));
370 sprintf (command, "%s %s", FC_EDIT_COMMAND, fn);
371 }
372 retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
373 if (retval != EXECUTION_SUCCESS)
374 {
375 unlink (fn);
376 free (fn);
377 return (EXECUTION_FAILURE);
378 }
379
380 /* Make sure parse_and_execute doesn't turn this off, even though a
381 call to parse_and_execute farther up the function call stack (e.g.,
382 if this is called by vi_edit_and_execute_command) may have already
383 called bash_history_disable. */
384 remember_on_history = 1;
385
386 /* Turn on the `v' flag while fc_execute_file runs so the commands
387 will be echoed as they are read by the parser. */
388 begin_unwind_frame ("fc builtin");
389 add_unwind_protect ((Function *)xfree, fn);
390 add_unwind_protect (unlink, fn);
391 unwind_protect_int (echo_input_at_read);
392 echo_input_at_read = 1;
393
394 retval = fc_execute_file (fn);
395
396 run_unwind_frame ("fc builtin");
397
398 return (retval);
399 }
400
401 /* Return 1 if LIST->word->word is a legal number for fc's use. */
402 static int
403 fc_number (list)
404 WORD_LIST *list;
405 {
406 char *s;
407
408 if (list == 0)
409 return 0;
410 s = list->word->word;
411 if (*s == '-')
412 s++;
413 return (legal_number (s, (long *)NULL));
414 }
415
416 /* Return an absolute index into HLIST which corresponds to COMMAND. If
417 COMMAND is a number, then it was specified in relative terms. If it
418 is a string, then it is the start of a command line present in HLIST. */
419 static int
420 fc_gethnum (command, hlist)
421 char *command;
422 HIST_ENTRY **hlist;
423 {
424 int sign = 1, n, clen;
425 register int i, j;
426 register char *s;
427
428 /* Count history elements. */
429 for (i = 0; hlist[i]; i++);
430
431 /* With the Bash implementation of history, the current command line
432 ("fc blah..." and so on) is already part of the history list by
433 the time we get to this point. This just skips over that command
434 and makes the last command that this deals with be the last command
435 the user entered before the fc. We need to check whether the
436 line was actually added (HISTIGNORE may have caused it to not be),
437 so we check hist_last_line_added. */
438 i -= 1 + hist_last_line_added;
439
440 /* No specification defaults to most recent command. */
441 if (command == NULL)
442 return (i);
443
444 /* Otherwise, there is a specification. It can be a number relative to
445 the current position, or an absolute history number. */
446 s = command;
447
448 /* Handle possible leading minus sign. */
449 if (s && (*s == '-'))
450 {
451 sign = -1;
452 s++;
453 }
454
455 if (s && DIGIT(*s))
456 {
457 n = atoi (s);
458 n *= sign;
459
460 /* Anything specified greater than the last history element that we
461 deal with is an error. */
462 if (n > i + history_base)
463 return (-1);
464
465 /* If the value is negative or zero, then it is an offset from
466 the current history item. */
467 if (n < 0)
468 return (i + n + 1);
469 else if (n == 0)
470 return (i);
471 else
472 return (n - history_base);
473 }
474
475 clen = strlen (command);
476 for (j = i; j >= 0; j--)
477 {
478 if (STREQN (command, histline (j), clen))
479 return (j);
480 }
481 return (-1);
482 }
483
484 /* Locate the most recent history line which begins with
485 COMMAND in HLIST, and return a malloc()'ed copy of it. */
486 static char *
487 fc_gethist (command, hlist)
488 char *command;
489 HIST_ENTRY **hlist;
490 {
491 int i;
492
493 if (!hlist)
494 return ((char *)NULL);
495
496 i = fc_gethnum (command, hlist);
497
498 if (i >= 0)
499 return (savestring (histline (i)));
500 else
501 return ((char *)NULL);
502 }
503
504 #ifdef INCLUDE_UNUSED
505 /* Read the edited history lines from STREAM and return them
506 one at a time. This can read unlimited length lines. The
507 caller should free the storage. */
508 static char *
509 fc_readline (stream)
510 FILE *stream;
511 {
512 register int c;
513 int line_len = 0, lindex = 0;
514 char *line = (char *)NULL;
515
516 while ((c = getc (stream)) != EOF)
517 {
518 if ((lindex + 2) >= line_len)
519 line = (char *)xrealloc (line, (line_len += 128));
520
521 if (c == '\n')
522 {
523 line[lindex++] = '\n';
524 line[lindex++] = '\0';
525 return (line);
526 }
527 else
528 line[lindex++] = c;
529 }
530
531 if (!lindex)
532 {
533 if (line)
534 free (line);
535
536 return ((char *)NULL);
537 }
538
539 if (lindex + 2 >= line_len)
540 line = (char *)xrealloc (line, lindex + 3);
541
542 line[lindex++] = '\n'; /* Finish with newline if none in file */
543 line[lindex++] = '\0';
544 return (line);
545 }
546 #endif
547
548 /* Perform the SUBS on COMMAND.
549 SUBS is a list of substitutions, and COMMAND is a simple string.
550 Return a pointer to a malloc'ed string which contains the substituted
551 command. */
552 static char *
553 fc_dosubs (command, subs)
554 char *command;
555 REPL *subs;
556 {
557 register char *new, *t;
558 register REPL *r;
559
560 for (new = savestring (command), r = subs; r; r = r->next)
561 {
562 t = strsub (new, r->pat, r->rep, 1);
563 free (new);
564 new = t;
565 }
566 return (new);
567 }
568
569 /* Use `command' to replace the last entry in the history list, which,
570 by this time, is `fc blah...'. The intent is that the new command
571 become the history entry, and that `fc' should never appear in the
572 history list. This way you can do `r' to your heart's content. */
573 static void
574 fc_replhist (command)
575 char *command;
576 {
577 register int i;
578 HIST_ENTRY **hlist, *histent, *discard;
579 int n;
580
581 if (command == 0 || *command == '\0')
582 return;
583
584 hlist = history_list ();
585
586 if (hlist == NULL)
587 return;
588
589 for (i = 0; hlist[i]; i++);
590 i--;
591
592 /* History_get () takes a parameter that should be
593 offset by history_base. */
594
595 histent = history_get (history_base + i); /* Don't free this */
596 if (histent == NULL)
597 return;
598
599 n = strlen (command);
600
601 if (command[n - 1] == '\n')
602 command[n - 1] = '\0';
603
604 if (command && *command)
605 {
606 discard = remove_history (i);
607 if (discard)
608 {
609 FREE (discard->line);
610 free ((char *) discard);
611 }
612 maybe_add_history (command); /* Obeys HISTCONTROL setting. */
613 }
614 }
615
616 #ifdef INCLUDE_UNUSED
617 /* Add LINE to the history, after removing a single trailing newline. */
618 static void
619 fc_addhist (line)
620 char *line;
621 {
622 register int n;
623
624 n = strlen (line);
625
626 if (line[n - 1] == '\n')
627 line[n - 1] = '\0';
628
629 if (line && *line)
630 maybe_add_history (line);
631 }
632 #endif
633
634 #endif /* HISTORY */