📄 pcomplete.c
字号:
/* pcomplete.c - functions to generate lists of matches for programmable completion. *//* Copyright (C) 1999-2009 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. Bash is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Bash is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Bash. If not, see <http://www.gnu.org/licenses/>.*/#include <config.h>#if defined (PROGRAMMABLE_COMPLETION)#include "bashtypes.h"#include "posixstat.h"#if defined (HAVE_UNISTD_H)# include <unistd.h>#endif#include <signal.h>#if defined (PREFER_STDARG)# include <stdarg.h>#else# include <varargs.h>#endif#include <stdio.h>#include "bashansi.h"#include "bashintl.h"#include "shell.h"#include "pcomplete.h"#include "alias.h"#include "bashline.h"#include "execute_cmd.h"#include "pathexp.h"#if defined (JOB_CONTROL)# include "jobs.h"#endif#if !defined (NSIG)# include "trap.h"#endif#include "builtins.h"#include "builtins/common.h"#include <glob/glob.h>#include <glob/strmatch.h>#include <readline/rlconf.h>#include <readline/readline.h>#include <readline/history.h>#define PCOMP_RETRYFAIL 256#ifdef STRDUP# undef STRDUP#endif#define STRDUP(x) ((x) ? savestring (x) : (char *)NULL)typedef SHELL_VAR **SVFUNC ();#ifndef HAVE_STRPBRKextern char *strpbrk __P((char *, char *));#endifextern int array_needs_making;extern STRING_INT_ALIST word_token_alist[];extern char *signal_names[];#if defined (DEBUG)#if defined (PREFER_STDARG)static void debug_printf (const char *, ...) __attribute__((__format__ (printf, 1, 2)));#endif#endif /* DEBUG */static int it_init_joblist __P((ITEMLIST *, int));static int it_init_aliases __P((ITEMLIST *));static int it_init_arrayvars __P((ITEMLIST *));static int it_init_bindings __P((ITEMLIST *));static int it_init_builtins __P((ITEMLIST *));static int it_init_disabled __P((ITEMLIST *));static int it_init_enabled __P((ITEMLIST *));static int it_init_exported __P((ITEMLIST *));static int it_init_functions __P((ITEMLIST *));static int it_init_hostnames __P((ITEMLIST *));static int it_init_jobs __P((ITEMLIST *));static int it_init_running __P((ITEMLIST *));static int it_init_stopped __P((ITEMLIST *));static int it_init_keywords __P((ITEMLIST *));static int it_init_signals __P((ITEMLIST *));static int it_init_variables __P((ITEMLIST *));static int it_init_setopts __P((ITEMLIST *));static int it_init_shopts __P((ITEMLIST *));static int shouldexp_filterpat __P((char *));static char *preproc_filterpat __P((char *, char *));static void init_itemlist_from_varlist __P((ITEMLIST *, SVFUNC *));static STRINGLIST *gen_matches_from_itemlist __P((ITEMLIST *, const char *));static STRINGLIST *gen_action_completions __P((COMPSPEC *, const char *));static STRINGLIST *gen_globpat_matches __P((COMPSPEC *, const char *));static STRINGLIST *gen_wordlist_matches __P((COMPSPEC *, const char *));static STRINGLIST *gen_shell_function_matches __P((COMPSPEC *, const char *, char *, int, WORD_LIST *, int, int, int *));static STRINGLIST *gen_command_matches __P((COMPSPEC *, const char *, char *, int, WORD_LIST *, int, int));static STRINGLIST *gen_progcomp_completions __P((const char *, const char *, const char *, int, int, int *, int *, COMPSPEC **));static char *pcomp_filename_completion_function __P((const char *, int));#if defined (ARRAY_VARS)static SHELL_VAR *bind_comp_words __P((WORD_LIST *));#endifstatic void bind_compfunc_variables __P((char *, int, WORD_LIST *, int, int));static void unbind_compfunc_variables __P((int));static WORD_LIST *build_arg_list __P((char *, const char *, WORD_LIST *, int));static WORD_LIST *command_line_to_word_list __P((char *, int, int, int *, int *));#ifdef DEBUGstatic int progcomp_debug = 0;#endifint prog_completion_enabled = 1;/* These are used to manage the arrays of strings for possible completions. */ITEMLIST it_aliases = { 0, it_init_aliases, (STRINGLIST *)0 };ITEMLIST it_arrayvars = { LIST_DYNAMIC, it_init_arrayvars, (STRINGLIST *)0 };ITEMLIST it_bindings = { 0, it_init_bindings, (STRINGLIST *)0 };ITEMLIST it_builtins = { 0, it_init_builtins, (STRINGLIST *)0 };ITEMLIST it_commands = { LIST_DYNAMIC }; /* unused */ITEMLIST it_directories = { LIST_DYNAMIC }; /* unused */ITEMLIST it_disabled = { 0, it_init_disabled, (STRINGLIST *)0 };ITEMLIST it_enabled = { 0, it_init_enabled, (STRINGLIST *)0 };ITEMLIST it_exports = { LIST_DYNAMIC, it_init_exported, (STRINGLIST *)0 };ITEMLIST it_files = { LIST_DYNAMIC }; /* unused */ITEMLIST it_functions = { 0, it_init_functions, (STRINGLIST *)0 };ITEMLIST it_hostnames = { LIST_DYNAMIC, it_init_hostnames, (STRINGLIST *)0 };ITEMLIST it_groups = { LIST_DYNAMIC }; /* unused */ITEMLIST it_jobs = { LIST_DYNAMIC, it_init_jobs, (STRINGLIST *)0 };ITEMLIST it_keywords = { 0, it_init_keywords, (STRINGLIST *)0 };ITEMLIST it_running = { LIST_DYNAMIC, it_init_running, (STRINGLIST *)0 };ITEMLIST it_services = { LIST_DYNAMIC }; /* unused */ITEMLIST it_setopts = { 0, it_init_setopts, (STRINGLIST *)0 };ITEMLIST it_shopts = { 0, it_init_shopts, (STRINGLIST *)0 };ITEMLIST it_signals = { 0, it_init_signals, (STRINGLIST *)0 };ITEMLIST it_stopped = { LIST_DYNAMIC, it_init_stopped, (STRINGLIST *)0 };ITEMLIST it_users = { LIST_DYNAMIC }; /* unused */ITEMLIST it_variables = { LIST_DYNAMIC, it_init_variables, (STRINGLIST *)0 };COMPSPEC *pcomp_curcs;const char *pcomp_curcmd;#ifdef DEBUG/* Debugging code */static void#if defined (PREFER_STDARG)debug_printf (const char *format, ...)#elsedebug_printf (format, va_alist) const char *format; va_dcl#endif{ va_list args; if (progcomp_debug == 0) return; SH_VA_START (args, format); fprintf (stdout, "DEBUG: "); vfprintf (stdout, format, args); fprintf (stdout, "\n"); rl_on_new_line (); va_end (args);}#endif/* Functions to manage the item lists */voidset_itemlist_dirty (it) ITEMLIST *it;{ it->flags |= LIST_DIRTY;}voidinitialize_itemlist (itp) ITEMLIST *itp;{ (*itp->list_getter) (itp); itp->flags |= LIST_INITIALIZED; itp->flags &= ~LIST_DIRTY;}voidclean_itemlist (itp) ITEMLIST *itp;{ STRINGLIST *sl; sl = itp->slist; if (sl) { if ((itp->flags & (LIST_DONTFREEMEMBERS|LIST_DONTFREE)) == 0) strvec_flush (sl->list); if ((itp->flags & LIST_DONTFREE) == 0) free (sl->list); free (sl); } itp->slist = (STRINGLIST *)NULL; itp->flags &= ~(LIST_DONTFREE|LIST_DONTFREEMEMBERS|LIST_INITIALIZED|LIST_DIRTY);}static intshouldexp_filterpat (s) char *s;{ register char *p; for (p = s; p && *p; p++) { if (*p == '\\') p++; else if (*p == '&') return 1; } return 0;}/* Replace any instance of `&' in PAT with TEXT. Backslash may be used to quote a `&' and inhibit substitution. Returns a new string. This just calls stringlib.c:strcreplace(). */static char *preproc_filterpat (pat, text) char *pat; char *text;{ char *ret; ret = strcreplace (pat, '&', text, 1); return ret;} /* Remove any match of FILTERPAT from SL. A `&' in FILTERPAT is replaced by TEXT. A leading `!' in FILTERPAT negates the pattern; in this case any member of SL->list that does *not* match will be removed. This returns a new STRINGLIST with the matching members of SL *copied*. Any non-matching members of SL->list are *freed*. */ STRINGLIST *filter_stringlist (sl, filterpat, text) STRINGLIST *sl; char *filterpat, *text;{ int i, m, not; STRINGLIST *ret; char *npat, *t; if (sl == 0 || sl->list == 0 || sl->list_len == 0) return sl; npat = shouldexp_filterpat (filterpat) ? preproc_filterpat (filterpat, text) : filterpat; not = (npat[0] == '!'); t = not ? npat + 1 : npat; ret = strlist_create (sl->list_size); for (i = 0; i < sl->list_len; i++) { m = strmatch (t, sl->list[i], FNMATCH_EXTFLAG); if ((not && m == FNM_NOMATCH) || (not == 0 && m != FNM_NOMATCH)) free (sl->list[i]); else ret->list[ret->list_len++] = sl->list[i]; } ret->list[ret->list_len] = (char *)NULL; if (npat != filterpat) free (npat); return ret;}/* Turn an array of strings returned by rl_completion_matches into a STRINGLIST. This understands how rl_completion_matches sets matches[0] (the lcd of the strings in the list, unless it's the only match). */STRINGLIST *completions_to_stringlist (matches) char **matches;{ STRINGLIST *sl; int mlen, i, n; mlen = (matches == 0) ? 0 : strvec_len (matches); sl = strlist_create (mlen + 1); if (matches == 0 || matches[0] == 0) return sl; if (matches[1] == 0) { sl->list[0] = STRDUP (matches[0]); sl->list[sl->list_len = 1] = (char *)NULL; return sl; } for (i = 1, n = 0; i < mlen; i++, n++) sl->list[n] = STRDUP (matches[i]); sl->list_len = n; sl->list[n] = (char *)NULL; return sl;}/* Functions to manage the various ITEMLISTs that we populate internally. The caller is responsible for setting ITP->flags correctly. */static intit_init_aliases (itp) ITEMLIST *itp;{#ifdef ALIAS alias_t **alias_list; register int i, n; STRINGLIST *sl; alias_list = all_aliases (); if (alias_list == 0) { itp->slist = (STRINGLIST *)NULL; return 0; } for (n = 0; alias_list[n]; n++) ; sl = strlist_create (n+1); for (i = 0; i < n; i++) sl->list[i] = STRDUP (alias_list[i]->name); sl->list[n] = (char *)NULL; sl->list_size = sl->list_len = n; itp->slist = sl;#else itp->slist = (STRINGLIST *)NULL;#endif return 1;}static voidinit_itemlist_from_varlist (itp, svfunc) ITEMLIST *itp; SVFUNC *svfunc;{ SHELL_VAR **vlist; STRINGLIST *sl; register int i, n; vlist = (*svfunc) (); if (vlist == 0) { itp->slist = (STRINGLIST *)NULL; return; } for (n = 0; vlist[n]; n++) ; sl = strlist_create (n+1); for (i = 0; i < n; i++) sl->list[i] = savestring (vlist[i]->name); sl->list[sl->list_len = n] = (char *)NULL; itp->slist = sl;}static intit_init_arrayvars (itp) ITEMLIST *itp;{#if defined (ARRAY_VARS) init_itemlist_from_varlist (itp, all_array_variables); return 1;#else return 0;#endif}static intit_init_bindings (itp) ITEMLIST *itp;{ char **blist; STRINGLIST *sl; /* rl_funmap_names allocates blist, but not its members */ blist = (char **)rl_funmap_names (); /* XXX fix const later */ sl = strlist_create (0); sl->list = blist; sl->list_size = 0; sl->list_len = strvec_len (sl->list); itp->flags |= LIST_DONTFREEMEMBERS; itp->slist = sl; return 0;}static intit_init_builtins (itp) ITEMLIST *itp;{ STRINGLIST *sl; register int i, n; sl = strlist_create (num_shell_builtins); for (i = n = 0; i < num_shell_builtins; i++) if (shell_builtins[i].function) sl->list[n++] = shell_builtins[i].name; sl->list[sl->list_len = n] = (char *)NULL; itp->flags |= LIST_DONTFREEMEMBERS; itp->slist = sl; return 0;}static intit_init_enabled (itp) ITEMLIST *itp;{ STRINGLIST *sl; register int i, n; sl = strlist_create (num_shell_builtins); for (i = n = 0; i < num_shell_builtins; i++) { if (shell_builtins[i].function && (shell_builtins[i].flags & BUILTIN_ENABLED)) sl->list[n++] = shell_builtins[i].name; } sl->list[sl->list_len = n] = (char *)NULL; itp->flags |= LIST_DONTFREEMEMBERS; itp->slist = sl; return 0;}static intit_init_disabled (itp) ITEMLIST *itp;{ STRINGLIST *sl; register int i, n; sl = strlist_create (num_shell_builtins); for (i = n = 0; i < num_shell_builtins; i++) { if (shell_builtins[i].function && ((shell_builtins[i].flags & BUILTIN_ENABLED) == 0)) sl->list[n++] = shell_builtins[i].name; } sl->list[sl->list_len = n] = (char *)NULL; itp->flags |= LIST_DONTFREEMEMBERS; itp->slist = sl; return 0;}static intit_init_exported (itp) ITEMLIST *itp;{ init_itemlist_from_varlist (itp, all_exported_variables); return 0;}static intit_init_functions (itp) ITEMLIST *itp;{ init_itemlist_from_varlist (itp, all_visible_functions); return 0;}static intit_init_hostnames (itp) ITEMLIST *itp;{ STRINGLIST *sl; sl = strlist_create (0); sl->list = get_hostname_list (); sl->list_len = sl->list ? strvec_len (sl->list) : 0; sl->list_size = sl->list_len; itp->slist = sl; itp->flags |= LIST_DONTFREEMEMBERS|LIST_DONTFREE; return 0;}static intit_init_joblist (itp, jstate)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -