1This file is fc.def, from which is created fc.c.
2It implements the builtin "fc" in Bash.
3
4Copyright (C) 1987-2005 Free Software Foundation, Inc.
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
8Bash is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
12
13Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License along
19with Bash; see the file COPYING.  If not, write to the Free Software
20Foundation, 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]
28fc is used to list or edit and re-execute commands from the history list.
29FIRST and LAST can be numbers specifying the range, or FIRST can be a
30string, which means the most recent command beginning with that
31string.
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
40With the `fc -s [pat=rep ...] [command]' format, the command is
41re-executed after the substitution OLD=NEW is performed.
42
43A useful alias to use with this is r='fc -s', so that typing `r cc'
44runs the last command beginning with `cc' and typing `r' re-executes
45the 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)
81extern int errno;
82#endif /* !errno */
83
84extern int current_command_line_count;
85extern int literal_history;
86extern int posixly_correct;
87
88extern int unlink __P((const char *));
89
90extern FILE *sh_mktmpfp __P((char *, int, char **));
91extern 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. */
123typedef 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
147static char *fc_dosubs __P((char *, REPL *));
148static char *fc_gethist __P((char *, HIST_ENTRY **));
149static int fc_gethnum __P((char *, HIST_ENTRY **));
150static int fc_number __P((WORD_LIST *));
151static void fc_replhist __P((char *));
152#ifdef INCLUDE_UNUSED
153static char *fc_readline __P((FILE *));
154static 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
165int
166fc_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. */
417static int
418fc_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. */
434static int
435fc_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. */
502static char *
503fc_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. */
524static char *
525fc_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. */
568static char *
569fc_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. */
589static void
590fc_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. */
611static void
612fc_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 */
631