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

📄 complete.c

📁 UNIX下SH的实现源码
💻 C
📖 第 1 页 / 共 4 页
字号:
     int len, max;
{
  int count, limit, printed_len;
  int i, j, k, l;
  char *temp;

  /* How many items of MAX length can we fit in the screen window? */
  max += 2;
  limit = screenwidth / max;
  if (limit != 1 && (limit * max == screenwidth))
    limit--;

  /* Avoid a possible floating exception.  If max > screenwidth,
     limit will be 0 and a divide-by-zero fault will result. */
  if (limit == 0)
    limit = 1;

  /* How many iterations of the printing loop? */
  count = (len + (limit - 1)) / limit;

  /* Watch out for special case.  If LEN is less than LIMIT, then
     just do the inner printing loop.
	   0 < len <= limit  implies  count = 1. */

  /* Sort the items if they are not already sorted. */
  if (rl_ignore_completion_duplicates == 0)
    qsort (matches + 1, len, sizeof (char *), (QSFUNC *)_rl_qsort_string_compare);

  crlf ();

  if (_rl_print_completions_horizontally == 0)
    {
      /* Print the sorted items, up-and-down alphabetically, like ls. */
      for (i = 1; i <= count; i++)
	{
	  for (j = 0, l = i; j < limit; j++)
	    {
	      if (l > len || matches[l] == 0)
		break;
	      else
		{
		  temp = printable_part (matches[l]);
		  printed_len = print_filename (temp, matches[l]);

		  if (j + 1 < limit)
		    for (k = 0; k < max - printed_len; k++)
		      putc (' ', rl_outstream);
		}
	      l += count;
	    }
	  crlf ();
	}
    }
  else
    {
      /* Print the sorted items, across alphabetically, like ls -x. */
      for (i = 1; matches[i]; i++)
	{
	  temp = printable_part (matches[i]);
	  printed_len = print_filename (temp, matches[i]);
	  /* Have we reached the end of this line? */
	  if (matches[i+1])
	    {
	      if (i && (limit > 1) && (i % limit) == 0)
		crlf ();
	      else
		for (k = 0; k < max - printed_len; k++)
		  putc (' ', rl_outstream);
	    }
	}
      crlf ();
    }
}

/* Display MATCHES, a list of matching filenames in argv format.  This
   handles the simple case -- a single match -- first.  If there is more
   than one match, we compute the number of strings in the list and the
   length of the longest string, which will be needed by the display
   function.  If the application wants to handle displaying the list of
   matches itself, it sets RL_COMPLETION_DISPLAY_MATCHES_HOOK to the
   address of a function, and we just call it.  If we're handling the
   display ourselves, we just call rl_display_match_list.  We also check
   that the list of matches doesn't exceed the user-settable threshold,
   and ask the user if he wants to see the list if there are more matches
   than RL_COMPLETION_QUERY_ITEMS. */
static void
display_matches (matches)
     char **matches;
{
  int len, max, i;
  char *temp;

  /* Move to the last visible line of a possibly-multiple-line command. */
  _rl_move_vert (_rl_vis_botlin);

  /* Handle simple case first.  What if there is only one answer? */
  if (matches[1] == 0)
    {
      temp = printable_part (matches[0]);
      crlf ();
      print_filename (temp, matches[0]);
      crlf ();

      rl_forced_update_display ();
      rl_display_fixed = 1;

      return;
    }

  /* There is more than one answer.  Find out how many there are,
     and find the maximum printed length of a single entry. */
  for (max = 0, i = 1; matches[i]; i++)
    {
      temp = printable_part (matches[i]);
      len = strlen (temp);

      if (len > max)
	max = len;
    }

  len = i - 1;

  /* If the caller has defined a display hook, then call that now. */
  if (rl_completion_display_matches_hook)
    {
      (*rl_completion_display_matches_hook) (matches, len, max);
      return;
    }
	
  /* If there are many items, then ask the user if she really wants to
     see them all. */
  if (len >= rl_completion_query_items)
    {
      crlf ();
      fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len);
      fflush (rl_outstream);
      if (get_y_or_n () == 0)
	{
	  crlf ();

	  rl_forced_update_display ();
	  rl_display_fixed = 1;

	  return;
	}
    }

  rl_display_match_list (matches, len, max);

  rl_forced_update_display ();
  rl_display_fixed = 1;
}

