Annotation of embedaddon/readline/history.c, revision 1.1
1.1 ! misho 1: /* history.c -- standalone history library */
! 2:
! 3: /* Copyright (C) 1989-2011 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) strtol (ts + 1, (char **)NULL, 10); /* 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 || history_length < 1)
! 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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>