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

📄 history.c

📁 linux下bash的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
    case SUBST_FAILED:      emsg = "substitution failed";      elen = 19;      break;    case BAD_MODIFIER:      emsg = "unrecognized history modifier";      elen = 29;      break;    default:      emsg = "unknown expansion error";      elen = 23;      break;    }  temp = 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 = (char *) NULL;  i = *iptr;  for (si = i; str[si] && str[si] != delimiter; si++)    if (str[si] == '\\' && str[si + 1] == delimiter)      si++;  if (si > i || is_rhs)    {      s = 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 = 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 = 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 = 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, want_quotes, print_only;  char *event, *temp, *result, *tstr, *t, c, *word_spec;  int result_len;  result = xmalloc (result_len = 128);  i = start;  /* If it is followed by something that starts a word specifier,     then !! is implied as the event specifier. */  if (member (string[i + 1], ":$*%^"))    {      char fake_s[3];      int fake_i = 0;      i++;      fake_s[0] = fake_s[1] = history_expansion_char;      fake_s[2] = '\0';      event = get_history_event (fake_s, &fake_i, 0);    }  else if (string[i + 1] == '#')    {      i += 2;      event = current_line;    }  else    {      int quoted_search_delimiter = 0;      /* If the character before this `!' is a double or single	 quote, then this expansion takes place inside of the	 quoted string.  If we have to search for some text ("!foo"),	 allow the delimiter to end the search string. */      if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))	quoted_search_delimiter = string[i - 1];      event = get_history_event (string, &i, quoted_search_delimiter);    }	    if (!event)    {      *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND);      free (result);      return (-1);    }  /* If a word specifier is found, then do what that requires. */  starting_index = i;  word_spec = get_history_word_specifier (string, event, &i);  /* There is no such thing as a `malformed word specifier'.  However,     it is possible for a specifier that has no match.  In that case,     we complain. */  if (word_spec == (char *)&error_pointer)    {      *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC);      free (result);      return (-1);    }  /* If no word specifier, than the thing of interest was the event. */  if (!word_spec)    temp = savestring (event);  else    {      temp = savestring (word_spec);      free (word_spec);    }  /* Perhaps there are other modifiers involved.  Do what they say. */  want_quotes = substitute_globally = print_only = 0;  starting_index = i;  while (string[i] == ':')    {      c = string[i + 1];      if (c == 'g')	{	  substitute_globally = 1;	  i++;	  c = string[i + 1];	}      switch (c)	{	default:	  *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER);	  free (result);	  free (temp);	  return -1;#if defined (SHELL)	case 'q':	  want_quotes = 'q';	  break;	case 'x':	  want_quotes = 'x';	  break;#endif /* SHELL */	  /* :p means make this the last executed line.  So we	     return an error state after adding this line to the	     history. */	case 'p':	  print_only++;	  break;	  /* :t discards all but the last part of the pathname. */	case 't':	  tstr = strrchr (temp, '/');	  if (tstr)	    {	      tstr++;	      t = savestring (tstr);	      free (temp);	      temp = t;	    }	  break;	  /* :h discards the last part of a pathname. */	case 'h':	  tstr = strrchr (temp, '/');	  if (tstr)	    *tstr = '\0';	  break;	  /* :r discards the suffix. */	case 'r':	  tstr = strrchr (temp, '.');	  if (tstr)	    *tstr = '\0';	  break;	  /* :e discards everything but the suffix. */	case 'e':	  tstr = strrchr (temp, '.');	  if (tstr)	    {	      t = savestring (tstr);	      free (temp);	      temp = t;	    }	  break;	/* :s/this/that substitutes `that' for the first	   occurrence of `this'.  :gs/this/that substitutes `that'	   for each occurrence of `this'.  :& repeats the last	   substitution.  :g& repeats the last substitution	   globally. */	case '&':	case 's':	  {	    char *new_event, *t;	    int delimiter, failed, si, l_temp;	    if (c == 's')	      {		if (i + 2 < (int)strlen (string))		  delimiter = string[i + 2];		else		  break;	/* no search delimiter */		i += 3;		t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len);		/* An empty substitution lhs with no previous substitution		   uses the last search string as the lhs. */		if (t)		  {		    if (subst_lhs)		      free (subst_lhs);		    subst_lhs = t;		  }		else if (!subst_lhs)		  {		    if (search_string && *search_string)		      {			subst_lhs = savestring (search_string);			subst_lhs_len = strlen (subst_lhs);		      }		    else		      {		        subst_lhs = (char *) NULL;		        subst_lhs_len = 0;		      }		  }		/* If there is no lhs, the substitution can't succeed. */		if (subst_lhs_len == 0)		  {		    *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);		    free (result);		    free (temp);		    return -1;		  }		if (subst_rhs)		  free (subst_rhs);		subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);		/* If `&' appears in the rhs, it's supposed to be replaced		   with the lhs. */		if (member ('&', subst_rhs))		  postproc_subst_rhs ();	      }	    else	      i += 2;	    l_temp = strlen (temp);	    /* Ignore impossible cases. */	    if (subst_lhs_len > l_temp)	      {		*ret_string = hist_error (string, starting_index, i, SUBST_FAILED);		free (result);		free (temp);		return (-1);	      }	    /* Find the first occurrence of THIS in TEMP. */	    si = 0;	    for (failed = 1; (si + subst_lhs_len) <= l_temp; si++)	      if (STREQN (temp+si, subst_lhs, subst_lhs_len))		{		  int len = subst_rhs_len - subst_lhs_len + l_temp;		  new_event = xmalloc (1 + len);		  strncpy (new_event, temp, si);		  strncpy (new_event + si, subst_rhs, subst_rhs_len);		  strncpy (new_event + si + subst_rhs_len,			   temp + si + subst_lhs_len,			   l_temp - (si + subst_lhs_len));		  new_event[len] = '\0';		  free (temp);		  temp = new_event;		  failed = 0;		  if (substitute_globally)		    {		      si += subst_rhs_len;		      l_temp = strlen (temp);		      substitute_globally++;		      continue;		    }		  else		    break;		}	    if (substitute_globally > 1)	      {		substitute_globally = 0;		continue;	/* don't want to increment i */	      }	    if (failed == 0)	      continue;		/* don't want to increment i */	    *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);	    free (result);	    free (temp);	    return (-1);	  }	}      i += 2;    }  /* Done with modfiers. */  /* Believe it or not, we have to back the pointer up by one. */  --i;#if defined (SHELL)  if (want_quotes)    {      char *x;      if (want_quotes == 'q')	x = single_quote (temp);      else if (want_quotes == 'x')	x = quote_breaks (temp);      else	x = savestring (temp);      free (temp);      temp = x;    }#endif /* SHELL */  n = strlen (temp);  if (n > result_len)    result = xrealloc (result, n + 2);  strcpy (result, temp);  free (temp);  *end_index_ptr = i;  *ret_string = result;  return (print_only);}/* Expand the string STRING, placing the result into OUTPUT, a pointer   to a string.  Returns:  -1) If there was an error in expansion.   0) If no expansions took place (or, if the only change in      the text was the de-slashifying of the history expansion      character)   1) If expansions did take place   2) If the `p' modifier was given and the caller should print the result  If an error ocurred in expansion, then OUTPUT contains a descriptive  error message. */#define ADD_STRING(s) \	do \	  { \	    int sl = strlen (s); \	    j += sl; \	    if (j >= result_len) \	      { \		while (j >= result_len) \		  result_len += 128; \		result = xrealloc (result, result_len); \	      } \	    strcpy (result + j - sl, s); \	  } \	while (0)#define ADD_CHAR(c) \	do \	  { \	    if (j >= result_len - 1) \	      result = xrealloc (result, result_len += 64); \	    result[j++] = c; \	    result[j] = '\0'; \	  } \	while (0)inthistory_expand (hstring, output)     char *hstring;     char **output;{  register int j;  int i, r, l, passc, cc, modified, eindex, only_printing;  char *string;  /* The output string, and its length. */  int result_len;  char *result;  /* Used when adding the string. */  char *temp;  /* Setting the history expansion character to 0 inhibits all     history expansion. */  if (history_expansion_char == 0)    {      *output = savestring (hstring);      return (0);    }      /* Prepare the buffer for printing error messages. */  result = xmalloc (result_len = 256);  result[0] = '\0';  only_printing = modified = 0;  l = strlen (hstring);  /* Grovel the string.  Only backslash can quote the history escape     character.  We also handle arg specifiers. */  /* Before we grovel forever, see if the history_expansion_char appears     anywhere within the text. */  /* The quick substitution character is a history expansion all right.  That     is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,     that is the substitution that we do. */  if (hstring[0] == history_subst_char)    {      string = xmalloc (l + 5);      string[0] = string[1] = history_expansion_char;      string[2] = ':';      string[3] = 's';      strcpy (string + 4, hstring);      l += 4;    }  else    {      string = hstring;      /* If not quick substitution, still maybe have to do expansion. */      /* `!' followed by one of the characters in history_no_expand_chars	 is NOT an expansion. */      for (i = 0; string[i]; i++)	{	  cc = string[i + 1];          if (string[i] == history_expansion_char)	    {	      if (!cc || member (cc, history_no_expand_chars))		continue;#if defined (SHELL)	      /* The shell uses ! as a pattern negation character	         in globbing [...] expressions, so let those pass	         without expansion. */	      else if (i > 0 && (string[i - 1] == '[') &&		       member (']', string + i + 1))		continue;#endif /* SHELL */	      else		break;	    }#if defined (SHELL)	  else if (string[i] == '\'')	    {	      /* If this is bash, single quotes inhibit history expansion. */	      i++;	      rl_string_extract_single_quoted (string, &i);	    }	  else if (string[i] == '\\')	    {	      /* If this is bash, allow backslashes to quote single		 quotes and		 the history expansion character. */	      if (cc == '\'' || cc == history_expansion_char)		i++;	    }#endif /* SHELL */	}	        if (string[i] != history_expansion_char)	{	  free (result);	  *output = savestring (string);	  return (0);	}    }  /* Extract and perform the substitution. */  for (passc = i = j = 0; i < l; i++)

⌨️ 快捷键说明

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