Merge from vendor branch NTPD:
[dragonfly.git] / contrib / readline-5.0 / history.c
1 /* history.c -- standalone history library */
2
3 /* Copyright (C) 1989-2003 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
55 static 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. */
64 static 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. */
68 static int history_stifled;
69
70 /* The current number of slots allocated to the input_history. */
71 static int history_size;
72
73 /* If HISTORY_STIFLED is non-zero, then this is the maximum number of
74    entries to remember. */
75 int history_max_entries;
76 int max_input_history;  /* backwards compatibility */
77
78 /* The current location of the interactive history pointer.  Just makes
79    life easier for outside callers. */
80 int history_offset;
81
82 /* The number of strings currently stored in the history list. */
83 int history_length;
84
85 /* The logical `base' of the history array.  It defaults to 1. */
86 int history_base = 1;
87
88 /* Return the current HISTORY_STATE of the history. */
89 HISTORY_STATE *
90 history_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. */
107 void
108 history_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. */
121 void
122 using_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. */
130 int
131 history_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. */
143 int
144 where_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. */
151 int
152 history_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. */
164 HIST_ENTRY **
165 history_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. */
172 HIST_ENTRY *
173 current_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. */
183 HIST_ENTRY *
184 previous_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. */
192 HIST_ENTRY *
193 next_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. */
200 HIST_ENTRY *
201 history_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)
208                 ? (HIST_ENTRY *)NULL
209                 : the_history[local_index];
210 }
211
212 time_t
213 history_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
228 static char *
229 hist_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. */
248 void
249 add_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. */
304 void
305 add_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. */
317 histdata_t
318 free_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. */
335 HIST_ENTRY *
336 replace_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 >= 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. */
360 HIST_ENTRY *
361 remove_history (which)
362      int which;
363 {
364   HIST_ENTRY *return_value;
365   register int i;
366
367   if (which >= history_length || !history_length)
368     return_value = (HIST_ENTRY *)NULL;
369   else
370     {
371       return_value = the_history[which];
372
373       for (i = which; i < history_length; i++)
374         the_history[i] = the_history[i + 1];
375
376       history_length--;
377     }
378
379   return (return_value);
380 }
381
382 /* Stifle the history list, remembering only MAX number of lines. */
383 void
384 stifle_history (max)
385      int max;
386 {
387   register int i, j;
388
389   if (max < 0)
390     max = 0;
391
392   if (history_length > max)
393     {
394       /* This loses because we cannot free the data. */
395       for (i = 0, j = history_length - max; i < j; i++)
396         free_history_entry (the_history[i]);
397
398       history_base = i;
399       for (j = 0, i = history_length - max; j < max; i++, j++)
400         the_history[j] = the_history[i];
401       the_history[j] = (HIST_ENTRY *)NULL;
402       history_length = j;
403     }
404
405   history_stifled = 1;
406   max_input_history = history_max_entries = max;
407 }
408
409 /* Stop stifling the history.  This returns the previous maximum
410    number of history entries.  The value is positive if the history
411    was stifled,  negative if it wasn't. */
412 int
413 unstifle_history ()
414 {
415   if (history_stifled)
416     {
417       history_stifled = 0;
418       return (history_max_entries);
419     }
420   else
421     return (-history_max_entries);
422 }
423
424 int
425 history_is_stifled ()
426 {
427   return (history_stifled);
428 }
429
430 void
431 clear_history ()
432 {
433   register int i;
434
435   /* This loses because we cannot free the data. */
436   for (i = 0; i < history_length; i++)
437     {
438       free_history_entry (the_history[i]);
439       the_history[i] = (HIST_ENTRY *)NULL;
440     }
441
442   history_offset = history_length = 0;
443 }