/* This file is part of GDBM, the GNU data base manager.
Copyright (C) 2016-2021 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:
free (out);
break;
case 1:
pre_input_line = out;
return 1;
case 2:
printf ("%s\n", out);
free (out);
return 1;
}
return 0;
}
#define HISTFILE_PREFIX "~/."
#define HISTFILE_SUFFIX "_history"
static char *history_file_name;
static char *
get_history_file_name (void)
{
if (!history_file_name)
{
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);
history_file_name = tildexpand (hname);
free (hname);
}
return history_file_name;
}
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);
}
static void
instream_readline_close (instream_t istr)
{
if (history_file_name)
{
write_history (history_file_name);
free (history_file_name);
history_file_name = NULL;
}
free (istr);
}
static ssize_t
stdin_read_readline (instream_t istr, 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)
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;
}
static ssize_t
instream_readline_read (instream_t istr, char *buf, size_t size)
{
if (istr->in_inter)
return stdin_read_readline (istr, buf, size);
return fread (buf, 1, size, stdin);
}
static int
instream_readline_eq (instream_t a, instream_t b)
{
return 0;
}
static int
instream_readline_history_size (instream_t istr)
{
return history_length;
}
static const char *
instream_readline_history_get (instream_t instr, int n)
{
if (n < history_length)
return history_list ()[n]->line;
return NULL;
}
instream_t
instream_readline_create (void)
{
struct instream *istr;
if (isatty (fileno (stdin)))
{
istr = emalloc (sizeof *istr);
istr->in_name = "stdin";
istr->in_inter = 1;
istr->in_read = instream_readline_read;
istr->in_close = instream_readline_close;
istr->in_eq = instream_readline_eq;
istr->in_history_size = instream_readline_history_size;
istr->in_history_get = instream_readline_history_get;
/* Allow conditional parsing of the ~/.inputrc file. */
rl_readline_name = (char *) progname;
rl_attempted_completion_function = shell_completion;
rl_pre_input_hook = pre_input;
read_history (get_history_file_name ());
}
else
istr = instream_stdin_create ();
return istr;
}