static char *histfile;
static char **history;
static size_t histsz, histpos;
static size_t cap = 0;
static struct item *backup_items = NULL;
void
cleanhistory(void)
{
int i;
for (i = 0; i < histsz; i++) {
free(history[i]);
}
free(history);
}
void
loadhistory(void)
{
FILE *fp = NULL;
size_t llen;
char *line;
if (!histfile) {
return;
}
fp = fopen(histfile, "r");
if (!fp) {
return;
}
for (;;) {
line = NULL;
llen = 0;
if (-1 == getline(&line, &llen, fp)) {
if (ferror(fp)) {
die("failed to read history");
}
free(line);
break;
}
addhistory(line);
free(line);
}
histpos = histsz;
if (fclose(fp)) {
die("failed to close file %s", histfile);
}
}
void
navhistory(int dir)
{
static char def[BUFSIZ];
char *p = NULL;
size_t len = 0;
if (!history || histpos + 1 == 0)
return;
if (histsz == histpos) {
strncpy(def, text, sizeof(def));
}
switch(dir) {
case 1:
if (histpos < histsz - 1) {
p = history[++histpos];
} else if (histpos == histsz - 1) {
p = def;
histpos++;
}
break;
case -1:
if (histpos > 0) {
p = history[--histpos];
}
break;
}
if (p == NULL) {
return;
}
len = MIN(strlen(p), BUFSIZ - 1);
strncpy(text, p, len);
text[len] = '\0';
cursor = len;
match();
}
void
addhistory(char *input)
{
unsigned int i;
if (!histfile ||
0 == maxhist ||
0 == strlen(input)) {
return;
}
strtok(input, "\n");
if (histnodup) {
for (i = 0; i < histsz; i++) {
if (!strcmp(input, history[i])) {
return;
}
}
}
if (cap == histsz) {
reallochistory();
}
history[histsz] = strdup(input);
histsz++;
}
void
addhistoryitem(struct item *item)
{
#if SEPARATOR_PATCH
if (separator && item->text_output && item->text != item->text_output) {
int histlen = strlen(item->text) + strlen(item->text_output) + 2;
char *histitem = ecalloc(histlen + 1, sizeof(char *));
snprintf(histitem, histlen, "%s%c%s", item->text, separator, item->text_output);
addhistory(histitem);
free(histitem);
return;
}
#endif // SEPARATOR_PATCH
addhistory(item->text);
}
void
reallochistory(void)
{
size_t oldcap = cap;
cap += 64;
char **newhistory = realloc(history, cap * sizeof *history);
if (!newhistory) {
die("failed to realloc memory");
}
history = newhistory;
memset(history + oldcap, 0, (cap - oldcap) * sizeof *history);
}
void
togglehistoryitems(void)
{
int i;
#if SEPARATOR_PATCH || TSV_PATCH
char *p;
#endif // SEPARATOR_PATCH
if (!histfile)
return;
if (backup_items) {
restorebackupitems();
return;
}
backup_items = items;
items = calloc(histsz + 1, sizeof(struct item));
if (!items) {
die("cannot allocate memory");
}
for (i = 0; i < histsz; i++) {
items[i].text = strdup(history[i]);
#if SEPARATOR_PATCH
if (separator && (p = sepchr(items[i].text, separator)) != NULL) {
*p = '\0';
items[i].text_output = ++p;
} else {
items[i].text_output = items[i].text;
}
#elif TSV_PATCH
items[i].stext = strdup(items[i].text);
if ((p = strchr(items[i].stext, '\t')))
*p = '\0';
#endif // SEPARATOR_PATCH
}
}
void
restorebackupitems(void)
{
size_t i;
if (!backup_items)
return;
for (i = 0; items && items[i].text; ++i) {
free(items[i].text);
}
free(items);
items = backup_items;
backup_items = NULL;
}
void
savehistory(void)
{
unsigned int i;
FILE *fp;
if (!histfile || 0 == maxhist)
return;
fp = fopen(histfile, "w");
if (!fp) {
die("failed to open %s", histfile);
}
for (i = histsz < maxhist ? 0 : histsz - maxhist; i < histsz; i++) {
if (0 >= fprintf(fp, "%s\n", history[i])) {
die("failed to write to %s", histfile);
}
}
if (fclose(fp)) {
die("failed to close file %s", histfile);
}
}