📄 complete.c
字号:
RL_UNSETSTATE(RL_STATE_COMPLETING); return 0;}/***************************************************************//* *//* Application-callable completion match generator functions *//* *//***************************************************************//* Return an array of (char *) which is a list of completions for TEXT. If there are no completions, return a NULL pointer. The first entry in the returned array is the substitution for TEXT. The remaining entries are the possible completions. The array is terminated with a NULL pointer. ENTRY_FUNCTION is a function of two args, and returns a (char *). The first argument is TEXT. The second is a state argument; it should be zero on the first call, and non-zero on subsequent calls. It returns a NULL pointer to the caller when there are no more matches. */char **rl_completion_matches (text, entry_function) const char *text; rl_compentry_func_t *entry_function;{ /* Number of slots in match_list. */ int match_list_size; /* The list of matches. */ char **match_list; /* Number of matches actually found. */ int matches; /* Temporary string binder. */ char *string; matches = 0; match_list_size = 10; match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *)); match_list[1] = (char *)NULL; while (string = (*entry_function) (text, matches)) { if (matches + 1 == match_list_size) match_list = (char **)xrealloc (match_list, ((match_list_size += 10) + 1) * sizeof (char *)); match_list[++matches] = string; match_list[matches + 1] = (char *)NULL; } /* If there were any matches, then look through them finding out the lowest common denominator. That then becomes match_list[0]. */ if (matches) compute_lcd_of_matches (match_list, matches, text); else /* There were no matches. */ { free (match_list); match_list = (char **)NULL; } return (match_list);}/* A completion function for usernames. TEXT contains a partial username preceded by a random character (usually `~'). */char *rl_username_completion_function (text, state) const char *text; int state;{#if defined (__WIN32__) || defined (__OPENNT) return (char *)NULL;#else /* !__WIN32__ && !__OPENNT) */ static char *username = (char *)NULL; static struct passwd *entry; static int namelen, first_char, first_char_loc; char *value; if (state == 0) { FREE (username); first_char = *text; first_char_loc = first_char == '~'; username = savestring (&text[first_char_loc]); namelen = strlen (username); setpwent (); } while (entry = getpwent ()) { /* Null usernames should result in all users as possible completions. */ if (namelen == 0 || (STREQN (username, entry->pw_name, namelen))) break; } if (entry == 0) { endpwent (); return ((char *)NULL); } else { value = (char *)xmalloc (2 + strlen (entry->pw_name)); *value = *text; strcpy (value + first_char_loc, entry->pw_name); if (first_char == '~') rl_filename_completion_desired = 1; return (value); }#endif /* !__WIN32__ && !__OPENNT */}/* Okay, now we write the entry_function for filename completion. In the general case. Note that completion in the shell is a little different because of all the pathnames that must be followed when looking up the completion for a command. */char *rl_filename_completion_function (text, state) const char *text; int state;{ static DIR *directory = (DIR *)NULL; static char *filename = (char *)NULL; static char *dirname = (char *)NULL; static char *users_dirname = (char *)NULL; static int filename_len; char *temp; int dirlen; struct dirent *entry; /* If we don't have any state, then do some initialization. */ if (state == 0) { /* If we were interrupted before closing the directory or reading all of its contents, close it. */ if (directory) { closedir (directory); directory = (DIR *)NULL; } FREE (dirname); FREE (filename); FREE (users_dirname); filename = savestring (text); if (*text == 0) text = "."; dirname = savestring (text); temp = strrchr (dirname, '/');#if defined (__MSDOS__) /* special hack for //X/... */ if (dirname[0] == '/' && dirname[1] == '/' && ISALPHA ((unsigned char)dirname[2]) && dirname[3] == '/') temp = strrchr (dirname + 3, '/');#endif if (temp) { strcpy (filename, ++temp); *temp = '\0'; }#if defined (__MSDOS__) /* searches from current directory on the drive */ else if (ISALPHA ((unsigned char)dirname[0]) && dirname[1] == ':') { strcpy (filename, dirname + 2); dirname[2] = '\0'; }#endif else { dirname[0] = '.'; dirname[1] = '\0'; } /* We aren't done yet. We also support the "~user" syntax. */ /* Save the version of the directory that the user typed. */ users_dirname = savestring (dirname); if (*dirname == '~') { temp = tilde_expand (dirname); free (dirname); dirname = temp; } if (rl_directory_rewrite_hook) (*rl_directory_rewrite_hook) (&dirname); if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&dirname)) { free (users_dirname); users_dirname = savestring (dirname); } directory = opendir (dirname); filename_len = strlen (filename); rl_filename_completion_desired = 1; } /* At this point we should entertain the possibility of hacking wildcarded filenames, like /usr/man/man<WILD>/te<TAB>. If the directory name contains globbing characters, then build an array of directories, and then map over that list while completing. */ /* *** UNIMPLEMENTED *** */ /* Now that we have some state, we can read the directory. */ entry = (struct dirent *)NULL; while (directory && (entry = readdir (directory))) { /* Special case for no filename. If the user has disabled the `match-hidden-files' variable, skip filenames beginning with `.'. All other entries except "." and ".." match. */ if (filename_len == 0) { if (_rl_match_hidden_files == 0 && HIDDEN_FILE (entry->d_name)) continue; if (entry->d_name[0] != '.' || (entry->d_name[1] && (entry->d_name[1] != '.' || entry->d_name[2]))) break; } else { /* Otherwise, if these match up to the length of filename, then it is a match. */ if (_rl_completion_case_fold) { if ((_rl_to_lower (entry->d_name[0]) == _rl_to_lower (filename[0])) && (((int)D_NAMLEN (entry)) >= filename_len) && (_rl_strnicmp (filename, entry->d_name, filename_len) == 0)) break; } else { if ((entry->d_name[0] == filename[0]) && (((int)D_NAMLEN (entry)) >= filename_len) && (strncmp (filename, entry->d_name, filename_len) == 0)) break; } } } if (entry == 0) { if (directory) { closedir (directory); directory = (DIR *)NULL; } if (dirname) { free (dirname); dirname = (char *)NULL; } if (filename) { free (filename); filename = (char *)NULL; } if (users_dirname) { free (users_dirname); users_dirname = (char *)NULL; } return (char *)NULL; } else { /* dirname && (strcmp (dirname, ".") != 0) */ if (dirname && (dirname[0] != '.' || dirname[1])) { if (rl_complete_with_tilde_expansion && *users_dirname == '~') { dirlen = strlen (dirname); temp = (char *)xmalloc (2 + dirlen + D_NAMLEN (entry)); strcpy (temp, dirname); /* Canonicalization cuts off any final slash present. We may need to add it back. */ if (dirname[dirlen - 1] != '/') { temp[dirlen++] = '/'; temp[dirlen] = '\0'; } } else { dirlen = strlen (users_dirname); temp = (char *)xmalloc (2 + dirlen + D_NAMLEN (entry)); strcpy (temp, users_dirname); /* Make sure that temp has a trailing slash here. */ if (users_dirname[dirlen - 1] != '/') temp[dirlen++] = '/'; } strcpy (temp + dirlen, entry->d_name); } else temp = savestring (entry->d_name); return (temp); }}/* An initial implementation of a menu completion function a la tcsh. The first time (if the last readline command was not rl_menu_complete), we generate the list of matches. This code is very similar to the code in rl_complete_internal -- there should be a way to combine the two. Then, for each item in the list of matches, we insert the match in an undoable fashion, with the appropriate character appended (this happens on the second and subsequent consecutive calls to rl_menu_complete). When we hit the end of the match list, we restore the original unmatched text, ring the bell, and reset the counter to zero. */intrl_menu_complete (count, ignore) int count, ignore;{ rl_compentry_func_t *our_func; int matching_filenames, found_quote; static char *orig_text; static char **matches = (char **)0; static int match_list_index = 0; static int match_list_size = 0; static int orig_start, orig_end; static char quote_char; static int delimiter; /* The first time through, we generate the list of matches and set things up to insert them. */ if (rl_last_func != rl_menu_complete) { /* Clean up from previous call, if any. */ FREE (orig_text); if (matches) _rl_free_match_list (matches); match_list_index = match_list_size = 0; matches = (char **)NULL; /* Only the completion entry function can change these. */ set_completion_defaults ('%'); our_func = rl_completion_entry_function ? rl_completion_entry_function : rl_filename_completion_function; /* We now look backwards for the start of a filename/variable word. */ orig_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 = _rl_find_completion_word (&found_quote, &delimiter); orig_start = rl_point; rl_point = orig_end; orig_text = rl_copy_text (orig_start, orig_end); matches = gen_completion_matches (orig_text, orig_start, orig_end, our_func, found_quote, quote_char); /* If we are matching filenames, the attempted completion function will have set rl_filename_completion_desired to a non-zero value. The basic rl_filename_completion_function does this. */ matching_filenames = rl_filename_completion_desired; if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0) { rl_ding (); FREE (matches); matches = (char **)0; FREE (orig_text); orig_text = (char *)0; completion_changed_buffer = 0; return (0); } for (match_list_size = 0; matches[match_list_size]; match_list_size++) ; /* matches[0] is lcd if match_list_size > 1, but the circular buffer code below should take care of it. */ } /* Now we have the list of matches. Replace the text between rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with matches[match_list_index], and add any necessary closing char. */ if (matches == 0 || match_list_size == 0) { rl_ding (); FREE (matches); matches = (char **)0; completion_changed_buffer = 0; return (0); } match_list_index = (match_list_index + count) % match_list_size; if (match_list_index < 0) match_list_index += match_list_size; if (match_list_index == 0 && match_list_size > 1) { rl_ding (); insert_match (orig_text, orig_start, MULT_MATCH, "e_char); } else { insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char); append_to_match (matches[match_list_index], delimiter, quote_char, strcmp (orig_text, matches[match_list_index])); } completion_changed_buffer = 1; return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -