df416ae515f925c56f62c4dfe11dcbafb474a11d
[platform/upstream/bash.git] / builtins / history.def
1 This file is history.def, from which is created history.c.
2 It implements the builtin "history" 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 history.c
23
24 $BUILTIN history
25 $FUNCTION history_builtin
26 $DEPENDS_ON HISTORY
27 $SHORT_DOC history [-c] [-d offset] [n] or history -awrn [filename] or history -ps arg [arg...]
28 Display the history list with line numbers.  Lines listed with
29 with a `*' have been modified.  Argument of N says to list only
30 the last N lines.  The `-c' option causes the history list to be
31 cleared by deleting all of the entries.  The `-d' option deletes
32 the history entry at offset OFFSET.  The `-w' option writes out the
33 current history to the history file;  `-r' means to read the file and
34 append the contents to the history list instead.  `-a' means
35 to append history lines from this session to the history file.
36 Argument `-n' means to read all history lines not already read
37 from the history file and append them to the history list.  If
38 FILENAME is given, then that is used as the history file else
39 if $HISTFILE has a value, that is used, else ~/.bash_history.
40 If the -s option is supplied, the non-option ARGs are appended to
41 the history list as a single entry.  The -p option means to perform
42 history expansion on each ARG and display the result, without storing
43 anything in the history list.
44 $END
45
46 #include <config.h>
47
48 #if defined (HISTORY)
49 #include "../bashtypes.h"
50 #ifndef _MINIX
51 #  include <sys/file.h>
52 #endif
53 #include "posixstat.h"
54 #include "filecntl.h"
55 #include <errno.h>
56 #include <stdio.h>
57 #if defined (HAVE_UNISTD_H)
58 #  include <unistd.h>
59 #endif
60
61 #include "../bashansi.h"
62
63 #include "../shell.h"
64 #include "../bashhist.h"
65 #include <readline/history.h>
66 #include "bashgetopt.h"
67 #include "common.h"
68
69 #if !defined (errno)
70 extern int errno;
71 #endif
72
73 static void display_history __P((WORD_LIST *));
74 static int delete_histent __P((int));
75 static int delete_last_history __P((void));
76 static void push_history __P((WORD_LIST *));
77 static int expand_and_print_history __P((WORD_LIST *));
78
79 #define AFLAG   0x01
80 #define RFLAG   0x02
81 #define WFLAG   0x04
82 #define NFLAG   0x08
83 #define SFLAG   0x10
84 #define PFLAG   0x20
85 #define CFLAG   0x40
86 #define DFLAG   0x80
87
88 int
89 history_builtin (list)
90      WORD_LIST *list;
91 {
92   int flags, opt, result;
93   char *filename, *delete_arg;
94   long delete_offset;
95
96   flags = 0;
97   reset_internal_getopt ();
98   while ((opt = internal_getopt (list, "acd:npsrw")) != -1)
99     {
100       switch (opt)
101         {
102         case 'a':
103           flags |= AFLAG;
104           break;
105         case 'c':
106           flags |= CFLAG;
107           break;
108         case 'n':
109           flags |= NFLAG;
110           break;
111         case 'r':
112           flags |= RFLAG;
113           break;
114         case 'w':
115           flags |= WFLAG;
116           break;
117         case 's':
118           flags |= SFLAG;
119           break;
120         case 'd':
121           flags |= DFLAG;
122           delete_arg = list_optarg;
123           break;
124         case 'p':
125 #if defined (BANG_HISTORY)
126           flags |= PFLAG;
127 #endif
128           break;
129         default:
130           builtin_usage ();
131           return (EX_USAGE);
132         }
133     }
134   list = loptend;
135
136   opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG);
137   if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG)
138     {
139       builtin_error ("cannot use more than one of -anrw");
140       return (EXECUTION_FAILURE);
141     }
142
143   /* clear the history, but allow other arguments to add to it again. */
144   if (flags & CFLAG)
145     {
146       clear_history ();
147       if (list == 0)
148         return (EXECUTION_SUCCESS);
149     }
150
151   if (flags & SFLAG)
152     {
153       if (list)
154         push_history (list);
155       return (EXECUTION_SUCCESS);
156     }
157 #if defined (BANG_HISTORY)
158   else if (flags & PFLAG)
159     {
160       if (list)
161         return (expand_and_print_history (list));
162       return (EXECUTION_SUCCESS);
163     }
164 #endif
165   else if (flags & DFLAG)
166     {
167       if ((legal_number (delete_arg, &delete_offset) == 0)
168           || (delete_offset < history_base)
169           || (delete_offset > (history_base + history_length)))
170         {
171           builtin_error ("%s: not a valid history position", delete_arg);
172           return (EXECUTION_FAILURE);
173         }
174       opt = delete_offset;
175       result = delete_histent (opt - history_base);
176       /* Since remove_history changes history_length, this can happen if
177          we delete the last history entry. */
178       if (where_history () > history_length)
179         history_set_pos (history_length);
180       return (result ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
181     }
182   else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0)
183     {
184       display_history (list);
185       return (EXECUTION_SUCCESS);
186     }
187
188   filename = list ? list->word->word : get_string_value ("HISTFILE");
189   result = EXECUTION_SUCCESS;
190
191   if (flags & AFLAG)            /* Append session's history to file. */
192     result = maybe_append_history (filename);
193   else if (flags & WFLAG)       /* Write entire history. */
194     result = write_history (filename);
195   else if (flags & RFLAG)       /* Read entire file. */
196     result = read_history (filename);
197   else if (flags & NFLAG)       /* Read `new' history from file. */
198     {
199       /* Read all of the lines in the file that we haven't already read. */
200       using_history ();
201       result = read_history_range (filename, history_lines_in_file, -1);
202       using_history ();
203       history_lines_in_file = where_history ();
204     }
205
206   return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
207 }
208
209 /* Accessors for HIST_ENTRY lists that are called HLIST. */
210 #define histline(i) (hlist[(i)]->line)
211 #define histdata(i) (hlist[(i)]->data)
212
213 static void
214 display_history (list)
215      WORD_LIST *list;
216 {
217   register int i;
218   long limit;
219   HIST_ENTRY **hlist;
220
221   if (list)
222     {
223       limit = get_numeric_arg (list, 0);
224       if (limit < 0)
225         limit = -limit;
226     }
227   else
228     limit = -1;
229
230   hlist = history_list ();
231
232   if (hlist)
233     {
234       for (i = 0;  hlist[i]; i++)
235         ;
236
237       if (0 <= limit && limit < i)
238         i -= limit;
239       else
240         i = 0;
241
242       while (hlist[i])
243         {
244           QUIT;
245           printf ("%5d%c %s\n", i + history_base,
246                   histdata(i) ? '*' : ' ',
247                   histline(i));
248           i++;
249         }
250     }
251 }
252
253 /* Delete and free the history list entry at offset I. */
254 static int
255 delete_histent (i)
256      int i;
257 {
258   HIST_ENTRY *discard;
259
260   discard = remove_history (i);
261   if (discard)
262     {
263       if (discard->line)
264         free (discard->line);
265       free ((char *) discard);
266     }
267   return 1;
268 }
269
270 static int
271 delete_last_history ()
272 {
273   register int i;
274   HIST_ENTRY **hlist, *histent;
275
276   hlist = history_list ();
277   if (hlist == NULL)
278     return 0;
279
280   for (i = 0; hlist[i]; i++)
281     ;
282   i--;
283
284   /* History_get () takes a parameter that must be offset by history_base. */
285   histent = history_get (history_base + i);     /* Don't free this */
286   if (histent == NULL)
287     return 0;
288
289   return (delete_histent (i));
290 }
291
292 /* Remove the last entry in the history list and add each argument in
293    LIST to the history. */
294 static void
295 push_history (list)
296      WORD_LIST *list;
297 {
298   char *s;
299
300   if (hist_last_line_added && delete_last_history () == 0)
301     return;
302   s = string_list (list);
303   maybe_add_history (s);        /* Obeys HISTCONTROL setting. */
304   free (s);
305 }
306
307 #if defined (BANG_HISTORY)
308 static int
309 expand_and_print_history (list)
310      WORD_LIST *list;
311 {
312   char *s;
313   int r, result;
314
315   if (hist_last_line_added && delete_last_history () == 0)
316     return EXECUTION_FAILURE;
317   result = EXECUTION_SUCCESS;
318   while (list)
319     {
320       r = history_expand (list->word->word, &s);
321       if (r < 0)
322         {
323           builtin_error ("%s: history expansion failed", list->word->word);
324           result = EXECUTION_FAILURE;
325         }
326       else
327         {
328           fputs (s, stdout);
329           putchar ('\n');
330         }
331       FREE (s);
332       list = list->next;
333     }
334   fflush (stdout);
335   return result;
336 }
337 #endif /* BANG_HISTORY */
338 #endif /* HISTORY */