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

📄 histexpand.c

📁 UNIX下SH的实现源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	}
    }

  /* Extract and perform the substitution. */
  for (passc = i = j = 0; i < l; i++)
    {
      int tchar = string[i];

      if (passc)
	{
	  passc = 0;
	  ADD_CHAR (tchar);
	  continue;
	}

      if (tchar == history_expansion_char)
	tchar = -3;
      else if (tchar == history_comment_char)
	tchar = -2;

      switch (tchar)
	{
	default:
	  ADD_CHAR (string[i]);
	  break;

	case '\\':
	  passc++;
	  ADD_CHAR (tchar);
	  break;

	case '\'':
	  {
	    /* If history_quotes_inhibit_expansion is set, single quotes
	       inhibit history expansion. */
	    if (history_quotes_inhibit_expansion)
	      {
		int quote, slen;

		quote = i++;
		hist_string_extract_single_quoted (string, &i);

		slen = i - quote + 2;
		temp = xmalloc (slen);
		strncpy (temp, string + quote, slen);
		temp[slen - 1] = '\0';
		ADD_STRING (temp);
		free (temp);
	      }
	    else
	      ADD_CHAR (string[i]);
	    break;
	  }

	case -2:		/* history_comment_char */
	  if (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS))
	    {
	      temp = xmalloc (l - i + 1);
	      strcpy (temp, string + i);
	      ADD_STRING (temp);
	      free (temp);
	      i = l;
	    }
	  else
	    ADD_CHAR (string[i]);
	  break;

	case -3:		/* history_expansion_char */
	  cc = string[i + 1];

	  /* If the history_expansion_char is followed by one of the
	     characters in history_no_expand_chars, then it is not a
	     candidate for expansion of any kind. */
	  if (member (cc, history_no_expand_chars))
	    {
	      ADD_CHAR (string[i]);
	      break;
	    }

#if defined (NO_BANG_HASH_MODIFIERS)
	  /* There is something that is listed as a `word specifier' in csh
	     documentation which means `the expanded text to this point'.
	     That is not a word specifier, it is an event specifier.  If we
	     don't want to allow modifiers with `!#', just stick the current
	     output line in again. */
	  if (cc == '#')
	    {
	      if (result)
		{
		  temp = xmalloc (1 + strlen (result));
		  strcpy (temp, result);
		  ADD_STRING (temp);
		  free (temp);
		}
	      i++;
	      break;
	    }
#endif

	  r = history_expand_internal (string, i, &eindex, &temp, result);
	  if (r < 0)
	    {
	      *output = temp;
	      free (result);
	      if (string != hstring)
		free (string);
	      return -1;
	    }
	  else
	    {
	      if (temp)
		{
		  modified++;
		  if (*temp)
		    ADD_STRING (temp);
		  free (temp);
		}
	      only_printing = r == 1;
	      i = eindex;
	    }
	  break;
	}
    }

  *output = result;
  if (string != hstring)
    free (string);

  if (only_printing)
    {
      add_history (result);
      return (2);
    }

  return (modified != 0);
}

/* Return a consed string which is the word specified in SPEC, and found
   in FROM.  NULL is returned if there is no spec.  The address of
   ERROR_POINTER is returned if the word specified cannot be found.
   CALLER_INDEX is the offset in SPEC to start looking; it is updated
   to point to just after the last character parsed. */
static char *
get_history_word_specifier (spec, from, caller_index)
     char *spec, *from;
     int *caller_index;
{
  register int i = *caller_index;
  int first, last;
  int expecting_word_spec = 0;
  char *result;

  /* The range of words to return doesn't exist yet. */
  first = last = 0;
  result = (char *)NULL;

  /* If we found a colon, then this *must* be a word specification.  If
     it isn't, then it is an error. */
  if (spec[i] == ':')
    {
      i++;
      expecting_word_spec++;
    }

  /* Handle special cases first. */

  /* `%' is the word last searched for. */
  if (spec[i] == '%')
    {
      *caller_index = i + 1;
      return (search_match ? savestring (search_match) : savestring (""));
    }

  /* `*' matches all of the arguments, but not the command. */
  if (spec[i] == '*')
    {
      *caller_index = i + 1;
      result = history_arg_extract (1, '$', from);
      return (result ? result : savestring (""));
    }

  /* `$' is last arg. */
  if (spec[i] == '$')
    {
      *caller_index = i + 1;
      return (history_arg_extract ('$', '$', from));
    }

  /* Try to get FIRST and LAST figured out. */

  if (spec[i] == '-')
    first = 0;
  else if (spec[i] == '^')
    first = 1;
  else if (_rl_digit_p (spec[i]) && expecting_word_spec)
    {
      for (first = 0; _rl_digit_p (spec[i]); i++)
	first = (first * 10) + _rl_digit_value (spec[i]);
    }
  else
    return ((char *)NULL);	/* no valid `first' for word specifier */

  if (spec[i] == '^' || spec[i] == '*')
    {
      last = (spec[i] == '^') ? 1 : '$';	/* x* abbreviates x-$ */
      i++;
    }
  else if (spec[i] != '-')
    last = first;
  else
    {
      i++;

      if (_rl_digit_p (spec[i]))
	{
	  for (last = 0; _rl_digit_p (spec[i]); i++)
	    last = (last * 10) + _rl_digit_value (spec[i]);
	}
      else if (spec[i] == '$')
	{
	  i++;
	  last = '$';
	}
      else if (!spec[i] || spec[i] == ':')  /* could be modifier separator */
	last = -1;		/* x- abbreviates x-$ omitting word `$' */
    }

  *caller_index = i;

  if (last >= first || last == '$' || last < 0)
    result = history_arg_extract (first, last, from);

  return (result ? result : (char *)&error_pointer);
}

