1/* history.c, created from history.def. */ 2#line 23 "history.def" 3 4#line 50 "history.def" 5 6#include <config.h> 7 8#if defined (HISTORY) 9#include "../bashtypes.h" 10#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H) 11# include <sys/file.h> 12#endif 13#include "posixstat.h" 14#include "filecntl.h" 15#include <errno.h> 16#include <stdio.h> 17#if defined (HAVE_UNISTD_H) 18# include <unistd.h> 19#endif 20 21#include "../bashansi.h" 22#include "../bashintl.h" 23 24#include "../shell.h" 25#include "../bashhist.h" 26#include <readline/history.h> 27#include "bashgetopt.h" 28#include "common.h" 29 30#if !defined (errno) 31extern int errno; 32#endif 33 34extern int current_command_line_count; 35extern int force_append_history; /* shopt -s histappend */ 36 37int delete_last_history __P((void)); 38 39static char *histtime __P((HIST_ENTRY *, const char *)); 40static void display_history __P((WORD_LIST *)); 41static int delete_histent __P((int)); 42static void push_history __P((WORD_LIST *)); 43static int expand_and_print_history __P((WORD_LIST *)); 44 45#define AFLAG 0x01 46#define RFLAG 0x02 47#define WFLAG 0x04 48#define NFLAG 0x08 49#define SFLAG 0x10 50#define PFLAG 0x20 51#define CFLAG 0x40 52#define DFLAG 0x80 53 54int 55history_builtin (list) 56 WORD_LIST *list; 57{ 58 int flags, opt, result, old_history_lines, obase; 59 char *filename, *delete_arg; 60 intmax_t delete_offset; 61 62 flags = 0; 63 reset_internal_getopt (); 64 while ((opt = internal_getopt (list, "acd:npsrw")) != -1) 65 { 66 switch (opt) 67 { 68 case 'a': 69 flags |= AFLAG; 70 break; 71 case 'c': 72 flags |= CFLAG; 73 break; 74 case 'n': 75 flags |= NFLAG; 76 break; 77 case 'r': 78 flags |= RFLAG; 79 break; 80 case 'w': 81 flags |= WFLAG; 82 break; 83 case 's': 84 flags |= SFLAG; 85 break; 86 case 'd': 87 flags |= DFLAG; 88 delete_arg = list_optarg; 89 break; 90 case 'p': 91#if defined (BANG_HISTORY) 92 flags |= PFLAG; 93#endif 94 break; 95 default: 96 builtin_usage (); 97 return (EX_USAGE); 98 } 99 } 100 list = loptend; 101 102 opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG); 103 if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG) 104 { 105 builtin_error (_("cannot use more than one of -anrw")); 106 return (EXECUTION_FAILURE); 107 } 108 109 /* clear the history, but allow other arguments to add to it again. */ 110 if (flags & CFLAG) 111 { 112 clear_history (); 113 if (list == 0) 114 return (EXECUTION_SUCCESS); 115 } 116 117 if (flags & SFLAG) 118 { 119 if (list) 120 push_history (list); 121 return (EXECUTION_SUCCESS); 122 } 123#if defined (BANG_HISTORY) 124 else if (flags & PFLAG) 125 { 126 if (list) 127 return (expand_and_print_history (list)); 128 return (EXECUTION_SUCCESS); 129 } 130#endif 131 else if (flags & DFLAG) 132 { 133 if ((legal_number (delete_arg, &delete_offset) == 0) 134 || (delete_offset < history_base) 135 || (delete_offset > (history_base + history_length))) 136 { 137 sh_erange (delete_arg, _("history position")); 138 return (EXECUTION_FAILURE); 139 } 140 opt = delete_offset; 141 result = delete_histent (opt - history_base); 142 /* Since remove_history changes history_length, this can happen if 143 we delete the last history entry. */ 144 if (where_history () > history_length) 145 history_set_pos (history_length); 146 return (result ? EXECUTION_SUCCESS : EXECUTION_FAILURE); 147 } 148 else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0) 149 { 150 display_history (list); 151 return (EXECUTION_SUCCESS); 152 } 153 154 filename = list ? list->word->word : get_string_value ("HISTFILE"); 155 result = EXECUTION_SUCCESS; 156 157 if (flags & AFLAG) /* Append session's history to file. */ 158 result = maybe_append_history (filename); 159 else if (flags & WFLAG) /* Write entire history. */ 160 result = write_history (filename); 161 else if (flags & RFLAG) /* Read entire file. */ 162 result = read_history (filename); 163 else if (flags & NFLAG) /* Read `new' history from file. */ 164 { 165 /* Read all of the lines in the file that we haven't already read. */ 166 old_history_lines = history_lines_in_file; 167 obase = history_base; 168 169 using_history (); 170 result = read_history_range (filename, history_lines_in_file, -1); 171 using_history (); 172 173 history_lines_in_file = where_history (); 174 175 /* If we're rewriting the history file at shell exit rather than just 176 appending the lines from this session to it, the question is whether 177 we reset history_lines_this_session to 0, losing any history entries 178 we had before we read the new entries from the history file, or 179 whether we count the new entries we just read from the file as 180 history lines added during this session. 181 Right now, we do the latter. This will cause these history entries 182 to be written to the history file along with any intermediate entries 183 we add when we do a `history -a', but the alternative is losing 184 them altogether. */ 185 if (force_append_history == 0) 186 history_lines_this_session += history_lines_in_file - old_history_lines + 187 history_base - obase; 188 } 189 190 return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS); 191} 192 193/* Accessors for HIST_ENTRY lists that are called HLIST. */ 194#define histline(i) (hlist[(i)]->line) 195#define histdata(i) (hlist[(i)]->data) 196 197static char * 198histtime (hlist, histtimefmt) 199 HIST_ENTRY *hlist; 200 const char *histtimefmt; 201{ 202 static char timestr[128]; 203 time_t t; 204 205 t = history_get_time (hlist); 206 if (t) 207 strftime (timestr, sizeof (timestr), histtimefmt, localtime (&t)); 208 else 209 strcpy (timestr, "??"); 210 return timestr; 211} 212 213static void 214display_history (list) 215 WORD_LIST *list; 216{ 217 register int i; 218 intmax_t limit; 219 HIST_ENTRY **hlist; 220 char *histtimefmt, *timestr; 221 222 if (list) 223 { 224 limit = get_numeric_arg (list, 0); 225 if (limit < 0) 226 limit = -limit; 227 } 228 else 229 limit = -1; 230 231 hlist = history_list (); 232 233 if (hlist) 234 { 235 for (i = 0; hlist[i]; i++) 236 ; 237 238 if (0 <= limit && limit < i) 239 i -= limit; 240 else 241 i = 0; 242 243 244 histtimefmt = get_string_value ("HISTTIMEFORMAT"); 245 246 while (hlist[i]) 247 { 248 QUIT; 249 250 timestr = (histtimefmt && *histtimefmt) ? histtime (hlist[i], histtimefmt) : (char *)NULL; 251 printf ("%5d%c %s%s\n", i + history_base, 252 histdata(i) ? '*' : ' ', 253 ((timestr && *timestr) ? timestr : ""), 254 histline(i)); 255 i++; 256 } 257 } 258} 259 260/* Delete and free the history list entry at offset I. */ 261static int 262delete_histent (i) 263 int i; 264{ 265 HIST_ENTRY *discard; 266 267 discard = remove_history (i); 268 if (discard) 269 free_history_entry (discard); 270 271 return 1; 272} 273 274int 275delete_last_history () 276{ 277 register int i; 278 HIST_ENTRY **hlist, *histent; 279 int r; 280 281 hlist = history_list (); 282 if (hlist == NULL) 283 return 0; 284 285 for (i = 0; hlist[i]; i++) 286 ; 287 i--; 288 289 /* History_get () takes a parameter that must be offset by history_base. */ 290 histent = history_get (history_base + i); /* Don't free this */ 291 if (histent == NULL) 292 return 0; 293 294 r = delete_histent (i); 295 296 if (where_history () > history_length) 297 history_set_pos (history_length); 298 299 return r; 300} 301 302/* Remove the last entry in the history list and add each argument in 303 LIST to the history. */ 304static void 305push_history (list) 306 WORD_LIST *list; 307{ 308 char *s; 309 310 /* Delete the last history entry if it was a single entry added to the 311 history list (generally the `history -s' itself), or if `history -s' 312 is being used in a compound command and the compound command was 313 added to the history as a single element (command-oriented history). 314 If you don't want history -s to remove the compound command from the 315 history, change #if 0 to #if 1 below. */ 316#if 0 317 if (hist_last_line_pushed == 0 && hist_last_line_added && delete_last_history () == 0) 318#else 319 if (hist_last_line_pushed == 0 && 320 (hist_last_line_added || 321 (current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history)) 322 && delete_last_history () == 0) 323#endif 324 return; 325 326 s = string_list (list); 327 /* Call check_add_history with FORCE set to 1 to skip the check against 328 current_command_line_count. If history -s is used in a compound 329 command, the above code will delete the compound command's history 330 entry and this call will add the line to the history as a separate 331 entry. Without FORCE=1, if current_command_line_count were > 1, the 332 line would be appended to the entry before the just-deleted entry. */ 333 check_add_history (s, 1); /* obeys HISTCONTROL, HISTIGNORE */ 334 335 hist_last_line_pushed = 1; /* XXX */ 336 free (s); 337} 338 339#if defined (BANG_HISTORY) 340static int 341expand_and_print_history (list) 342 WORD_LIST *list; 343{ 344 char *s; 345 int r, result; 346 347 if (hist_last_line_pushed == 0 && hist_last_line_added && delete_last_history () == 0) 348 return EXECUTION_FAILURE; 349 result = EXECUTION_SUCCESS; 350 while (list) 351 { 352 r = history_expand (list->word->word, &s); 353 if (r < 0) 354 { 355 builtin_error (_("%s: history expansion failed"), list->word->word); 356 result = EXECUTION_FAILURE; 357 } 358 else 359 { 360 fputs (s, stdout); 361 putchar ('\n'); 362 } 363 FREE (s); 364 list = list->next; 365 } 366 fflush (stdout); 367 return result; 368} 369#endif /* BANG_HISTORY */ 370#endif /* HISTORY */ 371