1 /* history.c -- standalone history library */
3 /* Copyright (C) 1989-2023 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>
45 #include "posixtime.h"
58 /* How big to make the_history when we first allocate it. */
59 #define DEFAULT_HISTORY_INITIAL_SIZE 502
61 #define MAX_HISTORY_INITIAL_SIZE 8192
63 /* The number of slots to increase the_history by. */
64 #define DEFAULT_HISTORY_GROW_SIZE 50
66 static char *hist_inittime (void);
68 /* **************************************************************** */
70 /* History Functions */
72 /* **************************************************************** */
74 /* An array of HIST_ENTRY. This is where we store the history. */
75 static HIST_ENTRY
**the_history
= (HIST_ENTRY
**)NULL
;
77 /* Non-zero means that we have enforced a limit on the amount of
78 history that we save. */
79 static int history_stifled
;
81 /* The current number of slots allocated to the input_history. */
82 static int history_size
;
84 /* If HISTORY_STIFLED is non-zero, then this is the maximum number of
85 entries to remember. */
86 int history_max_entries
;
87 int max_input_history
; /* backwards compatibility */
89 /* The current location of the interactive history pointer. Just makes
90 life easier for outside callers. */
93 /* The number of strings currently stored in the history list. */
96 /* The logical `base' of the history array. It defaults to 1. */
99 /* Return the current HISTORY_STATE of the history. */
101 history_get_history_state (void)
103 HISTORY_STATE
*state
;
105 state
= (HISTORY_STATE
*)xmalloc (sizeof (HISTORY_STATE
));
106 state
->entries
= the_history
;
107 state
->offset
= history_offset
;
108 state
->length
= history_length
;
109 state
->size
= history_size
;
112 state
->flags
|= HS_STIFLED
;
117 /* Set the state of the current history array to STATE. */
119 history_set_history_state (HISTORY_STATE
*state
)
121 the_history
= state
->entries
;
122 history_offset
= state
->offset
;
123 history_length
= state
->length
;
124 history_size
= state
->size
;
125 if (state
->flags
& HS_STIFLED
)
129 /* Begin a session in which the history functions might be used. This
130 initializes interactive variables. */
134 history_offset
= history_length
;
137 /* Return the number of bytes that the primary history entries are using.
138 This just adds up the lengths of the_history->lines and the associated
141 history_total_bytes (void)
143 register int i
, result
;
145 for (i
= result
= 0; the_history
&& the_history
[i
]; i
++)
146 result
+= HISTENT_BYTES (the_history
[i
]);
151 /* Returns the magic number which says what history element we are
152 looking at now. In this implementation, it returns history_offset. */
156 return (history_offset
);
159 /* Make the current history item be the one at POS, an absolute index.
160 Returns zero if POS is out of range, else non-zero. */
162 history_set_pos (int pos
)
164 if (pos
> history_length
|| pos
< 0 || !the_history
)
166 history_offset
= pos
;
170 /* Are we currently at the end of the history list? */
172 _hs_at_end_of_history (void)
174 return (the_history
== 0 || history_offset
== history_length
);
177 /* Return the current history array. The caller has to be careful, since this
178 is the actual array of data, and could be bashed or made corrupt easily.
179 The array is terminated with a NULL pointer. */
183 return (the_history
);
186 /* Return the history entry at the current position, as determined by
187 history_offset. If there is no entry there, return a NULL pointer. */
189 current_history (void)
191 return ((history_offset
== history_length
) || the_history
== 0)
193 : the_history
[history_offset
];
196 /* Back up history_offset to the previous history entry, and return
197 a pointer to that entry. If there is no previous entry then return
200 previous_history (void)
202 return history_offset
? the_history
[--history_offset
] : (HIST_ENTRY
*)NULL
;
205 /* Move history_offset forward to the next history entry, and return
206 a pointer to that entry. If there is no next entry then return a
211 return (history_offset
== history_length
) ? (HIST_ENTRY
*)NULL
: the_history
[++history_offset
];
214 /* Return the history entry which is logically at OFFSET in the history array.
215 OFFSET is relative to history_base. */
217 history_get (int offset
)
221 local_index
= offset
- history_base
;
222 return (local_index
>= history_length
|| local_index
< 0 || the_history
== 0)
224 : the_history
[local_index
];
228 alloc_history_entry (char *string
, char *ts
)
232 temp
= (HIST_ENTRY
*)xmalloc (sizeof (HIST_ENTRY
));
234 temp
->line
= string
? savestring (string
) : string
;
235 temp
->data
= (char *)NULL
;
236 temp
->timestamp
= ts
;
242 history_get_time (HIST_ENTRY
*hist
)
247 if (hist
== 0 || hist
->timestamp
== 0)
249 ts
= hist
->timestamp
;
250 if (ts
[0] != history_comment_char
)
253 t
= (time_t) strtol (ts
+ 1, (char **)NULL
, 10); /* XXX - should use strtol() here */
266 #if defined (HAVE_VSNPRINTF) /* assume snprintf if vsnprintf exists */
267 snprintf (ts
, sizeof (ts
) - 1, "X%lu", (unsigned long) t
);
269 sprintf (ts
, "X%lu", (unsigned long) t
);
271 ret
= savestring (ts
);
272 ret
[0] = history_comment_char
;
277 /* Place STRING at the end of the history list. The data field
280 add_history (const char *string
)
285 if (history_stifled
&& (history_length
== history_max_entries
))
287 /* If the history is stifled, and history_length is zero,
288 and it equals history_max_entries, we don't save items. */
289 if (history_length
== 0)
292 /* If there is something in the slot, then remove it. */
294 (void) free_history_entry (the_history
[0]);
296 /* Copy the rest of the entries, moving down one slot. Copy includes
298 memmove (the_history
, the_history
+ 1, history_length
* sizeof (HIST_ENTRY
*));
300 new_length
= history_length
;
305 if (history_size
== 0)
307 if (history_stifled
&& history_max_entries
> 0)
308 history_size
= (history_max_entries
> MAX_HISTORY_INITIAL_SIZE
)
309 ? MAX_HISTORY_INITIAL_SIZE
310 : history_max_entries
+ 2;
312 history_size
= DEFAULT_HISTORY_INITIAL_SIZE
;
313 the_history
= (HIST_ENTRY
**)xmalloc (history_size
* sizeof (HIST_ENTRY
*));
318 if (history_length
== (history_size
- 1))
320 history_size
+= DEFAULT_HISTORY_GROW_SIZE
;
321 the_history
= (HIST_ENTRY
**)
322 xrealloc (the_history
, history_size
* sizeof (HIST_ENTRY
*));
324 new_length
= history_length
+ 1;
328 temp
= alloc_history_entry ((char *)string
, hist_inittime ());
330 the_history
[new_length
] = (HIST_ENTRY
*)NULL
;
331 the_history
[new_length
- 1] = temp
;
332 history_length
= new_length
;
335 /* Change the time stamp of the most recent history entry to STRING. */
337 add_history_time (const char *string
)
341 if (string
== 0 || history_length
< 1)
343 hs
= the_history
[history_length
- 1];
344 FREE (hs
->timestamp
);
345 hs
->timestamp
= savestring (string
);
348 /* Free HIST and return the data so the calling application can free it
349 if necessary and desired. */
351 free_history_entry (HIST_ENTRY
*hist
)
356 return ((histdata_t
) 0);
358 FREE (hist
->timestamp
);
365 copy_history_entry (HIST_ENTRY
*hist
)
373 ret
= alloc_history_entry (hist
->line
, (char *)NULL
);
375 ts
= hist
->timestamp
? savestring (hist
->timestamp
) : hist
->timestamp
;
378 ret
->data
= hist
->data
;
383 /* Make the history entry at WHICH have LINE and DATA. This returns
384 the old entry so you can dispose of the data. In the case of an
385 invalid WHICH, a NULL pointer is returned. */
387 replace_history_entry (int which
, const char *line
, histdata_t data
)
389 HIST_ENTRY
*temp
, *old_value
;
391 if (which
< 0 || which
>= history_length
)
392 return ((HIST_ENTRY
*)NULL
);
394 temp
= (HIST_ENTRY
*)xmalloc (sizeof (HIST_ENTRY
));
395 old_value
= the_history
[which
];
397 temp
->line
= savestring (line
);
399 temp
->timestamp
= old_value
->timestamp
? savestring (old_value
->timestamp
) : 0;
400 the_history
[which
] = temp
;
405 /* Append LINE to the history line at offset WHICH, adding a newline to the
406 end of the current line first. This can be used to construct multi-line
407 history entries while reading lines from the history file. */
409 _hs_append_history_line (int which
, const char *line
)
412 size_t newlen
, curlen
, minlen
;
415 hent
= the_history
[which
];
416 curlen
= strlen (hent
->line
);
417 minlen
= curlen
+ strlen (line
) + 2; /* min space needed */
418 if (curlen
> 256) /* XXX - for now */
420 newlen
= 512; /* now realloc in powers of 2 */
421 /* we recalcluate every time; the operations are cheap */
422 while (newlen
< minlen
)
427 /* Assume that realloc returns the same pointer and doesn't try a new
428 alloc/copy if the new size is the same as the one last passed. */
429 newline
= realloc (hent
->line
, newlen
);
432 hent
->line
= newline
;
433 hent
->line
[curlen
++] = '\n';
434 strcpy (hent
->line
+ curlen
, line
);
438 /* Replace the DATA in the specified history entries, replacing OLD with
439 NEW. WHICH says which one(s) to replace: WHICH == -1 means to replace
440 all of the history entries where entry->data == OLD; WHICH == -2 means
441 to replace the `newest' history entry where entry->data == OLD; and
442 WHICH >= 0 means to replace that particular history entry's data, as
443 long as it matches OLD. */
445 _hs_replace_history_data (int which
, histdata_t
*old
, histdata_t
*new)
448 register int i
, last
;
450 if (which
< -2 || which
>= history_length
|| history_length
== 0 || the_history
== 0)
455 entry
= the_history
[which
];
456 if (entry
&& entry
->data
== old
)
462 for (i
= history_length
- 1; i
>= 0; i
--)
464 entry
= the_history
[i
];
467 if (entry
->data
== old
)
474 if (which
== -2 && last
>= 0)
476 entry
= the_history
[last
];
477 entry
->data
= new; /* XXX - we don't check entry->old */
482 _hs_search_history_data (histdata_t
*needle
)
487 if (history_length
== 0 || the_history
== 0)
490 for (i
= history_length
- 1; i
>= 0; i
--)
492 entry
= the_history
[i
];
495 if (entry
->data
== needle
)
501 /* Remove history element WHICH from the history. The removed
502 element is returned to you so you can free the line, data,
503 and containing structure. */
505 remove_history (int which
)
507 HIST_ENTRY
*return_value
;
511 HIST_ENTRY
**start
, **end
;
514 if (which
< 0 || which
>= history_length
|| history_length
== 0 || the_history
== 0)
515 return ((HIST_ENTRY
*)NULL
);
517 return_value
= the_history
[which
];
520 /* Copy the rest of the entries, moving down one slot. Copy includes
522 nentries
= history_length
- which
;
523 start
= the_history
+ which
;
525 memmove (start
, end
, nentries
* sizeof (HIST_ENTRY
*));
527 for (i
= which
; i
< history_length
; i
++)
528 the_history
[i
] = the_history
[i
+ 1];
533 return (return_value
);
537 remove_history_range (int first
, int last
)
539 HIST_ENTRY
**return_value
;
542 HIST_ENTRY
**start
, **end
;
544 if (the_history
== 0 || history_length
== 0)
545 return ((HIST_ENTRY
**)NULL
);
546 if (first
< 0 || first
>= history_length
|| last
< 0 || last
>= history_length
)
547 return ((HIST_ENTRY
**)NULL
);
549 return (HIST_ENTRY
**)NULL
;
551 nentries
= last
- first
+ 1;
552 return_value
= (HIST_ENTRY
**)malloc ((nentries
+ 1) * sizeof (HIST_ENTRY
*));
553 if (return_value
== 0)
556 /* Return all the deleted entries in a list */
557 for (i
= first
; i
<= last
; i
++)
558 return_value
[i
- first
] = the_history
[i
];
559 return_value
[i
- first
] = (HIST_ENTRY
*)NULL
;
561 /* Copy the rest of the entries, moving down NENTRIES slots. Copy includes
563 start
= the_history
+ first
;
564 end
= the_history
+ last
+ 1;
565 memmove (start
, end
, (history_length
- last
) * sizeof (HIST_ENTRY
*));
567 history_length
-= nentries
;
569 return (return_value
);
572 /* Stifle the history list, remembering only MAX number of lines. */
574 stifle_history (int max
)
581 if (history_length
> max
)
583 /* This loses because we cannot free the data. */
584 for (i
= 0, j
= history_length
- max
; i
< j
; i
++)
585 free_history_entry (the_history
[i
]);
588 for (j
= 0, i
= history_length
- max
; j
< max
; i
++, j
++)
589 the_history
[j
] = the_history
[i
];
590 the_history
[j
] = (HIST_ENTRY
*)NULL
;
595 max_input_history
= history_max_entries
= max
;
598 /* Stop stifling the history. This returns the previous maximum
599 number of history entries. The value is positive if the history
600 was stifled, negative if it wasn't. */
602 unstifle_history (void)
607 return (history_max_entries
);
610 return (-history_max_entries
);
614 history_is_stifled (void)
616 return (history_stifled
);
624 /* This loses because we cannot free the data. */
625 for (i
= 0; i
< history_length
; i
++)
627 free_history_entry (the_history
[i
]);
628 the_history
[i
] = (HIST_ENTRY
*)NULL
;
631 history_offset
= history_length
= 0;
632 history_base
= 1; /* reset history base to default */