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
54static 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. */
63static 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. */
67static int history_stifled;
68
69/* The current number of slots allocated to the input_history. */
70static int history_size;
71
72/* If HISTORY_STIFLED is non-zero, then this is the maximum number of
73   entries to remember. */
74int history_max_entries;
75int max_input_history;	/* backwards compatibility */
76
77/* The current location of the interactive history pointer.  Just makes
78   life easier for outside callers. */
79int history_offset;
80
81/* The number of strings currently stored in the history list. */
82int history_length;
83
84/* The logical `base' of the history array.  It defaults to 1. */
85int history_base = 1;
86
87/* Return the current HISTORY_STATE of the history. */
88HISTORY_STATE *
89history_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. */
106void
107history_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. */
120void
121using_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. */
129int
130history_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. */
142int
143where_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. */
150int
151history_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. */
163HIST_ENTRY **
164history_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. */
171HIST_ENTRY *
172current_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. */
182HIST_ENTRY *
183previous_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. */
191HIST_ENTRY *
192next_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. */
199HIST_ENTRY *
200history_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
211HIST_ENTRY *
212alloc_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
227time_t
228history_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
243static char *
244hist_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. */
263void
264add_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. */
315void
316add_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. */
330histdata_t
331free_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  free (hist);
342  return (x);
343}
344
345HIST_ENTRY *
346copy_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. */
368HIST_ENTRY *
369replace_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. */
396void
397replace_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. */
438HIST_ENTRY *
439remove_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. */
459void
460stifle_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. */
488int
489unstifle_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
500int
501history_is_stifled ()
502{
503  return (history_stifled);
504}
505
506void
507clear_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