static char *
make_quoted_replacement (match, mtype, qc)
     char *match;
     int mtype;
     char *qc;	/* Pointer to quoting character, if any */
{
  int should_quote, do_replace;
  char *replacement;

  /* If we are doing completion on quoted substrings, and any matches
     contain any of the completer_word_break_characters, then auto-
     matically prepend the substring with a quote character (just pick
     the first one from the list of such) if it does not already begin
     with a quote string.  FIXME: Need to remove any such automatically
     inserted quote character when it no longer is necessary, such as
     if we change the string we are completing on and the new set of
     matches don't require a quoted substring. */
  replacement = match;

  should_quote = match && rl_completer_quote_characters &&
			rl_filename_completion_desired &&
			rl_filename_quoting_desired;

  if (should_quote)
    should_quote = should_quote && (!qc || !*qc ||
		     (rl_completer_quote_characters && strchr (rl_completer_quote_characters, *qc)));

  if (should_quote)
    {
      /* If there is a single match, see if we need to quote it.
         This also checks whether the common prefix of several
	 matches needs to be quoted. */
#if !defined (HAVE_DOS_STYLE_FILE_SYSTEM)
      should_quote = rl_filename_quote_characters
			? (rl_strpbrk (match, rl_filename_quote_characters) != 0)
			: 0;

#else /* HAVE_DOS_STYLE_FILE_SYSTEM */
     {
        /* To get here, the match must be a filename.
           Do not allow ':' to be quoted in DOS-style filenames,
           to avoid confusing people.  */
        char *token = NULL;
        should_quote = rl_filename_quote_characters
                        ? ((token = rl_strpbrk (match, rl_filename_quote_characters)) != 0)
			: 0;
        if (token && *token == ':')
          should_quote = 0;
      }
#endif
      do_replace = should_quote ? mtype : NO_MATCH;
      /* Quote the replacement, since we found an embedded
	 word break character in a potential match. */
      if (do_replace != NO_MATCH && rl_filename_quoting_function)
	replacement = (*rl_filename_quoting_function) (match, do_replace, qc);
    }
  return (replacement);
}

static void
insert_match (match, start, mtype, qc)
     char *match;
     int start, mtype;
     char *qc;
{
  char *replacement;
  char oqc;

  oqc = qc ? *qc : '\0';
  replacement = make_quoted_replacement (match, mtype, qc);

  /* Now insert the match. */
  if (replacement)
    {
      /* Don't double an opening quote character. */
      if (qc && *qc && start && rl_line_buffer[start - 1] == *qc &&
	    replacement[0] == *qc)
	start--;
      /* If make_quoted_replacement changed the quoting character, remove
	 the opening quote and insert the (fully-quoted) replacement. */
      else if (qc && (*qc != oqc) && start && rl_line_buffer[start - 1] == oqc &&
	    replacement[0] != oqc)
	start--;
      _rl_replace_text (replacement, start, rl_point - 1);
      if (replacement != match)
        free (replacement);
    }
}

/* Append any necessary closing quote and a separator character to the
   just-inserted match.  If the user has specified that directories
   should be marked by a trailing `/', append one of those instead.  The
   default trailing character is a space.  Returns the number of characters
   appended. */
static int
append_to_match (text, delimiter, quote_char)
     char *text;
     int delimiter, quote_char;
{
  char temp_string[4], *filename;
  int temp_string_index;
  struct stat finfo;

  temp_string_index = 0;
  if (quote_char && rl_point && rl_line_buffer[rl_point - 1] != quote_char)
    temp_string[temp_string_index++] = quote_char;

  if (delimiter)
    temp_string[temp_string_index++] = delimiter;
  else if (rl_completion_append_character)
    temp_string[temp_string_index++] = rl_completion_append_character;

  temp_string[temp_string_index++] = '\0';

  if (rl_filename_completion_desired)
    {
      filename = tilde_expand (text);
      if (stat (filename, &finfo) == 0 && S_ISDIR (finfo.st_mode))
	{
	  if (_rl_complete_mark_directories && rl_line_buffer[rl_point] != '/')
	    rl_insert_text ("/");
	}
      else
	{
	  if (rl_point == rl_end)
	    rl_insert_text (temp_string);
	}
      free (filename);
    }
  else
    {
      if (rl_point == rl_end)
	rl_insert_text (temp_string);
    }

  return (temp_string_index);
}

