7311705d34d31bbe926e99a0e10f7abc57c545a2
[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-2002 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 extern int current_command_line_count;
74
75 static void display_history __P((WORD_LIST *));
76 static int delete_histent __P((int));
77 static int delete_last_history __P((void));
78 static void push_history __P((WORD_LIST *));
79 static int expand_and_print_history __P((WORD_LIST *));
80
81 #define AFLAG   0x01
82 #define RFLAG   0x02
83 #define WFLAG   0x04
84 #define NFLAG   0x08
85 #define SFLAG   0x10
86 #define PFLAG   0x20
87 #define CFLAG   0x40
88 #define DFLAG   0x80
89
90 int
91 history_builtin (list)
92      WORD_LIST *list;
93 {
94   int flags, opt, result, old_history_lines;
95   char *filename, *delete_arg;
96   intmax_t delete_offset;
97
98   flags = 0;
99   reset_internal_getopt ();
100   while ((opt = internal_getopt (list, "acd:npsrw")) != -1)
101     {
102       switch (opt)
103         {
104         case 'a':
105           flags |= AFLAG;
106           break;
107         case 'c':
108           flags |= CFLAG;
109           break;
110         case 'n':
111           flags |= NFLAG;
112           break;
113         case 'r':
114           flags |= RFLAG;
115           break;
116         case 'w':
117           flags |= WFLAG;
118           break;
119         case 's':
120           flags |= SFLAG;
121           break;
122         case 'd':
123           flags |= DFLAG;
124           delete_arg = list_optarg;
125           break;
126         case 'p':
127 #if defined (BANG_HISTORY)
128           flags |= PFLAG;
129 #endif
130           break;
131         default:
132           builtin_usage ();
133           return (EX_USAGE);
134         }
135     }
136   list = loptend;
137
138   opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG);
139   if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG)
140     {
141       builtin_error ("cannot use more than one of -anrw");
142       return (EXECUTION_FAILURE);
143     }
144
145   /* clear the history, but allow other arguments to add to it again. */
146   if (flags & CFLAG)
147     {
148       clear_history ();
149       if (list == 0)
150         return (EXECUTION_SUCCESS);
151     }
152
153   if (flags & SFLAG)
154     {
155       if (list)
156         push_history (list);
157       return (EXECUTION_SUCCESS);
158     }
159 #if defined (BANG_HISTORY)
160   else if (flags & PFLAG)
161     {
162       if (list)
163         return (expand_and_print_history (list));
164       return (EXECUTION_SUCCESS);
165     }
166 #endif
167   else if (flags & DFLAG)
168     {
169       if ((legal_number (delete_arg, &delete_offset) == 0)
170           || (delete_offset < history_base)
171           || (delete_offset > (history_base + history_length)))
172         {
173           sh_erange (delete_arg, "history position");
174           return (EXECUTION_FAILURE);
175         }
176       opt = delete_offset;
177       result = delete_histent (opt - history_base);
178       /* Since remove_history changes history_length, this can happen if
179          we delete the last history entry. */
180       if (where_history () > history_length)
181         history_set_pos (history_length);
182       return (result ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
183     }
184   else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0)
185     {
186       display_history (list);
187       return (EXECUTION_SUCCESS);
188     }
189
190   filename = list ? list->word->word : get_string_value ("HISTFILE");
191   result = EXECUTION_SUCCESS;
192
193   if (flags & AFLAG)            /* Append session's history to file. */
194     result = maybe_append_history (filename);
195   else if (flags & WFLAG)       /* Write entire history. */
196     result = write_history (filename);
197   else if (flags & RFLAG)       /* Read entire file. */
198     result = read_history (filename);
199   else if (flags & NFLAG)       /* Read `new' history from file. */
200     {
201       /* Read all of the lines in the file that we haven't already read. */
202       old_history_lines = history_lines_in_file;
203       using_history ();
204       result = read_history_range (filename, history_lines_in_file, -1);
205       using_history ();
206       history_lines_in_file = where_history ();
207       history_lines_this_session += history_lines_in_file - old_history_lines;
208     }
209
210   return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
211 }
212
213 /* Accessors for HIST_ENTRY lists that are called HLIST. */
214 #define histline(i) (hlist[(i)]->line)
215 #define histdata(i) (hlist[(i)]->data)
216
217 static void
218 display_history (list)
219      WORD_LIST *list;
220 {
221   register int i;
222   intmax_t limit;
223   HIST_ENTRY **hlist;
224
225   if (list)
226     {
227       limit = get_numeric_arg (list, 0);
228       if (limit < 0)
229         limit = -limit;
230     }
231   else
232     limit = -1;
233
234   hlist = history_list ();
235
236   if (hlist)
237     {
238       for (i = 0;  hlist[i]; i++)
239         ;
240
241       if (0 <= limit && limit < i)
242         i -= limit;
243       else
244         i = 0;
245
246       while (hlist[i])
247         {
248           QUIT;
249           printf ("%5d%c %s\n", i + history_base,
250                   histdata(i) ? '*' : ' ',
251                   histline(i));
252           i++;
253         }
254     }
255 }
256
257 /* Delete and free the history list entry at offset I. */
258 static int
259 delete_histent (i)
260      int i;
261 {
262   HIST_ENTRY *discard;
263
264   discard = remove_history (i);
265   if (discard)
266     {
267       if (discard->line)
268         free (discard->line);
269       free ((char *) discard);
270     }
271   return 1;
272 }
273
274 static int
275 delete_last_history ()
276 {
277   register int i;
278   HIST_ENTRY **hlist, *histent;
279
280   hlist = history_list ();
281   if (hlist == NULL)
282     return 0;
283
284   for (i = 0; hlist[i]; i++)
285     ;
286   i--;
287
288   /* History_get () takes a parameter that must be offset by history_base. */
289   histent = history_get (history_base + i);     /* Don't free this */
290   if (histent == NULL)
291     return 0;
292
293   return (delete_histent (i));
294 }
295
296 /* Remove the last entry in the history list and add each argument in
297    LIST to the history. */
298 static void
299 push_history (list)
300      WORD_LIST *list;
301 {
302   char *s;
303
304   /* Delete the last history entry if it was a single entry added to the
305      history list (generally the `history -s' itself), or if `history -s'
306      is being used in a compound command and the compound command was
307      added to the history as a single element (command-oriented history).
308      If you don't want history -s to remove the compound command from the
309      history, change #if 0 to #if 1 below. */
310 #if 0
311   if (hist_last_line_added && delete_last_history () == 0)
312 #else
313   if ((hist_last_line_added || (current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history))
314       && delete_last_history () == 0)
315 #endif
316       return;
317
318   s = string_list (list);
319   /* Call check_add_history with FORCE set to 1 to skip the check against
320      current_command_line_count.  If history -s is used in a compound
321      command, the above code will delete the compound command's history
322      entry and this call will add the line to the history as a separate
323      entry.  Without FORCE=1, if current_command_line_count were > 1, the
324      line would be appended to the entry before the just-deleted entry. */
325   check_add_history (s, 1);     /* obeys HISTCONTROL, HISTIGNORE */
326   free (s);
327 }
328
329 #if defined (BANG_HISTORY)
330 static int
331 expand_and_print_history (list)
332      WORD_LIST *list;
333 {
334   char *s;
335   int r, result;
336
337   if (hist_last_line_added && delete_last_history () == 0)
338     return EXECUTION_FAILURE;
339   result = EXECUTION_SUCCESS;
340   while (list)
341     {
342       r = history_expand (list->word->word, &s);
343       if (r < 0)
344         {
345           builtin_error ("%s: history expansion failed", list->word->word);
346           result = EXECUTION_FAILURE;
347         }
348       else
349         {
350           fputs (s, stdout);
351           putchar ('\n');
352         }
353       FREE (s);
354       list = list->next;
355     }
356   fflush (stdout);
357   return result;
358 }
359 #endif /* BANG_HISTORY */
360 #endif /* HISTORY */