Imported from ../bash-2.05.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
67 #include "../bashansi.h"
68 #include <errno.h>
69
70 #include "../shell.h"
71 #include "../builtins.h"
72 #include "../flags.h"
73 #include "../bashhist.h"
74 #include "maxpath.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 FILE *sh_mktmpfp __P((char *, int, char **));
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;
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       stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
331       if (stream == 0)
332         {
333           builtin_error ("cannot open temp file %s", fn ? fn : "");
334           FREE (fn);
335           return (EXECUTION_FAILURE);
336         }
337     }
338
339   for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
340     {
341       QUIT;
342       if (numbering)
343         fprintf (stream, "%d", i + history_base);
344       if (listing)
345         fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
346       fprintf (stream, "%s\n", histline (i));
347     }
348
349   if (listing)
350     return (EXECUTION_SUCCESS);
351
352   fclose (stream);
353
354   /* Now edit the file of commands. */
355   if (ename)
356     {
357       command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
358       sprintf (command, "%s %s", ename, fn);
359     }
360   else
361     {
362       command = (char *)xmalloc (3 + strlen (FC_EDIT_COMMAND) + strlen (fn));
363       sprintf (command, "%s %s", FC_EDIT_COMMAND, fn);
364     }
365   retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
366   if (retval != EXECUTION_SUCCESS)
367     {
368       unlink (fn);
369       free (fn);
370       return (EXECUTION_FAILURE);
371     }
372
373   /* Make sure parse_and_execute doesn't turn this off, even though a
374      call to parse_and_execute farther up the function call stack (e.g.,
375      if this is called by vi_edit_and_execute_command) may have already
376      called bash_history_disable. */
377   remember_on_history = 1;
378
379   /* Turn on the `v' flag while fc_execute_file runs so the commands
380      will be echoed as they are read by the parser. */
381   begin_unwind_frame ("fc builtin");
382   add_unwind_protect ((Function *)xfree, fn);
383   add_unwind_protect (unlink, fn);
384   unwind_protect_int (echo_input_at_read);
385   echo_input_at_read = 1;
386     
387   retval = fc_execute_file (fn);
388
389   run_unwind_frame ("fc builtin");
390
391   return (retval);
392 }
393
394 /* Return 1 if LIST->word->word is a legal number for fc's use. */
395 static int
396 fc_number (list)
397      WORD_LIST *list;
398 {
399   char *s;
400
401   if (list == 0)
402     return 0;
403   s = list->word->word;
404   if (*s == '-')
405     s++;
406   return (legal_number (s, (long *)NULL));
407 }
408
409 /* Return an absolute index into HLIST which corresponds to COMMAND.  If
410    COMMAND is a number, then it was specified in relative terms.  If it
411    is a string, then it is the start of a command line present in HLIST. */
412 static int
413 fc_gethnum (command, hlist)
414      char *command;
415      HIST_ENTRY **hlist;
416 {
417   int sign = 1, n, clen;
418   register int i, j;
419   register char *s;
420
421   /* Count history elements. */
422   for (i = 0; hlist[i]; i++);
423
424   /* With the Bash implementation of history, the current command line
425      ("fc blah..." and so on) is already part of the history list by
426      the time we get to this point.  This just skips over that command
427      and makes the last command that this deals with be the last command
428      the user entered before the fc.  We need to check whether the
429      line was actually added (HISTIGNORE may have caused it to not be),
430      so we check hist_last_line_added. */
431   i -= 1 + hist_last_line_added;
432
433   /* No specification defaults to most recent command. */
434   if (command == NULL)
435     return (i);
436
437   /* Otherwise, there is a specification.  It can be a number relative to
438      the current position, or an absolute history number. */
439   s = command;
440
441   /* Handle possible leading minus sign. */
442   if (s && (*s == '-'))
443     {
444       sign = -1;
445       s++;
446     }
447
448   if (s && digit(*s))
449     {
450       n = atoi (s);
451       n *= sign;
452
453       /* Anything specified greater than the last history element that we
454          deal with is an error. */
455       if (n > i + history_base)
456         return (-1);
457
458       /* If the value is negative or zero, then it is an offset from
459          the current history item. */
460       if (n < 0)
461         return (i + n + 1);
462       else if (n == 0)
463         return (i);
464       else
465         return (n - history_base);
466     }
467
468   clen = strlen (command);
469   for (j = i; j >= 0; j--)
470     {
471       if (STREQN (command, histline (j), clen))
472         return (j);
473     }
474   return (-1);
475 }
476
477 /* Locate the most recent history line which begins with
478    COMMAND in HLIST, and return a malloc()'ed copy of it. */
479 static char *
480 fc_gethist (command, hlist)
481      char *command;
482      HIST_ENTRY **hlist;
483 {
484   int i;
485
486   if (!hlist)
487     return ((char *)NULL);
488
489   i = fc_gethnum (command, hlist);
490
491   if (i >= 0)
492     return (savestring (histline (i)));
493   else
494     return ((char *)NULL);
495 }
496
497 /* Read the edited history lines from STREAM and return them
498    one at a time.  This can read unlimited length lines.  The
499    caller should free the storage. */
500 static char *
501 fc_readline (stream)
502      FILE *stream;
503 {
504   register int c;
505   int line_len = 0, lindex = 0;
506   char *line = (char *)NULL;
507
508   while ((c = getc (stream)) != EOF)
509     {
510       if ((lindex + 2) >= line_len)
511         line = (char *) xrealloc (line, (line_len += 128));
512
513       if (c == '\n')
514         {
515           line[lindex++] = '\n';
516           line[lindex++] = '\0';
517           return (line);
518         }
519       else
520         line[lindex++] = c;
521     }
522
523   if (!lindex)
524     {
525       if (line)
526         free (line);
527
528       return ((char *)NULL);
529     }
530
531   if (lindex + 2 >= line_len)
532     line = (char *)xrealloc (line, lindex + 3);
533
534   line[lindex++] = '\n';            /* Finish with newline if none in file */
535   line[lindex++] = '\0';
536   return (line);
537 }
538
539 /* Perform the SUBS on COMMAND.
540    SUBS is a list of substitutions, and COMMAND is a simple string.
541    Return a pointer to a malloc'ed string which contains the substituted
542    command. */
543 static char *
544 fc_dosubs (command, subs)
545      char *command;
546      REPL *subs;
547 {
548   register char *new, *t;
549   register REPL *r;
550
551   for (new = savestring (command), r = subs; r; r = r->next)
552     {
553       t = strsub (new, r->pat, r->rep, 1);
554       free (new);
555       new = t;
556     }
557   return (new);
558 }
559
560 /* Use `command' to replace the last entry in the history list, which,
561    by this time, is `fc blah...'.  The intent is that the new command
562    become the history entry, and that `fc' should never appear in the
563    history list.  This way you can do `r' to your heart's content. */
564 static void
565 fc_replhist (command)
566      char *command;
567 {
568   register int i;
569   HIST_ENTRY **hlist, *histent, *discard;
570   int n;
571
572   if (command == 0 || *command == '\0')
573     return;
574
575   hlist = history_list ();
576
577   if (hlist == NULL)
578     return;
579
580   for (i = 0; hlist[i]; i++);
581   i--;
582
583   /* History_get () takes a parameter that should be
584      offset by history_base. */
585
586   histent = history_get (history_base + i);     /* Don't free this */
587   if (histent == NULL)
588     return;
589
590   n = strlen (command);
591
592   if (command[n - 1] == '\n')
593     command[n - 1] = '\0';
594
595   if (command && *command)
596     {
597       discard = remove_history (i);
598       if (discard)
599         {
600           FREE (discard->line);
601           free ((char *) discard);
602         }
603       maybe_add_history (command);      /* Obeys HISTCONTROL setting. */
604     }
605 }
606
607 /* Add LINE to the history, after removing a single trailing newline. */
608 static void
609 fc_addhist (line)
610      char *line;
611 {
612   register int n;
613
614   n = strlen (line);
615
616   if (line[n - 1] == '\n')
617     line[n - 1] = '\0';
618
619   if (line && *line)
620     maybe_add_history (line);
621 }
622 #endif /* HISTORY */