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