pcomplete.c
来自「android-w.song.android.widget」· C语言 代码 · 共 1,547 行 · 第 1/3 页
C
1,547 行
return ((STRINGLIST *)NULL); }#if !defined (ARRAY_VARS) return ((STRINGLIST *)NULL);#else /* We pass cw - 1 because command_line_to_word_list returns indices that are 1-based, while bash arrays are 0-based. */ bind_compfunc_variables (line, ind, lwords, cw - 1, 0); cmdlist = build_arg_list (funcname, text, lwords, cw); pps = &ps; save_parser_state (pps); begin_unwind_frame ("gen-shell-function-matches"); add_unwind_protect (restore_parser_state, (char *)pps); add_unwind_protect (dispose_words, (char *)cmdlist); add_unwind_protect (unbind_compfunc_variables, (char *)0); fval = execute_shell_function (f, cmdlist); discard_unwind_frame ("gen-shell-function-matches"); restore_parser_state (pps); found = fval != EX_NOTFOUND; if (fval == EX_RETRYFAIL) found |= PCOMP_RETRYFAIL; if (foundp) *foundp = found; /* Now clean up and destroy everything. */ dispose_words (cmdlist); unbind_compfunc_variables (0); /* The list of completions is returned in the array variable COMPREPLY. */ v = find_variable ("COMPREPLY"); if (v == 0) return ((STRINGLIST *)NULL); if (array_p (v) == 0) v = convert_var_to_array (v); VUNSETATTR (v, att_invisible); a = array_cell (v); if (found == 0 || (found & PCOMP_RETRYFAIL) || a == 0 || array_empty (a)) sl = (STRINGLIST *)NULL; else { /* XXX - should we filter the list of completions so only those matching TEXT are returned? Right now, we do not. */ sl = strlist_create (0); sl->list = array_to_argv (a); sl->list_len = sl->list_size = array_num_elements (a); } /* XXX - should we unbind COMPREPLY here? */ unbind_variable ("COMPREPLY"); return (sl);#endif}/* Build a command string with $0 == cs->command (command to execute for completion list) $1 == command name (command being completed) $2 = word to be completed (possibly null) $3 = previous word and run in with command substitution. Parse the results, one word per line, with backslashes allowed to escape newlines. Build a STRINGLIST from the results and return it. */static STRINGLIST *gen_command_matches (cs, text, line, ind, lwords, nw, cw) COMPSPEC *cs; const char *text; char *line; int ind; WORD_LIST *lwords; int nw, cw;{ char *csbuf, *cscmd, *t; int cmdlen, cmdsize, n, ws, we; WORD_LIST *cmdlist, *cl; WORD_DESC *tw; STRINGLIST *sl; bind_compfunc_variables (line, ind, lwords, cw, 1); cmdlist = build_arg_list (cs->command, text, lwords, cw); /* Estimate the size needed for the buffer. */ n = strlen (cs->command); cmdsize = n + 1; for (cl = cmdlist->next; cl; cl = cl->next) cmdsize += STRLEN (cl->word->word) + 3; cmdsize += 2; /* allocate the string for the command and fill it in. */ cscmd = (char *)xmalloc (cmdsize + 1); strcpy (cscmd, cs->command); /* $0 */ cmdlen = n; cscmd[cmdlen++] = ' '; for (cl = cmdlist->next; cl; cl = cl->next) /* $1, $2, $3, ... */ { t = sh_single_quote (cl->word->word ? cl->word->word : ""); n = strlen (t); RESIZE_MALLOCED_BUFFER (cscmd, cmdlen, n + 2, cmdsize, 64); strcpy (cscmd + cmdlen, t); cmdlen += n; if (cl->next) cscmd[cmdlen++] = ' '; free (t); } cscmd[cmdlen] = '\0'; tw = command_substitute (cscmd, 0); csbuf = tw ? tw->word : (char *)NULL; dispose_word_desc (tw); /* Now clean up and destroy everything. */ dispose_words (cmdlist); free (cscmd); unbind_compfunc_variables (1); if (csbuf == 0 || *csbuf == '\0') { FREE (csbuf); return ((STRINGLIST *)NULL); } /* Now break CSBUF up at newlines, with backslash allowed to escape a newline, and put the individual words into a STRINGLIST. */ sl = strlist_create (16); for (ws = 0; csbuf[ws]; ) { we = ws; while (csbuf[we] && csbuf[we] != '\n') { if (csbuf[we] == '\\' && csbuf[we+1] == '\n') we++; we++; } t = substring (csbuf, ws, we); if (sl->list_len >= sl->list_size - 1) strlist_resize (sl, sl->list_size + 16); sl->list[sl->list_len++] = t; while (csbuf[we] == '\n') we++; ws = we; } sl->list[sl->list_len] = (char *)NULL; free (csbuf); return (sl);}static WORD_LIST *command_line_to_word_list (line, llen, sentinel, nwp, cwp) char *line; int llen, sentinel, *nwp, *cwp;{ WORD_LIST *ret; char *delims;#if 0 delims = "()<>;&| \t\n"; /* shell metacharacters break words */#else delims = rl_completer_word_break_characters;#endif ret = split_at_delims (line, llen, delims, sentinel, SD_NOQUOTEDELIM, nwp, cwp); return (ret);}/* Evaluate COMPSPEC *cs and return all matches for WORD. */STRINGLIST *gen_compspec_completions (cs, cmd, word, start, end, foundp) COMPSPEC *cs; const char *cmd; const char *word; int start, end; int *foundp;{ STRINGLIST *ret, *tmatches; char *line; int llen, nw, cw, found, foundf; WORD_LIST *lwords; COMPSPEC *tcs; found = 1;#ifdef DEBUG debug_printf ("gen_compspec_completions (%s, %s, %d, %d)", cmd, word, start, end); debug_printf ("gen_compspec_completions: %s -> %p", cmd, cs);#endif ret = gen_action_completions (cs, word);#ifdef DEBUG if (ret && progcomp_debug) { debug_printf ("gen_action_completions (%p, %s) -->", cs, word); strlist_print (ret, "\t"); rl_on_new_line (); }#endif /* Now we start generating completions based on the other members of CS. */ if (cs->globpat) { tmatches = gen_globpat_matches (cs, word); if (tmatches) {#ifdef DEBUG if (progcomp_debug) { debug_printf ("gen_globpat_matches (%p, %s) -->", cs, word); strlist_print (tmatches, "\t"); rl_on_new_line (); }#endif ret = strlist_append (ret, tmatches); strlist_dispose (tmatches); rl_filename_completion_desired = 1; } } if (cs->words) { tmatches = gen_wordlist_matches (cs, word); if (tmatches) {#ifdef DEBUG if (progcomp_debug) { debug_printf ("gen_wordlist_matches (%p, %s) -->", cs, word); strlist_print (tmatches, "\t"); rl_on_new_line (); }#endif ret = strlist_append (ret, tmatches); strlist_dispose (tmatches); } } lwords = (WORD_LIST *)NULL; line = (char *)NULL; if (cs->command || cs->funcname) { /* If we have a command or function to execute, we need to first break the command line into individual words, find the number of words, and find the word in the list containing the word to be completed. */ line = substring (rl_line_buffer, start, end); llen = end - start;#ifdef DEBUG debug_printf ("command_line_to_word_list (%s, %d, %d, %p, %p)", line, llen, rl_point - start, &nw, &cw);#endif lwords = command_line_to_word_list (line, llen, rl_point - start, &nw, &cw);#ifdef DEBUG if (lwords == 0 && llen > 0) debug_printf ("ERROR: command_line_to_word_list returns NULL"); else if (progcomp_debug) { debug_printf ("command_line_to_word_list -->"); printf ("\t"); print_word_list (lwords, "!"); printf ("\n"); fflush(stdout); rl_on_new_line (); }#endif } if (cs->funcname) { foundf = 0; tmatches = gen_shell_function_matches (cs, word, line, rl_point - start, lwords, nw, cw, &foundf); if (foundf != 0) found = foundf; if (tmatches) {#ifdef DEBUG if (progcomp_debug) { debug_printf ("gen_shell_function_matches (%p, %s, %p, %d, %d) -->", cs, word, lwords, nw, cw); strlist_print (tmatches, "\t"); rl_on_new_line (); }#endif ret = strlist_append (ret, tmatches); strlist_dispose (tmatches); } } if (cs->command) { tmatches = gen_command_matches (cs, word, line, rl_point - start, lwords, nw, cw); if (tmatches) {#ifdef DEBUG if (progcomp_debug) { debug_printf ("gen_command_matches (%p, %s, %p, %d, %d) -->", cs, word, lwords, nw, cw); strlist_print (tmatches, "\t"); rl_on_new_line (); }#endif ret = strlist_append (ret, tmatches); strlist_dispose (tmatches); } } if (cs->command || cs->funcname) { if (lwords) dispose_words (lwords); FREE (line); } if (foundp) *foundp = found; if (found == 0 || (found & PCOMP_RETRYFAIL)) { strlist_dispose (ret); return NULL; } if (cs->filterpat) { tmatches = filter_stringlist (ret, cs->filterpat, word);#ifdef DEBUG if (progcomp_debug) { debug_printf ("filter_stringlist (%p, %s, %s) -->", ret, cs->filterpat, word); strlist_print (tmatches, "\t"); rl_on_new_line (); }#endif if (ret && ret != tmatches) { FREE (ret->list); free (ret); } ret = tmatches; } if (cs->prefix || cs->suffix) ret = strlist_prefix_suffix (ret, cs->prefix, cs->suffix); /* If no matches have been generated and the user has specified that directory completion should be done as a default, call gen_action_completions again to generate a list of matching directory names. */ if ((ret == 0 || ret->list_len == 0) && (cs->options & COPT_DIRNAMES)) { tcs = compspec_create (); tcs->actions = CA_DIRECTORY; ret = gen_action_completions (tcs, word); compspec_dispose (tcs); } else if (cs->options & COPT_PLUSDIRS) { tcs = compspec_create (); tcs->actions = CA_DIRECTORY; tmatches = gen_action_completions (tcs, word); ret = strlist_append (ret, tmatches); strlist_dispose (tmatches); compspec_dispose (tcs); } return (ret);}voidpcomp_set_readline_variables (flags, nval) int flags, nval;{ /* If the user specified that the compspec returns filenames, make sure that readline knows it. */ if (flags & COPT_FILENAMES) rl_filename_completion_desired = nval; /* If the user doesn't want a space appended, tell readline. */ if (flags & COPT_NOSPACE) rl_completion_suppress_append = nval;}/* Set or unset FLAGS in the options word of the current compspec. SET_OR_UNSET is 1 for setting, 0 for unsetting. */voidpcomp_set_compspec_options (cs, flags, set_or_unset) COMPSPEC *cs; int flags, set_or_unset;{ if (cs == 0 && ((cs = pcomp_curcs) == 0)) return; if (set_or_unset) cs->options |= flags; else cs->options &= ~flags;}static STRINGLIST *gen_progcomp_completions (ocmd, cmd, word, start, end, foundp, retryp, lastcs) const char *ocmd; const char *cmd; const char *word; int start, end; int *foundp, *retryp; COMPSPEC **lastcs;{ COMPSPEC *cs, *oldcs; const char *oldcmd; STRINGLIST *ret; cs = progcomp_search (ocmd); if (cs == 0 || cs == *lastcs) return (NULL); if (*lastcs) compspec_dispose (*lastcs); cs->refcount++; /* XXX */ *lastcs = cs; cs = compspec_copy (cs); oldcs = pcomp_curcs; oldcmd = pcomp_curcmd; pcomp_curcs = cs; pcomp_curcmd = cmd; ret = gen_compspec_completions (cs, cmd, word, start, end, foundp); pcomp_curcs = oldcs; pcomp_curcmd = oldcmd; /* We need to conditionally handle setting *retryp here */ if (retryp) *retryp = foundp && (*foundp & PCOMP_RETRYFAIL); if (foundp) { *foundp &= ~PCOMP_RETRYFAIL; *foundp |= cs->options; } compspec_dispose (cs); return ret; }/* The driver function for the programmable completion code. Returns a list of matches for WORD, which is an argument to command CMD. START and END bound the command currently being completed in rl_line_buffer. */char **programmable_completions (cmd, word, start, end, foundp) const char *cmd; const char *word; int start, end, *foundp;{ COMPSPEC *cs, *lastcs; STRINGLIST *ret; char **rmatches, *t; int found, retry, count; lastcs = 0; found = count = 0; do { retry = 0; /* We look at the basename of CMD if the full command does not have an associated COMPSPEC. */ ret = gen_progcomp_completions (cmd, cmd, word, start, end, &found, &retry, &lastcs); if (found == 0) { t = strrchr (cmd, '/'); if (t && *(++t)) ret = gen_progcomp_completions (t, cmd, word, start, end, &found, &retry, &lastcs); } if (found == 0) ret = gen_progcomp_completions (DEFAULTCMD, cmd, word, start, end, &found, &retry, &lastcs); count++; if (count > 32) { internal_warning ("programmable_completion: %s: possible retry loop", cmd); break; } } while (retry); if (ret) { rmatches = ret->list; free (ret); } else rmatches = (char **)NULL; if (foundp) *foundp = found; if (lastcs) /* XXX - should be while? */ compspec_dispose (lastcs); return (rmatches);}#endif /* PROGRAMMABLE_COMPLETION */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?