version 1.1.1.1, 2014/07/30 08:16:45
|
version 1.1.1.2, 2021/03/17 01:01:01
|
Line 1
|
Line 1
|
/* history.c -- standalone history library */ |
/* history.c -- standalone history library */ |
|
|
/* Copyright (C) 1989-2011 Free Software Foundation, Inc. | /* Copyright (C) 1989-2017 Free Software Foundation, Inc. |
|
|
This file contains the GNU History Library (History), a set of |
This file contains the GNU History Library (History), a set of |
routines for managing the text of previously typed lines. |
routines for managing the text of previously typed lines. |
Line 43
|
Line 43
|
# include <unistd.h> |
# include <unistd.h> |
#endif |
#endif |
|
|
|
#include <errno.h> |
|
|
#include "history.h" |
#include "history.h" |
#include "histlib.h" |
#include "histlib.h" |
|
|
#include "xmalloc.h" |
#include "xmalloc.h" |
|
|
|
#if !defined (errno) |
|
extern int errno; |
|
#endif |
|
|
|
/* How big to make the_history when we first allocate it. */ |
|
#define DEFAULT_HISTORY_INITIAL_SIZE 502 |
|
|
|
#define MAX_HISTORY_INITIAL_SIZE 8192 |
|
|
/* The number of slots to increase the_history by. */ |
/* The number of slots to increase the_history by. */ |
#define DEFAULT_HISTORY_GROW_SIZE 50 |
#define DEFAULT_HISTORY_GROW_SIZE 50 |
|
|
Line 86 int history_base = 1;
|
Line 97 int history_base = 1;
|
|
|
/* Return the current HISTORY_STATE of the history. */ |
/* Return the current HISTORY_STATE of the history. */ |
HISTORY_STATE * |
HISTORY_STATE * |
history_get_history_state () | history_get_history_state (void) |
{ |
{ |
HISTORY_STATE *state; |
HISTORY_STATE *state; |
|
|
Line 104 history_get_history_state ()
|
Line 115 history_get_history_state ()
|
|
|
/* Set the state of the current history array to STATE. */ |
/* Set the state of the current history array to STATE. */ |
void |
void |
history_set_history_state (state) | history_set_history_state (HISTORY_STATE *state) |
HISTORY_STATE *state; | |
{ |
{ |
the_history = state->entries; |
the_history = state->entries; |
history_offset = state->offset; |
history_offset = state->offset; |
Line 118 history_set_history_state (state)
|
Line 128 history_set_history_state (state)
|
/* Begin a session in which the history functions might be used. This |
/* Begin a session in which the history functions might be used. This |
initializes interactive variables. */ |
initializes interactive variables. */ |
void |
void |
using_history () | using_history (void) |
{ |
{ |
history_offset = history_length; |
history_offset = history_length; |
} |
} |
Line 127 using_history ()
|
Line 137 using_history ()
|
This just adds up the lengths of the_history->lines and the associated |
This just adds up the lengths of the_history->lines and the associated |
timestamps. */ |
timestamps. */ |
int |
int |
history_total_bytes () | history_total_bytes (void) |
{ |
{ |
register int i, result; |
register int i, result; |
|
|
Line 140 history_total_bytes ()
|
Line 150 history_total_bytes ()
|
/* Returns the magic number which says what history element we are |
/* Returns the magic number which says what history element we are |
looking at now. In this implementation, it returns history_offset. */ |
looking at now. In this implementation, it returns history_offset. */ |
int |
int |
where_history () | where_history (void) |
{ |
{ |
return (history_offset); |
return (history_offset); |
} |
} |
Line 148 where_history ()
|
Line 158 where_history ()
|
/* Make the current history item be the one at POS, an absolute index. |
/* Make the current history item be the one at POS, an absolute index. |
Returns zero if POS is out of range, else non-zero. */ |
Returns zero if POS is out of range, else non-zero. */ |
int |
int |
history_set_pos (pos) | history_set_pos (int pos) |
int pos; | |
{ |
{ |
if (pos > history_length || pos < 0 || !the_history) |
if (pos > history_length || pos < 0 || !the_history) |
return (0); |
return (0); |
Line 161 history_set_pos (pos)
|
Line 170 history_set_pos (pos)
|
is the actual array of data, and could be bashed or made corrupt easily. |
is the actual array of data, and could be bashed or made corrupt easily. |
The array is terminated with a NULL pointer. */ |
The array is terminated with a NULL pointer. */ |
HIST_ENTRY ** |
HIST_ENTRY ** |
history_list () | history_list (void) |
{ |
{ |
return (the_history); |
return (the_history); |
} |
} |
Line 169 history_list ()
|
Line 178 history_list ()
|
/* Return the history entry at the current position, as determined by |
/* Return the history entry at the current position, as determined by |
history_offset. If there is no entry there, return a NULL pointer. */ |
history_offset. If there is no entry there, return a NULL pointer. */ |
HIST_ENTRY * |
HIST_ENTRY * |
current_history () | current_history (void) |
{ |
{ |
return ((history_offset == history_length) || the_history == 0) |
return ((history_offset == history_length) || the_history == 0) |
? (HIST_ENTRY *)NULL |
? (HIST_ENTRY *)NULL |
Line 180 current_history ()
|
Line 189 current_history ()
|
a pointer to that entry. If there is no previous entry then return |
a pointer to that entry. If there is no previous entry then return |
a NULL pointer. */ |
a NULL pointer. */ |
HIST_ENTRY * |
HIST_ENTRY * |
previous_history () | previous_history (void) |
{ |
{ |
return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL; |
return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL; |
} |
} |
Line 189 previous_history ()
|
Line 198 previous_history ()
|
a pointer to that entry. If there is no next entry then return a |
a pointer to that entry. If there is no next entry then return a |
NULL pointer. */ |
NULL pointer. */ |
HIST_ENTRY * |
HIST_ENTRY * |
next_history () | next_history (void) |
{ |
{ |
return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset]; |
return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset]; |
} |
} |
Line 197 next_history ()
|
Line 206 next_history ()
|
/* Return the history entry which is logically at OFFSET in the history array. |
/* Return the history entry which is logically at OFFSET in the history array. |
OFFSET is relative to history_base. */ |
OFFSET is relative to history_base. */ |
HIST_ENTRY * |
HIST_ENTRY * |
history_get (offset) | history_get (int offset) |
int offset; | |
{ |
{ |
int local_index; |
int local_index; |
|
|
Line 209 history_get (offset)
|
Line 217 history_get (offset)
|
} |
} |
|
|
HIST_ENTRY * |
HIST_ENTRY * |
alloc_history_entry (string, ts) | alloc_history_entry (char *string, char *ts) |
char *string; | |
char *ts; | |
{ |
{ |
HIST_ENTRY *temp; |
HIST_ENTRY *temp; |
|
|
Line 225 alloc_history_entry (string, ts)
|
Line 231 alloc_history_entry (string, ts)
|
} |
} |
|
|
time_t |
time_t |
history_get_time (hist) | history_get_time (HIST_ENTRY *hist) |
HIST_ENTRY *hist; | |
{ |
{ |
char *ts; |
char *ts; |
time_t t; |
time_t t; |
Line 236 history_get_time (hist)
|
Line 241 history_get_time (hist)
|
ts = hist->timestamp; |
ts = hist->timestamp; |
if (ts[0] != history_comment_char) |
if (ts[0] != history_comment_char) |
return 0; |
return 0; |
|
errno = 0; |
t = (time_t) strtol (ts + 1, (char **)NULL, 10); /* XXX - should use strtol() here */ |
t = (time_t) strtol (ts + 1, (char **)NULL, 10); /* XXX - should use strtol() here */ |
|
if (errno == ERANGE) |
|
return (time_t)0; |
return t; |
return t; |
} |
} |
|
|
static char * |
static char * |
hist_inittime () | hist_inittime (void) |
{ |
{ |
time_t t; |
time_t t; |
char ts[64], *ret; |
char ts[64], *ret; |
Line 261 hist_inittime ()
|
Line 269 hist_inittime ()
|
/* Place STRING at the end of the history list. The data field |
/* Place STRING at the end of the history list. The data field |
is set to NULL. */ |
is set to NULL. */ |
void |
void |
add_history (string) | add_history (const char *string) |
const char *string; | |
{ |
{ |
HIST_ENTRY *temp; |
HIST_ENTRY *temp; |
|
int new_length; |
|
|
if (history_stifled && (history_length == history_max_entries)) |
if (history_stifled && (history_length == history_max_entries)) |
{ |
{ |
Line 279 add_history (string)
|
Line 287 add_history (string)
|
if (the_history[0]) |
if (the_history[0]) |
(void) free_history_entry (the_history[0]); |
(void) free_history_entry (the_history[0]); |
|
|
/* Copy the rest of the entries, moving down one slot. */ | /* Copy the rest of the entries, moving down one slot. Copy includes |
for (i = 0; i < history_length; i++) | trailing NULL. */ |
the_history[i] = the_history[i + 1]; | memmove (the_history, the_history + 1, history_length * sizeof (HIST_ENTRY *)); |
|
|
|
new_length = history_length; |
history_base++; |
history_base++; |
} |
} |
else |
else |
{ |
{ |
if (history_size == 0) |
if (history_size == 0) |
{ |
{ |
history_size = DEFAULT_HISTORY_GROW_SIZE; | if (history_stifled && history_max_entries > 0) |
| history_size = (history_max_entries > MAX_HISTORY_INITIAL_SIZE) |
| ? MAX_HISTORY_INITIAL_SIZE |
| : history_max_entries + 2; |
| else |
| history_size = DEFAULT_HISTORY_INITIAL_SIZE; |
the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *)); |
the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *)); |
history_length = 1; | new_length = 1; |
} |
} |
else |
else |
{ |
{ |
Line 301 add_history (string)
|
Line 315 add_history (string)
|
the_history = (HIST_ENTRY **) |
the_history = (HIST_ENTRY **) |
xrealloc (the_history, history_size * sizeof (HIST_ENTRY *)); |
xrealloc (the_history, history_size * sizeof (HIST_ENTRY *)); |
} |
} |
history_length++; | new_length = history_length + 1; |
} |
} |
} |
} |
|
|
temp = alloc_history_entry (string, hist_inittime ()); | temp = alloc_history_entry ((char *)string, hist_inittime ()); |
|
|
the_history[history_length] = (HIST_ENTRY *)NULL; | the_history[new_length] = (HIST_ENTRY *)NULL; |
the_history[history_length - 1] = temp; | the_history[new_length - 1] = temp; |
| history_length = new_length; |
} |
} |
|
|
/* Change the time stamp of the most recent history entry to STRING. */ |
/* Change the time stamp of the most recent history entry to STRING. */ |
void |
void |
add_history_time (string) | add_history_time (const char *string) |
const char *string; | |
{ |
{ |
HIST_ENTRY *hs; |
HIST_ENTRY *hs; |
|
|
Line 328 add_history_time (string)
|
Line 342 add_history_time (string)
|
/* Free HIST and return the data so the calling application can free it |
/* Free HIST and return the data so the calling application can free it |
if necessary and desired. */ |
if necessary and desired. */ |
histdata_t |
histdata_t |
free_history_entry (hist) | free_history_entry (HIST_ENTRY *hist) |
HIST_ENTRY *hist; | |
{ |
{ |
histdata_t x; |
histdata_t x; |
|
|
Line 343 free_history_entry (hist)
|
Line 356 free_history_entry (hist)
|
} |
} |
|
|
HIST_ENTRY * |
HIST_ENTRY * |
copy_history_entry (hist) | copy_history_entry (HIST_ENTRY *hist) |
HIST_ENTRY *hist; | |
{ |
{ |
HIST_ENTRY *ret; |
HIST_ENTRY *ret; |
char *ts; |
char *ts; |
Line 366 copy_history_entry (hist)
|
Line 378 copy_history_entry (hist)
|
the old entry so you can dispose of the data. In the case of an |
the old entry so you can dispose of the data. In the case of an |
invalid WHICH, a NULL pointer is returned. */ |
invalid WHICH, a NULL pointer is returned. */ |
HIST_ENTRY * |
HIST_ENTRY * |
replace_history_entry (which, line, data) | replace_history_entry (int which, const char *line, histdata_t data) |
int which; | |
const char *line; | |
histdata_t data; | |
{ |
{ |
HIST_ENTRY *temp, *old_value; |
HIST_ENTRY *temp, *old_value; |
|
|
Line 387 replace_history_entry (which, line, data)
|
Line 396 replace_history_entry (which, line, data)
|
return (old_value); |
return (old_value); |
} |
} |
|
|
|
/* Append LINE to the history line at offset WHICH, adding a newline to the |
|
end of the current line first. This can be used to construct multi-line |
|
history entries while reading lines from the history file. */ |
|
void |
|
_hs_append_history_line (int which, const char *line) |
|
{ |
|
HIST_ENTRY *hent; |
|
size_t newlen, curlen, minlen; |
|
char *newline; |
|
|
|
hent = the_history[which]; |
|
curlen = strlen (hent->line); |
|
minlen = curlen + strlen (line) + 2; /* min space needed */ |
|
if (curlen > 256) /* XXX - for now */ |
|
{ |
|
newlen = 512; /* now realloc in powers of 2 */ |
|
/* we recalcluate every time; the operations are cheap */ |
|
while (newlen < minlen) |
|
newlen <<= 1; |
|
} |
|
else |
|
newlen = minlen; |
|
/* Assume that realloc returns the same pointer and doesn't try a new |
|
alloc/copy if the new size is the same as the one last passed. */ |
|
newline = realloc (hent->line, newlen); |
|
if (newline) |
|
{ |
|
hent->line = newline; |
|
hent->line[curlen++] = '\n'; |
|
strcpy (hent->line + curlen, line); |
|
} |
|
} |
|
|
/* Replace the DATA in the specified history entries, replacing OLD with |
/* Replace the DATA in the specified history entries, replacing OLD with |
NEW. WHICH says which one(s) to replace: WHICH == -1 means to replace |
NEW. WHICH says which one(s) to replace: WHICH == -1 means to replace |
all of the history entries where entry->data == OLD; WHICH == -2 means |
all of the history entries where entry->data == OLD; WHICH == -2 means |
Line 394 replace_history_entry (which, line, data)
|
Line 436 replace_history_entry (which, line, data)
|
WHICH >= 0 means to replace that particular history entry's data, as |
WHICH >= 0 means to replace that particular history entry's data, as |
long as it matches OLD. */ |
long as it matches OLD. */ |
void |
void |
replace_history_data (which, old, new) | _hs_replace_history_data (int which, histdata_t *old, histdata_t *new) |
int which; | |
histdata_t *old, *new; | |
{ |
{ |
HIST_ENTRY *entry; |
HIST_ENTRY *entry; |
register int i, last; |
register int i, last; |
Line 436 replace_history_data (which, old, new)
|
Line 476 replace_history_data (which, old, new)
|
element is returned to you so you can free the line, data, |
element is returned to you so you can free the line, data, |
and containing structure. */ |
and containing structure. */ |
HIST_ENTRY * |
HIST_ENTRY * |
remove_history (which) | remove_history (int which) |
int which; | |
{ |
{ |
HIST_ENTRY *return_value; |
HIST_ENTRY *return_value; |
register int i; |
register int i; |
|
#if 1 |
|
int nentries; |
|
HIST_ENTRY **start, **end; |
|
#endif |
|
|
if (which < 0 || which >= history_length || history_length == 0 || the_history == 0) |
if (which < 0 || which >= history_length || history_length == 0 || the_history == 0) |
return ((HIST_ENTRY *)NULL); |
return ((HIST_ENTRY *)NULL); |
|
|
return_value = the_history[which]; |
return_value = the_history[which]; |
|
|
|
#if 1 |
|
/* Copy the rest of the entries, moving down one slot. Copy includes |
|
trailing NULL. */ |
|
nentries = history_length - which; |
|
start = the_history + which; |
|
end = start + 1; |
|
memmove (start, end, nentries * sizeof (HIST_ENTRY *)); |
|
#else |
for (i = which; i < history_length; i++) |
for (i = which; i < history_length; i++) |
the_history[i] = the_history[i + 1]; |
the_history[i] = the_history[i + 1]; |
|
#endif |
|
|
history_length--; |
history_length--; |
|
|
return (return_value); |
return (return_value); |
} |
} |
|
|
|
HIST_ENTRY ** |
|
remove_history_range (int first, int last) |
|
{ |
|
HIST_ENTRY **return_value; |
|
register int i; |
|
int nentries; |
|
HIST_ENTRY **start, **end; |
|
|
|
if (the_history == 0 || history_length == 0) |
|
return ((HIST_ENTRY **)NULL); |
|
if (first < 0 || first >= history_length || last < 0 || last >= history_length) |
|
return ((HIST_ENTRY **)NULL); |
|
if (first > last) |
|
return (HIST_ENTRY **)NULL; |
|
|
|
nentries = last - first + 1; |
|
return_value = (HIST_ENTRY **)malloc ((nentries + 1) * sizeof (HIST_ENTRY *)); |
|
if (return_value == 0) |
|
return return_value; |
|
|
|
/* Return all the deleted entries in a list */ |
|
for (i = first ; i <= last; i++) |
|
return_value[i - first] = the_history[i]; |
|
return_value[i - first] = (HIST_ENTRY *)NULL; |
|
|
|
/* Copy the rest of the entries, moving down NENTRIES slots. Copy includes |
|
trailing NULL. */ |
|
start = the_history + first; |
|
end = the_history + last + 1; |
|
memmove (start, end, (history_length - last) * sizeof (HIST_ENTRY *)); |
|
|
|
history_length -= nentries; |
|
|
|
return (return_value); |
|
} |
|
|
/* Stifle the history list, remembering only MAX number of lines. */ |
/* Stifle the history list, remembering only MAX number of lines. */ |
void |
void |
stifle_history (max) | stifle_history (int max) |
int max; | |
{ |
{ |
register int i, j; |
register int i, j; |
|
|
Line 486 stifle_history (max)
|
Line 573 stifle_history (max)
|
number of history entries. The value is positive if the history |
number of history entries. The value is positive if the history |
was stifled, negative if it wasn't. */ |
was stifled, negative if it wasn't. */ |
int |
int |
unstifle_history () | unstifle_history (void) |
{ |
{ |
if (history_stifled) |
if (history_stifled) |
{ |
{ |
Line 498 unstifle_history ()
|
Line 585 unstifle_history ()
|
} |
} |
|
|
int |
int |
history_is_stifled () | history_is_stifled (void) |
{ |
{ |
return (history_stifled); |
return (history_stifled); |
} |
} |
|
|
void |
void |
clear_history () | clear_history (void) |
{ |
{ |
register int i; |
register int i; |
|
|
Line 516 clear_history ()
|
Line 603 clear_history ()
|
} |
} |
|
|
history_offset = history_length = 0; |
history_offset = history_length = 0; |
|
history_base = 1; /* reset history base to default */ |
} |
} |