1 /* history.c -- standalone history library */
3 /* Copyright (C) 1989-2009 Free Software Foundation, Inc.
5 This file contains the GNU History Library (History), a set of
6 routines for managing the text of previously typed lines.
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.
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.
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/>.
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
27 #if defined (HAVE_CONFIG_H)
33 #if defined (HAVE_STDLIB_H)
36 # include "ansi_stdlib.h"
37 #endif /* HAVE_STDLIB_H */
39 #if defined (HAVE_UNISTD_H)
41 # include <sys/types.h>
51 /* The number of slots to increase the_history by. */
52 #define DEFAULT_HISTORY_GROW_SIZE 50
54 static char *hist_inittime PARAMS((void));
56 /* **************************************************************** */
58 /* History Functions */
60 /* **************************************************************** */
62 /* An array of HIST_ENTRY. This is where we store the history. */
63 static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
65 /* Non-zero means that we have enforced a limit on the amount of
66 history that we save. */
67 static int history_stifled;
69 /* The current number of slots allocated to the input_history. */
70 static int history_size;
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 */
77 /* The current location of the interactive history pointer. Just makes
78 life easier for outside callers. */
81 /* The number of strings currently stored in the history list. */
84 /* The logical `base' of the history array. It defaults to 1. */
87 /* Return the current HISTORY_STATE of the history. */
89 history_get_history_state ()
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;
100 state->flags |= HS_STIFLED;
105 /* Set the state of the current history array to STATE. */
107 history_set_history_state (state)
108 HISTORY_STATE *state;
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)
118 /* Begin a session in which the history functions might be used. This
119 initializes interactive variables. */
123 history_offset = history_length;
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
130 history_total_bytes ()
132 register int i, result;
134 for (i = result = 0; the_history && the_history[i]; i++)
135 result += HISTENT_BYTES (the_history[i]);
140 /* Returns the magic number which says what history element we are
141 looking at now. In this implementation, it returns history_offset. */
145 return (history_offset);
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. */
151 history_set_pos (pos)
154 if (pos > history_length || pos < 0 || !the_history)
156 history_offset = pos;
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. */
166 return (the_history);
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. */
174 return ((history_offset == history_length) || the_history == 0)
176 : the_history[history_offset];
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
185 return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL;
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
194 return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset];
197 /* Return the history entry which is logically at OFFSET in the history array.
198 OFFSET is relative to history_base. */
205 local_index = offset - history_base;
206 return (local_index >= history_length || local_index < 0 || the_history == 0)
208 : the_history[local_index];
212 alloc_history_entry (string, ts)
218 temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
220 temp->line = string ? savestring (string) : string;
221 temp->data = (char *)NULL;
222 temp->timestamp = ts;
228 history_get_time (hist)
234 if (hist == 0 || hist->timestamp == 0)
236 ts = hist->timestamp;
237 if (ts[0] != history_comment_char)
239 t = (time_t) atol (ts + 1); /* XXX - should use strtol() here */
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);
253 sprintf (ts, "X%lu", (unsigned long) t);
255 ret = savestring (ts);
256 ret[0] = history_comment_char;
261 /* Place STRING at the end of the history list. The data field
269 if (history_stifled && (history_length == history_max_entries))
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)
278 /* If there is something in the slot, then remove it. */
280 (void) free_history_entry (the_history[0]);
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];
290 if (history_size == 0)
292 history_size = DEFAULT_HISTORY_GROW_SIZE;
293 the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *));
298 if (history_length == (history_size - 1))
300 history_size += DEFAULT_HISTORY_GROW_SIZE;
301 the_history = (HIST_ENTRY **)
302 xrealloc (the_history, history_size * sizeof (HIST_ENTRY *));
308 temp = alloc_history_entry (string, hist_inittime ());
310 the_history[history_length] = (HIST_ENTRY *)NULL;
311 the_history[history_length - 1] = temp;
314 /* Change the time stamp of the most recent history entry to STRING. */
316 add_history_time (string)
323 hs = the_history[history_length - 1];
324 FREE (hs->timestamp);
325 hs->timestamp = savestring (string);
328 /* Free HIST and return the data so the calling application can free it
329 if necessary and desired. */
331 free_history_entry (hist)
337 return ((histdata_t) 0);
339 FREE (hist->timestamp);
346 copy_history_entry (hist)
355 ret = alloc_history_entry (hist->line, (char *)NULL);
357 ts = hist->timestamp ? savestring (hist->timestamp) : hist->timestamp;
360 ret->data = hist->data;
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. */
369 replace_history_entry (which, line, data)
374 HIST_ENTRY *temp, *old_value;
376 if (which < 0 || which >= history_length)
377 return ((HIST_ENTRY *)NULL);
379 temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
380 old_value = the_history[which];
382 temp->line = savestring (line);
384 temp->timestamp = savestring (old_value->timestamp);
385 the_history[which] = temp;
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. */
397 replace_history_data (which,old, new)
399 histdata_t *old, *new;
402 register int i, last;
404 if (which < -2 || which >= history_length || history_length == 0 || the_history == 0)
409 entry = the_history[which];
410 if (entry && entry->data == old)
416 for (i = 0; i < history_length; i++)
418 entry = the_history[i];
421 if (entry->data == old)
428 if (which == -2 && last >= 0)
430 entry = the_history[last];
431 entry->data = new; /* XXX - we don't check entry->old */
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. */
439 remove_history (which)
442 HIST_ENTRY *return_value;
445 if (which < 0 || which >= history_length || history_length == 0 || the_history == 0)
446 return ((HIST_ENTRY *)NULL);
448 return_value = the_history[which];
450 for (i = which; i < history_length; i++)
451 the_history[i] = the_history[i + 1];
455 return (return_value);
458 /* Stifle the history list, remembering only MAX number of lines. */
468 if (history_length > max)
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]);
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;
482 max_input_history = history_max_entries = max;
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. */
494 return (history_max_entries);
497 return (-history_max_entries);
501 history_is_stifled ()
503 return (history_stifled);
511 /* This loses because we cannot free the data. */
512 for (i = 0; i < history_length; i++)
514 free_history_entry (the_history[i]);
515 the_history[i] = (HIST_ENTRY *)NULL;
518 history_offset = history_length = 0;