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 212time_t 213history_get_time (hist) 214 HIST_ENTRY *hist; 215{ 216 char *ts; 217 time_t t; 218 219 if (hist == 0 || hist->timestamp == 0) 220 return 0; 221 ts = hist->timestamp; 222 if (ts[0] != history_comment_char) 223 return 0; 224 t = (time_t) atol (ts + 1); /* XXX - should use strtol() here */ 225 return t; 226} 227 228static char * 229hist_inittime () 230{ 231 time_t t; 232 char ts[64], *ret; 233 234 t = (time_t) time ((time_t *)0); 235#if defined (HAVE_VSNPRINTF) /* assume snprintf if vsnprintf exists */ 236 snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t); 237#else 238 sprintf (ts, "X%lu", (unsigned long) t); 239#endif 240 ret = savestring (ts); 241 ret[0] = history_comment_char; 242 243 return ret; 244} 245 246/* Place STRING at the end of the history list. The data field 247 is set to NULL. */ 248void 249add_history (string) 250 const char *string; 251{ 252 HIST_ENTRY *temp; 253 254 if (history_stifled && (history_length == history_max_entries)) 255 { 256 register int i; 257 258 /* If the history is stifled, and history_length is zero, 259 and it equals history_max_entries, we don't save items. */ 260 if (history_length == 0) 261 return; 262 263 /* If there is something in the slot, then remove it. */ 264 if (the_history[0]) 265 (void) free_history_entry (the_history[0]); 266 267 /* Copy the rest of the entries, moving down one slot. */ 268 for (i = 0; i < history_length; i++) 269 the_history[i] = the_history[i + 1]; 270 271 history_base++; 272 } 273 else 274 { 275 if (history_size == 0) 276 { 277 history_size = DEFAULT_HISTORY_GROW_SIZE; 278 the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *)); 279 history_length = 1; 280 } 281 else 282 { 283 if (history_length == (history_size - 1)) 284 { 285 history_size += DEFAULT_HISTORY_GROW_SIZE; 286 the_history = (HIST_ENTRY **) 287 xrealloc (the_history, history_size * sizeof (HIST_ENTRY *)); 288 } 289 history_length++; 290 } 291 } 292 293 temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); 294 temp->line = savestring (string); 295 temp->data = (char *)NULL; 296 297 temp->timestamp = hist_inittime (); 298 299 the_history[history_length] = (HIST_ENTRY *)NULL; 300 the_history[history_length - 1] = temp; 301} 302 303/* Change the time stamp of the most recent history entry to STRING. */ 304void 305add_history_time (string) 306 const char *string; 307{ 308 HIST_ENTRY *hs; 309 310 hs = the_history[history_length - 1]; 311 FREE (hs->timestamp); 312 hs->timestamp = savestring (string); 313} 314 315/* Free HIST and return the data so the calling application can free it 316 if necessary and desired. */ 317histdata_t 318free_history_entry (hist) 319 HIST_ENTRY *hist; 320{ 321 histdata_t x; 322 323 if (hist == 0) 324 return ((histdata_t) 0); 325 FREE (hist->line); 326 FREE (hist->timestamp); 327 x = hist->data; 328 free (hist); 329 return (x); 330} 331 332/* Make the history entry at WHICH have LINE and DATA. This returns 333 the old entry so you can dispose of the data. In the case of an 334 invalid WHICH, a NULL pointer is returned. */ 335HIST_ENTRY * 336replace_history_entry (which, line, data) 337 int which; 338 const char *line; 339 histdata_t data; 340{ 341 HIST_ENTRY *temp, *old_value; 342 343 if (which < 0 || which >= history_length) 344 return ((HIST_ENTRY *)NULL); 345 346 temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); 347 old_value = the_history[which]; 348 349 temp->line = savestring (line); 350 temp->data = data; 351 temp->timestamp = savestring (old_value->timestamp); 352 the_history[which] = temp; 353 354 return (old_value); 355} 356 357/* Remove history element WHICH from the history. The removed 358 element is returned to you so you can free the line, data, 359 and containing structure. */ 360HIST_ENTRY * 361remove_history (which) 362 int which; 363{ 364 HIST_ENTRY *return_value; 365 register int i; 366 367 if (which < 0 || which >= history_length || history_length == 0 || the_history == 0) 368 return ((HIST_ENTRY *)NULL); 369 370 return_value = the_history[which]; 371 372 for (i = which; i < history_length; i++) 373 the_history[i] = the_history[i + 1]; 374 375 history_length--; 376 377 return (return_value); 378} 379 380/* Stifle the history list, remembering only MAX number of lines. */ 381void 382stifle_history (max) 383 int max; 384{ 385 register int i, j; 386 387 if (max < 0) 388 max = 0; 389 390 if (history_length > max) 391 { 392 /* This loses because we cannot free the data. */ 393 for (i = 0, j = history_length - max; i < j; i++) 394 free_history_entry (the_history[i]); 395 396 history_base = i; 397 for (j = 0, i = history_length - max; j < max; i++, j++) 398 the_history[j] = the_history[i]; 399 the_history[j] = (HIST_ENTRY *)NULL; 400 history_length = j; 401 } 402 403 history_stifled = 1; 404 max_input_history = history_max_entries = max; 405} 406 407/* Stop stifling the history. This returns the previous maximum 408 number of history entries. The value is positive if the history 409 was stifled, negative if it wasn't. */ 410int 411unstifle_history () 412{ 413 if (history_stifled) 414 { 415 history_stifled = 0; 416 return (history_max_entries); 417 } 418 else 419 return (-history_max_entries); 420} 421 422int 423history_is_stifled () 424{ 425 return (history_stifled); 426} 427 428void 429clear_history () 430{ 431 register int i; 432 433 /* This loses because we cannot free the data. */ 434 for (i = 0; i < history_length; i++) 435 { 436 free_history_entry (the_history[i]); 437 the_history[i] = (HIST_ENTRY *)NULL; 438 } 439 440 history_offset = history_length = 0; 441} 442