aboutsummaryrefslogtreecommitdiffstats
path: root/bashhist.c
diff options
context:
space:
mode:
authorJari Aalto <jari.aalto@cante.net>1996-08-26 18:22:31 +0000
committerJari Aalto <jari.aalto@cante.net>2009-09-12 16:46:49 +0000
commit726f63884db0132f01745f1fb4465e6621088ccf (patch)
tree6c2f7765a890a97e0e513cb539df43283a8f7c4d /bashhist.c
downloadandroid_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.c390
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 */
+}