?? complete.c
字號:
temp = pathname + 1;#endif if (temp == 0 || *temp == '\0') return (pathname); /* If the basename is NULL, we might have a pathname like '/usr/src/'. Look for a previous slash and, if one is found, return the portion following that slash. If there's no previous slash, just return the pathname we were passed. */ else if (temp[1] == '\0') { for (x = temp - 1; x > pathname; x--) if (*x == '/') break; return ((*x == '/') ? x + 1 : pathname); } else return ++temp;}/* Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we are using it, check for and output a single character for `special' filenames. Return the number of characters we output. */#define PUTX(c) \ do { \ if (CTRL_CHAR (c)) \ { \ putc ('^', rl_outstream); \ putc (UNCTRL (c), rl_outstream); \ printed_len += 2; \ } \ else if (c == RUBOUT) \ { \ putc ('^', rl_outstream); \ putc ('?', rl_outstream); \ printed_len += 2; \ } \ else \ { \ putc (c, rl_outstream); \ printed_len++; \ } \ } while (0)static intprint_filename (to_print, full_pathname) char *to_print, *full_pathname;{ int printed_len = 0;#if !defined (VISIBLE_STATS) char *s; for (s = to_print; *s; s++) { PUTX (*s); }#else char *s, c, *new_full_pathname; int extension_char, slen, tlen; for (s = to_print; *s; s++) { PUTX (*s); } if (rl_filename_completion_desired && rl_visible_stats) { /* If to_print != full_pathname, to_print is the basename of the path passed. In this case, we try to expand the directory name before checking for the stat character. */ if (to_print != full_pathname) { /* Terminate the directory name. */ c = to_print[-1]; to_print[-1] = '\0'; /* If setting the last slash in full_pathname to a NUL results in full_pathname being the empty string, we are trying to complete files in the root directory. If we pass a null string to the bash directory completion hook, for example, it will expand it to the current directory. We just want the `/'. */ s = tilde_expand (full_pathname && *full_pathname ? full_pathname : "/"); if (rl_directory_completion_hook) (*rl_directory_completion_hook) (&s); slen = strlen (s); tlen = strlen (to_print); new_full_pathname = (char *)xmalloc (slen + tlen + 2); strcpy (new_full_pathname, s); new_full_pathname[slen] = '/'; strcpy (new_full_pathname + slen + 1, to_print); extension_char = stat_char (new_full_pathname); free (new_full_pathname); to_print[-1] = c; } else { s = tilde_expand (full_pathname); extension_char = stat_char (s); } free (s); if (extension_char) { putc (extension_char, rl_outstream); printed_len++; } }#endif /* VISIBLE_STATS */ return printed_len;}static char *rl_quote_filename (s, rtype, qcp) char *s; int rtype; char *qcp;{ char *r; r = (char *)xmalloc (strlen (s) + 2); *r = *rl_completer_quote_characters; strcpy (r + 1, s); if (qcp) *qcp = *rl_completer_quote_characters; return r;}/* Find the bounds of the current word for completion purposes, and leave rl_point set to the end of the word. This function skips quoted substrings (characters between matched pairs of characters in rl_completer_quote_characters). First we try to find an unclosed quoted substring on which to do matching. If one is not found, we use the word break characters to find the boundaries of the current word. We call an application-specific function to decide whether or not a particular word break character is quoted; if that function returns a non-zero result, the character does not break a word. This function returns the opening quote character if we found an unclosed quoted substring, '\0' otherwise. FP, if non-null, is set to a value saying which (shell-like) quote characters we found (single quote, double quote, or backslash) anywhere in the string. DP, if non-null, is set to the value of the delimiter character that caused a word break. */char_rl_find_completion_word (fp, dp) int *fp, *dp;{ int scan, end, found_quote, delimiter, pass_next, isbrk; char quote_char; end = rl_point; found_quote = delimiter = 0; quote_char = '\0'; if (rl_completer_quote_characters) { /* We have a list of characters which can be used in pairs to quote substrings for the completer. Try to find the start of an unclosed quoted substring. */ /* FOUND_QUOTE is set so we know what kind of quotes we found. */ for (scan = pass_next = 0; scan < end; scan++) { if (pass_next) { pass_next = 0; continue; } /* Shell-like semantics for single quotes -- don't allow backslash to quote anything in single quotes, especially not the closing quote. If you don't like this, take out the check on the value of quote_char. */ if (quote_char != '\'' && rl_line_buffer[scan] == '\\') { pass_next = 1; found_quote |= RL_QF_BACKSLASH; continue; } if (quote_char != '\0') { /* Ignore everything until the matching close quote char. */ if (rl_line_buffer[scan] == quote_char) { /* Found matching close. Abandon this substring. */ quote_char = '\0'; rl_point = end; } } else if (strchr (rl_completer_quote_characters, rl_line_buffer[scan])) { /* Found start of a quoted substring. */ quote_char = rl_line_buffer[scan]; rl_point = scan + 1; /* Shell-like quoting conventions. */ if (quote_char == '\'') found_quote |= RL_QF_SINGLE_QUOTE; else if (quote_char == '"') found_quote |= RL_QF_DOUBLE_QUOTE; else found_quote |= RL_QF_OTHER_QUOTE; } } } if (rl_point == end && quote_char == '\0') { /* We didn't find an unclosed quoted substring upon which to do completion, so use the word break characters to find the substring on which to complete. */#if defined (HANDLE_MULTIBYTE) while (rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_ANY))#else while (--rl_point)#endif { scan = rl_line_buffer[rl_point]; if (strchr (rl_completer_word_break_characters, scan) == 0) continue; /* Call the application-specific function to tell us whether this word break character is quoted and should be skipped. */ if (rl_char_is_quoted_p && found_quote && (*rl_char_is_quoted_p) (rl_line_buffer, rl_point)) continue; /* Convoluted code, but it avoids an n^2 algorithm with calls to char_is_quoted. */ break; } } /* If we are at an unquoted word break, then advance past it. */ scan = rl_line_buffer[rl_point]; /* If there is an application-specific function to say whether or not a character is quoted and we found a quote character, let that function decide whether or not a character is a word break, even if it is found in rl_completer_word_break_characters. Don't bother if we're at the end of the line, though. */ if (scan) { if (rl_char_is_quoted_p) isbrk = (found_quote == 0 || (*rl_char_is_quoted_p) (rl_line_buffer, rl_point) == 0) && strchr (rl_completer_word_break_characters, scan) != 0; else isbrk = strchr (rl_completer_word_break_characters, scan) != 0; if (isbrk) { /* If the character that caused the word break was a quoting character, then remember it as the delimiter. */ if (rl_basic_quote_characters && strchr (rl_basic_quote_characters, scan) && (end - rl_point) > 1) delimiter = scan; /* If the character isn't needed to determine something special about what kind of completion to perform, then advance past it. */ if (rl_special_prefixes == 0 || strchr (rl_special_prefixes, scan) == 0) rl_point++; } } if (fp) *fp = found_quote; if (dp) *dp = delimiter; return (quote_char);}static char **gen_completion_matches (text, start, end, our_func, found_quote, quote_char) char *text; int start, end; rl_compentry_func_t *our_func; int found_quote, quote_char;{ char **matches, *temp; /* If the user wants to TRY to complete, but then wants to give up and use the default completion function, they set the variable rl_attempted_completion_function. */ if (rl_attempted_completion_function) { matches = (*rl_attempted_completion_function) (text, start, end); if (matches || rl_attempted_completion_over) { rl_attempted_completion_over = 0; return (matches); } } /* Beware -- we're stripping the quotes here. Do this only if we know we are doing filename completion and the application has defined a filename dequoting function. */ temp = (char *)NULL; if (found_quote && our_func == rl_filename_completion_function && rl_filename_dequoting_function) { /* delete single and double quotes */ temp = (*rl_filename_dequoting_function) (text, quote_char); text = temp; /* not freeing text is not a memory leak */ } matches = rl_completion_matches (text, our_func); FREE (temp); return matches; }/* Filter out duplicates in MATCHES. This frees up the strings in MATCHES. */static char **remove_duplicate_matches (matches) char **matches;{ char *lowest_common; int i, j, newlen; char dead_slot; char **temp_array; /* Sort the items. */ for (i = 0; matches[i]; i++) ; /* Sort the array without matches[0], since we need it to stay in place no matter what. */ if (i) qsort (matches+1, i-1, sizeof (char *), (QSFUNC *)_rl_qsort_string_compare); /* Remember the lowest common denominator for it may be unique. */ lowest_common = savestring (matches[0]); for (i = newlen = 0; matches[i + 1]; i++) { if (strcmp (matches[i], matches[i + 1]) == 0) { free (matches[i]); matches[i] = (char *)&dead_slot; } else newlen++; } /* We have marked all the dead slots with (char *)&dead_slot. Copy all the non-dead entries into a new array. */ temp_array = (char **)xmalloc ((3 + newlen) * sizeof (char *)); for (i = j = 1; matches[i]; i++) { if (matches[i] != (char *)&dead_slot) temp_array[j++] = matches[i]; } temp_array[j] = (char *)NULL; if (matches[0] != (char *)&dead_slot) free (matches[0]); /* Place the lowest common denominator back in [0]. */ temp_array[0] = lowest_common; /* If there is one string left, and it is identical to the lowest common denominator, then the LCD is the string to insert. */ if (j == 2 && strcmp (temp_array[0], temp_array[1]) == 0) { free (temp_array[1]); temp_array[1] = (char *)NULL; } return (temp_array);}/* Find the common prefix of the list of matches, and put it into matches[0]. */static intcompute_lcd_of_matches (match_list, matches, text) char **match_list; int matches; const char *text;{ register int i, c1, c2, si; int low; /* Count of max-matched characters. */#if defined (HANDLE_MULTIBYTE) int v; mbstate_t ps1, ps2; wchar_t wc1, wc2;#endif /* If only one match, just use that. Otherwise, compare each member of the list with the next, finding out where they stop matching. */ if (matches == 1) { match_list[0] = match_list[1]; match_list[1] = (char *)NULL; return 1; } for (i = 1, low = 100000; i < matches; i++) {#if defined (HANDLE_MULTIBYTE) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) { memset (&ps1, 0, sizeof (mbstate_t)); memset (&ps2, 0, sizeof (mbstate_t)); }#endif if (_rl_completion_case_fold) { for (si = 0; (c1 = _rl_to_lower(match_list[i][si])) && (c2 = _rl_to_lower(match_list[i + 1][si])); si++)#if defined (HANDLE_MULTIBYTE) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) { v = mbrtowc (&wc1, match_list[i]+si, strlen (match_list[i]+si), &ps1); mbrtowc (&wc2, match_list[i+1]+si, strlen (match_list[i+1]+si), &ps2); wc1 = towlower (wc1); wc2 = towlower (wc2); if (wc1 != wc2) break; else if (v > 1) si += v - 1; } else#endif if (c1 != c2) break; } else { for (si = 0; (c1 = match_list[i][si]) && (c2 = match_list[i + 1][si]); si++)#if defined (HANDLE_MULTIBYTE) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) { mbstate_t ps_back = ps1; if (!_rl_compare_chars (match_list[i], si, &ps1, match_list[i+1], si, &ps2)) break; else if ((v = _rl_get_char_len (&match_list[i][si], &ps_back)) > 1) si += v - 1; } else#endif if (c1 != c2) break; } if (low > si) low = si; } /* If there were multiple matches, but none matched up to even the first character, and the user typed something, use that as the value of matches[0]. */ if (low == 0 && text && *text) { match_list[0] = (char *)xmalloc (strlen (text) + 1); strcpy (match_list[0], text); } else { match_list[0] = (char *)xmalloc (low + 1); /* XXX - this might need changes in the presence of multibyte chars */ /* If we are ignoring case, try to preserve the case of the string the user typed in the face of multiple matches differing in case. */ if (_rl_completion_case_fold) { /* sort the list to get consistent answers. */ qsort (match_list+1, matches, sizeof(char *), (QSFUNC *)_rl_qsort_string_compare); si = strlen (text); if (si <= low) { for (i = 1; i <= matches; i++) if (strncmp (match_list[i], text, si) == 0) { strncpy (match_list[0], match_list[i], low); break; } /* no casematch, use first entry */ if (i > matches) strncpy (match_list[0], match_list[1], low); } else /* otherwise, just use the text the user typed. */ strncpy (match_list[0], text, low); } else strncpy (match_list[0], match_list[1], low);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -