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