1 /* history.c -- standalone history library */ 2 3 /* Copyright (C) 1989-2009 Free Software Foundation, Inc. 4 5 This file contains the GNU History Library (History), a set of 6 routines for managing the text of previously typed lines. 7 8 History 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. 12 13 History 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. 17 18 You should have received a copy of the GNU General Public License 19 along with History. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 22 /* The goal is to make the implementation transparent, so that you 23 don't have to know what data types are used, just what functions 24 you can call. I think I have done that. */ 25 #define READLINE_LIBRARY 26 27 #if defined (HAVE_CONFIG_H) 28 # include <config.h> 29 #endif 30 31 #include <stdio.h> 32 33 #if defined (HAVE_STDLIB_H) 34 # include <stdlib.h> 35 #else 36 # include "ansi_stdlib.h" 37 #endif /* HAVE_STDLIB_H */ 38 39 #if defined (HAVE_UNISTD_H) 40 # ifdef _MINIX 41 # include <sys/types.h> 42 # endif 43 # include <unistd.h> 44 #endif 45 46 #include "history.h" 47 #include "histlib.h" 48 49 #include "xmalloc.h" 50 51 /* The number of slots to increase the_history by. */ 52 #define DEFAULT_HISTORY_GROW_SIZE 50 53 54 static char *hist_inittime PARAMS((void)); 55 56 /* **************************************************************** */ 57 /* */ 58 /* History Functions */ 59 /* */ 60 /* **************************************************************** */ 61 62 /* An array of HIST_ENTRY. This is where we store the history. */ 63 static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL; 64 65 /* Non-zero means that we have enforced a limit on the amount of 66 history that we save. */ 67 static int history_stifled; 68 69 /* The current number of slots allocated to the input_history. */ 70 static int history_size; 71 72 /* If HISTORY_STIFLED is non-zero, then this is the maximum number of 73 entries to remember. */ 74 int history_max_entries; 75 int max_input_history; /* backwards compatibility */ 76 77 /* The current location of the interactive history pointer. Just makes 78 life easier for outside callers. */ 79 int history_offset; 80 81 /* The number of strings currently stored in the history list. */ 82 int history_length; 83 84 /* The logical `base' of the history array. It defaults to 1. */ 85 int history_base = 1; 86 87 /* Return the current HISTORY_STATE of the history. */ 88 HISTORY_STATE * 89 history_get_history_state () 90 { 91 HISTORY_STATE *state; 92 93 state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE)); 94 state->entries = the_history; 95 state->offset = history_offset; 96 state->length = history_length; 97 state->size = history_size; 98 state->flags = 0; 99 if (history_stifled) 100 state->flags |= HS_STIFLED; 101 102 return (state); 103 } 104 105 /* Set the state of the current history array to STATE. */ 106 void 107 history_set_history_state (state) 108 HISTORY_STATE *state; 109 { 110 the_history = state->entries; 111 history_offset = state->offset; 112 history_length = state->length; 113 history_size = state->size; 114 if (state->flags & HS_STIFLED) 115 history_stifled = 1; 116 } 117 118 /* Begin a session in which the history functions might be used. This 119 initializes interactive variables. */ 120 void 121 using_history () 122 { 123 history_offset = history_length; 124 } 125 126 /* Return the number of bytes that the primary history entries are using. 127 This just adds up the lengths of the_history->lines and the associated 128 timestamps. */ 129 int 130 history_total_bytes () 131 { 132 register int i, result; 133 134 for (i = result = 0; the_history && the_history[i]; i++) 135 result += HISTENT_BYTES (the_history[i]); 136 137 return (result); 138 } 139 140 /* Returns the magic number which says what history element we are 141 looking at now. In this implementation, it returns history_offset. */ 142 int 143 where_history () 144 { 145 return (history_offset); 146 } 147 148 /* Make the current history item be the one at POS, an absolute index. 149 Returns zero if POS is out of range, else non-zero. */ 150 int 151 history_set_pos (pos) 152 int pos; 153 { 154 if (pos > history_length || pos < 0 || !the_history) 155 return (0); 156 history_offset = pos; 157 return (1); 158 } 159 160 /* Return the current history array. The caller has to be careful, since this 161 is the actual array of data, and could be bashed or made corrupt easily. 162 The array is terminated with a NULL pointer. */ 163 HIST_ENTRY ** 164 history_list () 165 { 166 return (the_history); 167 } 168 169 /* Return the history entry at the current position, as determined by 170 history_offset. If there is no entry there, return a NULL pointer. */ 171 HIST_ENTRY * 172 current_history () 173 { 174 return ((history_offset == history_length) || the_history == 0) 175 ? (HIST_ENTRY *)NULL 176 : the_history[history_offset]; 177 } 178 179 /* Back up history_offset to the previous history entry, and return 180 a pointer to that entry. If there is no previous entry then return 181 a NULL pointer. */ 182 HIST_ENTRY * 183 previous_history () 184 { 185 return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL; 186 } 187 188 /* Move history_offset forward to the next history entry, and return 189 a pointer to that entry. If there is no next entry then return a 190 NULL pointer. */ 191 HIST_ENTRY * 192 next_history () 193 { 194 return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset]; 195 } 196 197 /* Return the history entry which is logically at OFFSET in the history array. 198 OFFSET is relative to history_base. */ 199 HIST_ENTRY * 200 history_get (offset) 201 int offset; 202 { 203 int local_index; 204 205 local_index = offset - history_base; 206 return (local_index >= history_length || local_index < 0 || the_history == 0) 207 ? (HIST_ENTRY *)NULL 208 : the_history[local_index]; 209 } 210 211 HIST_ENTRY * 212 alloc_history_entry (string, ts) 213 char *string; 214 char *ts; 215 { 216 HIST_ENTRY *temp; 217 218 temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); 219 220 temp->line = string ? savestring (string) : string; 221 temp->data = (char *)NULL; 222 temp->timestamp = ts; 223 224 return temp; 225 } 226 227 time_t 228 history_get_time (hist) 229 HIST_ENTRY *hist; 230 { 231 char *ts; 232 time_t t; 233 234 if (hist == 0 || hist->timestamp == 0) 235 return 0; 236 ts = hist->timestamp; 237 if (ts[0] != history_comment_char) 238 return 0; 239 t = (time_t) atol (ts + 1); /* XXX - should use strtol() here */ 240 return t; 241 } 242 243 static char * 244 hist_inittime () 245 { 246 time_t t; 247 char ts[64], *ret; 248 249 t = (time_t) time ((time_t *)0); 250 #if defined (HAVE_VSNPRINTF) /* assume snprintf if vsnprintf exists */ 251 snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t); 252 #else 253 sprintf (ts, "X%lu", (unsigned long) t); 254 #endif 255 ret = savestring (ts); 256 ret[0] = history_comment_char; 257 258 return ret; 259 } 260 261 /* Place STRING at the end of the history list. The data field 262 is set to NULL. */ 263 void 264 add_history (string) 265 const char *string; 266 { 267 HIST_ENTRY *temp; 268 269 if (history_stifled && (history_length == history_max_entries)) 270 { 271 register int i; 272 273 /* If the history is stifled, and history_length is zero, 274 and it equals history_max_entries, we don't save items. */ 275 if (history_length == 0) 276 return; 277 278 /* If there is something in the slot, then remove it. */ 279 if (the_history[0]) 280 (void) free_history_entry (the_history[0]); 281 282 /* Copy the rest of the entries, moving down one slot. */ 283 for (i = 0; i < history_length; i++) 284 the_history[i] = the_history[i + 1]; 285 286 history_base++; 287 } 288 else 289 { 290 if (history_size == 0) 291 { 292 history_size = DEFAULT_HISTORY_GROW_SIZE; 293 the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *)); 294 history_length = 1; 295 } 296 else 297 { 298 if (history_length == (history_size - 1)) 299 { 300 history_size += DEFAULT_HISTORY_GROW_SIZE; 301 the_history = (HIST_ENTRY **) 302 xrealloc (the_history, history_size * sizeof (HIST_ENTRY *)); 303 } 304 history_length++; 305 } 306 } 307 308 temp = alloc_history_entry (string, hist_inittime ()); 309 310 the_history[history_length] = (HIST_ENTRY *)NULL; 311 the_history[history_length - 1] = temp; 312 } 313 314 /* Change the time stamp of the most recent history entry to STRING. */ 315 void 316 add_history_time (string) 317 const char *string; 318 { 319 HIST_ENTRY *hs; 320 321 if (string == 0) 322 return; 323 hs = the_history[history_length - 1]; 324 FREE (hs->timestamp); 325 hs->timestamp = savestring (string); 326 } 327 328 /* Free HIST and return the data so the calling application can free it 329 if necessary and desired. */ 330 histdata_t 331 free_history_entry (hist) 332 HIST_ENTRY *hist; 333 { 334 histdata_t x; 335 336 if (hist == 0) 337 return ((histdata_t) 0); 338 FREE (hist->line); 339 FREE (hist->timestamp); 340 x = hist->data; 341 xfree (hist); 342 return (x); 343 } 344 345 HIST_ENTRY * 346 copy_history_entry (hist) 347 HIST_ENTRY *hist; 348 { 349 HIST_ENTRY *ret; 350 char *ts; 351 352 if (hist == 0) 353 return hist; 354 355 ret = alloc_history_entry (hist->line, (char *)NULL); 356 357 ts = hist->timestamp ? savestring (hist->timestamp) : hist->timestamp; 358 ret->timestamp = ts; 359 360 ret->data = hist->data; 361 362 return ret; 363 } 364 365 /* Make the history entry at WHICH have LINE and DATA. This returns 366 the old entry so you can dispose of the data. In the case of an 367 invalid WHICH, a NULL pointer is returned. */ 368 HIST_ENTRY * 369 replace_history_entry (which, line, data) 370 int which; 371 const char *line; 372 histdata_t data; 373 { 374 HIST_ENTRY *temp, *old_value; 375 376 if (which < 0 || which >= history_length) 377 return ((HIST_ENTRY *)NULL); 378 379 temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); 380 old_value = the_history[which]; 381 382 temp->line = savestring (line); 383 temp->data = data; 384 temp->timestamp = savestring (old_value->timestamp); 385 the_history[which] = temp; 386 387 return (old_value); 388 } 389 390 /* Replace the DATA in the specified history entries, replacing OLD with 391 NEW. WHICH says which one(s) to replace: WHICH == -1 means to replace 392 all of the history entries where entry->data == OLD; WHICH == -2 means 393 to replace the `newest' history entry where entry->data == OLD; and 394 WHICH >= 0 means to replace that particular history entry's data, as 395 long as it matches OLD. */ 396 void 397 replace_history_data (which,old, new) 398 int which; 399 histdata_t *old, *new; 400 { 401 HIST_ENTRY *entry; 402 register int i, last; 403 404 if (which < -2 || which >= history_length || history_length == 0 || the_history == 0) 405 return; 406 407 if (which >= 0) 408 { 409 entry = the_history[which]; 410 if (entry && entry->data == old) 411 entry->data = new; 412 return; 413 } 414 415 last = -1; 416 for (i = 0; i < history_length; i++) 417 { 418 entry = the_history[i]; 419 if (entry == 0) 420 continue; 421 if (entry->data == old) 422 { 423 last = i; 424 if (which == -1) 425 entry->data = new; 426 } 427 } 428 if (which == -2 && last >= 0) 429 { 430 entry = the_history[last]; 431 entry->data = new; /* XXX - we don't check entry->old */ 432 } 433 } 434 435 /* Remove history element WHICH from the history. The removed 436 element is returned to you so you can free the line, data, 437 and containing structure. */ 438 HIST_ENTRY * 439 remove_history (which) 440 int which; 441 { 442 HIST_ENTRY *return_value; 443 register int i; 444 445 if (which < 0 || which >= history_length || history_length == 0 || the_history == 0) 446 return ((HIST_ENTRY *)NULL); 447 448 return_value = the_history[which]; 449 450 for (i = which; i < history_length; i++) 451 the_history[i] = the_history[i + 1]; 452 453 history_length--; 454 455 return (return_value); 456 } 457 458 /* Stifle the history list, remembering only MAX number of lines. */ 459 void 460 stifle_history (max) 461 int max; 462 { 463 register int i, j; 464 465 if (max < 0) 466 max = 0; 467 468 if (history_length > max) 469 { 470 /* This loses because we cannot free the data. */ 471 for (i = 0, j = history_length - max; i < j; i++) 472 free_history_entry (the_history[i]); 473 474 history_base = i; 475 for (j = 0, i = history_length - max; j < max; i++, j++) 476 the_history[j] = the_history[i]; 477 the_history[j] = (HIST_ENTRY *)NULL; 478 history_length = j; 479 } 480 481 history_stifled = 1; 482 max_input_history = history_max_entries = max; 483 } 484 485 /* Stop stifling the history. This returns the previous maximum 486 number of history entries. The value is positive if the history 487 was stifled, negative if it wasn't. */ 488 int 489 unstifle_history () 490 { 491 if (history_stifled) 492 { 493 history_stifled = 0; 494 return (history_max_entries); 495 } 496 else 497 return (-history_max_entries); 498 } 499 500 int 501 history_is_stifled () 502 { 503 return (history_stifled); 504 } 505 506 void 507 clear_history () 508 { 509 register int i; 510 511 /* This loses because we cannot free the data. */ 512 for (i = 0; i < history_length; i++) 513 { 514 free_history_entry (the_history[i]); 515 the_history[i] = (HIST_ENTRY *)NULL; 516 } 517 518 history_offset = history_length = 0; 519 } 520