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