X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fterminal%2Fread-line.c;h=544e18d55dd965608919ba6b5e435c002edeb165;hb=81579d9e9f994fb2908f50af41c3eb033d216e58;hp=2a0bfd5e2be55ca584ef6c6c2f1088a5a90d22c7;hpb=9f1d9ea8ac4f5e35a773581cf3d5ebd9e219bff8;p=pspp-builds.git diff --git a/src/ui/terminal/read-line.c b/src/ui/terminal/read-line.c index 2a0bfd5e..544e18d5 100644 --- a/src/ui/terminal/read-line.c +++ b/src/ui/terminal/read-line.c @@ -1,53 +1,69 @@ -/* PSPP - computes sample statistics. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. - Written by Ben Pfaff . +/* PSPP - a program for statistical analysis. + Copyright (C) 1997-9, 2000, 2007, 2009, 2011 Free Software Foundation, Inc. - This program 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 2 of the - License, or (at your option) any later version. + This program 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 of the License, or + (at your option) any later version. - This program 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. + This program 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 this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ + along with this program. If not, see . */ #include -#include "read-line.h" +#include "ui/terminal/read-line.h" #include #include #include #include +#if ! HAVE_READLINE +#include +#endif -#include "msg-ui.h" +#include "data/file-name.h" +#include "data/settings.h" +#include "language/command.h" +#include "language/prompt.h" +#include "libpspp/cast.h" +#include "libpspp/message.h" +#include "libpspp/str.h" +#include "libpspp/version.h" +#include "output/driver.h" +#include "output/journal.h" +#include "ui/terminal/msg-ui.h" +#include "ui/terminal/terminal.h" -#include -#include -#include -#include -#include -#include -#include -#include +#include "gl/xalloc.h" #include "gettext.h" #define _(msgid) gettext (msgid) - #if HAVE_READLINE #include #include static char *history_file; + +static char **complete_command_name (const char *, int, int); +static char **dont_complete (const char *, int, int); #endif /* HAVE_READLINE */ + +struct readln_source +{ + struct getl_interface parent ; + + bool (*interactive_func) (struct string *line, + enum prompt_style) ; +}; + + static bool initialised = false; /* Initialize getl. */ @@ -56,18 +72,20 @@ readln_initialize (void) { initialised = true; -#if HAVE_READLINE - rl_completion_entry_function = pspp_completion_function; -#ifdef unix +#if HAVE_READLINE + rl_basic_word_break_characters = "\n"; + using_history (); + stifle_history (500); if (history_file == NULL) { - history_file = tilde_expand ("~/.pspp_history"); - using_history (); - read_history (history_file); - stifle_history (500); + const char *home_dir = getenv ("HOME"); + if (home_dir != NULL) + { + history_file = xasprintf ("%s/.pspp_history", home_dir); + read_history (history_file); + } } #endif -#endif } /* Close getl. */ @@ -76,12 +94,30 @@ readln_uninitialize (void) { initialised = false; -#if HAVE_READLINE && unix - if (history_file != NULL) +#if HAVE_READLINE + if (history_file != NULL && false == settings_get_testing_mode () ) write_history (history_file); + clear_history (); + free (history_file); #endif } + +static bool +read_interactive (struct getl_interface *s, + struct string *line) +{ + struct readln_source *is = UP_CAST (s, struct readln_source, parent); + + return is->interactive_func (line, prompt_get_style ()); +} + +static bool +always_true (const struct getl_interface *s UNUSED) +{ + return true; +} + /* Display a welcoming message. */ static void welcome (void) @@ -95,56 +131,134 @@ welcome (void) "conditions.\nThere is ABSOLUTELY NO WARRANTY for PSPP; type \"show " "warranty.\" for details.\n", stdout); puts (stat_version); - -#if HAVE_READLINE && unix - if (history_file == NULL) - { - history_file = tilde_expand ("~/.pspp_history"); - using_history (); - read_history (history_file); - stifle_history (500); - } -#endif + readln_initialize (); + journal_enable (); } /* Gets a line from the user and stores it into LINE. Prompts the user with PROMPT. Returns true if successful, false at end of file. - Suitable for passing to getl_append_interactive(). */ -bool -readln_read (struct string *line, const char *prompt) + */ +static bool +readln_read (struct string *line, enum prompt_style style) { + const char *prompt = prompt_get (style); #if HAVE_READLINE char *string; #endif - - assert(initialised); + bool eof; - reset_msg_count (); + assert (initialised); + + msg_ui_reset_counts (); welcome (); + output_flush (); + #if HAVE_READLINE + rl_attempted_completion_function = (style == PROMPT_FIRST + ? complete_command_name + : dont_complete); string = readline (prompt); if (string == NULL) - return false; - else + eof = true; + else { if (string[0]) add_history (string); - ds_assign_c_str (line, string); + ds_assign_cstr (line, string); free (string); - return true; + eof = false; } #else fputs (prompt, stdout); fflush (stdout); - if (ds_gets (line, stdin)) + if (ds_read_line (line, stdin, SIZE_MAX)) { ds_chomp (line, '\n'); - return true; + eof = false; } else - return false; + eof = true; #endif + + /* Check whether the size of the window has changed, so that + the output drivers can adjust their settings as needed. We + only do this for the first line of a command, as it's + possible that the output drivers are actually in use + afterward, and we don't want to confuse them in the middle + of output. */ + if (style == PROMPT_FIRST) + terminal_check_size (); + + return !eof; } + +static void +readln_close (struct getl_interface *i) +{ + free (i); +} + +/* Creates a source which uses readln to get its line */ +struct getl_interface * +create_readln_source (void) +{ + struct readln_source *rlns = xzalloc (sizeof (*rlns)); + + rlns->interactive_func = readln_read; + + rlns->parent.interactive = always_true; + rlns->parent.read = read_interactive; + rlns->parent.close = readln_close; + + return &rlns->parent; +} + + +#if HAVE_READLINE +static char *command_generator (const char *text, int state); + +/* Returns a set of command name completions for TEXT. + This is of the proper form for assigning to + rl_attempted_completion_function. */ +static char ** +complete_command_name (const char *text, int start, int end UNUSED) +{ + if (start == 0) + { + /* Complete command name at start of line. */ + return rl_completion_matches (text, command_generator); + } + else + { + /* Otherwise don't do any completion. */ + rl_attempted_completion_over = 1; + return NULL; + } +} + +/* Do not do any completion for TEXT. */ +static char ** +dont_complete (const char *text UNUSED, int start UNUSED, int end UNUSED) +{ + rl_attempted_completion_over = 1; + return NULL; +} + +/* If STATE is 0, returns the first command name matching TEXT. + Otherwise, returns the next command name matching TEXT. + Returns a null pointer when no matches are left. */ +static char * +command_generator (const char *text, int state) +{ + static const struct command *cmd; + const char *name; + + if (state == 0) + cmd = NULL; + name = cmd_complete (text, &cmd); + return name ? xstrdup (name) : NULL; +} +#endif /* HAVE_READLINE */