Line data Source code
1 : /* pcomplete.c - functions to generate lists of matches for programmable completion. */
2 :
3 : /* Copyright (C) 1999-2012 Free Software Foundation, Inc.
4 :
5 : This file is part of GNU Bash, the Bourne Again SHell.
6 :
7 : Bash is free software: you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation, either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : Bash is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with Bash. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <config.h>
22 :
23 : #if defined (PROGRAMMABLE_COMPLETION)
24 :
25 : #include "bashtypes.h"
26 : #include "posixstat.h"
27 :
28 : #if defined (HAVE_UNISTD_H)
29 : # include <unistd.h>
30 : #endif
31 :
32 : #include <signal.h>
33 :
34 : #if defined (PREFER_STDARG)
35 : # include <stdarg.h>
36 : #else
37 : # include <varargs.h>
38 : #endif
39 :
40 : #include <sys/time.h>
41 :
42 : #include <stdio.h>
43 : #include "bashansi.h"
44 : #include "bashintl.h"
45 :
46 : #include "shell.h"
47 : #include "pcomplete.h"
48 : #include "alias.h"
49 : #include "bashline.h"
50 : #include "execute_cmd.h"
51 : #include "pathexp.h"
52 :
53 : #if defined (JOB_CONTROL)
54 : # include "jobs.h"
55 : #endif
56 :
57 : #if !defined (NSIG)
58 : # include "trap.h"
59 : #endif
60 :
61 : #include "shmbutil.h"
62 :
63 : #include "builtins.h"
64 : #include "builtins/common.h"
65 : #include "builtins/builtext.h"
66 :
67 : #include <glob/glob.h>
68 : #include <glob/strmatch.h>
69 :
70 : #include <readline/rlconf.h>
71 : #include <readline/readline.h>
72 : #include <readline/history.h>
73 :
74 : #define PCOMP_RETRYFAIL 256
75 :
76 : #ifdef STRDUP
77 : # undef STRDUP
78 : #endif
79 : #define STRDUP(x) ((x) ? savestring (x) : (char *)NULL)
80 :
81 : typedef SHELL_VAR **SVFUNC ();
82 :
83 : #ifndef HAVE_STRPBRK
84 : extern char *strpbrk __P((char *, char *));
85 : #endif
86 :
87 : extern int array_needs_making;
88 : extern STRING_INT_ALIST word_token_alist[];
89 : extern char *signal_names[];
90 : extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;
91 :
92 : #if defined (DEBUG)
93 : #if defined (PREFER_STDARG)
94 : static void debug_printf (const char *, ...) __attribute__((__format__ (printf, 1, 2)));
95 : #endif
96 : #endif /* DEBUG */
97 :
98 : static int it_init_joblist __P((ITEMLIST *, int));
99 :
100 : static int it_init_aliases __P((ITEMLIST *));
101 : static int it_init_arrayvars __P((ITEMLIST *));
102 : static int it_init_bindings __P((ITEMLIST *));
103 : static int it_init_builtins __P((ITEMLIST *));
104 : static int it_init_disabled __P((ITEMLIST *));
105 : static int it_init_enabled __P((ITEMLIST *));
106 : static int it_init_exported __P((ITEMLIST *));
107 : static int it_init_functions __P((ITEMLIST *));
108 : static int it_init_helptopics __P((ITEMLIST *));
109 : static int it_init_hostnames __P((ITEMLIST *));
110 : static int it_init_jobs __P((ITEMLIST *));
111 : static int it_init_running __P((ITEMLIST *));
112 : static int it_init_stopped __P((ITEMLIST *));
113 : static int it_init_keywords __P((ITEMLIST *));
114 : static int it_init_signals __P((ITEMLIST *));
115 : static int it_init_variables __P((ITEMLIST *));
116 : static int it_init_setopts __P((ITEMLIST *));
117 : static int it_init_shopts __P((ITEMLIST *));
118 :
119 : static int shouldexp_filterpat __P((char *));
120 : static char *preproc_filterpat __P((char *, const char *));
121 :
122 : static void init_itemlist_from_varlist __P((ITEMLIST *, SVFUNC *));
123 :
124 : static STRINGLIST *gen_matches_from_itemlist __P((ITEMLIST *, const char *));
125 : static STRINGLIST *gen_action_completions __P((COMPSPEC *, const char *));
126 : static STRINGLIST *gen_globpat_matches __P((COMPSPEC *, const char *));
127 : static STRINGLIST *gen_wordlist_matches __P((COMPSPEC *, const char *));
128 : static STRINGLIST *gen_shell_function_matches __P((COMPSPEC *, const char *,
129 : const char *,
130 : char *, int, WORD_LIST *,
131 : int, int, int *));
132 : static STRINGLIST *gen_command_matches __P((COMPSPEC *, const char *,
133 : const char *,
134 : char *, int, WORD_LIST *,
135 : int, int));
136 :
137 : static STRINGLIST *gen_progcomp_completions __P((const char *, const char *,
138 : const char *,
139 : int, int, int *, int *,
140 : COMPSPEC **));
141 :
142 : static char *pcomp_filename_completion_function __P((const char *, int));
143 :
144 : #if defined (ARRAY_VARS)
145 : static SHELL_VAR *bind_comp_words __P((WORD_LIST *));
146 : #endif
147 : static void bind_compfunc_variables __P((char *, int, WORD_LIST *, int, int));
148 : static void unbind_compfunc_variables __P((int));
149 : static WORD_LIST *build_arg_list __P((char *, const char *, const char *, WORD_LIST *, int));
150 : static WORD_LIST *command_line_to_word_list __P((char *, int, int, int *, int *));
151 :
152 : #ifdef DEBUG
153 : static int progcomp_debug = 0;
154 : #endif
155 :
156 : int prog_completion_enabled = 1;
157 :
158 : /* These are used to manage the arrays of strings for possible completions. */
159 : ITEMLIST it_aliases = { 0, it_init_aliases, (STRINGLIST *)0 };
160 : ITEMLIST it_arrayvars = { LIST_DYNAMIC, it_init_arrayvars, (STRINGLIST *)0 };
161 : ITEMLIST it_bindings = { 0, it_init_bindings, (STRINGLIST *)0 };
162 : ITEMLIST it_builtins = { 0, it_init_builtins, (STRINGLIST *)0 };
163 : ITEMLIST it_commands = { LIST_DYNAMIC }; /* unused */
164 : ITEMLIST it_directories = { LIST_DYNAMIC }; /* unused */
165 : ITEMLIST it_disabled = { 0, it_init_disabled, (STRINGLIST *)0 };
166 : ITEMLIST it_enabled = { 0, it_init_enabled, (STRINGLIST *)0 };
167 : ITEMLIST it_exports = { LIST_DYNAMIC, it_init_exported, (STRINGLIST *)0 };
168 : ITEMLIST it_files = { LIST_DYNAMIC }; /* unused */
169 : ITEMLIST it_functions = { 0, it_init_functions, (STRINGLIST *)0 };
170 : ITEMLIST it_helptopics = { 0, it_init_helptopics, (STRINGLIST *)0 };
171 : ITEMLIST it_hostnames = { LIST_DYNAMIC, it_init_hostnames, (STRINGLIST *)0 };
172 : ITEMLIST it_groups = { LIST_DYNAMIC }; /* unused */
173 : ITEMLIST it_jobs = { LIST_DYNAMIC, it_init_jobs, (STRINGLIST *)0 };
174 : ITEMLIST it_keywords = { 0, it_init_keywords, (STRINGLIST *)0 };
175 : ITEMLIST it_running = { LIST_DYNAMIC, it_init_running, (STRINGLIST *)0 };
176 : ITEMLIST it_services = { LIST_DYNAMIC }; /* unused */
177 : ITEMLIST it_setopts = { 0, it_init_setopts, (STRINGLIST *)0 };
178 : ITEMLIST it_shopts = { 0, it_init_shopts, (STRINGLIST *)0 };
179 : ITEMLIST it_signals = { 0, it_init_signals, (STRINGLIST *)0 };
180 : ITEMLIST it_stopped = { LIST_DYNAMIC, it_init_stopped, (STRINGLIST *)0 };
181 : ITEMLIST it_users = { LIST_DYNAMIC }; /* unused */
182 : ITEMLIST it_variables = { LIST_DYNAMIC, it_init_variables, (STRINGLIST *)0 };
183 :
184 : COMPSPEC *pcomp_curcs;
185 : const char *pcomp_curcmd;
186 : const char *pcomp_curtxt;
187 :
188 : #ifdef DEBUG
189 : /* Debugging code */
190 : static void
191 : #if defined (PREFER_STDARG)
192 : debug_printf (const char *format, ...)
193 : #else
194 : debug_printf (format, va_alist)
195 : const char *format;
196 : va_dcl
197 : #endif
198 : {
199 : va_list args;
200 :
201 : if (progcomp_debug == 0)
202 : return;
203 :
204 : SH_VA_START (args, format);
205 :
206 : fprintf (stdout, "DEBUG: ");
207 : vfprintf (stdout, format, args);
208 : fprintf (stdout, "\n");
209 :
210 : rl_on_new_line ();
211 :
212 : va_end (args);
213 : }
214 : #endif
215 :
216 : /* Functions to manage the item lists */
217 :
218 : void
219 17166379 : set_itemlist_dirty (it)
220 : ITEMLIST *it;
221 : {
222 17166379 : it->flags |= LIST_DIRTY;
223 17166379 : }
224 :
225 : void
226 0 : initialize_itemlist (itp)
227 : ITEMLIST *itp;
228 : {
229 0 : (*itp->list_getter) (itp);
230 0 : itp->flags |= LIST_INITIALIZED;
231 0 : itp->flags &= ~LIST_DIRTY;
232 0 : }
233 :
234 : void
235 0 : clean_itemlist (itp)
236 : ITEMLIST *itp;
237 : {
238 0 : STRINGLIST *sl;
239 :
240 0 : sl = itp->slist;
241 0 : if (sl)
242 : {
243 0 : if ((itp->flags & (LIST_DONTFREEMEMBERS|LIST_DONTFREE)) == 0)
244 0 : strvec_flush (sl->list);
245 0 : if ((itp->flags & LIST_DONTFREE) == 0)
246 0 : free (sl->list);
247 0 : free (sl);
248 : }
249 0 : itp->slist = (STRINGLIST *)NULL;
250 0 : itp->flags &= ~(LIST_DONTFREE|LIST_DONTFREEMEMBERS|LIST_INITIALIZED|LIST_DIRTY);
251 0 : }
252 :
253 :
254 : static int
255 : shouldexp_filterpat (s)
256 : char *s;
257 : {
258 : register char *p;
259 :
260 0 : for (p = s; p && *p; p++)
261 : {
262 0 : if (*p == '\\')
263 0 : p++;
264 0 : else if (*p == '&')
265 : return 1;
266 : }
267 : return 0;
268 : }
269 :
270 : /* Replace any instance of `&' in PAT with TEXT. Backslash may be used to
271 : quote a `&' and inhibit substitution. Returns a new string. This just
272 : calls stringlib.c:strcreplace(). */
273 : static char *
274 : preproc_filterpat (pat, text)
275 : char *pat;
276 : const char *text;
277 : {
278 0 : char *ret;
279 :
280 0 : ret = strcreplace (pat, '&', text, 1);
281 0 : return ret;
282 : }
283 :
284 : /* Remove any match of FILTERPAT from SL. A `&' in FILTERPAT is replaced by
285 : TEXT. A leading `!' in FILTERPAT negates the pattern; in this case
286 : any member of SL->list that does *not* match will be removed. This returns
287 : a new STRINGLIST with the matching members of SL *copied*. Any
288 : non-matching members of SL->list are *freed*. */
289 : STRINGLIST *
290 0 : filter_stringlist (sl, filterpat, text)
291 : STRINGLIST *sl;
292 : char *filterpat;
293 : const char *text;
294 : {
295 0 : int i, m, not;
296 0 : STRINGLIST *ret;
297 0 : char *npat, *t;
298 :
299 0 : if (sl == 0 || sl->list == 0 || sl->list_len == 0)
300 : return sl;
301 :
302 0 : npat = shouldexp_filterpat (filterpat) ? preproc_filterpat (filterpat, text) : filterpat;
303 :
304 : #if defined (EXTENDED_GLOB)
305 0 : not = (npat[0] == '!' && (extended_glob == 0 || npat[1] != '(')); /*)*/
306 : #else
307 : not = (npat[0] == '!');
308 : #endif
309 0 : t = not ? npat + 1 : npat;
310 :
311 0 : ret = strlist_create (sl->list_size);
312 0 : for (i = 0; i < sl->list_len; i++)
313 : {
314 0 : m = strmatch (t, sl->list[i], FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
315 0 : if ((not && m == FNM_NOMATCH) || (not == 0 && m != FNM_NOMATCH))
316 0 : free (sl->list[i]);
317 : else
318 0 : ret->list[ret->list_len++] = sl->list[i];
319 : }
320 :
321 0 : ret->list[ret->list_len] = (char *)NULL;
322 0 : if (npat != filterpat)
323 0 : free (npat);
324 :
325 : return ret;
326 : }
327 :
328 : /* Turn an array of strings returned by rl_completion_matches into a STRINGLIST.
329 : This understands how rl_completion_matches sets matches[0] (the lcd of the
330 : strings in the list, unless it's the only match). */
331 : STRINGLIST *
332 0 : completions_to_stringlist (matches)
333 : char **matches;
334 : {
335 0 : STRINGLIST *sl;
336 0 : int mlen, i, n;
337 :
338 0 : mlen = (matches == 0) ? 0 : strvec_len (matches);
339 0 : sl = strlist_create (mlen + 1);
340 :
341 0 : if (matches == 0 || matches[0] == 0)
342 : return sl;
343 :
344 0 : if (matches[1] == 0)
345 : {
346 0 : sl->list[0] = STRDUP (matches[0]);
347 0 : sl->list[sl->list_len = 1] = (char *)NULL;
348 0 : return sl;
349 : }
350 :
351 0 : for (i = 1, n = 0; i < mlen; i++, n++)
352 0 : sl->list[n] = STRDUP (matches[i]);
353 0 : sl->list_len = n;
354 0 : sl->list[n] = (char *)NULL;
355 :
356 0 : return sl;
357 : }
358 :
359 : /* Functions to manage the various ITEMLISTs that we populate internally.
360 : The caller is responsible for setting ITP->flags correctly. */
361 :
362 : static int
363 0 : it_init_aliases (itp)
364 : ITEMLIST *itp;
365 : {
366 : #ifdef ALIAS
367 0 : alias_t **alias_list;
368 0 : register int i, n;
369 0 : STRINGLIST *sl;
370 :
371 0 : alias_list = all_aliases ();
372 0 : if (alias_list == 0)
373 : {
374 0 : itp->slist = (STRINGLIST *)NULL;
375 0 : return 0;
376 : }
377 0 : for (n = 0; alias_list[n]; n++)
378 0 : ;
379 0 : sl = strlist_create (n+1);
380 0 : for (i = 0; i < n; i++)
381 0 : sl->list[i] = STRDUP (alias_list[i]->name);
382 0 : sl->list[n] = (char *)NULL;
383 0 : sl->list_size = sl->list_len = n;
384 0 : itp->slist = sl;
385 : #else
386 : itp->slist = (STRINGLIST *)NULL;
387 : #endif
388 0 : free (alias_list);
389 0 : return 1;
390 : }
391 :
392 : static void
393 0 : init_itemlist_from_varlist (itp, svfunc)
394 : ITEMLIST *itp;
395 : SVFUNC *svfunc;
396 : {
397 0 : SHELL_VAR **vlist;
398 0 : STRINGLIST *sl;
399 0 : register int i, n;
400 :
401 0 : vlist = (*svfunc) ();
402 0 : if (vlist == 0)
403 : {
404 0 : itp->slist = (STRINGLIST *)NULL;
405 0 : return;
406 : }
407 0 : for (n = 0; vlist[n]; n++)
408 0 : ;
409 0 : sl = strlist_create (n+1);
410 0 : for (i = 0; i < n; i++)
411 0 : sl->list[i] = savestring (vlist[i]->name);
412 0 : sl->list[sl->list_len = n] = (char *)NULL;
413 0 : itp->slist = sl;
414 : }
415 :
416 : static int
417 0 : it_init_arrayvars (itp)
418 : ITEMLIST *itp;
419 : {
420 : #if defined (ARRAY_VARS)
421 0 : init_itemlist_from_varlist (itp, all_array_variables);
422 0 : return 1;
423 : #else
424 : return 0;
425 : #endif
426 : }
427 :
428 : static int
429 0 : it_init_bindings (itp)
430 : ITEMLIST *itp;
431 : {
432 0 : char **blist;
433 0 : STRINGLIST *sl;
434 :
435 : /* rl_funmap_names allocates blist, but not its members */
436 0 : blist = (char **)rl_funmap_names (); /* XXX fix const later */
437 0 : sl = strlist_create (0);
438 0 : sl->list = blist;
439 0 : sl->list_size = 0;
440 0 : sl->list_len = strvec_len (sl->list);
441 0 : itp->flags |= LIST_DONTFREEMEMBERS;
442 0 : itp->slist = sl;
443 :
444 0 : return 0;
445 : }
446 :
447 : static int
448 0 : it_init_builtins (itp)
449 : ITEMLIST *itp;
450 : {
451 0 : STRINGLIST *sl;
452 0 : register int i, n;
453 :
454 0 : sl = strlist_create (num_shell_builtins);
455 0 : for (i = n = 0; i < num_shell_builtins; i++)
456 0 : if (shell_builtins[i].function)
457 0 : sl->list[n++] = shell_builtins[i].name;
458 0 : sl->list[sl->list_len = n] = (char *)NULL;
459 0 : itp->flags |= LIST_DONTFREEMEMBERS;
460 0 : itp->slist = sl;
461 0 : return 0;
462 : }
463 :
464 : static int
465 0 : it_init_enabled (itp)
466 : ITEMLIST *itp;
467 : {
468 0 : STRINGLIST *sl;
469 0 : register int i, n;
470 :
471 0 : sl = strlist_create (num_shell_builtins);
472 0 : for (i = n = 0; i < num_shell_builtins; i++)
473 : {
474 0 : if (shell_builtins[i].function && (shell_builtins[i].flags & BUILTIN_ENABLED))
475 0 : sl->list[n++] = shell_builtins[i].name;
476 : }
477 0 : sl->list[sl->list_len = n] = (char *)NULL;
478 0 : itp->flags |= LIST_DONTFREEMEMBERS;
479 0 : itp->slist = sl;
480 0 : return 0;
481 : }
482 :
483 : static int
484 0 : it_init_disabled (itp)
485 : ITEMLIST *itp;
486 : {
487 0 : STRINGLIST *sl;
488 0 : register int i, n;
489 :
490 0 : sl = strlist_create (num_shell_builtins);
491 0 : for (i = n = 0; i < num_shell_builtins; i++)
492 : {
493 0 : if (shell_builtins[i].function && ((shell_builtins[i].flags & BUILTIN_ENABLED) == 0))
494 0 : sl->list[n++] = shell_builtins[i].name;
495 : }
496 0 : sl->list[sl->list_len = n] = (char *)NULL;
497 0 : itp->flags |= LIST_DONTFREEMEMBERS;
498 0 : itp->slist = sl;
499 0 : return 0;
500 : }
501 :
502 : static int
503 0 : it_init_exported (itp)
504 : ITEMLIST *itp;
505 : {
506 0 : init_itemlist_from_varlist (itp, all_exported_variables);
507 0 : return 0;
508 : }
509 :
510 : static int
511 0 : it_init_functions (itp)
512 : ITEMLIST *itp;
513 : {
514 0 : init_itemlist_from_varlist (itp, all_visible_functions);
515 0 : return 0;
516 : }
517 :
518 : /* Like it_init_builtins, but includes everything the help builtin looks at,
519 : not just builtins with an active implementing function. */
520 : static int
521 0 : it_init_helptopics (itp)
522 : ITEMLIST *itp;
523 : {
524 0 : STRINGLIST *sl;
525 0 : register int i, n;
526 :
527 0 : sl = strlist_create (num_shell_builtins);
528 0 : for (i = n = 0; i < num_shell_builtins; i++)
529 0 : sl->list[n++] = shell_builtins[i].name;
530 0 : sl->list[sl->list_len = n] = (char *)NULL;
531 0 : itp->flags |= LIST_DONTFREEMEMBERS;
532 0 : itp->slist = sl;
533 0 : return 0;
534 : }
535 :
536 : static int
537 0 : it_init_hostnames (itp)
538 : ITEMLIST *itp;
539 : {
540 0 : STRINGLIST *sl;
541 :
542 0 : sl = strlist_create (0);
543 0 : sl->list = get_hostname_list ();
544 0 : sl->list_len = sl->list ? strvec_len (sl->list) : 0;
545 0 : sl->list_size = sl->list_len;
546 0 : itp->slist = sl;
547 0 : itp->flags |= LIST_DONTFREEMEMBERS|LIST_DONTFREE;
548 0 : return 0;
549 : }
550 :
551 : static int
552 0 : it_init_joblist (itp, jstate)
553 : ITEMLIST *itp;
554 : int jstate;
555 : {
556 : #if defined (JOB_CONTROL)
557 0 : STRINGLIST *sl;
558 0 : register int i;
559 0 : register PROCESS *p;
560 0 : char *s, *t;
561 0 : JOB *j;
562 0 : JOB_STATE ws; /* wanted state */
563 :
564 0 : ws = JNONE;
565 0 : if (jstate == 0)
566 : ws = JRUNNING;
567 0 : else if (jstate == 1)
568 0 : ws = JSTOPPED;
569 :
570 0 : sl = strlist_create (js.j_jobslots);
571 0 : for (i = js.j_jobslots - 1; i >= 0; i--)
572 : {
573 0 : j = get_job_by_jid (i);
574 0 : if (j == 0)
575 0 : continue;
576 0 : p = j->pipe;
577 0 : if (jstate == -1 || JOBSTATE(i) == ws)
578 : {
579 0 : s = savestring (p->command);
580 0 : t = strpbrk (s, " \t\n");
581 0 : if (t)
582 0 : *t = '\0';
583 0 : sl->list[sl->list_len++] = s;
584 : }
585 : }
586 0 : itp->slist = sl;
587 : #else
588 : itp->slist = (STRINGLIST *)NULL;
589 : #endif
590 0 : return 0;
591 : }
592 :
593 : static int
594 0 : it_init_jobs (itp)
595 : ITEMLIST *itp;
596 : {
597 0 : return (it_init_joblist (itp, -1));
598 : }
599 :
600 : static int
601 0 : it_init_running (itp)
602 : ITEMLIST *itp;
603 : {
604 0 : return (it_init_joblist (itp, 0));
605 : }
606 :
607 : static int
608 0 : it_init_stopped (itp)
609 : ITEMLIST *itp;
610 : {
611 0 : return (it_init_joblist (itp, 1));
612 : }
613 :
614 : static int
615 0 : it_init_keywords (itp)
616 : ITEMLIST *itp;
617 : {
618 0 : STRINGLIST *sl;
619 0 : register int i, n;
620 :
621 0 : for (n = 0; word_token_alist[n].word; n++)
622 0 : ;
623 0 : sl = strlist_create (n);
624 0 : for (i = 0; i < n; i++)
625 0 : sl->list[i] = word_token_alist[i].word;
626 0 : sl->list[sl->list_len = i] = (char *)NULL;
627 0 : itp->flags |= LIST_DONTFREEMEMBERS;
628 0 : itp->slist = sl;
629 0 : return 0;
630 : }
631 :
632 : static int
633 0 : it_init_signals (itp)
634 : ITEMLIST *itp;
635 : {
636 0 : STRINGLIST *sl;
637 :
638 0 : sl = strlist_create (0);
639 0 : sl->list = signal_names;
640 0 : sl->list_len = strvec_len (sl->list);
641 0 : itp->flags |= LIST_DONTFREE;
642 0 : itp->slist = sl;
643 0 : return 0;
644 : }
645 :
646 : static int
647 0 : it_init_variables (itp)
648 : ITEMLIST *itp;
649 : {
650 0 : init_itemlist_from_varlist (itp, all_visible_variables);
651 0 : return 0;
652 : }
653 :
654 : static int
655 0 : it_init_setopts (itp)
656 : ITEMLIST *itp;
657 : {
658 0 : STRINGLIST *sl;
659 :
660 0 : sl = strlist_create (0);
661 0 : sl->list = get_minus_o_opts ();
662 0 : sl->list_len = strvec_len (sl->list);
663 0 : itp->slist = sl;
664 0 : itp->flags |= LIST_DONTFREEMEMBERS;
665 0 : return 0;
666 : }
667 :
668 : static int
669 0 : it_init_shopts (itp)
670 : ITEMLIST *itp;
671 : {
672 0 : STRINGLIST *sl;
673 :
674 0 : sl = strlist_create (0);
675 0 : sl->list = get_shopt_options ();
676 0 : sl->list_len = strvec_len (sl->list);
677 0 : itp->slist = sl;
678 0 : itp->flags |= LIST_DONTFREEMEMBERS;
679 0 : return 0;
680 : }
681 :
682 : /* Generate a list of all matches for TEXT using the STRINGLIST in itp->slist
683 : as the list of possibilities. If the itemlist has been marked dirty or
684 : it should be regenerated every time, destroy the old STRINGLIST and make a
685 : new one before trying the match. TEXT is dequoted before attempting a
686 : match. */
687 : static STRINGLIST *
688 0 : gen_matches_from_itemlist (itp, text)
689 : ITEMLIST *itp;
690 : const char *text;
691 : {
692 0 : STRINGLIST *ret, *sl;
693 0 : int tlen, i, n;
694 0 : char *ntxt;
695 :
696 0 : if ((itp->flags & (LIST_DIRTY|LIST_DYNAMIC)) ||
697 : (itp->flags & LIST_INITIALIZED) == 0)
698 : {
699 0 : if (itp->flags & (LIST_DIRTY|LIST_DYNAMIC))
700 0 : clean_itemlist (itp);
701 0 : if ((itp->flags & LIST_INITIALIZED) == 0)
702 0 : initialize_itemlist (itp);
703 : }
704 0 : if (itp->slist == 0)
705 : return ((STRINGLIST *)NULL);
706 0 : ret = strlist_create (itp->slist->list_len+1);
707 0 : sl = itp->slist;
708 :
709 0 : ntxt = bash_dequote_text (text);
710 0 : tlen = STRLEN (ntxt);
711 :
712 0 : for (i = n = 0; i < sl->list_len; i++)
713 : {
714 0 : if (tlen == 0 || STREQN (sl->list[i], ntxt, tlen))
715 0 : ret->list[n++] = STRDUP (sl->list[i]);
716 : }
717 0 : ret->list[ret->list_len = n] = (char *)NULL;
718 :
719 0 : FREE (ntxt);
720 : return ret;
721 : }
722 :
723 : /* A wrapper for rl_filename_completion_function that dequotes the filename
724 : before attempting completions. */
725 : static char *
726 0 : pcomp_filename_completion_function (text, state)
727 : const char *text;
728 : int state;
729 : {
730 0 : static char *dfn; /* dequoted filename */
731 0 : int iscompgen, iscompleting;
732 :
733 0 : if (state == 0)
734 : {
735 0 : FREE (dfn);
736 : /* remove backslashes quoting special characters in filenames. */
737 : /* There are roughly three paths we can follow to get here:
738 : 1. complete -f
739 : 2. compgen -f "$word" from a completion function
740 : 3. compgen -f "$word" from the command line
741 : They all need to be handled.
742 :
743 : In the first two cases, readline will run the filename dequoting
744 : function in rl_filename_completion_function if it found a filename
745 : quoting character in the word to be completed
746 : (rl_completion_found_quote). We run the dequoting function here
747 : if we're running compgen, we're not completing, and the
748 : rl_filename_completion_function won't dequote the filename
749 : (rl_completion_found_quote == 0). */
750 0 : iscompgen = this_shell_builtin == compgen_builtin;
751 0 : iscompleting = RL_ISSTATE (RL_STATE_COMPLETING);
752 0 : if (iscompgen && iscompleting == 0 && rl_completion_found_quote == 0
753 0 : && rl_filename_dequoting_function)
754 : {
755 : /* Use rl_completion_quote_character because any single or
756 : double quotes have been removed by the time TEXT makes it
757 : here, and we don't want to remove backslashes inside
758 : quoted strings. */
759 0 : dfn = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character);
760 : }
761 : /* Intended to solve a mismatched assumption by bash-completion. If
762 : the text to be completed is empty, but bash-completion turns it into
763 : a quoted string ('') assuming that this code will dequote it before
764 : calling readline, do the dequoting. */
765 0 : else if (iscompgen && iscompleting &&
766 0 : pcomp_curtxt && *pcomp_curtxt == 0 &&
767 0 : text && (*text == '\'' || *text == '"') && text[1] == text[0] && text[2] == 0 &&
768 : rl_filename_dequoting_function)
769 0 : dfn = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character);
770 : /* Another mismatched assumption by bash-completion. If compgen is being
771 : run as part of bash-completion, and the argument to compgen is not
772 : the same as the word originally passed to the programmable completion
773 : code, dequote the argument if it has quote characters. It's an
774 : attempt to detect when bash-completion is quoting its filename
775 : argument before calling compgen. */
776 : /* We could check whether gen_shell_function_matches is in the call
777 : stack by checking whether the gen-shell-function-matches tag is in
778 : the unwind-protect stack, but there's no function to do that yet.
779 : We could simply check whether we're executing in a function by
780 : checking variable_context, and may end up doing that. */
781 0 : else if (iscompgen && iscompleting && rl_filename_dequoting_function &&
782 0 : pcomp_curtxt && text &&
783 0 : STREQ (pcomp_curtxt, text) == 0 &&
784 0 : variable_context &&
785 0 : sh_contains_quotes (text)) /* guess */
786 0 : dfn = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character);
787 : else
788 0 : dfn = savestring (text);
789 : }
790 :
791 0 : return (rl_filename_completion_function (dfn, state));
792 : }
793 :
794 : #define GEN_COMPS(bmap, flag, it, text, glist, tlist) \
795 : do { \
796 : if (bmap & flag) \
797 : { \
798 : tlist = gen_matches_from_itemlist (it, text); \
799 : if (tlist) \
800 : { \
801 : glist = strlist_append (glist, tlist); \
802 : strlist_dispose (tlist); \
803 : } \
804 : } \
805 : } while (0)
806 :
807 : #define GEN_XCOMPS(bmap, flag, text, func, cmatches, glist, tlist) \
808 : do { \
809 : if (bmap & flag) \
810 : { \
811 : cmatches = rl_completion_matches (text, func); \
812 : tlist = completions_to_stringlist (cmatches); \
813 : glist = strlist_append (glist, tlist); \
814 : strvec_dispose (cmatches); \
815 : strlist_dispose (tlist); \
816 : } \
817 : } while (0)
818 :
819 : /* Functions to generate lists of matches from the actions member of CS. */
820 :
821 : static STRINGLIST *
822 0 : gen_action_completions (cs, text)
823 : COMPSPEC *cs;
824 : const char *text;
825 : {
826 0 : STRINGLIST *ret, *tmatches;
827 0 : char **cmatches; /* from rl_completion_matches ... */
828 0 : unsigned long flags;
829 0 : int t;
830 :
831 0 : ret = tmatches = (STRINGLIST *)NULL;
832 0 : flags = cs->actions;
833 :
834 0 : GEN_COMPS (flags, CA_ALIAS, &it_aliases, text, ret, tmatches);
835 0 : GEN_COMPS (flags, CA_ARRAYVAR, &it_arrayvars, text, ret, tmatches);
836 0 : GEN_COMPS (flags, CA_BINDING, &it_bindings, text, ret, tmatches);
837 0 : GEN_COMPS (flags, CA_BUILTIN, &it_builtins, text, ret, tmatches);
838 0 : GEN_COMPS (flags, CA_DISABLED, &it_disabled, text, ret, tmatches);
839 0 : GEN_COMPS (flags, CA_ENABLED, &it_enabled, text, ret, tmatches);
840 0 : GEN_COMPS (flags, CA_EXPORT, &it_exports, text, ret, tmatches);
841 0 : GEN_COMPS (flags, CA_FUNCTION, &it_functions, text, ret, tmatches);
842 0 : GEN_COMPS (flags, CA_HELPTOPIC, &it_helptopics, text, ret, tmatches);
843 0 : GEN_COMPS (flags, CA_HOSTNAME, &it_hostnames, text, ret, tmatches);
844 0 : GEN_COMPS (flags, CA_JOB, &it_jobs, text, ret, tmatches);
845 0 : GEN_COMPS (flags, CA_KEYWORD, &it_keywords, text, ret, tmatches);
846 0 : GEN_COMPS (flags, CA_RUNNING, &it_running, text, ret, tmatches);
847 0 : GEN_COMPS (flags, CA_SETOPT, &it_setopts, text, ret, tmatches);
848 0 : GEN_COMPS (flags, CA_SHOPT, &it_shopts, text, ret, tmatches);
849 0 : GEN_COMPS (flags, CA_SIGNAL, &it_signals, text, ret, tmatches);
850 0 : GEN_COMPS (flags, CA_STOPPED, &it_stopped, text, ret, tmatches);
851 0 : GEN_COMPS (flags, CA_VARIABLE, &it_variables, text, ret, tmatches);
852 :
853 0 : GEN_XCOMPS(flags, CA_COMMAND, text, command_word_completion_function, cmatches, ret, tmatches);
854 0 : GEN_XCOMPS(flags, CA_FILE, text, pcomp_filename_completion_function, cmatches, ret, tmatches);
855 0 : GEN_XCOMPS(flags, CA_USER, text, rl_username_completion_function, cmatches, ret, tmatches);
856 0 : GEN_XCOMPS(flags, CA_GROUP, text, bash_groupname_completion_function, cmatches, ret, tmatches);
857 0 : GEN_XCOMPS(flags, CA_SERVICE, text, bash_servicename_completion_function, cmatches, ret, tmatches);
858 :
859 : /* And lastly, the special case for directories */
860 0 : if (flags & CA_DIRECTORY)
861 : {
862 0 : t = rl_filename_completion_desired;
863 0 : rl_completion_mark_symlink_dirs = 1; /* override user preference */
864 0 : cmatches = bash_directory_completion_matches (text);
865 : /* If we did not want filename completion before this, and there are
866 : no matches, turn off rl_filename_completion_desired so whatever
867 : matches we get are not treated as filenames (it gets turned on by
868 : rl_filename_completion_function unconditionally). */
869 0 : if (t == 0 && cmatches == 0 && rl_filename_completion_desired == 1)
870 0 : rl_filename_completion_desired = 0;
871 0 : tmatches = completions_to_stringlist (cmatches);
872 0 : ret = strlist_append (ret, tmatches);
873 0 : strvec_dispose (cmatches);
874 0 : strlist_dispose (tmatches);
875 : }
876 :
877 0 : return ret;
878 : }
879 :
880 : /* Generate a list of matches for CS->globpat. Unresolved: should this use
881 : TEXT as a match prefix, or just go without? Currently, the code does not
882 : use TEXT, just globs CS->globpat and returns the results. If we do decide
883 : to use TEXT, we should call quote_string_for_globbing before the call to
884 : glob_filename. */
885 : static STRINGLIST *
886 0 : gen_globpat_matches (cs, text)
887 : COMPSPEC *cs;
888 : const char *text;
889 : {
890 0 : STRINGLIST *sl;
891 :
892 0 : sl = strlist_create (0);
893 0 : sl->list = glob_filename (cs->globpat, 0);
894 0 : if (GLOB_FAILED (sl->list))
895 0 : sl->list = (char **)NULL;
896 0 : if (sl->list)
897 0 : sl->list_len = sl->list_size = strvec_len (sl->list);
898 0 : return sl;
899 : }
900 :
901 : /* Perform the shell word expansions on CS->words and return the results.
902 : Again, this ignores TEXT. */
903 : static STRINGLIST *
904 0 : gen_wordlist_matches (cs, text)
905 : COMPSPEC *cs;
906 : const char *text;
907 : {
908 0 : WORD_LIST *l, *l2;
909 0 : STRINGLIST *sl;
910 0 : int nw, tlen;
911 0 : char *ntxt; /* dequoted TEXT to use in comparisons */
912 :
913 0 : if (cs->words == 0 || cs->words[0] == '\0')
914 0 : return ((STRINGLIST *)NULL);
915 :
916 : /* This used to be a simple expand_string(cs->words, 0), but that won't
917 : do -- there's no way to split a simple list into individual words
918 : that way, since the shell semantics say that word splitting is done
919 : only on the results of expansion. split_at_delims also handles embedded
920 : quoted strings and preserves the quotes for the expand_words_shellexp
921 : function call that follows. */
922 : /* XXX - this is where this function spends most of its time */
923 0 : l = split_at_delims (cs->words, strlen (cs->words), (char *)NULL, -1, 0, (int *)NULL, (int *)NULL);
924 0 : if (l == 0)
925 0 : return ((STRINGLIST *)NULL);
926 : /* This will jump back to the top level if the expansion fails... */
927 0 : l2 = expand_words_shellexp (l);
928 0 : dispose_words (l);
929 :
930 0 : nw = list_length (l2);
931 0 : sl = strlist_create (nw + 1);
932 :
933 0 : ntxt = bash_dequote_text (text);
934 0 : tlen = STRLEN (ntxt);
935 :
936 0 : for (nw = 0, l = l2; l; l = l->next)
937 : {
938 0 : if (tlen == 0 || STREQN (l->word->word, ntxt, tlen))
939 0 : sl->list[nw++] = STRDUP (l->word->word);
940 : }
941 0 : sl->list[sl->list_len = nw] = (char *)NULL;
942 :
943 0 : dispose_words (l2);
944 0 : FREE (ntxt);
945 : return sl;
946 : }
947 :
948 : #ifdef ARRAY_VARS
949 :
950 : static SHELL_VAR *
951 0 : bind_comp_words (lwords)
952 : WORD_LIST *lwords;
953 : {
954 0 : SHELL_VAR *v;
955 :
956 0 : v = find_variable ("COMP_WORDS");
957 0 : if (v == 0)
958 0 : v = make_new_array_variable ("COMP_WORDS");
959 0 : if (readonly_p (v))
960 0 : VUNSETATTR (v, att_readonly);
961 0 : if (array_p (v) == 0)
962 0 : v = convert_var_to_array (v);
963 0 : v = assign_array_var_from_word_list (v, lwords, 0);
964 :
965 0 : VUNSETATTR (v, att_invisible);
966 0 : return v;
967 : }
968 : #endif /* ARRAY_VARS */
969 :
970 : static void
971 0 : bind_compfunc_variables (line, ind, lwords, cw, exported)
972 : char *line;
973 : int ind;
974 : WORD_LIST *lwords;
975 : int cw, exported;
976 : {
977 0 : char ibuf[INT_STRLEN_BOUND(int) + 1];
978 0 : char *value;
979 0 : SHELL_VAR *v;
980 0 : size_t llen;
981 0 : int c;
982 :
983 : /* Set the variables that the function expects while it executes. Maybe
984 : these should be in the function environment (temporary_env). */
985 0 : v = bind_variable ("COMP_LINE", line, 0);
986 0 : if (v && exported)
987 0 : VSETATTR(v, att_exported);
988 :
989 : /* Post bash-4.2: COMP_POINT is characters instead of bytes. */
990 0 : c = line[ind];
991 0 : line[ind] = '\0';
992 0 : llen = MB_STRLEN (line);
993 0 : line[ind] = c;
994 0 : value = inttostr (llen, ibuf, sizeof(ibuf));
995 0 : v = bind_int_variable ("COMP_POINT", value);
996 0 : if (v && exported)
997 0 : VSETATTR(v, att_exported);
998 :
999 0 : value = inttostr (rl_completion_type, ibuf, sizeof (ibuf));
1000 0 : v = bind_int_variable ("COMP_TYPE", value);
1001 0 : if (v && exported)
1002 0 : VSETATTR(v, att_exported);
1003 :
1004 0 : value = inttostr (rl_completion_invoking_key, ibuf, sizeof (ibuf));
1005 0 : v = bind_int_variable ("COMP_KEY", value);
1006 0 : if (v && exported)
1007 0 : VSETATTR(v, att_exported);
1008 :
1009 : /* Since array variables can't be exported, we don't bother making the
1010 : array of words. */
1011 0 : if (exported == 0)
1012 : {
1013 : #ifdef ARRAY_VARS
1014 0 : v = bind_comp_words (lwords);
1015 0 : value = inttostr (cw, ibuf, sizeof(ibuf));
1016 0 : bind_int_variable ("COMP_CWORD", value);
1017 : #endif
1018 : }
1019 : else
1020 0 : array_needs_making = 1;
1021 0 : }
1022 :
1023 : static void
1024 0 : unbind_compfunc_variables (exported)
1025 : int exported;
1026 : {
1027 0 : unbind_variable_noref ("COMP_LINE");
1028 0 : unbind_variable_noref ("COMP_POINT");
1029 0 : unbind_variable_noref ("COMP_TYPE");
1030 0 : unbind_variable_noref ("COMP_KEY");
1031 : #ifdef ARRAY_VARS
1032 0 : unbind_variable_noref ("COMP_WORDS");
1033 0 : unbind_variable_noref ("COMP_CWORD");
1034 : #endif
1035 0 : if (exported)
1036 0 : array_needs_making = 1;
1037 0 : }
1038 :
1039 : /* Build the list of words to pass to a function or external command
1040 : as arguments. When the function or command is invoked,
1041 :
1042 : $0 == function or command being invoked
1043 : $1 == command name
1044 : $2 == word to be completed (possibly null)
1045 : $3 == previous word
1046 :
1047 : Functions can access all of the words in the current command line
1048 : with the COMP_WORDS array. External commands cannot; they have to
1049 : make do with the COMP_LINE and COMP_POINT variables. */
1050 :
1051 : static WORD_LIST *
1052 0 : build_arg_list (cmd, cname, text, lwords, ind)
1053 : char *cmd;
1054 : const char *cname;
1055 : const char *text;
1056 : WORD_LIST *lwords;
1057 : int ind;
1058 : {
1059 0 : WORD_LIST *ret, *cl, *l;
1060 0 : WORD_DESC *w;
1061 0 : int i;
1062 :
1063 0 : ret = (WORD_LIST *)NULL;
1064 0 : w = make_word (cmd);
1065 0 : ret = make_word_list (w, (WORD_LIST *)NULL); /* $0 */
1066 :
1067 0 : w = make_word (cname); /* $1 */
1068 0 : cl = ret->next = make_word_list (w, (WORD_LIST *)NULL);
1069 :
1070 0 : w = make_word (text);
1071 0 : cl->next = make_word_list (w, (WORD_LIST *)NULL); /* $2 */
1072 0 : cl = cl->next;
1073 :
1074 : /* Search lwords for current word */
1075 0 : for (l = lwords, i = 1; l && i < ind-1; l = l->next, i++)
1076 0 : ;
1077 0 : w = (l && l->word) ? copy_word (l->word) : make_word ("");
1078 0 : cl->next = make_word_list (w, (WORD_LIST *)NULL);
1079 :
1080 0 : return ret;
1081 : }
1082 :
1083 : /* Build a command string with
1084 : $0 == cs->funcname (function to execute for completion list)
1085 : $1 == command name (command being completed)
1086 : $2 = word to be completed (possibly null)
1087 : $3 = previous word
1088 : and run in the current shell. The function should put its completion
1089 : list into the array variable COMPREPLY. We build a STRINGLIST
1090 : from the results and return it.
1091 :
1092 : Since the shell function should return its list of matches in an array
1093 : variable, this does nothing if arrays are not compiled into the shell. */
1094 :
1095 : static STRINGLIST *
1096 0 : gen_shell_function_matches (cs, cmd, text, line, ind, lwords, nw, cw, foundp)
1097 : COMPSPEC *cs;
1098 : const char *cmd;
1099 : const char *text;
1100 : char *line;
1101 : int ind;
1102 : WORD_LIST *lwords;
1103 : int nw, cw;
1104 : int *foundp;
1105 : {
1106 0 : char *funcname;
1107 0 : STRINGLIST *sl;
1108 0 : SHELL_VAR *f, *v;
1109 0 : WORD_LIST *cmdlist;
1110 0 : int fval, found;
1111 0 : sh_parser_state_t ps;
1112 0 : sh_parser_state_t * restrict pps;
1113 : #if defined (ARRAY_VARS)
1114 0 : ARRAY *a;
1115 : #endif
1116 :
1117 0 : found = 0;
1118 0 : if (foundp)
1119 0 : *foundp = found;
1120 :
1121 0 : funcname = cs->funcname;
1122 0 : f = find_function (funcname);
1123 0 : if (f == 0)
1124 : {
1125 0 : internal_error (_("completion: function `%s' not found"), funcname);
1126 0 : rl_ding ();
1127 0 : rl_on_new_line ();
1128 0 : return ((STRINGLIST *)NULL);
1129 : }
1130 :
1131 : #if !defined (ARRAY_VARS)
1132 : return ((STRINGLIST *)NULL);
1133 : #else
1134 :
1135 : /* We pass cw - 1 because command_line_to_word_list returns indices that are
1136 : 1-based, while bash arrays are 0-based. */
1137 0 : bind_compfunc_variables (line, ind, lwords, cw - 1, 0);
1138 :
1139 0 : cmdlist = build_arg_list (funcname, cmd, text, lwords, cw);
1140 :
1141 0 : pps = &ps;
1142 0 : save_parser_state (pps);
1143 0 : begin_unwind_frame ("gen-shell-function-matches");
1144 0 : add_unwind_protect (restore_parser_state, (char *)pps);
1145 0 : add_unwind_protect (dispose_words, (char *)cmdlist);
1146 0 : add_unwind_protect (unbind_compfunc_variables, (char *)0);
1147 :
1148 0 : fval = execute_shell_function (f, cmdlist);
1149 :
1150 0 : discard_unwind_frame ("gen-shell-function-matches");
1151 0 : restore_parser_state (pps);
1152 :
1153 0 : found = fval != EX_NOTFOUND;
1154 0 : if (fval == EX_RETRYFAIL)
1155 0 : found |= PCOMP_RETRYFAIL;
1156 0 : if (foundp)
1157 0 : *foundp = found;
1158 :
1159 : /* Now clean up and destroy everything. */
1160 0 : dispose_words (cmdlist);
1161 0 : unbind_compfunc_variables (0);
1162 :
1163 : /* The list of completions is returned in the array variable COMPREPLY. */
1164 0 : v = find_variable ("COMPREPLY");
1165 0 : if (v == 0)
1166 0 : return ((STRINGLIST *)NULL);
1167 0 : if (array_p (v) == 0)
1168 0 : v = convert_var_to_array (v);
1169 :
1170 0 : VUNSETATTR (v, att_invisible);
1171 :
1172 0 : a = array_cell (v);
1173 0 : if (found == 0 || (found & PCOMP_RETRYFAIL) || a == 0 || array_empty (a))
1174 : sl = (STRINGLIST *)NULL;
1175 : else
1176 : {
1177 : /* XXX - should we filter the list of completions so only those matching
1178 : TEXT are returned? Right now, we do not. */
1179 0 : sl = strlist_create (0);
1180 0 : sl->list = array_to_argv (a);
1181 0 : sl->list_len = sl->list_size = array_num_elements (a);
1182 : }
1183 :
1184 : /* XXX - should we unbind COMPREPLY here? */
1185 0 : unbind_variable_noref ("COMPREPLY");
1186 :
1187 0 : return (sl);
1188 : #endif
1189 : }
1190 :
1191 : /* Build a command string with
1192 : $0 == cs->command (command to execute for completion list)
1193 : $1 == command name (command being completed)
1194 : $2 == word to be completed (possibly null)
1195 : $3 == previous word
1196 : and run it with command substitution. Parse the results, one word
1197 : per line, with backslashes allowed to escape newlines. Build a
1198 : STRINGLIST from the results and return it. */
1199 :
1200 : static STRINGLIST *
1201 0 : gen_command_matches (cs, cmd, text, line, ind, lwords, nw, cw)
1202 : COMPSPEC *cs;
1203 : const char *cmd;
1204 : const char *text;
1205 : char *line;
1206 : int ind;
1207 : WORD_LIST *lwords;
1208 : int nw, cw;
1209 : {
1210 0 : char *csbuf, *cscmd, *t;
1211 0 : int cmdlen, cmdsize, n, ws, we;
1212 0 : WORD_LIST *cmdlist, *cl;
1213 0 : WORD_DESC *tw;
1214 0 : STRINGLIST *sl;
1215 :
1216 0 : bind_compfunc_variables (line, ind, lwords, cw, 1);
1217 0 : cmdlist = build_arg_list (cs->command, cmd, text, lwords, cw);
1218 :
1219 : /* Estimate the size needed for the buffer. */
1220 0 : n = strlen (cs->command);
1221 0 : cmdsize = n + 1;
1222 0 : for (cl = cmdlist->next; cl; cl = cl->next)
1223 0 : cmdsize += STRLEN (cl->word->word) + 3;
1224 0 : cmdsize += 2;
1225 :
1226 : /* allocate the string for the command and fill it in. */
1227 0 : cscmd = (char *)xmalloc (cmdsize + 1);
1228 :
1229 0 : strcpy (cscmd, cs->command); /* $0 */
1230 0 : cmdlen = n;
1231 0 : cscmd[cmdlen++] = ' ';
1232 0 : for (cl = cmdlist->next; cl; cl = cl->next) /* $1, $2, $3, ... */
1233 : {
1234 0 : t = sh_single_quote (cl->word->word ? cl->word->word : "");
1235 0 : n = strlen (t);
1236 0 : RESIZE_MALLOCED_BUFFER (cscmd, cmdlen, n + 2, cmdsize, 64);
1237 0 : strcpy (cscmd + cmdlen, t);
1238 0 : cmdlen += n;
1239 0 : if (cl->next)
1240 0 : cscmd[cmdlen++] = ' ';
1241 0 : free (t);
1242 : }
1243 0 : cscmd[cmdlen] = '\0';
1244 :
1245 0 : tw = command_substitute (cscmd, 0);
1246 0 : csbuf = tw ? tw->word : (char *)NULL;
1247 0 : if (tw)
1248 0 : dispose_word_desc (tw);
1249 :
1250 : /* Now clean up and destroy everything. */
1251 0 : dispose_words (cmdlist);
1252 0 : free (cscmd);
1253 0 : unbind_compfunc_variables (1);
1254 :
1255 0 : if (csbuf == 0 || *csbuf == '\0')
1256 : {
1257 0 : FREE (csbuf);
1258 0 : return ((STRINGLIST *)NULL);
1259 : }
1260 :
1261 : /* Now break CSBUF up at newlines, with backslash allowed to escape a
1262 : newline, and put the individual words into a STRINGLIST. */
1263 0 : sl = strlist_create (16);
1264 0 : for (ws = 0; csbuf[ws]; )
1265 : {
1266 : we = ws;
1267 0 : while (csbuf[we] && csbuf[we] != '\n')
1268 : {
1269 0 : if (csbuf[we] == '\\' && csbuf[we+1] == '\n')
1270 0 : we++;
1271 0 : we++;
1272 : }
1273 0 : t = substring (csbuf, ws, we);
1274 0 : if (sl->list_len >= sl->list_size - 1)
1275 0 : strlist_resize (sl, sl->list_size + 16);
1276 0 : sl->list[sl->list_len++] = t;
1277 0 : while (csbuf[we] == '\n') we++;
1278 : ws = we;
1279 : }
1280 0 : sl->list[sl->list_len] = (char *)NULL;
1281 :
1282 0 : free (csbuf);
1283 0 : return (sl);
1284 : }
1285 :
1286 : static WORD_LIST *
1287 : command_line_to_word_list (line, llen, sentinel, nwp, cwp)
1288 : char *line;
1289 : int llen, sentinel, *nwp, *cwp;
1290 : {
1291 0 : WORD_LIST *ret;
1292 0 : char *delims;
1293 :
1294 : #if 0
1295 : delims = "()<>;&| \t\n"; /* shell metacharacters break words */
1296 : #else
1297 0 : delims = rl_completer_word_break_characters;
1298 : #endif
1299 0 : ret = split_at_delims (line, llen, delims, sentinel, SD_NOQUOTEDELIM|SD_COMPLETE, nwp, cwp);
1300 0 : return (ret);
1301 : }
1302 :
1303 : /* Evaluate COMPSPEC *cs and return all matches for WORD. */
1304 :
1305 : STRINGLIST *
1306 0 : gen_compspec_completions (cs, cmd, word, start, end, foundp)
1307 : COMPSPEC *cs;
1308 : const char *cmd;
1309 : const char *word;
1310 : int start, end;
1311 : int *foundp;
1312 : {
1313 0 : STRINGLIST *ret, *tmatches;
1314 0 : char *line;
1315 0 : int llen, nw, cw, found, foundf;
1316 0 : WORD_LIST *lwords;
1317 0 : WORD_DESC *lw;
1318 0 : COMPSPEC *tcs;
1319 :
1320 0 : found = 1;
1321 :
1322 : #ifdef DEBUG
1323 : debug_printf ("gen_compspec_completions (%s, %s, %d, %d)", cmd, word, start, end);
1324 : debug_printf ("gen_compspec_completions: %s -> %p", cmd, cs);
1325 : #endif
1326 0 : ret = gen_action_completions (cs, word);
1327 : #ifdef DEBUG
1328 : if (ret && progcomp_debug)
1329 : {
1330 : debug_printf ("gen_action_completions (%p, %s) -->", cs, word);
1331 : strlist_print (ret, "\t");
1332 : rl_on_new_line ();
1333 : }
1334 : #endif
1335 :
1336 : /* Now we start generating completions based on the other members of CS. */
1337 0 : if (cs->globpat)
1338 : {
1339 0 : tmatches = gen_globpat_matches (cs, word);
1340 0 : if (tmatches)
1341 : {
1342 : #ifdef DEBUG
1343 : if (progcomp_debug)
1344 : {
1345 : debug_printf ("gen_globpat_matches (%p, %s) -->", cs, word);
1346 : strlist_print (tmatches, "\t");
1347 : rl_on_new_line ();
1348 : }
1349 : #endif
1350 0 : ret = strlist_append (ret, tmatches);
1351 0 : strlist_dispose (tmatches);
1352 0 : rl_filename_completion_desired = 1;
1353 : }
1354 : }
1355 :
1356 0 : if (cs->words)
1357 : {
1358 0 : tmatches = gen_wordlist_matches (cs, word);
1359 0 : if (tmatches)
1360 : {
1361 : #ifdef DEBUG
1362 : if (progcomp_debug)
1363 : {
1364 : debug_printf ("gen_wordlist_matches (%p, %s) -->", cs, word);
1365 : strlist_print (tmatches, "\t");
1366 : rl_on_new_line ();
1367 : }
1368 : #endif
1369 0 : ret = strlist_append (ret, tmatches);
1370 0 : strlist_dispose (tmatches);
1371 : }
1372 : }
1373 :
1374 0 : lwords = (WORD_LIST *)NULL;
1375 0 : line = (char *)NULL;
1376 0 : if (cs->command || cs->funcname)
1377 : {
1378 : /* If we have a command or function to execute, we need to first break
1379 : the command line into individual words, find the number of words,
1380 : and find the word in the list containing the word to be completed. */
1381 0 : line = substring (rl_line_buffer, start, end);
1382 0 : llen = end - start;
1383 :
1384 : #ifdef DEBUG
1385 : debug_printf ("command_line_to_word_list (%s, %d, %d, %p, %p)",
1386 : line, llen, rl_point - start, &nw, &cw);
1387 : #endif
1388 0 : lwords = command_line_to_word_list (line, llen, rl_point - start, &nw, &cw);
1389 : /* If we skipped a NULL word at the beginning of the line, add it back */
1390 0 : if (lwords && lwords->word && cmd[0] == 0 && lwords->word->word[0] != 0)
1391 : {
1392 0 : lw = make_bare_word (cmd);
1393 0 : lwords = make_word_list (lw, lwords);
1394 0 : nw++;
1395 0 : cw++;
1396 : }
1397 : #ifdef DEBUG
1398 : if (lwords == 0 && llen > 0)
1399 : debug_printf ("ERROR: command_line_to_word_list returns NULL");
1400 : else if (progcomp_debug)
1401 : {
1402 : debug_printf ("command_line_to_word_list -->");
1403 : printf ("\t");
1404 : print_word_list (lwords, "!");
1405 : printf ("\n");
1406 : fflush(stdout);
1407 : rl_on_new_line ();
1408 : }
1409 : #endif
1410 : }
1411 :
1412 0 : if (cs->funcname)
1413 : {
1414 0 : foundf = 0;
1415 0 : tmatches = gen_shell_function_matches (cs, cmd, word, line, rl_point - start, lwords, nw, cw, &foundf);
1416 0 : if (foundf != 0)
1417 0 : found = foundf;
1418 0 : if (tmatches)
1419 : {
1420 : #ifdef DEBUG
1421 : if (progcomp_debug)
1422 : {
1423 : debug_printf ("gen_shell_function_matches (%p, %s, %s, %p, %d, %d) -->", cs, cmd, word, lwords, nw, cw);
1424 : strlist_print (tmatches, "\t");
1425 : rl_on_new_line ();
1426 : }
1427 : #endif
1428 0 : ret = strlist_append (ret, tmatches);
1429 0 : strlist_dispose (tmatches);
1430 : }
1431 : }
1432 :
1433 0 : if (cs->command)
1434 : {
1435 0 : tmatches = gen_command_matches (cs, cmd, word, line, rl_point - start, lwords, nw, cw);
1436 0 : if (tmatches)
1437 : {
1438 : #ifdef DEBUG
1439 : if (progcomp_debug)
1440 : {
1441 : debug_printf ("gen_command_matches (%p, %s, %s, %p, %d, %d) -->", cs, cmd, word, lwords, nw, cw);
1442 : strlist_print (tmatches, "\t");
1443 : rl_on_new_line ();
1444 : }
1445 : #endif
1446 0 : ret = strlist_append (ret, tmatches);
1447 0 : strlist_dispose (tmatches);
1448 : }
1449 : }
1450 :
1451 0 : if (cs->command || cs->funcname)
1452 : {
1453 0 : if (lwords)
1454 0 : dispose_words (lwords);
1455 0 : FREE (line);
1456 : }
1457 :
1458 0 : if (foundp)
1459 0 : *foundp = found;
1460 :
1461 0 : if (found == 0 || (found & PCOMP_RETRYFAIL))
1462 : {
1463 0 : strlist_dispose (ret);
1464 0 : return NULL;
1465 : }
1466 :
1467 0 : if (cs->filterpat)
1468 : {
1469 0 : tmatches = filter_stringlist (ret, cs->filterpat, word);
1470 : #ifdef DEBUG
1471 : if (progcomp_debug)
1472 : {
1473 : debug_printf ("filter_stringlist (%p, %s, %s) -->", ret, cs->filterpat, word);
1474 : strlist_print (tmatches, "\t");
1475 : rl_on_new_line ();
1476 : }
1477 : #endif
1478 0 : if (ret && ret != tmatches)
1479 : {
1480 0 : FREE (ret->list);
1481 0 : free (ret);
1482 : }
1483 : ret = tmatches;
1484 : }
1485 :
1486 0 : if (cs->prefix || cs->suffix)
1487 0 : ret = strlist_prefix_suffix (ret, cs->prefix, cs->suffix);
1488 :
1489 : /* If no matches have been generated and the user has specified that
1490 : directory completion should be done as a default, call
1491 : gen_action_completions again to generate a list of matching directory
1492 : names. */
1493 0 : if ((ret == 0 || ret->list_len == 0) && (cs->options & COPT_DIRNAMES))
1494 : {
1495 0 : tcs = compspec_create ();
1496 0 : tcs->actions = CA_DIRECTORY;
1497 0 : FREE (ret);
1498 0 : ret = gen_action_completions (tcs, word);
1499 0 : compspec_dispose (tcs);
1500 : }
1501 0 : else if (cs->options & COPT_PLUSDIRS)
1502 : {
1503 0 : tcs = compspec_create ();
1504 0 : tcs->actions = CA_DIRECTORY;
1505 0 : tmatches = gen_action_completions (tcs, word);
1506 0 : ret = strlist_append (ret, tmatches);
1507 0 : strlist_dispose (tmatches);
1508 0 : compspec_dispose (tcs);
1509 : }
1510 :
1511 : return (ret);
1512 : }
1513 :
1514 : void
1515 0 : pcomp_set_readline_variables (flags, nval)
1516 : int flags, nval;
1517 : {
1518 : /* If the user specified that the compspec returns filenames, make
1519 : sure that readline knows it. */
1520 0 : if (flags & COPT_FILENAMES)
1521 0 : rl_filename_completion_desired = nval;
1522 : /* If the user doesn't want a space appended, tell readline. */
1523 0 : if (flags & COPT_NOSPACE)
1524 0 : rl_completion_suppress_append = nval;
1525 : /* The value here is inverted, since the default is on and the `noquote'
1526 : option is supposed to turn it off */
1527 0 : if (flags & COPT_NOQUOTE)
1528 0 : rl_filename_quoting_desired = 1 - nval;
1529 0 : if (flags & COPT_NOSORT)
1530 0 : rl_sort_completion_matches = 1 - nval;
1531 0 : }
1532 :
1533 : /* Set or unset FLAGS in the options word of the current compspec.
1534 : SET_OR_UNSET is 1 for setting, 0 for unsetting. */
1535 : void
1536 0 : pcomp_set_compspec_options (cs, flags, set_or_unset)
1537 : COMPSPEC *cs;
1538 : int flags, set_or_unset;
1539 : {
1540 0 : if (cs == 0 && ((cs = pcomp_curcs) == 0))
1541 : return;
1542 0 : if (set_or_unset)
1543 0 : cs->options |= flags;
1544 : else
1545 0 : cs->options &= ~flags;
1546 : }
1547 :
1548 : static STRINGLIST *
1549 0 : gen_progcomp_completions (ocmd, cmd, word, start, end, foundp, retryp, lastcs)
1550 : const char *ocmd;
1551 : const char *cmd;
1552 : const char *word;
1553 : int start, end;
1554 : int *foundp, *retryp;
1555 : COMPSPEC **lastcs;
1556 : {
1557 0 : COMPSPEC *cs, *oldcs;
1558 0 : const char *oldcmd, *oldtxt;
1559 0 : STRINGLIST *ret;
1560 :
1561 0 : cs = progcomp_search (ocmd);
1562 :
1563 0 : if (cs == 0 || cs == *lastcs)
1564 : {
1565 : #if 0
1566 : if (foundp)
1567 : *foundp = 0;
1568 : #endif
1569 : return (NULL);
1570 : }
1571 :
1572 0 : if (*lastcs)
1573 0 : compspec_dispose (*lastcs);
1574 0 : cs->refcount++; /* XXX */
1575 0 : *lastcs = cs;
1576 :
1577 0 : cs = compspec_copy (cs);
1578 :
1579 0 : oldcs = pcomp_curcs;
1580 0 : oldcmd = pcomp_curcmd;
1581 0 : oldtxt = pcomp_curtxt;
1582 :
1583 0 : pcomp_curcs = cs;
1584 0 : pcomp_curcmd = cmd;
1585 0 : pcomp_curtxt = word;
1586 :
1587 0 : ret = gen_compspec_completions (cs, cmd, word, start, end, foundp);
1588 :
1589 0 : pcomp_curcs = oldcs;
1590 0 : pcomp_curcmd = oldcmd;
1591 0 : pcomp_curtxt = oldtxt;
1592 :
1593 : /* We need to conditionally handle setting *retryp here */
1594 0 : if (retryp)
1595 0 : *retryp = foundp && (*foundp & PCOMP_RETRYFAIL);
1596 :
1597 0 : if (foundp)
1598 : {
1599 0 : *foundp &= ~PCOMP_RETRYFAIL;
1600 0 : *foundp |= cs->options;
1601 : }
1602 :
1603 0 : compspec_dispose (cs);
1604 0 : return ret;
1605 : }
1606 :
1607 : /* The driver function for the programmable completion code. Returns a list
1608 : of matches for WORD, which is an argument to command CMD. START and END
1609 : bound the command currently being completed in rl_line_buffer. */
1610 : char **
1611 0 : programmable_completions (cmd, word, start, end, foundp)
1612 : const char *cmd;
1613 : const char *word;
1614 : int start, end, *foundp;
1615 : {
1616 0 : COMPSPEC *lastcs;
1617 0 : STRINGLIST *ret;
1618 0 : char **rmatches, *t;
1619 0 : int found, retry, count;
1620 :
1621 0 : lastcs = 0;
1622 0 : found = count = 0;
1623 :
1624 0 : do
1625 : {
1626 0 : retry = 0;
1627 :
1628 : /* We look at the basename of CMD if the full command does not have
1629 : an associated COMPSPEC. */
1630 0 : ret = gen_progcomp_completions (cmd, cmd, word, start, end, &found, &retry, &lastcs);
1631 0 : if (found == 0)
1632 : {
1633 0 : t = strrchr (cmd, '/');
1634 0 : if (t && *(++t))
1635 0 : ret = gen_progcomp_completions (t, cmd, word, start, end, &found, &retry, &lastcs);
1636 : }
1637 :
1638 0 : if (found == 0)
1639 0 : ret = gen_progcomp_completions (DEFAULTCMD, cmd, word, start, end, &found, &retry, &lastcs);
1640 :
1641 0 : count++;
1642 :
1643 0 : if (count > 32)
1644 : {
1645 0 : internal_warning (_("programmable_completion: %s: possible retry loop"), cmd);
1646 0 : break;
1647 : }
1648 : }
1649 0 : while (retry);
1650 :
1651 0 : if (ret)
1652 : {
1653 0 : rmatches = ret->list;
1654 0 : free (ret);
1655 : }
1656 : else
1657 : rmatches = (char **)NULL;
1658 :
1659 0 : if (foundp)
1660 0 : *foundp = found;
1661 :
1662 0 : if (lastcs) /* XXX - should be while? */
1663 0 : compspec_dispose (lastcs);
1664 :
1665 0 : return (rmatches);
1666 : }
1667 :
1668 : #endif /* PROGRAMMABLE_COMPLETION */
|