1This file is history.def, from which is created history.c. 2It implements the builtin "history" in Bash. 3 4Copyright (C) 1987-2009 Free Software Foundation, Inc. 5 6This file is part of GNU Bash, the Bourne Again SHell. 7 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. 12 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. 17 18You should have received a copy of the GNU General Public License 19along with Bash. If not, see <http://www.gnu.org/licenses/>. 20 21$PRODUCES history.c 22 23$BUILTIN history 24$FUNCTION history_builtin 25$DEPENDS_ON HISTORY 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, 48if $HISTFILE has a value, that is used, else ~/.bash_history. 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. 53 54Exit Status: 55Returns success unless an invalid option is given or an error occurs. 56$END 57 58#include <config.h> 59 60#if defined (HISTORY) 61#include "../bashtypes.h" 62#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H) 63# include <sys/file.h> 64#endif 65#include "posixstat.h" 66#include "filecntl.h" 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" 74#include "../bashintl.h" 75 76#include "../shell.h" 77#include "../bashhist.h" 78#include <readline/history.h> 79#include "bashgetopt.h" 80#include "common.h" 81 82#if !defined (errno) 83extern int errno; 84#endif 85 86extern int current_command_line_count; 87extern int force_append_history; /* shopt -s histappend */ 88 89static char *histtime __P((HIST_ENTRY *, const char *)); 90static int display_history __P((WORD_LIST *)); 91static void push_history __P((WORD_LIST *)); 92static int expand_and_print_history __P((WORD_LIST *)); 93 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 101#define DFLAG 0x80 102 103int 104history_builtin (list) 105 WORD_LIST *list; 106{ 107 int flags, opt, result, old_history_lines, obase; 108 char *filename, *delete_arg; 109 intmax_t delete_offset; 110 111 flags = 0; 112 reset_internal_getopt (); 113 while ((opt = internal_getopt (list, "acd:npsrw")) != -1) 114 { 115 switch (opt) 116 { 117 case 'a': 118 flags |= AFLAG; 119 break; 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; 135 case 'd': 136 flags |= DFLAG; 137 delete_arg = list_optarg; 138 break; 139 case 'p': 140#if defined (BANG_HISTORY) 141 flags |= PFLAG; 142#endif 143 break; 144 default: 145 builtin_usage (); 146 return (EX_USAGE); 147 } 148 } 149 list = loptend; 150 151 opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG); 152 if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG) 153 { 154 builtin_error (_("cannot use more than one of -anrw")); 155 return (EXECUTION_FAILURE); 156 } 157 158 /* clear the history, but allow other arguments to add to it again. */ 159 if (flags & CFLAG) 160 { 161 bash_clear_history (); 162 if (list == 0) 163 return (EXECUTION_SUCCESS); 164 } 165 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) 176 return (expand_and_print_history (list)); 177 return (sh_chkwrite (EXECUTION_SUCCESS)); 178 } 179#endif 180 else if (flags & DFLAG) 181 { 182 if ((legal_number (delete_arg, &delete_offset) == 0) 183 || (delete_offset < history_base) 184 || (delete_offset > (history_base + history_length))) 185 { 186 sh_erange (delete_arg, _("history position")); 187 return (EXECUTION_FAILURE); 188 } 189 opt = delete_offset; 190 result = bash_delete_histent (opt - history_base); 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 } 197 else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0) 198 { 199 result = display_history (list); 200 return (sh_chkwrite (result)); 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. */ 215 old_history_lines = history_lines_in_file; 216 obase = history_base; 217 218 using_history (); 219 result = read_history_range (filename, history_lines_in_file, -1); 220 using_history (); 221 222 history_lines_in_file = where_history (); 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. 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. */ 234 if (force_append_history == 0) 235 history_lines_this_session += history_lines_in_file - old_history_lines + 236 history_base - obase; 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 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 262static int 263display_history (list) 264 WORD_LIST *list; 265{ 266 register int i; 267 intmax_t limit; 268 HIST_ENTRY **hlist; 269 char *histtimefmt, *timestr; 270 271 if (list) 272 { 273 if (get_numeric_arg (list, 0, &limit) == 0) 274 return (EXECUTION_FAILURE); 275 276 if (limit < 0) 277 limit = -limit; 278 } 279 else 280 limit = -1; 281 282 hlist = history_list (); 283 284 if (hlist) 285 { 286 for (i = 0; hlist[i]; i++) 287 ; 288 289 if (0 <= limit && limit < i) 290 i -= limit; 291 else 292 i = 0; 293 294 histtimefmt = get_string_value ("HISTTIMEFORMAT"); 295 296 while (hlist[i]) 297 { 298 QUIT; 299 300 timestr = (histtimefmt && *histtimefmt) ? histtime (hlist[i], histtimefmt) : (char *)NULL; 301 printf ("%5d%c %s%s\n", i + history_base, 302 histdata(i) ? '*' : ' ', 303 ((timestr && *timestr) ? timestr : ""), 304 histline(i)); 305 i++; 306 } 307 } 308 309 return (EXECUTION_SUCCESS); 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 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 327 if (hist_last_line_pushed == 0 && hist_last_line_added && bash_delete_last_history () == 0) 328#else 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)) 332 && bash_delete_last_history () == 0) 333#endif 334 return; 335 336 s = string_list (list); 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 */ 344 345 hist_last_line_pushed = 1; /* XXX */ 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 357 if (hist_last_line_pushed == 0 && hist_last_line_added && bash_delete_last_history () == 0) 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 { 365 builtin_error (_("%s: history expansion failed"), list->word->word); 366 result = EXECUTION_FAILURE; 367 } 368 else 369 { 370 fputs (s, stdout); 371 putchar ('\n'); 372 } 373 FREE (s); 374 list = list->next; 375 } 376 fflush (stdout); 377 return result; 378} 379#endif /* BANG_HISTORY */ 380#endif /* HISTORY */ 381