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