]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/history.def
Imported from ../bash-4.0-rc1.tar.gz.
[thirdparty/bash.git] / builtins / history.def
CommitLineData
726f6388
JA
1This file is history.def, from which is created history.c.
2It implements the builtin "history" in Bash.
3
3185942a 4Copyright (C) 1987-2009 Free Software Foundation, Inc.
726f6388
JA
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
3185942a
JA
8Bash is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
726f6388 12
3185942a
JA
13Bash is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
726f6388 17
3185942a
JA
18You should have received a copy of the GNU General Public License
19along with Bash. If not, see <http://www.gnu.org/licenses/>.
726f6388
JA
20
21$PRODUCES history.c
22
23$BUILTIN history
24$FUNCTION history_builtin
25$DEPENDS_ON HISTORY
3185942a
JA
26$SHORT_DOC history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg [arg...]
27Display or manipulate the history list.
28
29Display the history list with line numbers, prefixing each modified
30entry with a `*'. An argument of N lists only the last N entries.
31
32Options:
33 -c clear the history list by deleting all of the entries
34 -d offset delete the history entry at offset OFFSET.
35
36 -a append history lines from this session to the history file
37 -n read all history lines not already read from the history file
38 -r read the history file and append the contents to the history
39 list
40 -w write the current history to the history file
41 and append them to the history list
42
43 -p perform history expansion on each ARG and display the result
44 without storing it in the history list
45 -s append the ARGs to the history list as a single entry
46
47If FILENAME is given, it is used as the history file. Otherwise,
ccc6cda3 48if $HISTFILE has a value, that is used, else ~/.bash_history.
b80f6443
JA
49
50If the $HISTTIMEFORMAT variable is set and not null, its value is used
51as a format string for strftime(3) to print the time stamp associated
52with each displayed history entry. No time stamps are printed otherwise.
3185942a
JA
53
54Exit Status:
55Returns success unless an invalid option is given or an error occurs.
726f6388
JA
56$END
57
ccc6cda3
JA
58#include <config.h>
59
726f6388 60#if defined (HISTORY)
d166f048 61#include "../bashtypes.h"
b80f6443 62#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
cce855bc
JA
63# include <sys/file.h>
64#endif
bb70624e
JA
65#include "posixstat.h"
66#include "filecntl.h"
ccc6cda3
JA
67#include <errno.h>
68#include <stdio.h>
69#if defined (HAVE_UNISTD_H)
70# include <unistd.h>
71#endif
72
73#include "../bashansi.h"
b80f6443 74#include "../bashintl.h"
ccc6cda3
JA
75
76#include "../shell.h"
726f6388
JA
77#include "../bashhist.h"
78#include <readline/history.h>
ccc6cda3
JA
79#include "bashgetopt.h"
80#include "common.h"
81
82#if !defined (errno)
83extern int errno;
84#endif
726f6388 85
7117c2d2 86extern int current_command_line_count;
95732b49
JA
87extern int force_append_history; /* shopt -s histappend */
88
b80f6443 89static char *histtime __P((HIST_ENTRY *, const char *));
3185942a 90static int display_history __P((WORD_LIST *));
f73dda09
JA
91static void push_history __P((WORD_LIST *));
92static int expand_and_print_history __P((WORD_LIST *));
726f6388 93
ccc6cda3
JA
94#define AFLAG 0x01
95#define RFLAG 0x02
96#define WFLAG 0x04
97#define NFLAG 0x08
98#define SFLAG 0x10
99#define PFLAG 0x20
100#define CFLAG 0x40
bb70624e 101#define DFLAG 0x80
ccc6cda3
JA
102
103int
726f6388
JA
104history_builtin (list)
105 WORD_LIST *list;
106{
b80f6443 107 int flags, opt, result, old_history_lines, obase;
bb70624e 108 char *filename, *delete_arg;
7117c2d2 109 intmax_t delete_offset;
726f6388 110
ccc6cda3
JA
111 flags = 0;
112 reset_internal_getopt ();
bb70624e 113 while ((opt = internal_getopt (list, "acd:npsrw")) != -1)
726f6388 114 {
ccc6cda3 115 switch (opt)
726f6388 116 {
ccc6cda3
JA
117 case 'a':
118 flags |= AFLAG;
726f6388 119 break;
ccc6cda3
JA
120 case 'c':
121 flags |= CFLAG;
122 break;
123 case 'n':
124 flags |= NFLAG;
125 break;
126 case 'r':
127 flags |= RFLAG;
128 break;
129 case 'w':
130 flags |= WFLAG;
131 break;
132 case 's':
133 flags |= SFLAG;
134 break;
bb70624e
JA
135 case 'd':
136 flags |= DFLAG;
137 delete_arg = list_optarg;
138 break;
ccc6cda3
JA
139 case 'p':
140#if defined (BANG_HISTORY)
141 flags |= PFLAG;
142#endif
143 break;
144 default:
145 builtin_usage ();
726f6388
JA
146 return (EX_USAGE);
147 }
ccc6cda3
JA
148 }
149 list = loptend;
150
151 opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG);
152 if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG)
153 {
b80f6443 154 builtin_error (_("cannot use more than one of -anrw"));
ccc6cda3
JA
155 return (EXECUTION_FAILURE);
156 }
157
158 /* clear the history, but allow other arguments to add to it again. */
159 if (flags & CFLAG)
160 {
3185942a 161 bash_clear_history ();
ccc6cda3
JA
162 if (list == 0)
163 return (EXECUTION_SUCCESS);
726f6388
JA
164 }
165
ccc6cda3
JA
166 if (flags & SFLAG)
167 {
168 if (list)
169 push_history (list);
170 return (EXECUTION_SUCCESS);
171 }
172#if defined (BANG_HISTORY)
173 else if (flags & PFLAG)
174 {
175 if (list)
28ef6c31 176 return (expand_and_print_history (list));
3185942a 177 return (sh_chkwrite (EXECUTION_SUCCESS));
ccc6cda3
JA
178 }
179#endif
bb70624e
JA
180 else if (flags & DFLAG)
181 {
f73dda09
JA
182 if ((legal_number (delete_arg, &delete_offset) == 0)
183 || (delete_offset < history_base)
184 || (delete_offset > (history_base + history_length)))
bb70624e 185 {
b80f6443 186 sh_erange (delete_arg, _("history position"));
bb70624e
JA
187 return (EXECUTION_FAILURE);
188 }
189 opt = delete_offset;
3185942a 190 result = bash_delete_histent (opt - history_base);
bb70624e
JA
191 /* Since remove_history changes history_length, this can happen if
192 we delete the last history entry. */
193 if (where_history () > history_length)
194 history_set_pos (history_length);
195 return (result ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
196 }
ccc6cda3
JA
197 else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0)
198 {
3185942a
JA
199 result = display_history (list);
200 return (sh_chkwrite (result));
ccc6cda3
JA
201 }
202
203 filename = list ? list->word->word : get_string_value ("HISTFILE");
204 result = EXECUTION_SUCCESS;
205
206 if (flags & AFLAG) /* Append session's history to file. */
207 result = maybe_append_history (filename);
208 else if (flags & WFLAG) /* Write entire history. */
209 result = write_history (filename);
210 else if (flags & RFLAG) /* Read entire file. */
211 result = read_history (filename);
212 else if (flags & NFLAG) /* Read `new' history from file. */
213 {
214 /* Read all of the lines in the file that we haven't already read. */
7117c2d2 215 old_history_lines = history_lines_in_file;
b80f6443
JA
216 obase = history_base;
217
ccc6cda3
JA
218 using_history ();
219 result = read_history_range (filename, history_lines_in_file, -1);
220 using_history ();
b80f6443 221
ccc6cda3 222 history_lines_in_file = where_history ();
95732b49
JA
223
224 /* If we're rewriting the history file at shell exit rather than just
225 appending the lines from this session to it, the question is whether
226 we reset history_lines_this_session to 0, losing any history entries
227 we had before we read the new entries from the history file, or
228 whether we count the new entries we just read from the file as
229 history lines added during this session.
b80f6443
JA
230 Right now, we do the latter. This will cause these history entries
231 to be written to the history file along with any intermediate entries
232 we add when we do a `history -a', but the alternative is losing
233 them altogether. */
95732b49
JA
234 if (force_append_history == 0)
235 history_lines_this_session += history_lines_in_file - old_history_lines +
b80f6443 236 history_base - obase;
ccc6cda3
JA
237 }
238
239 return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
240}
241
242/* Accessors for HIST_ENTRY lists that are called HLIST. */
243#define histline(i) (hlist[(i)]->line)
244#define histdata(i) (hlist[(i)]->data)
245
b80f6443
JA
246static char *
247histtime (hlist, histtimefmt)
248 HIST_ENTRY *hlist;
249 const char *histtimefmt;
250{
251 static char timestr[128];
252 time_t t;
253
254 t = history_get_time (hlist);
255 if (t)
256 strftime (timestr, sizeof (timestr), histtimefmt, localtime (&t));
257 else
258 strcpy (timestr, "??");
259 return timestr;
260}
261
3185942a 262static int
ccc6cda3
JA
263display_history (list)
264 WORD_LIST *list;
265{
266 register int i;
7117c2d2 267 intmax_t limit;
ccc6cda3 268 HIST_ENTRY **hlist;
b80f6443 269 char *histtimefmt, *timestr;
ccc6cda3 270
726f6388
JA
271 if (list)
272 {
3185942a
JA
273 if (get_numeric_arg (list, 0, &limit) == 0)
274 return (EXECUTION_FAILURE);
275
f73dda09
JA
276 if (limit < 0)
277 limit = -limit;
726f6388 278 }
ccc6cda3 279 else
f73dda09 280 limit = -1;
726f6388
JA
281
282 hlist = history_list ();
283
284 if (hlist)
285 {
ccc6cda3
JA
286 for (i = 0; hlist[i]; i++)
287 ;
726f6388 288
f73dda09
JA
289 if (0 <= limit && limit < i)
290 i -= limit;
291 else
726f6388 292 i = 0;
726f6388 293
b80f6443
JA
294 histtimefmt = get_string_value ("HISTTIMEFORMAT");
295
726f6388
JA
296 while (hlist[i])
297 {
298 QUIT;
b80f6443
JA
299
300 timestr = (histtimefmt && *histtimefmt) ? histtime (hlist[i], histtimefmt) : (char *)NULL;
301 printf ("%5d%c %s%s\n", i + history_base,
ccc6cda3 302 histdata(i) ? '*' : ' ',
b80f6443 303 ((timestr && *timestr) ? timestr : ""),
ccc6cda3 304 histline(i));
726f6388
JA
305 i++;
306 }
307 }
b80f6443 308
3185942a 309 return (EXECUTION_SUCCESS);
ccc6cda3
JA
310}
311
312/* Remove the last entry in the history list and add each argument in
313 LIST to the history. */
314static void
315push_history (list)
316 WORD_LIST *list;
317{
318 char *s;
319
7117c2d2
JA
320 /* Delete the last history entry if it was a single entry added to the
321 history list (generally the `history -s' itself), or if `history -s'
322 is being used in a compound command and the compound command was
323 added to the history as a single element (command-oriented history).
324 If you don't want history -s to remove the compound command from the
325 history, change #if 0 to #if 1 below. */
326#if 0
3185942a 327 if (hist_last_line_pushed == 0 && hist_last_line_added && bash_delete_last_history () == 0)
7117c2d2 328#else
95732b49
JA
329 if (hist_last_line_pushed == 0 &&
330 (hist_last_line_added ||
331 (current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history))
3185942a 332 && bash_delete_last_history () == 0)
7117c2d2
JA
333#endif
334 return;
335
ccc6cda3 336 s = string_list (list);
7117c2d2
JA
337 /* Call check_add_history with FORCE set to 1 to skip the check against
338 current_command_line_count. If history -s is used in a compound
339 command, the above code will delete the compound command's history
340 entry and this call will add the line to the history as a separate
341 entry. Without FORCE=1, if current_command_line_count were > 1, the
342 line would be appended to the entry before the just-deleted entry. */
343 check_add_history (s, 1); /* obeys HISTCONTROL, HISTIGNORE */
95732b49
JA
344
345 hist_last_line_pushed = 1; /* XXX */
ccc6cda3
JA
346 free (s);
347}
348
349#if defined (BANG_HISTORY)
350static int
351expand_and_print_history (list)
352 WORD_LIST *list;
353{
354 char *s;
355 int r, result;
356
3185942a 357 if (hist_last_line_pushed == 0 && hist_last_line_added && bash_delete_last_history () == 0)
ccc6cda3
JA
358 return EXECUTION_FAILURE;
359 result = EXECUTION_SUCCESS;
360 while (list)
361 {
362 r = history_expand (list->word->word, &s);
363 if (r < 0)
364 {
b80f6443 365 builtin_error (_("%s: history expansion failed"), list->word->word);
ccc6cda3
JA
366 result = EXECUTION_FAILURE;
367 }
368 else
28ef6c31 369 {
ccc6cda3
JA
370 fputs (s, stdout);
371 putchar ('\n');
28ef6c31 372 }
ccc6cda3
JA
373 FREE (s);
374 list = list->next;
375 }
376 fflush (stdout);
377 return result;
378}
379#endif /* BANG_HISTORY */
726f6388 380#endif /* HISTORY */