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