static void
insert_all_matches (matches, point, qc)
     char **matches;
     int point;
     char *qc;
{
  int i;
  char *rp;

  rl_begin_undo_group ();
  /* remove any opening quote character; make_quoted_replacement will add
     it back. */
  if (qc && *qc && point && rl_line_buffer[point - 1] == *qc)
    point--;
  rl_delete_text (point, rl_point);
  rl_point = point;

  if (matches[1])
    {
      for (i = 1; matches[i]; i++)
	{
	  rp = make_quoted_replacement (matches[i], SINGLE_MATCH, qc);
	  rl_insert_text (rp);
	  rl_insert_text (" ");
	  if (rp != matches[i])
	    free (rp);
	}
    }
  else
    {
      rp = make_quoted_replacement (matches[0], SINGLE_MATCH, qc);
      rl_insert_text (rp);
      rl_insert_text (" ");
      if (rp != matches[0])
	free (rp);
    }
  rl_end_undo_group ();
}

static void
free_match_list (matches)
     char **matches;
{
  register int i;

  for (i = 0; matches[i]; i++)
    free (matches[i]);
  free (matches);
}

/* Complete the word at or before point.
   WHAT_TO_DO says what to do with the completion.
   `?' means list the possible completions.
   TAB means do standard completion.
   `*' means insert all of the possible completions.
   `!' means to do standard completion, and list all possible completions if
   there is more than one. */
int
rl_complete_internal (what_to_do)
     int what_to_do;
{
  char **matches;
  Function *our_func;
  int start, end, delimiter, found_quote, i;
  char *text, *saved_line_buffer;
  char quote_char;

  /* Only the completion entry function can change these. */
  rl_filename_completion_desired = 0;
  rl_filename_quoting_desired = 1;
  rl_completion_type = what_to_do;

  saved_line_buffer = rl_line_buffer ? savestring (rl_line_buffer) : (char *)NULL;
  our_func = rl_completion_entry_function
		? rl_completion_entry_function
		: (Function *)filename_completion_function;

  /* We now look backwards for the start of a filename/variable word. */
  end = rl_point;
  found_quote = delimiter = 0;
  quote_char = '\0';

  if (rl_point)
    /* This (possibly) changes rl_point.  If it returns a non-zero char,
       we know we have an open quote. */
    quote_char = find_completion_word (&found_quote, &delimiter);

  start = rl_point;
  rl_point = end;

  text = rl_copy_text (start, end);
  matches = gen_completion_matches (text, start, end, our_func, found_quote, quote_char);
  free (text);

  if (matches == 0)
    {
      ding ();
      FREE (saved_line_buffer);
      return (0);
    }

#if 0
  /* If we are matching filenames, our_func will have been set to
     filename_completion_function */
  i = our_func == (Function *)filename_completion_function;
#else
  /* If we are matching filenames, the attempted completion function will
     have set rl_filename_completion_desired to a non-zero value.  The basic
     filename_completion_function does this. */
  i = rl_filename_completion_desired;
#endif

  if (postprocess_matches (&matches, i) == 0)
    {
      ding ();
      FREE (saved_line_buffer);
      completion_changed_buffer = 0;
      return (0);
    }

  switch (what_to_do)
    {
    case TAB:
    case '!':
      /* Insert the first match with proper quoting. */
      if (*matches[0])
	insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, &quote_char);

      /* If there are more matches, ring the bell to indicate.
	 If we are in vi mode, Posix.2 says to not ring the bell.
	 If the `show-all-if-ambiguous' variable is set, display
	 all the matches immediately.  Otherwise, if this was the
	 only match, and we are hacking files, check the file to
	 see if it was a directory.  If so, and the `mark-directories'
	 variable is set, add a '/' to the name.  If not, and we
	 are at the end of the line, then add a space.  */
      if (matches[1])
	{
	  if (what_to_do == '!')
	    {
	      display_matches (matches);
	      break;
	    }
	  else if (rl_editing_mode != vi_mode)
	    ding ();	/* There are other matches remaining. */
	}
      else
	append_to_match (matches[0], delimiter, quote_char);

      break;

    case '*':
      insert_all_matches (matches, start, &quote_char);
      break;

    case '?':
      display_matches (matches);
      break;

    default:

⌨️ 快捷键说明

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