Annotation of embedaddon/readline/history.c, revision 1.1.1.2
1.1 misho 1: /* history.c -- standalone history library */
2:
1.1.1.2 ! misho 3: /* Copyright (C) 1989-2017 Free Software Foundation, Inc.
1.1 misho 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:
1.1.1.2 ! misho 46: #include <errno.h>
! 47:
1.1 misho 48: #include "history.h"
49: #include "histlib.h"
50:
51: #include "xmalloc.h"
52:
1.1.1.2 ! misho 53: #if !defined (errno)
! 54: extern int errno;
! 55: #endif
! 56:
! 57: /* How big to make the_history when we first allocate it. */
! 58: #define DEFAULT_HISTORY_INITIAL_SIZE 502
! 59:
! 60: #define MAX_HISTORY_INITIAL_SIZE 8192
! 61:
1.1 misho 62: /* The number of slots to increase the_history by. */
63: #define DEFAULT_HISTORY_GROW_SIZE 50
64:
65: static char *hist_inittime PARAMS((void));
66:
67: /* **************************************************************** */
68: /* */
69: /* History Functions */
70: /* */
71: /* **************************************************************** */
72:
73: /* An array of HIST_ENTRY. This is where we store the history. */
74: static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
75:
76: /* Non-zero means that we have enforced a limit on the amount of
77: history that we save. */
78: static int history_stifled;
79:
80: /* The current number of slots allocated to the input_history. */
81: static int history_size;
82:
83: /* If HISTORY_STIFLED is non-zero, then this is the maximum number of
84: entries to remember. */
85: int history_max_entries;
86: int max_input_history; /* backwards compatibility */
87:
88: /* The current location of the interactive history pointer. Just makes
89: life easier for outside callers. */
90: int history_offset;
91:
92: /* The number of strings currently stored in the history list. */
93: int history_length;
94:
95: /* The logical `base' of the history array. It defaults to 1. */
96: int history_base = 1;
97:
98: /* Return the current HISTORY_STATE of the history. */
99: HISTORY_STATE *
1.1.1.2 ! misho 100: history_get_history_state (void)
1.1 misho 101: {
102: HISTORY_STATE *state;
103:
104: state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE));
105: state->entries = the_history;
106: state->offset = history_offset;
107: state->length = history_length;
108: state->size = history_size;
109: state->flags = 0;
110: if (history_stifled)
111: state->flags |= HS_STIFLED;
112:
113: return (state);
114: }
115:
116: /* Set the state of the current history array to STATE. */
117: void
1.1.1.2 ! misho 118: history_set_history_state (HISTORY_STATE *state)
1.1 misho 119: {
120: the_history = state->entries;
121: history_offset = state->offset;
122: history_length = state->length;
123: history_size = state->size;
124: if (state->flags & HS_STIFLED)
125: history_stifled = 1;
126: }
127:
128: /* Begin a session in which the history functions might be used. This
129: initializes interactive variables. */
130: void
1.1.1.2 ! misho 131: using_history (void)
1.1 misho 132: {
133: history_offset = history_length;
134: }
135:
136: /* Return the number of bytes that the primary history entries are using.
137: This just adds up the lengths of the_history->lines and the associated
138: timestamps. */
139: int
1.1.1.2 ! misho 140: history_total_bytes (void)
1.1 misho 141: {
142: register int i, result;
143:
144: for (i = result = 0; the_history && the_history[i]; i++)
145: result += HISTENT_BYTES (the_history[i]);
146:
147: return (result);
148: }
149:
150: /* Returns the magic number which says what history element we are
151: looking at now. In this implementation, it returns history_offset. */
152: int
1.1.1.2 ! misho 153: where_history (void)
1.1 misho 154: {
155: return (history_offset);
156: }
157:
158: /* Make the current history item be the one at POS, an absolute index.
159: Returns zero if POS is out of range, else non-zero. */
160: int
1.1.1.2 ! misho 161: history_set_pos (int pos)
1.1 misho 162: {
163: if (pos > history_length || pos < 0 || !the_history)
164: return (0);
165: history_offset = pos;
166: return (1);
167: }
168:
169: /* Return the current history array. The caller has to be careful, since this
170: is the actual array of data, and could be bashed or made corrupt easily.
171: The array is terminated with a NULL pointer. */
172: HIST_ENTRY **
1.1.1.2 ! misho 173: history_list (void)
1.1 misho 174: {
175: return (the_history);
176: }
177:
178: /* Return the history entry at the current position, as determined by
179: history_offset. If there is no entry there, return a NULL pointer. */
180: HIST_ENTRY *
1.1.1.2 ! misho 181: current_history (void)
1.1 misho 182: {
183: return ((history_offset == history_length) || the_history == 0)
184: ? (HIST_ENTRY *)NULL
185: : the_history[history_offset];
186: }
187:
188: /* Back up history_offset to the previous history entry, and return
189: a pointer to that entry. If there is no previous entry then return
190: a NULL pointer. */
191: HIST_ENTRY *
1.1.1.2 ! misho 192: previous_history (void)
1.1 misho 193: {
194: return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL;
195: }
196:
197: /* Move history_offset forward to the next history entry, and return
198: a pointer to that entry. If there is no next entry then return a
199: NULL pointer. */
200: HIST_ENTRY *
1.1.1.2 ! misho 201: next_history (void)
1.1 misho 202: {
203: return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset];
204: }
205:
206: /* Return the history entry which is logically at OFFSET in the history array.
207: OFFSET is relative to history_base. */
208: HIST_ENTRY *
1.1.1.2 ! misho 209: history_get (int offset)
1.1 misho 210: {
211: int local_index;
212:
213: local_index = offset - history_base;
214: return (local_index >= history_length || local_index < 0 || the_history == 0)
215: ? (HIST_ENTRY *)NULL
216: : the_history[local_index];
217: }
218:
219: HIST_ENTRY *
1.1.1.2 ! misho 220: alloc_history_entry (char *string, char *ts)
1.1 misho 221: {
222: HIST_ENTRY *temp;
223:
224: temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
225:
226: temp->line = string ? savestring (string) : string;
227: temp->data = (char *)NULL;
228: temp->timestamp = ts;
229:
230: return temp;
231: }
232:
233: time_t
1.1.1.2 ! misho 234: history_get_time (HIST_ENTRY *hist)
1.1 misho 235: {
236: char *ts;
237: time_t t;
238:
239: if (hist == 0 || hist->timestamp == 0)
240: return 0;
241: ts = hist->timestamp;
242: if (ts[0] != history_comment_char)
243: return 0;
1.1.1.2 ! misho 244: errno = 0;
1.1 misho 245: t = (time_t) strtol (ts + 1, (char **)NULL, 10); /* XXX - should use strtol() here */
1.1.1.2 ! misho 246: if (errno == ERANGE)
! 247: return (time_t)0;
1.1 misho 248: return t;
249: }
250:
251: static char *
1.1.1.2 ! misho 252: hist_inittime (void)
1.1 misho 253: {
254: time_t t;
255: char ts[64], *ret;
256:
257: t = (time_t) time ((time_t *)0);
258: #if defined (HAVE_VSNPRINTF) /* assume snprintf if vsnprintf exists */
259: snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t);
260: #else
261: sprintf (ts, "X%lu", (unsigned long) t);
262: #endif
263: ret = savestring (ts);
264: ret[0] = history_comment_char;
265:
266: return ret;
267: }
268:
269: /* Place STRING at the end of the history list. The data field
270: is set to NULL. */
271: void
1.1.1.2 ! misho 272: add_history (const char *string)
1.1 misho 273: {
274: HIST_ENTRY *temp;
1.1.1.2 ! misho 275: int new_length;
1.1 misho 276:
277: if (history_stifled && (history_length == history_max_entries))
278: {
279: register int i;
280:
281: /* If the history is stifled, and history_length is zero,
282: and it equals history_max_entries, we don't save items. */
283: if (history_length == 0)
284: return;
285:
286: /* If there is something in the slot, then remove it. */
287: if (the_history[0])
288: (void) free_history_entry (the_history[0]);
289:
1.1.1.2 ! misho 290: /* Copy the rest of the entries, moving down one slot. Copy includes
! 291: trailing NULL. */
! 292: memmove (the_history, the_history + 1, history_length * sizeof (HIST_ENTRY *));
1.1 misho 293:
1.1.1.2 ! misho 294: new_length = history_length;
1.1 misho 295: history_base++;
296: }
297: else
298: {
299: if (history_size == 0)
300: {
1.1.1.2 ! misho 301: if (history_stifled && history_max_entries > 0)
! 302: history_size = (history_max_entries > MAX_HISTORY_INITIAL_SIZE)
! 303: ? MAX_HISTORY_INITIAL_SIZE
! 304: : history_max_entries + 2;
! 305: else
! 306: history_size = DEFAULT_HISTORY_INITIAL_SIZE;
1.1 misho 307: the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *));
1.1.1.2 ! misho 308: new_length = 1;
1.1 misho 309: }
310: else
311: {
312: if (history_length == (history_size - 1))
313: {
314: history_size += DEFAULT_HISTORY_GROW_SIZE;
315: the_history = (HIST_ENTRY **)
316: xrealloc (the_history, history_size * sizeof (HIST_ENTRY *));
317: }
1.1.1.2 ! misho 318: new_length = history_length + 1;
1.1 misho 319: }
320: }
321:
1.1.1.2 ! misho 322: temp = alloc_history_entry ((char *)string, hist_inittime ());
1.1 misho 323:
1.1.1.2 ! misho 324: the_history[new_length] = (HIST_ENTRY *)NULL;
! 325: the_history[new_length - 1] = temp;
! 326: history_length = new_length;
1.1 misho 327: }
328:
329: /* Change the time stamp of the most recent history entry to STRING. */
330: void
1.1.1.2 ! misho 331: add_history_time (const char *string)
1.1 misho 332: {
333: HIST_ENTRY *hs;
334:
335: if (string == 0 || history_length < 1)
336: return;
337: hs = the_history[history_length - 1];
338: FREE (hs->timestamp);
339: hs->timestamp = savestring (string);
340: }
341:
342: /* Free HIST and return the data so the calling application can free it
343: if necessary and desired. */
344: histdata_t
1.1.1.2 ! misho 345: free_history_entry (HIST_ENTRY *hist)
1.1 misho 346: {
347: histdata_t x;
348:
349: if (hist == 0)
350: return ((histdata_t) 0);
351: FREE (hist->line);
352: FREE (hist->timestamp);
353: x = hist->data;
354: xfree (hist);
355: return (x);
356: }
357:
358: HIST_ENTRY *
1.1.1.2 ! misho 359: copy_history_entry (HIST_ENTRY *hist)
1.1 misho 360: {
361: HIST_ENTRY *ret;
362: char *ts;
363:
364: if (hist == 0)
365: return hist;
366:
367: ret = alloc_history_entry (hist->line, (char *)NULL);
368:
369: ts = hist->timestamp ? savestring (hist->timestamp) : hist->timestamp;
370: ret->timestamp = ts;
371:
372: ret->data = hist->data;
373:
374: return ret;
375: }
376:
377: /* Make the history entry at WHICH have LINE and DATA. This returns
378: the old entry so you can dispose of the data. In the case of an
379: invalid WHICH, a NULL pointer is returned. */
380: HIST_ENTRY *
1.1.1.2 ! misho 381: replace_history_entry (int which, const char *line, histdata_t data)
1.1 misho 382: {
383: HIST_ENTRY *temp, *old_value;
384:
385: if (which < 0 || which >= history_length)
386: return ((HIST_ENTRY *)NULL);
387:
388: temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
389: old_value = the_history[which];
390:
391: temp->line = savestring (line);
392: temp->data = data;
393: temp->timestamp = savestring (old_value->timestamp);
394: the_history[which] = temp;
395:
396: return (old_value);
397: }
398:
1.1.1.2 ! misho 399: /* Append LINE to the history line at offset WHICH, adding a newline to the
! 400: end of the current line first. This can be used to construct multi-line
! 401: history entries while reading lines from the history file. */
! 402: void
! 403: _hs_append_history_line (int which, const char *line)
! 404: {
! 405: HIST_ENTRY *hent;
! 406: size_t newlen, curlen, minlen;
! 407: char *newline;
! 408:
! 409: hent = the_history[which];
! 410: curlen = strlen (hent->line);
! 411: minlen = curlen + strlen (line) + 2; /* min space needed */
! 412: if (curlen > 256) /* XXX - for now */
! 413: {
! 414: newlen = 512; /* now realloc in powers of 2 */
! 415: /* we recalcluate every time; the operations are cheap */
! 416: while (newlen < minlen)
! 417: newlen <<= 1;
! 418: }
! 419: else
! 420: newlen = minlen;
! 421: /* Assume that realloc returns the same pointer and doesn't try a new
! 422: alloc/copy if the new size is the same as the one last passed. */
! 423: newline = realloc (hent->line, newlen);
! 424: if (newline)
! 425: {
! 426: hent->line = newline;
! 427: hent->line[curlen++] = '\n';
! 428: strcpy (hent->line + curlen, line);
! 429: }
! 430: }
! 431:
1.1 misho 432: /* Replace the DATA in the specified history entries, replacing OLD with
433: NEW. WHICH says which one(s) to replace: WHICH == -1 means to replace
434: all of the history entries where entry->data == OLD; WHICH == -2 means
435: to replace the `newest' history entry where entry->data == OLD; and
436: WHICH >= 0 means to replace that particular history entry's data, as
437: long as it matches OLD. */
438: void
1.1.1.2 ! misho 439: _hs_replace_history_data (int which, histdata_t *old, histdata_t *new)
1.1 misho 440: {
441: HIST_ENTRY *entry;
442: register int i, last;
443:
444: if (which < -2 || which >= history_length || history_length == 0 || the_history == 0)
445: return;
446:
447: if (which >= 0)
448: {
449: entry = the_history[which];
450: if (entry && entry->data == old)
451: entry->data = new;
452: return;
453: }
454:
455: last = -1;
456: for (i = 0; i < history_length; i++)
457: {
458: entry = the_history[i];
459: if (entry == 0)
460: continue;
461: if (entry->data == old)
462: {
463: last = i;
464: if (which == -1)
465: entry->data = new;
466: }
467: }
468: if (which == -2 && last >= 0)
469: {
470: entry = the_history[last];
471: entry->data = new; /* XXX - we don't check entry->old */
472: }
473: }
474:
475: /* Remove history element WHICH from the history. The removed
476: element is returned to you so you can free the line, data,
477: and containing structure. */
478: HIST_ENTRY *
1.1.1.2 ! misho 479: remove_history (int which)
1.1 misho 480: {
481: HIST_ENTRY *return_value;
482: register int i;
1.1.1.2 ! misho 483: #if 1
! 484: int nentries;
! 485: HIST_ENTRY **start, **end;
! 486: #endif
1.1 misho 487:
488: if (which < 0 || which >= history_length || history_length == 0 || the_history == 0)
489: return ((HIST_ENTRY *)NULL);
490:
491: return_value = the_history[which];
492:
1.1.1.2 ! misho 493: #if 1
! 494: /* Copy the rest of the entries, moving down one slot. Copy includes
! 495: trailing NULL. */
! 496: nentries = history_length - which;
! 497: start = the_history + which;
! 498: end = start + 1;
! 499: memmove (start, end, nentries * sizeof (HIST_ENTRY *));
! 500: #else
1.1 misho 501: for (i = which; i < history_length; i++)
502: the_history[i] = the_history[i + 1];
1.1.1.2 ! misho 503: #endif
1.1 misho 504:
505: history_length--;
506:
507: return (return_value);
508: }
509:
1.1.1.2 ! misho 510: HIST_ENTRY **
! 511: remove_history_range (int first, int last)
! 512: {
! 513: HIST_ENTRY **return_value;
! 514: register int i;
! 515: int nentries;
! 516: HIST_ENTRY **start, **end;
! 517:
! 518: if (the_history == 0 || history_length == 0)
! 519: return ((HIST_ENTRY **)NULL);
! 520: if (first < 0 || first >= history_length || last < 0 || last >= history_length)
! 521: return ((HIST_ENTRY **)NULL);
! 522: if (first > last)
! 523: return (HIST_ENTRY **)NULL;
! 524:
! 525: nentries = last - first + 1;
! 526: return_value = (HIST_ENTRY **)malloc ((nentries + 1) * sizeof (HIST_ENTRY *));
! 527: if (return_value == 0)
! 528: return return_value;
! 529:
! 530: /* Return all the deleted entries in a list */
! 531: for (i = first ; i <= last; i++)
! 532: return_value[i - first] = the_history[i];
! 533: return_value[i - first] = (HIST_ENTRY *)NULL;
! 534:
! 535: /* Copy the rest of the entries, moving down NENTRIES slots. Copy includes
! 536: trailing NULL. */
! 537: start = the_history + first;
! 538: end = the_history + last + 1;
! 539: memmove (start, end, (history_length - last) * sizeof (HIST_ENTRY *));
! 540:
! 541: history_length -= nentries;
! 542:
! 543: return (return_value);
! 544: }
! 545:
1.1 misho 546: /* Stifle the history list, remembering only MAX number of lines. */
547: void
1.1.1.2 ! misho 548: stifle_history (int max)
1.1 misho 549: {
550: register int i, j;
551:
552: if (max < 0)
553: max = 0;
554:
555: if (history_length > max)
556: {
557: /* This loses because we cannot free the data. */
558: for (i = 0, j = history_length - max; i < j; i++)
559: free_history_entry (the_history[i]);
560:
561: history_base = i;
562: for (j = 0, i = history_length - max; j < max; i++, j++)
563: the_history[j] = the_history[i];
564: the_history[j] = (HIST_ENTRY *)NULL;
565: history_length = j;
566: }
567:
568: history_stifled = 1;
569: max_input_history = history_max_entries = max;
570: }
571:
572: /* Stop stifling the history. This returns the previous maximum
573: number of history entries. The value is positive if the history
574: was stifled, negative if it wasn't. */
575: int
1.1.1.2 ! misho 576: unstifle_history (void)
1.1 misho 577: {
578: if (history_stifled)
579: {
580: history_stifled = 0;
581: return (history_max_entries);
582: }
583: else
584: return (-history_max_entries);
585: }
586:
587: int
1.1.1.2 ! misho 588: history_is_stifled (void)
1.1 misho 589: {
590: return (history_stifled);
591: }
592:
593: void
1.1.1.2 ! misho 594: clear_history (void)
1.1 misho 595: {
596: register int i;
597:
598: /* This loses because we cannot free the data. */
599: for (i = 0; i < history_length; i++)
600: {
601: free_history_entry (the_history[i]);
602: the_history[i] = (HIST_ENTRY *)NULL;
603: }
604:
605: history_offset = history_length = 0;
1.1.1.2 ! misho 606: history_base = 1; /* reset history base to default */
1.1 misho 607: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>