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 + -
显示快捷键?