diff options
author | Jari Aalto <jari.aalto@cante.net> | 1996-08-26 18:22:31 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:49 +0000 |
commit | 726f63884db0132f01745f1fb4465e6621088ccf (patch) | |
tree | 6c2f7765a890a97e0e513cb539df43283a8f7c4d /bashhist.c | |
download | android_external_bash-726f63884db0132f01745f1fb4465e6621088ccf.tar.gz android_external_bash-726f63884db0132f01745f1fb4465e6621088ccf.tar.bz2 android_external_bash-726f63884db0132f01745f1fb4465e6621088ccf.zip |
Imported from ../bash-1.14.7.tar.gz.
Diffstat (limited to 'bashhist.c')
-rw-r--r-- | bashhist.c | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/bashhist.c b/bashhist.c new file mode 100644 index 0000000..cd7134b --- /dev/null +++ b/bashhist.c @@ -0,0 +1,390 @@ +/* bashhist.c -- bash interface to the GNU history library. */ + +/* Copyright (C) 1993 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash 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, or (at your option) any later + version. + + Bash 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 Bash; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <sys/types.h> +#include <stdio.h> +#include <errno.h> +#include "bashansi.h" +#include "posixstat.h" +#include "filecntl.h" +#include "shell.h" +#include "flags.h" +#include <readline/history.h> + +/* Declarations of bash history variables. */ +/* Non-zero means to remember lines typed to the shell on the history + list. This is different than the user-controlled behaviour; this + becomes zero when we read lines from a file, for example. */ +int remember_on_history = 1; + +/* The number of lines that Bash has added to this history session. */ +int history_lines_this_session = 0; + +/* The number of lines that Bash has read from the history file. */ +int history_lines_in_file = 0; + +/* Non-zero means do no history expansion on this line, regardless + of what history_expansion says. */ +int history_expansion_inhibited = 0; + +/* By default, every line is saved in the history individually. I.e., + if the user enters: + bash$ for i in a b c + > do + > echo $i + > done + Each line will be individually saved in the history. + bash$ history + 10 for i in a b c + 11 do + 12 echo $i + 13 done + 14 history + If the variable command_oriented_history is set, multiple lines + which form one command will be saved as one history entry. + bash$ for i in a b c + > do + > echo $i + > done + bash$ history + 10 for i in a b c + do + echo $i + done + 11 history + The user can then recall the whole command all at once instead + of just being able to recall one line at a time. + */ +int command_oriented_history = 0; + +/* A nit for picking at history saving. + Value of 0 means save all lines parsed by the shell on the history. + Value of 1 means save all lines that do not start with a space. + Value of 2 means save all lines that do not match the last line saved. */ +int history_control = 0; + +/* Variables declared in other files used here. */ +extern int interactive; +extern int current_command_line_count; +extern int delimiter_depth; + +extern char *history_delimiting_chars (); +extern void maybe_add_history (); /* forward declaration */ + +static void bash_add_history (); + +/* Load the history list from the history file. */ +void +load_history () +{ + char *hf; + + /* Truncate history file for interactive shells which desire it. + Note that the history file is automatically truncated to the + size of HISTSIZE if the user does not explicitly set the size + differently. */ + set_if_not ("HISTFILESIZE", get_string_value ("HISTSIZE")); + stupidly_hack_special_variables ("HISTFILESIZE"); + + /* Read the history in HISTFILE into the history list. */ + hf = get_string_value ("HISTFILE"); + + if (hf && *hf) + { + struct stat buf; + + if (stat (hf, &buf) == 0) + { + read_history (hf); + using_history (); + history_lines_in_file = where_history (); + } + } +} + +/* Write the existing history out to the history file. */ +void +save_history () +{ + char *hf = get_string_value ("HISTFILE"); + + if (hf && *hf) + { + struct stat buf; + + if (stat (hf, &buf) == 0) + { + /* Append only the lines that occurred this session to + the history file. */ + using_history (); + + if (history_lines_this_session < where_history ()) + append_history (history_lines_this_session, hf); + else + write_history (hf); + } + } +} + +/* If this is an interactive shell, then append the lines executed + this session to the history file. */ +int +maybe_save_shell_history () +{ + int result = 0; + + if (history_lines_this_session) + { + char *hf = get_string_value ("HISTFILE"); + + if (hf && *hf) + { + struct stat buf; + + /* If the file doesn't exist, then create it. */ + if (stat (hf, &buf) == -1) + { + int file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (file != -1) + close (file); + } + + /* Now actually append the lines if the history hasn't been + stifled. If the history has been stifled, rewrite the + history file. */ + using_history (); + if (history_lines_this_session <= where_history ()) + { + result = append_history (history_lines_this_session, hf); + history_lines_in_file += history_lines_this_session; + } + else + { + result = write_history (hf); + history_lines_in_file = history_lines_this_session; + } + history_lines_this_session = 0; + } + } + return (result); +} + +#if defined (HISTORY_REEDITING) +/* Tell readline () that we have some text for it to edit. */ +static void +re_edit (text) + char *text; +{ +#if defined (READLINE) + if (strcmp (bash_input.name, "readline stdin") == 0) + bash_re_edit (text); +#endif /* READLINE */ +} +#endif /* HISTORY_REEDITING */ + +/* Do pre-processing on LINE. If PRINT_CHANGES is non-zero, then + print the results of expanding the line if there were any changes. + If there is an error, return NULL, otherwise the expanded line is + returned. If ADDIT is non-zero the line is added to the history + list after history expansion. ADDIT is just a suggestion; + REMEMBER_ON_HISTORY can veto, and does. + Right now this does history expansion. */ +char * +pre_process_line (line, print_changes, addit) + char *line; + int print_changes, addit; +{ + char *history_value; + char *return_value; + int expanded = 0; + + return_value = line; + +# if defined (BANG_HISTORY) + /* History expand the line. If this results in no errors, then + add that line to the history if ADDIT is non-zero. */ + if (!history_expansion_inhibited && history_expansion) + { + expanded = history_expand (line, &history_value); + + if (expanded) + { + if (print_changes) + { + if (expanded < 0) + internal_error (history_value); + else + fprintf (stderr, "%s\n", history_value); + } + + /* If there was an error, return NULL. */ + if (expanded < 0 || expanded == 2) /* 2 == print only */ + { + free (history_value); + +# if defined (HISTORY_REEDITING) + /* New hack. We can allow the user to edit the + failed history expansion. */ + re_edit (line); +# endif /* HISTORY_REEDITING */ + return ((char *)NULL); + } + } + + /* Let other expansions know that return_value can be free'ed, + and that a line has been added to the history list. Note + that we only add lines that have something in them. */ + expanded = 1; + return_value = history_value; + } +# endif /* BANG_HISTORY */ + + if (addit && remember_on_history && *return_value) + maybe_add_history (return_value); + + if (!expanded) + return_value = savestring (line); + + return (return_value); +} + +/* Add LINE to the history list depending on the value of HISTORY_CONTROL. */ +void +maybe_add_history (line) + char *line; +{ + int h; + + /* Don't use the value of history_control to affect the second + and subsequent lines of a multi-line command when + command_oriented_history is enabled. */ + if (command_oriented_history && current_command_line_count > 1) + h = 0; + else + h = history_control; + + switch (h) + { + case 0: + bash_add_history (line); + break; + case 1: + if (*line != ' ') + bash_add_history (line); + break; + case 3: + if (*line == ' ') + break; + /* FALLTHROUGH if case == 3 (`ignoreboth') */ + case 2: + { + HIST_ENTRY *temp; + + using_history (); + temp = previous_history (); + + if (!temp || (STREQ (temp->line, line) == 0)) + bash_add_history (line); + + using_history (); + } + break; + } +} + +/* Add a line to the history list. + The variable COMMAND_ORIENTED_HISTORY controls the style of history + remembering; when non-zero, and LINE is not the first line of a + complete parser construct, append LINE to the last history line instead + of adding it as a new line. */ +static void +bash_add_history (line) + char *line; +{ + int add_it = 1; + + if (command_oriented_history && current_command_line_count > 1) + { + register int offset; + register HIST_ENTRY *current, *old; + char *chars_to_add, *new_line; + + chars_to_add = history_delimiting_chars (); + + using_history (); + + current = previous_history (); + + if (current) + { + /* If the previous line ended with an escaped newline (escaped + with backslash, but otherwise unquoted), then remove the quoted + newline, since that is what happens when the line is parsed. */ + int curlen; + + curlen = strlen (current->line); + + if (!delimiter_depth && current->line[curlen - 1] == '\\' && + current->line[curlen - 2] != '\\') + { + current->line[curlen - 1] = '\0'; + curlen--; + chars_to_add = ""; + } + + offset = where_history (); + new_line = (char *) xmalloc (1 + + curlen + + strlen (line) + + strlen (chars_to_add)); + sprintf (new_line, "%s%s%s", current->line, chars_to_add, line); + old = replace_history_entry (offset, new_line, current->data); + free (new_line); + + if (old) + { + /* Note that the old data is not freed, since it was simply + copied to the new history entry. */ + if (old->line) + free (old->line); + + free (old); + } + add_it = 0; + } + } + + if (add_it) + { + add_history (line); + history_lines_this_session++; + } + using_history (); +} + +int +history_number () +{ + using_history (); + if (get_string_value ("HISTSIZE")) + return (history_base + where_history ()); + else + return (1); /* default to command number 1 */ +} |