/* 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; }