⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 history.c

📁 linux下bash的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* History.c -- standalone history library *//* Copyright (C) 1989, 1992 Free Software Foundation, Inc.   This file contains the GNU History Library (the Library), a set of   routines for managing the text of previously typed lines.   The Library 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 1, or (at your option)   any later version.   The Library 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.   The GNU General Public License is often shipped with GNU software, and   is generally kept in a file called COPYING or LICENSE.  If you do not   have a copy of the license, write to the Free Software Foundation,   675 Mass Ave, Cambridge, MA 02139, USA. *//* The goal is to make the implementation transparent, so that you   don't have to know what data types are used, just what functions   you can call.  I think I have done that. */#define READLINE_LIBRARY#include <stdio.h>#include <sys/types.h>#include <sys/file.h>#include <sys/stat.h>#include <fcntl.h>#if defined (HAVE_STDLIB_H)#  include <stdlib.h>#else#  include "ansi_stdlib.h"#endif /* HAVE_STDLIB_H */#if defined (HAVE_UNISTD_H)#  include <unistd.h>#endif#if defined (HAVE_STRING_H)#  include <string.h>#else#  include <strings.h>#endif /* !HAVE_STRING_H */#include <errno.h>/* Not all systems declare ERRNO in errno.h... and some systems #define it! */#if !defined (errno)extern int errno;#endif /* !errno */#include "memalloc.h"#include "history.h"#if defined (STATIC_MALLOC)static char *xmalloc (), *xrealloc ();#elseextern char *xmalloc (), *xrealloc ();#endif /* STATIC_MALLOC */#define STREQ(a, b)	(((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0))#define STREQN(a, b, n)	(((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0))#ifndef savestring#  ifndef strcpyextern char *strcpy ();#  endif#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))#endif#ifndef whitespace#define whitespace(c) (((c) == ' ') || ((c) == '\t'))#endif#ifndef digit_p#define digit_p(c)  ((c) >= '0' && (c) <= '9')#endif#ifndef digit_value#define digit_value(c) ((c) - '0')#endif#ifndef member#  ifndef strchrextern char *strchr ();#  endif#define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0)#endif/* Possible history errors passed to hist_error. */#define EVENT_NOT_FOUND 0#define BAD_WORD_SPEC	1#define SUBST_FAILED	2#define BAD_MODIFIER	3static char error_pointer;static char *subst_lhs;static char *subst_rhs;static int subst_lhs_len = 0;static int subst_rhs_len = 0;static char *get_history_word_specifier ();static char *history_find_word ();#if defined (SHELL)extern char *single_quote ();#endif/* **************************************************************** *//*								    *//*			History Functions			    *//*								    *//* **************************************************************** *//* An array of HIST_ENTRY.  This is where we store the history. */static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;/* Non-zero means that we have enforced a limit on the amount of   history that we save. */static int history_stifled = 0;/* If HISTORY_STIFLED is non-zero, then this is the maximum number of   entries to remember. */int max_input_history;/* The current location of the interactive history pointer.  Just makes   life easier for outside callers. */static int history_offset = 0;/* The number of strings currently stored in the input_history list. */int history_length = 0;/* The current number of slots allocated to the input_history. */static int history_size = 0;/* The number of slots to increase the_history by. */#define DEFAULT_HISTORY_GROW_SIZE 50/* The character that represents the start of a history expansion   request.  This is usually `!'. */char history_expansion_char = '!';/* The character that invokes word substitution if found at the start of   a line.  This is usually `^'. */char history_subst_char = '^';/* During tokenization, if this character is seen as the first character   of a word, then it, and all subsequent characters upto a newline are   ignored.  For a Bourne shell, this should be '#'.  Bash special cases   the interactive comment character to not be a comment delimiter. */char history_comment_char = '\0';/* The list of characters which inhibit the expansion of text if found   immediately following history_expansion_char. */char *history_no_expand_chars = " \t\n\r=";/* The logical `base' of the history array.  It defaults to 1. */int history_base = 1;/* Return the current HISTORY_STATE of the history. */HISTORY_STATE *history_get_history_state (){  HISTORY_STATE *state;  state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE));  state->entries = the_history;  state->offset = history_offset;  state->length = history_length;  state->size = history_size;  state->flags = 0;  if (history_stifled)    state->flags |= HS_STIFLED;  return (state);}/* Set the state of the current history array to STATE. */voidhistory_set_history_state (state)     HISTORY_STATE *state;{  the_history = state->entries;  history_offset = state->offset;  history_length = state->length;  history_size = state->size;  if (state->flags & HS_STIFLED)    history_stifled = 1;}/* Begin a session in which the history functions might be used.  This   initializes interactive variables. */voidusing_history (){  history_offset = history_length;}/* Return the number of bytes that the primary history entries are using.   This just adds up the lengths of the_history->lines. */inthistory_total_bytes (){  register int i, result;  result = 0;  for (i = 0; the_history && the_history[i]; i++)    result += strlen (the_history[i]->line);  return (result);}/* Place STRING at the end of the history list.  The data field   is  set to NULL. */voidadd_history (string)     char *string;{  HIST_ENTRY *temp;  if (history_stifled && (history_length == max_input_history))    {      register int i;      /* If the history is stifled, and history_length is zero,	 and it equals max_input_history, we don't save items. */      if (history_length == 0)	return;      /* If there is something in the slot, then remove it. */      if (the_history[0])	{	  free (the_history[0]->line);	  free (the_history[0]);	}      /* Copy the rest of the entries, moving down one slot. */      for (i = 0; i < history_length; i++)	the_history[i] = the_history[i + 1];      history_base++;    }  else    {      if (!history_size)	{	  history_size = DEFAULT_HISTORY_GROW_SIZE;	  the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *));	  history_length = 1;	}      else	{	  if (history_length == (history_size - 1))	    {	      history_size += DEFAULT_HISTORY_GROW_SIZE;	      the_history = (HIST_ENTRY **)		xrealloc (the_history, history_size * sizeof (HIST_ENTRY *));	    }	  history_length++;	}    }  temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));  temp->line = savestring (string);  temp->data = (char *)NULL;  the_history[history_length] = (HIST_ENTRY *)NULL;  the_history[history_length - 1] = temp;}/* Make the history entry at WHICH have LINE and DATA.  This returns   the old entry so you can dispose of the data.  In the case of an   invalid WHICH, a NULL pointer is returned. */HIST_ENTRY *replace_history_entry (which, line, data)     int which;     char *line;     char *data;{  HIST_ENTRY *temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));  HIST_ENTRY *old_value;  if (which >= history_length)    return ((HIST_ENTRY *)NULL);  old_value = the_history[which];  temp->line = savestring (line);  temp->data = data;  the_history[which] = temp;  return (old_value);}/* Returns the magic number which says what history element we are   looking at now.  In this implementation, it returns history_offset. */intwhere_history (){  return (history_offset);}/* Search the history for STRING, starting at history_offset.   If DIRECTION < 0, then the search is through previous entries, else   through subsequent.  If ANCHORED is non-zero, the string must   appear at the beginning of a history line, otherwise, the string   may appear anywhere in the line.  If the string is found, then   current_history () is the history entry, and the value of this   function is the offset in the line of that history entry that the   string was found in.  Otherwise, nothing is changed, and a -1 is   returned. */#define ANCHORED_SEARCH 1#define NON_ANCHORED_SEARCH 0static inthistory_search_internal (string, direction, anchored)     char *string;     int direction, anchored;{  register int i, reverse;  register char *line;  register int line_index;  int string_len;  i = history_offset;  reverse = (direction < 0);  /* Take care of trivial cases first. */  if (string == 0 || *string == '\0')    return (-1);  if (!history_length || ((i == history_length) && !reverse))    return (-1);  if (reverse && (i == history_length))    i--;#define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)  string_len = strlen (string);  while (1)    {      /* Search each line in the history list for STRING. */      /* At limit for direction? */      if ((reverse && i < 0) || (!reverse && i == history_length))	return (-1);      line = the_history[i]->line;      line_index = strlen (line);      /* If STRING is longer than line, no match. */      if (string_len > line_index)	{	  NEXT_LINE ();	  continue;	}      /* Handle anchored searches first. */      if (anchored == ANCHORED_SEARCH)	{	  if (STREQN (string, line, string_len))	    {	      history_offset = i;	      return (0);	    }	  NEXT_LINE ();	  continue;	}      /* Do substring search. */      if (reverse)	{	  line_index -= string_len;	  while (line_index >= 0)	    {	      if (STREQN (string, line + line_index, string_len))		{		  history_offset = i;		  return (line_index);		}	      line_index--;	    }	}      else	{	  register int limit = line_index - string_len + 1;	  line_index = 0;	  while (line_index < limit)	    {	      if (STREQN (string, line + line_index, string_len))		{		  history_offset = i;		  return (line_index);		}	      line_index++;	    }	}      NEXT_LINE ();    }}/* Do a non-anchored search for STRING through the history in DIRECTION. */inthistory_search (string, direction)     char *string;     int direction;{  return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));}/* Do an anchored search for string through the history in DIRECTION. */inthistory_search_prefix (string, direction)     char *string;     int direction;{  return (history_search_internal (string, direction, ANCHORED_SEARCH));}/* Remove history element WHICH from the history.  The removed   element is returned to you so you can free the line, data,   and containing structure. */HIST_ENTRY *remove_history (which)     int which;{  HIST_ENTRY *return_value;  if (which >= history_length || !history_length)    return_value = (HIST_ENTRY *)NULL;  else    {      register int i;      return_value = the_history[which];      for (i = which; i < history_length; i++)	the_history[i] = the_history[i + 1];      history_length--;    }  return (return_value);}/* Stifle the history list, remembering only MAX number of lines. */voidstifle_history (max)     int max;{  if (max < 0)    max = 0;  if (history_length > max)    {      register int i, j;      /* This loses because we cannot free the data. */      for (i = 0; i < (history_length - max); i++)	{	  free (the_history[i]->line);	  free (the_history[i]);	}      history_base = i;      for (j = 0, i = history_length - max; j < max; i++, j++)	the_history[j] = the_history[i];      the_history[j] = (HIST_ENTRY *)NULL;      history_length = j;    }  history_stifled = 1;  max_input_history = max;}/* Stop stifling the history.  This returns the previous amount the history was stifled by.  The value is positive if the history was stifled, negative if it wasn't. */intunstifle_history (){  int result = max_input_history;  if (history_stifled)    {      result = -result;      history_stifled = 0;    }  return (result);}inthistory_is_stifled (){  return (history_stifled);}/* Return the string that should be used in the place of this   filename.  This only matters when you don't specify the   filename to read_history (), or write_history (). */static char *history_filename (filename)     char *filename;{  char *return_val = filename ? savestring (filename) : (char *)NULL;  if (!return_val)    {      char *home;      int home_len;      home = getenv ("HOME");      if (!home)	home = ".";      home_len = strlen (home);      /* strlen(".history") == 8 */      return_val = xmalloc (2 + home_len + 8);      strcpy (return_val, home);      return_val[home_len] = '/';      strcpy (return_val + home_len + 1, ".history");    }  return (return_val);}/* Add the contents of FILENAME to the history list, a line at a time.   If FILENAME is NULL, then read from ~/.history.  Returns 0 if   successful, or errno if not. */intread_history (filename)     char *filename;{  return (read_history_range (filename, 0, -1));}/* Read a range of lines from FILENAME, adding them to the history list.   Start reading at the FROM'th line and end at the TO'th.  If FROM   is zero, start at the beginning.  If TO is less than FROM, read   until the end of the file.  If FILENAME is NULL, then read from   ~/.history.  Returns 0 if successful, or errno if not. */intread_history_range (filename, from, to)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -