Imported from ../bash-2.05a.tar.gz.
[platform/upstream/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 */