/* Extract the args specified, starting at FIRST, and ending at LAST.
   The args are taken from STRING.  If either FIRST or LAST is < 0,
   then make that arg count from the right (subtract from the number of
   tokens, so that FIRST = -1 means the next to last token on the line).
   If LAST is `$' the last arg from STRING is used. */
char *
history_arg_extract (first, last, string)
     int first, last;
     char *string;
{
  register int i, len;
  char *result;
  int size, offset;
  char **list;

  /* XXX - think about making history_tokenize return a struct array,
     each struct in array being a string and a length to avoid the
     calls to strlen below. */
  if ((list = history_tokenize (string)) == NULL)
    return ((char *)NULL);

  for (len = 0; list[len]; len++)
    ;

  if (last < 0)
    last = len + last - 1;

  if (first < 0)
    first = len + first - 1;

  if (last == '$')
    last = len - 1;

  if (first == '$')
    first = len - 1;

  last++;

  if (first >= len || last > len || first < 0 || last < 0 || first > last)
    result = ((char *)NULL);
  else
    {
      for (size = 0, i = first; i < last; i++)
	size += strlen (list[i]) + 1;
      result = xmalloc (size + 1);
      result[0] = '\0';

      for (i = first, offset = 0; i < last; i++)
	{
	  strcpy (result + offset, list[i]);
	  offset += strlen (list[i]);
	  if (i + 1 < last)
	    {
      	      result[offset++] = ' ';
	      result[offset] = 0;
	    }
	}
    }

  for (i = 0; i < len; i++)
    free (list[i]);
  free (list);

  return (result);
}

#define slashify_in_quotes "\\`\"$"

/* Parse STRING into tokens and return an array of strings.  If WIND is
   not -1 and INDP is not null, we also want the word surrounding index
   WIND.  The position in the returned array of strings is returned in
   *INDP. */
static char **
history_tokenize_internal (string, wind, indp)
     char *string;
     int wind, *indp;
{
  char **result;
  register int i, start, result_index, size;
  int len, delimiter;

  /* Get a token, and stuff it into RESULT.  The tokens are split
     exactly where the shell would split them. */
  for (i = result_index = size = 0, result = (char **)NULL; string[i]; )
    {
      delimiter = 0;

      /* Skip leading whitespace. */
      for (; string[i] && whitespace (string[i]); i++)
	;
      if (string[i] == 0 || string[i] == history_comment_char)
	return (result);

      start = i;
      
      if (member (string[i], "()\n"))
	{
	  i++;
	  goto got_token;
	}

      if (member (string[i], "<>;&|$"))
	{
	  int peek = string[i + 1];

	  if (peek == string[i] && peek != '$')
	    {
	      if (peek == '<' && string[i + 2] == '-')
		i++;
	      i += 2;
	      goto got_token;
	    }
	  else
	    {
	      if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
		  ((peek == '>') && (string[i] == '&')) ||
		  ((peek == '(') && (string[i] == '$')))
		{
		  i += 2;
		  goto got_token;
		}
	    }
	  if (string[i] != '$')
	    {
	      i++;
	      goto got_token;
	    }
	}

      /* Get word from string + i; */

      if (member (string[i], HISTORY_QUOTE_CHARACTERS))
	delimiter = string[i++];

      for (; string[i]; i++)
	{
	  if (string[i] == '\\' && string[i + 1] == '\n')
	    {
	      i++;
	      continue;
	    }

	  if (string[i] == '\\' && delimiter != '\'' &&
	      (delimiter != '"' || member (string[i], slashify_in_quotes)))
	    {
	      i++;
	      continue;
	    }

	  if (delimiter && string[i] == delimiter)
	    {
	      delimiter = 0;
	      continue;
	    }

	  if (!delimiter && (member (string[i], HISTORY_WORD_DELIMITERS)))
	    break;

	  if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS))
	    delimiter = string[i];
	}

    got_token:

      /* If we are looking for the word in which the character at a
	 particular index falls, remember it. */
      if (indp && wind != -1 && wind >= start && wind < i)
          *indp = result_index;

      len = i - start;
      if (result_index + 2 >= size)
	result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
      result[result_index] = xmalloc (1 + len);
      strncpy (result[result_index], string + start, len);
      result[result_index][len] = '\0';
      result[++result_index] = (char *)NULL;
    }

  return (result);
}

/* Return an array of tokens, much as the shell might.  The tokens are
   parsed out of STRING. */
char **
history_tokenize (string)
     char *string;
{
  return (history_tokenize_internal (string, -1, (int *)NULL));
}

/* Find and return the word which contains the character at index IND
   in the history line LINE.  Used to save the word matched by the
   last history !?string? search. */
static char *
history_find_word (line, ind)
     char *line;
     int ind;
{
  char **words, *s;
  int i, wind = -1;

  words = history_tokenize_internal (line, ind, &wind);
  if (wind == -1 && (words == NULL))
    return ((char *)NULL);

  if (wind != -1)
    s = words[wind];
  else
    s = NULL;

  for (i = 0; i < wind; i++)
    free (words[i]);
  for (i = wind + 1; words[i]; i++)
    free (words[i]);
  free (words);
  return s;
}

⌨️ 快捷键说明

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