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

📄 histexpand.c

📁 在非GUI环境下
💻 C
📖 第 1 页 / 共 3 页
字号:
/* histexpand.c -- history expansion. *//* Copyright (C) 1989-2004 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 2, 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,   59 Temple Place, Suite 330, Boston, MA 02111 USA. */#define READLINE_LIBRARY#if defined (HAVE_CONFIG_H)#  include <config.h>#endif#include <stdio.h>#if defined (HAVE_STDLIB_H)#  include <stdlib.h>#else#  include "ansi_stdlib.h"#endif /* HAVE_STDLIB_H */#if defined (HAVE_UNISTD_H)#  ifndef _MINIX#    include <sys/types.h>#  endif#  include <unistd.h>#endif#include "rlmbutil.h"#include "history.h"#include "histlib.h"#include "rlshell.h"#include "xmalloc.h"#define HISTORY_WORD_DELIMITERS		" \t\n;&()|<>"#define HISTORY_QUOTE_CHARACTERS	"\"'`"#define slashify_in_quotes "\\`\"$"typedef int _hist_search_func_t PARAMS((const char *, int));extern int rl_byte_oriented;	/* declared in mbutil.c */static char error_pointer;static char *subst_lhs;static char *subst_rhs;static int subst_lhs_len;static int subst_rhs_len;static char *get_history_word_specifier PARAMS((char *, char *, int *));static char *history_find_word PARAMS((char *, int));static int history_tokenize_word PARAMS((const char *, int));static char *history_substring PARAMS((const char *, int, int));static char *quote_breaks PARAMS((char *));/* Variables exported by this file. *//* 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=";/* If set to a non-zero value, single quotes inhibit history expansion.   The default is 0. */int history_quotes_inhibit_expansion = 0;/* Used to split words by history_tokenize_internal. */char *history_word_delimiters = HISTORY_WORD_DELIMITERS;/* If set, this points to a function that is called to verify that a   particular history expansion should be performed. */rl_linebuf_func_t *history_inhibit_expansion_function;/* **************************************************************** *//*								    *//*			History Expansion			    *//*								    *//* **************************************************************** *//* Hairy history expansion on text, not tokens.  This is of general   use, and thus belongs in this library. *//* The last string searched for by a !?string? search. */static char *search_string;/* The last string matched by a !?string? search. */static char *search_match;/* Return the event specified at TEXT + OFFSET modifying OFFSET to   point to after the event specifier.  Just a pointer to the history   line is returned; NULL is returned in the event of a bad specifier.   You pass STRING with *INDEX equal to the history_expansion_char that   begins this specification.   DELIMITING_QUOTE is a character that is allowed to end the string   specification for what to search for in addition to the normal   characters `:', ` ', `\t', `\n', and sometimes `?'.   So you might call this function like:   line = get_history_event ("!echo:p", &index, 0);  */char *get_history_event (string, caller_index, delimiting_quote)     const char *string;     int *caller_index;     int delimiting_quote;{  register int i;  register char c;  HIST_ENTRY *entry;  int which, sign, local_index, substring_okay;  _hist_search_func_t *search_func;  char *temp;  /* The event can be specified in a number of ways.     !!   the previous command     !n   command line N     !-n  current command-line minus N     !str the most recent command starting with STR     !?str[?]	  the most recent command containing STR     All values N are determined via HISTORY_BASE. */  i = *caller_index;  if (string[i] != history_expansion_char)    return ((char *)NULL);  /* Move on to the specification. */  i++;  sign = 1;  substring_okay = 0;#define RETURN_ENTRY(e, w) \	return ((e = history_get (w)) ? e->line : (char *)NULL)  /* Handle !! case. */  if (string[i] == history_expansion_char)    {      i++;      which = history_base + (history_length - 1);      *caller_index = i;      RETURN_ENTRY (entry, which);    }  /* Hack case of numeric line specification. */  if (string[i] == '-')    {      sign = -1;      i++;    }  if (_rl_digit_p (string[i]))    {      /* Get the extent of the digits and compute the value. */      for (which = 0; _rl_digit_p (string[i]); i++)	which = (which * 10) + _rl_digit_value (string[i]);      *caller_index = i;      if (sign < 0)	which = (history_length + history_base) - which;      RETURN_ENTRY (entry, which);    }  /* This must be something to search for.  If the spec begins with     a '?', then the string may be anywhere on the line.  Otherwise,     the string must be found at the start of a line. */  if (string[i] == '?')    {      substring_okay++;      i++;    }  /* Only a closing `?' or a newline delimit a substring search string. */  for (local_index = i; c = string[i]; i++)#if defined (HANDLE_MULTIBYTE)    if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)      {	int v;	mbstate_t ps;	memset (&ps, 0, sizeof (mbstate_t));	/* These produce warnings because we're passing a const string to a	   function that takes a non-const string. */	_rl_adjust_point ((char *)string, i, &ps);	if ((v = _rl_get_char_len ((char *)string + i, &ps)) > 1)	  {	    i += v - 1;	    continue;	  }      }    else#endif /* HANDLE_MULTIBYTE */      if ((!substring_okay && (whitespace (c) || c == ':' ||	  (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||	  string[i] == delimiting_quote)) ||	  string[i] == '\n' ||	  (substring_okay && string[i] == '?'))	break;  which = i - local_index;  temp = (char *)xmalloc (1 + which);  if (which)    strncpy (temp, string + local_index, which);  temp[which] = '\0';  if (substring_okay && string[i] == '?')    i++;  *caller_index = i;#define FAIL_SEARCH() \  do { \    history_offset = history_length; free (temp) ; return (char *)NULL; \  } while (0)  /* If there is no search string, try to use the previous search string,     if one exists.  If not, fail immediately. */  if (*temp == '\0' && substring_okay)    {      if (search_string)        {          free (temp);          temp = savestring (search_string);        }      else        FAIL_SEARCH ();    }  search_func = substring_okay ? history_search : history_search_prefix;  while (1)    {      local_index = (*search_func) (temp, -1);      if (local_index < 0)	FAIL_SEARCH ();      if (local_index == 0 || substring_okay)	{	  entry = current_history ();	  history_offset = history_length;		  /* If this was a substring search, then remember the	     string that we matched for word substitution. */	  if (substring_okay)	    {	      FREE (search_string);	      search_string = temp;	      FREE (search_match);	      search_match = history_find_word (entry->line, local_index);	    }	  else	    free (temp);	  return (entry->line);	}      if (history_offset)	history_offset--;      else	FAIL_SEARCH ();    }#undef FAIL_SEARCH#undef RETURN_ENTRY}/* Function for extracting single-quoted strings.  Used for inhibiting   history expansion within single quotes. *//* Extract the contents of STRING as if it is enclosed in single quotes.   SINDEX, when passed in, is the offset of the character immediately   following the opening single quote; on exit, SINDEX is left pointing   to the closing single quote. */static voidhist_string_extract_single_quoted (string, sindex)     char *string;     int *sindex;{  register int i;  for (i = *sindex; string[i] && string[i] != '\''; i++)    ;  *sindex = i;}static char *quote_breaks (s)     char *s;{  register char *p, *r;  char *ret;  int len = 3;  for (p = s; p && *p; p++, len++)    {      if (*p == '\'')	len += 3;      else if (whitespace (*p) || *p == '\n')	len += 2;    }  r = ret = (char *)xmalloc (len);  *r++ = '\'';  for (p = s; p && *p; )    {      if (*p == '\'')	{	  *r++ = '\'';	  *r++ = '\\';	  *r++ = '\'';	  *r++ = '\'';	  p++;	}      else if (whitespace (*p) || *p == '\n')	{	  *r++ = '\'';	  *r++ = *p++;	  *r++ = '\'';	}      else	*r++ = *p++;    }  *r++ = '\'';  *r = '\0';  return ret;}static char *hist_error(s, start, current, errtype)      char *s;      int start, current, errtype;{  char *temp;  const char *emsg;  int ll, elen;  ll = current - start;  switch (errtype)    {    case EVENT_NOT_FOUND:      emsg = "event not found";      elen = 15;      break;    case BAD_WORD_SPEC:      emsg = "bad word specifier";      elen = 18;      break;    case SUBST_FAILED:      emsg = "substitution failed";      elen = 19;      break;    case BAD_MODIFIER:      emsg = "unrecognized history modifier";      elen = 29;      break;    case NO_PREV_SUBST:      emsg = "no previous substitution";      elen = 24;      break;    default:      emsg = "unknown expansion error";      elen = 23;      break;    }  temp = (char *)xmalloc (ll + elen + 3);  strncpy (temp, s + start, ll);  temp[ll] = ':';  temp[ll + 1] = ' ';  strcpy (temp + ll + 2, emsg);  return (temp);}/* Get a history substitution string from STR starting at *IPTR   and return it.  The length is returned in LENPTR.   A backslash can quote the delimiter.  If the string is the   empty string, the previous pattern is used.  If there is   no previous pattern for the lhs, the last history search   string is used.   If IS_RHS is 1, we ignore empty strings and set the pattern   to "" anyway.  subst_lhs is not changed if the lhs is empty;   subst_rhs is allowed to be set to the empty string. */static char *get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr)     char *str;     int *iptr, delimiter, is_rhs, *lenptr;{  register int si, i, j, k;  char *s;#if defined (HANDLE_MULTIBYTE)  mbstate_t ps;#endif  s = (char *)NULL;  i = *iptr;#if defined (HANDLE_MULTIBYTE)  memset (&ps, 0, sizeof (mbstate_t));  _rl_adjust_point (str, i, &ps);#endif  for (si = i; str[si] && str[si] != delimiter; si++)#if defined (HANDLE_MULTIBYTE)    if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)      {	int v;	if ((v = _rl_get_char_len (str + si, &ps)) > 1)	  si += v - 1;	else if (str[si] == '\\' && str[si + 1] == delimiter)	  si++;      }    else#endif /* HANDLE_MULTIBYTE */      if (str[si] == '\\' && str[si + 1] == delimiter)	si++;  if (si > i || is_rhs)    {      s = (char *)xmalloc (si - i + 1);      for (j = 0, k = i; k < si; j++, k++)	{	  /* Remove a backslash quoting the search string delimiter. */	  if (str[k] == '\\' && str[k + 1] == delimiter)	    k++;	  s[j] = str[k];	}      s[j] = '\0';      if (lenptr)	*lenptr = j;    }  i = si;  if (str[i])    i++;  *iptr = i;  return s;}static voidpostproc_subst_rhs (){  char *new;  int i, j, new_size;  new = (char *)xmalloc (new_size = subst_rhs_len + subst_lhs_len);  for (i = j = 0; i < subst_rhs_len; i++)    {      if (subst_rhs[i] == '&')	{	  if (j + subst_lhs_len >= new_size)	    new = (char *)xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));	  strcpy (new + j, subst_lhs);	  j += subst_lhs_len;	}      else	{	  /* a single backslash protects the `&' from lhs interpolation */	  if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')	    i++;	  if (j >= new_size)	    new = (char *)xrealloc (new, new_size *= 2);	  new[j++] = subst_rhs[i];	}    }  new[j] = '\0';  free (subst_rhs);  subst_rhs = new;  subst_rhs_len = j;}/* Expand the bulk of a history specifier starting at STRING[START].   Returns 0 if everything is OK, -1 if an error occurred, and 1   if the `p' modifier was supplied and the caller should just print   the returned string.  Returns the new index into string in   *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */static inthistory_expand_internal (string, start, end_index_ptr, ret_string, current_line)     char *string;     int start, *end_index_ptr;     char **ret_string;     char *current_line;	/* for !# */{  int i, n, starting_index;  int substitute_globally, subst_bywords, want_quotes, print_only;  char *event, *temp, *result, *tstr, *t, c, *word_spec;  int result_len;#if defined (HANDLE_MULTIBYTE)  mbstate_t ps;  memset (&ps, 0, sizeof (mbstate_t));#endif

⌨️ 快捷键说明

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