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