/* This file is part of GDBM, the GNU data base manager.
Copyright (C) 2016-2017 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GDBM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDBM. If not, see . */
#include "gdbmtool.h"
#include
#include
static char *pre_input_line;
static int
pre_input (void)
{
if (pre_input_line)
{
rl_insert_text (pre_input_line);
free (pre_input_line);
pre_input_line = NULL;
rl_redisplay ();
}
return 0;
}
static int
retrieve_history (char *str)
{
char *out;
int rc;
rc = history_expand (str, &out);
switch (rc)
{
case -1:
yyerror (out);
free (out);
return 1;
case 0:
break;
case 1:
pre_input_line = out;
return 1;
case 2:
printf ("%s\n", out);
free (out);
return 1;
}
return 0;
}
ssize_t
input_read (FILE *fp, char *buf, size_t size)
{
static char *input_line;
static size_t input_length;
static size_t input_off;
#define input_ptr() (input_line + input_off)
#define input_size() (input_length - input_off)
if (interactive)
{
size_t len = input_size ();
if (!len)
{
if (input_line)
{
newline:
free (input_line);
input_line = NULL;
buf[0] = '\n';
return 1;
}
else
{
char *prompt;
again:
prompt = make_prompt ();
input_line = readline (prompt);
free (prompt);
if (!input_line)
return 0;
input_length = strlen (input_line);
input_off = 0;
if (input_length)
{
if (retrieve_history (input_line))
{
free (input_line);
goto again;
}
}
else
goto newline;
len = input_size ();
add_history (input_line);
}
}
if (len > size)
len = size;
memcpy (buf, input_ptr (), len);
input_off += len;
return len;
}
return fread (buf, 1, size, fp);
}
struct history_param
{
int from;
int count;
};
int
input_history_begin (struct handler_param *param, size_t *exp_count)
{
struct history_param *p;
int from = 0, count = history_length;
switch (param->argc)
{
case 1:
if (getnum (&count, param->argv[0]->v.string, NULL))
return 1;
if (count > history_length)
count = history_length;
else
from = history_length - count;
break;
case 2:
if (getnum (&from, param->argv[0]->v.string, NULL))
return 1;
if (from)
--from;
if (getnum (&count, param->argv[1]->v.string, NULL))
return 1;
if (count > history_length)
count = history_length;
}
p = emalloc (sizeof *p);
p->from = from;
p->count = count;
param->data = p;
if (exp_count)
*exp_count = count;
return 0;
}
void
input_history_handler (struct handler_param *param)
{
struct history_param *p = param->data;
int i;
HIST_ENTRY **hlist;
FILE *fp = param->fp;
hlist = history_list ();
for (i = 0; i < p->count; i++)
fprintf (fp, "%4d) %s\n", p->from + i + 1, hlist[p->from + i]->line);
}
#define HISTFILE_PREFIX "~/."
#define HISTFILE_SUFFIX "_history"
static char *
get_history_file_name ()
{
static char *filename = NULL;
if (!filename)
{
char *hname;
hname = emalloc (sizeof HISTFILE_PREFIX + strlen (rl_readline_name) +
sizeof HISTFILE_SUFFIX - 1);
strcpy (hname, HISTFILE_PREFIX);
strcat (hname, rl_readline_name);
strcat (hname, HISTFILE_SUFFIX);
filename = tildexpand (hname);
free (hname);
}
return filename;
}
static char **
shell_completion (const char *text, int start, int end)
{
char **matches;
matches = (char **) NULL;
/* If this word is at the start of the line, then it is a command
to complete. Otherwise it is the name of a file in the current
directory. */
if (start == 0)
matches = rl_completion_matches (text, command_generator);
return (matches);
}
void
input_init (void)
{
/* Allow conditional parsing of the ~/.inputrc file. */
rl_readline_name = (char *) progname;
rl_attempted_completion_function = shell_completion;
rl_pre_input_hook = pre_input;
if (interactive)
read_history (get_history_file_name ());
}
void
input_done (void)
{
if (interactive)
write_history (get_history_file_name ());
}