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