1 This file is history.def
, from which is created history.c.
2 It implements the builtin
"history" in Bush.
4 Copyright (C
) 1987-2020 Free Software Foundation
, Inc.
6 This file is part of GNU Bush
, the Bourne Again SHell.
8 Bush is free software
: you can redistribute it and
/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation
, either version
3 of the License
, or
11 (at your option
) any later version.
13 Bush is distributed in the hope that it will be useful
,
14 but WITHOUT ANY WARRANTY
; without even the implied warranty of
15 MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Bush. If not
, see
<http
://www.gnu.org
/licenses
/>.
24 $FUNCTION history_builtin
26 $SHORT_DOC history
[-c
] [-d offset
] [n
] or history
-anrw
[filename
] or history
-ps arg
[arg...
]
27 Display or manipulate the history list.
29 Display the history list with line numbers
, prefixing each modified
30 entry with a `
*'. An argument of N lists only the last N entries.
33 -c clear the history list by deleting all of the entries
34 -d offset delete the history entry at position OFFSET. Negative
35 offsets count back from the end of the history list
37 -a append history lines from this session to the history file
38 -n read all history lines not already read from the history file
39 and append them to the history list
40 -r read the history file and append the contents to the history
42 -w write the current history to the history file
44 -p perform history expansion on each ARG and display the result
45 without storing it in the history list
46 -s append the ARGs to the history list as a single entry
48 If FILENAME is given, it is used as the history file. Otherwise,
49 if HISTFILE has a value, that is used, else ~/.bush_history.
51 If the HISTTIMEFORMAT variable is set and not null, its value is used
52 as a format string for strftime(3) to print the time stamp associated
53 with each displayed history entry. No time stamps are printed otherwise.
56 Returns success unless an invalid option is given or an error occurs.
62 #include "../src/bushtypes.h"
63 #if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
64 # include <sys/file.h>
66 #include "posixstat.h"
70 #if defined (HAVE_UNISTD_H)
74 #include "../src/bushansi.h"
75 #include "../src/bushintl.h"
77 #include "../src/shell.h"
78 #include "../src/flags.h"
79 #include "../src/lxrgmr/parser.h"
80 #include "../src/bushhist.h"
81 #include <readline/history.h>
82 #include "bushgetopt.h"
89 static char *histtime PARAMS((HIST_ENTRY *, const char *));
90 static int display_history PARAMS((WORD_LIST *));
91 static void push_history PARAMS((WORD_LIST *));
92 static int expand_and_print_history PARAMS((WORD_LIST *));
104 history_builtin (list)
107 int flags, opt, result, old_history_lines, obase, ind;
108 char *filename, *delete_arg, *range;
109 intmax_t delete_offset;
112 reset_internal_getopt ();
113 while ((opt = internal_getopt (list, "acd:npsrw")) != -1)
137 delete_arg = list_optarg;
140 #if defined (BANG_HISTORY)
152 opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG);
153 if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG)
155 builtin_error (_("cannot use more than one of -anrw"));
156 return (EXECUTION_FAILURE);
159 /* clear the history, but allow other arguments to add to it again. */
162 bush_clear_history ();
164 return (EXECUTION_SUCCESS);
171 return (EXECUTION_SUCCESS);
173 #if defined (BANG_HISTORY)
174 else if (flags & PFLAG)
177 return (expand_and_print_history (list));
178 return (sh_chkwrite (EXECUTION_SUCCESS));
181 else if ((flags & DFLAG) && (range = strchr ((delete_arg[0] == '-') ? delete_arg + 1 : delete_arg, '-')))
183 intmax_t delete_start, delete_end;
185 if (legal_number (delete_arg, &delete_start) == 0 || legal_number (range, &delete_end) == 0)
188 sh_erange (delete_arg, _("history position"));
189 return (EXECUTION_FAILURE);
191 if (delete_arg[0] == '-' && delete_start < 0)
193 /* the_history[history_length] == 0x0, so this is correct */
194 delete_start += history_length;
195 if (delete_start < history_base)
198 sh_erange (delete_arg, _("history position"));
199 return (EXECUTION_FAILURE);
202 /* numbers as displayed by display_history are offset by history_base */
203 else if (delete_start > 0)
204 delete_start -= history_base;
205 if (delete_start < 0 || delete_start >= history_length)
207 if (range[0] == '-' && delete_end < 0)
209 delete_end += history_length;
210 if (delete_end < history_base)
213 sh_erange (range, _("history position"));
214 return (EXECUTION_FAILURE);
217 else if (delete_end > 0)
218 delete_end -= history_base;
219 if (delete_end < 0 || delete_end >= history_length)
221 result = bush_delete_history_range (delete_start, delete_end);
222 if (where_history () > history_length)
223 history_set_pos (history_length);
224 return (result ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
226 else if (flags & DFLAG)
228 if (legal_number (delete_arg, &delete_offset) == 0)
230 sh_erange (delete_arg, _("history position"));
231 return (EXECUTION_FAILURE);
233 /* check for negative offsets, count back from end of list */
234 if (delete_arg[0] == '-' && delete_offset < 0)
236 /* since the_history[history_length] == 0x0, this calculation means
237 that history -d -1 will delete the last history entry, which at
238 this point is the history -d -1 we just added. */
239 ind = history_length + delete_offset;
240 if (ind < history_base)
242 sh_erange (delete_arg, _("history position"));
243 return (EXECUTION_FAILURE);
245 opt = ind + history_base; /* compensate for opt - history_base below */
247 else if ((delete_offset < history_base) || (delete_offset >= (history_base + history_length)))
249 sh_erange (delete_arg, _("history position"));
250 return (EXECUTION_FAILURE);
255 /* Positive arguments from numbers as displayed by display_history need
256 to be offset by history_base */
257 result = bush_delete_histent (opt - history_base);
258 /* Since remove_history changes history_length, this can happen if
259 we delete the last history entry. */
260 if (where_history () > history_length)
261 history_set_pos (history_length);
262 return (result ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
264 else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0)
266 result = display_history (list);
267 return (sh_chkwrite (result));
270 filename = list ? list->word->word : get_string_value ("HISTFILE");
271 result = EXECUTION_SUCCESS;
273 #if defined (RESTRICTED_SHELL)
274 if (restricted && strchr (filename, '/'))
276 sh_restricted (filename);
277 return (EXECUTION_FAILURE);
281 if (flags & AFLAG) /* Append session's history to file.
*/
282 result
= maybe_append_history (filename
);
283 else
if (flags
& WFLAG
) /* Write entire history.
*/
284 result
= write_history (filename
);
285 else
if (flags
& RFLAG
) /* Read entire file.
*/
287 result
= read_history (filename
);
288 history_lines_in_file
= history_lines_read_from_file
;
289 /* history_lines_in_file
= where_history () + history_base
- 1; */
291 else
if (flags
& NFLAG
) /* Read `new
' history from file. */
293 /* Read all of the lines in the file that we haven't already read.
*/
294 old_history_lines
= history_lines_in_file
;
295 obase
= history_base
;
298 result
= read_history_range (filename
, history_lines_in_file
, -1);
301 history_lines_in_file
= history_lines_read_from_file
;
302 /* history_lines_in_file
= where_history () + history_base
- 1; */
304 /* If we
're rewriting the history file at shell exit rather than just
305 appending the lines from this session to it, the question is whether
306 we reset history_lines_this_session to 0, losing any history entries
307 we had before we read the new entries from the history file, or
308 whether we count the new entries we just read from the file as
309 history lines added during this session.
310 Right now, we do the latter. This will cause these history entries
311 to be written to the history file along with any intermediate entries
312 we add when we do a `history -a', but the alternative is losing
314 if (force_append_history
== 0)
315 history_lines_this_session
+= history_lines_in_file
- old_history_lines
+
316 history_base
- obase
;
319 return (result ? EXECUTION_FAILURE
: EXECUTION_SUCCESS
);
322 /* Accessors for HIST_ENTRY lists that are called HLIST.
*/
323 #define
histline(i
) (hlist
[(i
)]->line
)
324 #define
histdata(i
) (hlist
[(i
)]->data
)
327 histtime (hlist
, histtimefmt
)
329 const char
*histtimefmt
;
331 static char timestr
[128];
335 t
= history_get_time (hlist
);
336 tm
= t ?
localtime (&t
) : 0;
338 strftime (timestr
, sizeof (timestr
), histtimefmt
, tm
);
339 else
if (hlist
->timestamp
&& hlist
->timestamp
[0])
340 snprintf (timestr
, sizeof (timestr
), _("%s: invalid timestamp"),
341 (hlist
->timestamp
[0] == '#') ? hlist
->timestamp
+ 1: hlist
->timestamp
);
343 strcpy (timestr
, "??");
348 display_history (list
)
354 char
*histtimefmt
, *timestr
;
358 if (get_numeric_arg (list
, 0, &limit
) == 0)
359 return (EXECUTION_FAILURE
);
367 hlist
= history_list ();
371 for (i
= 0; hlist
[i
]; i
++)
374 if (0 <= limit
&& limit
< i
)
379 histtimefmt
= get_string_value ("HISTTIMEFORMAT");
385 timestr
= (histtimefmt
&& *histtimefmt
) ?
histtime (hlist
[i
], histtimefmt
) : (char *)NULL
;
386 printf ("%5d%c %s%s\n", i
+ history_base
,
387 histdata(i
) ?
'*' : ' ',
388 ((timestr
&& *timestr
) ? timestr
: ""),
394 return (EXECUTION_SUCCESS
);
397 /* Remove the last entry in the history list and add each argument in
398 LIST to the history.
*/
405 /* Delete the last history entry if it was a single entry added to the
406 history
list (generally the `history
-s
' itself), or if `history -s'
407 is being used in a compound command and the compound command was
408 added to the history as a single
element (command
-oriented history
).
409 If you don
't want history -s to remove the compound command from the
410 history, change #if 0 to #if 1 below. */
412 if (remember_on_history && hist_last_line_pushed == 0 &&
413 hist_last_line_added && bush_delete_last_history () == 0)
415 if (remember_on_history && hist_last_line_pushed == 0 &&
416 (hist_last_line_added ||
417 (current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history))
418 && bush_delete_last_history () == 0)
422 s = string_list (list);
423 /* Call check_add_history with FORCE set to 1 to skip the check against
424 current_command_line_count. If history -s is used in a compound
425 command, the above code will delete the compound command's history
426 entry and this call will add the line to the history as a separate
427 entry. Without FORCE
=1, if current_command_line_count were
> 1, the
428 line would be appended to the entry before the just
-deleted entry.
*/
429 check_add_history (s
, 1); /* obeys HISTCONTROL
, HISTIGNORE
*/
431 hist_last_line_pushed
= 1; /* XXX
*/
435 #if
defined (BANG_HISTORY
)
437 expand_and_print_history (list
)
443 if (hist_last_line_pushed
== 0 && hist_last_line_added
&& bush_delete_last_history () == 0)
444 return EXECUTION_FAILURE
;
445 result
= EXECUTION_SUCCESS
;
448 r
= history_expand (list
->word
->word
, &s
);
451 builtin_error (_("%s: history expansion failed"), list
->word
->word
);
452 result
= EXECUTION_FAILURE
;
465 #endif
/* BANG_HISTORY
*/