]> git.ipfire.org Git - thirdparty/bash.git/blame - alias.c
Bash-5.0 patch 4: the wait builtin without arguments only waits for known children...
[thirdparty/bash.git] / alias.c
CommitLineData
726f6388
JA
1/* alias.c -- Not a full alias, but just the kind that we use in the
2 shell. Csh style alias is somewhere else (`over there, in a box'). */
3
a0c0a00f 4/* Copyright (C) 1987-2015 Free Software Foundation, Inc.
726f6388
JA
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
3185942a
JA
8 Bash is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
726f6388 12
3185942a
JA
13 Bash is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
726f6388
JA
17
18 You should have received a copy of the GNU General Public License
3185942a
JA
19 along with Bash. If not, see <http://www.gnu.org/licenses/>.
20*/
726f6388 21
ccc6cda3
JA
22#include "config.h"
23
24#if defined (ALIAS)
25
26#if defined (HAVE_UNISTD_H)
cce855bc
JA
27# ifdef _MINIX
28# include <sys/types.h>
29# endif
ccc6cda3
JA
30# include <unistd.h>
31#endif
32
726f6388 33#include <stdio.h>
f73dda09 34#include "chartypes.h"
726f6388 35#include "bashansi.h"
726f6388
JA
36#include "command.h"
37#include "general.h"
ccc6cda3 38#include "externs.h"
726f6388
JA
39#include "alias.h"
40
bb70624e
JA
41#if defined (PROGRAMMABLE_COMPLETION)
42# include "pcomplete.h"
43#endif
44
a0c0a00f
CR
45#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
46# include <mbstr.h> /* mbschr */
47#endif
48
49#define ALIAS_HASH_BUCKETS 64 /* must be power of two */
7117c2d2 50
f73dda09
JA
51typedef int sh_alias_map_func_t __P((alias_t *));
52
53static void free_alias_data __P((PTR_T));
54static alias_t **map_over_aliases __P((sh_alias_map_func_t *));
55static void sort_aliases __P((alias_t **));
56static int qsort_alias_compare __P((alias_t **, alias_t **));
57
58#if defined (READLINE)
59static int skipquotes __P((char *, int));
60static int skipws __P((char *, int));
61static int rd_token __P((char *, int));
62#endif
726f6388
JA
63
64/* Non-zero means expand all words on the line. Otherwise, expand
65 after first expansion if the expansion ends in a space. */
66int alias_expand_all = 0;
67
68/* The list of aliases that we have. */
69HASH_TABLE *aliases = (HASH_TABLE *)NULL;
70
71void
72initialize_aliases ()
73{
3185942a 74 if (aliases == 0)
7117c2d2 75 aliases = hash_create (ALIAS_HASH_BUCKETS);
726f6388
JA
76}
77
78/* Scan the list of aliases looking for one with NAME. Return NULL
ccc6cda3
JA
79 if the alias doesn't exist, else a pointer to the alias_t. */
80alias_t *
726f6388
JA
81find_alias (name)
82 char *name;
83{
84 BUCKET_CONTENTS *al;
85
ccc6cda3
JA
86 if (aliases == 0)
87 return ((alias_t *)NULL);
726f6388 88
7117c2d2 89 al = hash_search (name, aliases, 0);
ccc6cda3 90 return (al ? (alias_t *)al->data : (alias_t *)NULL);
726f6388
JA
91}
92
93/* Return the value of the alias for NAME, or NULL if there is none. */
94char *
95get_alias_value (name)
96 char *name;
97{
ccc6cda3
JA
98 alias_t *alias;
99
100 if (aliases == 0)
726f6388 101 return ((char *)NULL);
ccc6cda3
JA
102
103 alias = find_alias (name);
104 return (alias ? alias->value : (char *)NULL);
726f6388
JA
105}
106
107/* Make a new alias from NAME and VALUE. If NAME can be found,
108 then replace its value. */
109void
110add_alias (name, value)
111 char *name, *value;
112{
ccc6cda3
JA
113 BUCKET_CONTENTS *elt;
114 alias_t *temp;
115 int n;
726f6388 116
ac50fbac 117 if (aliases == 0)
ccc6cda3
JA
118 {
119 initialize_aliases ();
120 temp = (alias_t *)NULL;
121 }
726f6388
JA
122 else
123 temp = find_alias (name);
124
125 if (temp)
126 {
127 free (temp->value);
128 temp->value = savestring (value);
7117c2d2 129 temp->flags &= ~AL_EXPANDNEXT;
ccc6cda3
JA
130 n = value[strlen (value) - 1];
131 if (n == ' ' || n == '\t')
132 temp->flags |= AL_EXPANDNEXT;
726f6388
JA
133 }
134 else
135 {
ccc6cda3 136 temp = (alias_t *)xmalloc (sizeof (alias_t));
726f6388
JA
137 temp->name = savestring (name);
138 temp->value = savestring (value);
ccc6cda3
JA
139 temp->flags = 0;
140
141 n = value[strlen (value) - 1];
142 if (n == ' ' || n == '\t')
143 temp->flags |= AL_EXPANDNEXT;
726f6388 144
7117c2d2
JA
145 elt = hash_insert (savestring (name), aliases, HASH_NOSRCH);
146 elt->data = temp;
bb70624e
JA
147#if defined (PROGRAMMABLE_COMPLETION)
148 set_itemlist_dirty (&it_aliases);
149#endif
726f6388
JA
150 }
151}
152
ccc6cda3
JA
153/* Delete a single alias structure. */
154static void
155free_alias_data (data)
f73dda09 156 PTR_T data;
ccc6cda3
JA
157{
158 register alias_t *a;
159
160 a = (alias_t *)data;
d233b485
CR
161
162 if (a->flags & AL_BEINGEXPANDED)
163 clear_string_list_expander (a); /* call back to the parser */
164
ccc6cda3
JA
165 free (a->value);
166 free (a->name);
167 free (data);
168}
169
726f6388
JA
170/* Remove the alias with name NAME from the alias table. Returns
171 the number of aliases left in the table, or -1 if the alias didn't
172 exist. */
173int
174remove_alias (name)
175 char *name;
176{
177 BUCKET_CONTENTS *elt;
178
ccc6cda3 179 if (aliases == 0)
726f6388
JA
180 return (-1);
181
7117c2d2 182 elt = hash_remove (name, aliases, 0);
726f6388
JA
183 if (elt)
184 {
ccc6cda3 185 free_alias_data (elt->data);
726f6388 186 free (elt->key); /* alias name */
d166f048 187 free (elt); /* XXX */
bb70624e
JA
188#if defined (PROGRAMMABLE_COMPLETION)
189 set_itemlist_dirty (&it_aliases);
190#endif
726f6388
JA
191 return (aliases->nentries);
192 }
193 return (-1);
194}
195
726f6388
JA
196/* Delete all aliases. */
197void
198delete_all_aliases ()
199{
ccc6cda3 200 if (aliases == 0)
726f6388
JA
201 return;
202
7117c2d2
JA
203 hash_flush (aliases, free_alias_data);
204 hash_dispose (aliases);
726f6388 205 aliases = (HASH_TABLE *)NULL;
bb70624e
JA
206#if defined (PROGRAMMABLE_COMPLETION)
207 set_itemlist_dirty (&it_aliases);
208#endif
726f6388
JA
209}
210
211/* Return an array of aliases that satisfy the conditions tested by FUNCTION.
212 If FUNCTION is NULL, return all aliases. */
ccc6cda3 213static alias_t **
726f6388 214map_over_aliases (function)
f73dda09 215 sh_alias_map_func_t *function;
726f6388
JA
216{
217 register int i;
218 register BUCKET_CONTENTS *tlist;
ccc6cda3 219 alias_t *alias, **list;
7117c2d2 220 int list_index;
726f6388 221
7117c2d2
JA
222 i = HASH_ENTRIES (aliases);
223 if (i == 0)
224 return ((alias_t **)NULL);
726f6388 225
7117c2d2
JA
226 list = (alias_t **)xmalloc ((i + 1) * sizeof (alias_t *));
227 for (i = list_index = 0; i < aliases->nbuckets; i++)
228 {
229 for (tlist = hash_items (i, aliases); tlist; tlist = tlist->next)
726f6388 230 {
ccc6cda3 231 alias = (alias_t *)tlist->data;
726f6388
JA
232
233 if (!function || (*function) (alias))
234 {
726f6388 235 list[list_index++] = alias;
ccc6cda3 236 list[list_index] = (alias_t *)NULL;
726f6388 237 }
726f6388
JA
238 }
239 }
240 return (list);
241}
242
243static void
244sort_aliases (array)
ccc6cda3 245 alias_t **array;
726f6388 246{
7117c2d2 247 qsort (array, strvec_len ((char **)array), sizeof (alias_t *), (QSFUNC *)qsort_alias_compare);
726f6388
JA
248}
249
250static int
251qsort_alias_compare (as1, as2)
ccc6cda3 252 alias_t **as1, **as2;
726f6388
JA
253{
254 int result;
ccc6cda3 255
726f6388
JA
256 if ((result = (*as1)->name[0] - (*as2)->name[0]) == 0)
257 result = strcmp ((*as1)->name, (*as2)->name);
258
259 return (result);
260}
ccc6cda3
JA
261
262/* Return a sorted list of all defined aliases */
263alias_t **
726f6388
JA
264all_aliases ()
265{
ccc6cda3 266 alias_t **list;
726f6388 267
7117c2d2 268 if (aliases == 0 || HASH_ENTRIES (aliases) == 0)
ccc6cda3 269 return ((alias_t **)NULL);
726f6388 270
f73dda09 271 list = map_over_aliases ((sh_alias_map_func_t *)NULL);
726f6388
JA
272 if (list)
273 sort_aliases (list);
274 return (list);
275}
276
277char *
278alias_expand_word (s)
279 char *s;
280{
ccc6cda3 281 alias_t *r;
726f6388 282
ccc6cda3
JA
283 r = find_alias (s);
284 return (r ? savestring (r->value) : (char *)NULL);
726f6388
JA
285}
286
d166f048
JA
287/* Readline support functions -- expand all aliases in a line. */
288
289#if defined (READLINE)
290
726f6388
JA
291/* Return non-zero if CHARACTER is a member of the class of characters
292 that are self-delimiting in the shell (this really means that these
293 characters delimit tokens). */
294#define self_delimiting(character) (member ((character), " \t\n\r;|&()"))
295
296/* Return non-zero if CHARACTER is a member of the class of characters
297 that delimit commands in the shell. */
298#define command_separator(character) (member ((character), "\r\n;|&("))
299
300/* If this is 1, we are checking the next token read for alias expansion
301 because it is the first word in a command. */
302static int command_word;
303
304/* This is for skipping quoted strings in alias expansions. */
305#define quote_char(c) (((c) == '\'') || ((c) == '"'))
306
307/* Consume a quoted string from STRING, starting at string[START] (so
308 string[START] is the opening quote character), and return the index
309 of the closing quote character matching the opening quote character.
310 This handles single matching pairs of unquoted quotes; it could afford
311 to be a little smarter... This skips words between balanced pairs of
312 quotes, words where the first character is quoted with a `\', and other
313 backslash-escaped characters. */
314
315static int
316skipquotes (string, start)
317 char *string;
318 int start;
319{
320 register int i;
321 int delimiter = string[start];
322
323 /* i starts at START + 1 because string[START] is the opening quote
324 character. */
325 for (i = start + 1 ; string[i] ; i++)
326 {
327 if (string[i] == '\\')
328 {
329 i++; /* skip backslash-quoted quote characters, too */
495aee44
CR
330 if (string[i] == 0)
331 break;
726f6388
JA
332 continue;
333 }
334
335 if (string[i] == delimiter)
336 return i;
337 }
338 return (i);
339}
340
341/* Skip the white space and any quoted characters in STRING, starting at
342 START. Return the new index into STRING, after zero or more characters
343 have been skipped. */
344static int
345skipws (string, start)
346 char *string;
347 int start;
348{
f73dda09
JA
349 register int i;
350 int pass_next, backslash_quoted_word;
351 unsigned char peekc;
726f6388
JA
352
353 /* skip quoted strings, in ' or ", and words in which a character is quoted
354 with a `\'. */
f73dda09 355 i = backslash_quoted_word = pass_next = 0;
726f6388
JA
356
357 /* Skip leading whitespace (or separator characters), and quoted words.
358 But save it in the output. */
359
360 for (i = start; string[i]; i++)
361 {
362 if (pass_next)
363 {
364 pass_next = 0;
365 continue;
366 }
367
368 if (whitespace (string[i]))
369 {
370 backslash_quoted_word = 0; /* we are no longer in a backslash-quoted word */
371 continue;
372 }
373
374 if (string[i] == '\\')
375 {
376 peekc = string[i+1];
495aee44
CR
377 if (peekc == 0)
378 break;
f73dda09 379 if (ISLETTER (peekc))
726f6388
JA
380 backslash_quoted_word++; /* this is a backslash-quoted word */
381 else
382 pass_next++;
383 continue;
384 }
385
386 /* This only handles single pairs of non-escaped quotes. This
387 overloads backslash_quoted_word to also mean that a word like
388 ""f is being scanned, so that the quotes will inhibit any expansion
389 of the word. */
390 if (quote_char(string[i]))
391 {
392 i = skipquotes (string, i);
393 /* This could be a line that contains a single quote character,
394 in which case skipquotes () terminates with string[i] == '\0'
395 (the end of the string). Check for that here. */
396 if (string[i] == '\0')
397 break;
398
399 peekc = string[i + 1];
f73dda09 400 if (ISLETTER (peekc))
726f6388
JA
401 backslash_quoted_word++;
402 continue;
403 }
404
405 /* If we're in the middle of some kind of quoted word, let it
406 pass through. */
407 if (backslash_quoted_word)
408 continue;
409
410 /* If this character is a shell command separator, then set a hint for
411 alias_expand that the next token is the first word in a command. */
412
413 if (command_separator (string[i]))
414 {
415 command_word++;
416 continue;
417 }
418 break;
419 }
420 return (i);
421}
422
423/* Characters that may appear in a token. Basically, anything except white
424 space and a token separator. */
425#define token_char(c) (!((whitespace (string[i]) || self_delimiting (string[i]))))
426
427/* Read from START in STRING until the next separator character, and return
428 the index of that separator. Skip backslash-quoted characters. Call
429 skipquotes () for quoted strings in the middle or at the end of tokens,
430 so all characters show up (e.g. foo'' and foo""bar) */
431static int
432rd_token (string, start)
ccc6cda3 433 char *string;
726f6388
JA
434 int start;
435{
436 register int i;
437
438 /* From here to next separator character is a token. */
439 for (i = start; string[i] && token_char (string[i]); i++)
440 {
441 if (string[i] == '\\')
442 {
443 i++; /* skip backslash-escaped character */
495aee44
CR
444 if (string[i] == 0)
445 break;
726f6388
JA
446 continue;
447 }
448
449 /* If this character is a quote character, we want to call skipquotes
450 to get the whole quoted portion as part of this word. That word
451 will not generally match an alias, even if te unquoted word would
ccc6cda3 452 have. The presence of the quotes in the token serves then to
726f6388
JA
453 inhibit expansion. */
454 if (quote_char (string[i]))
455 {
456 i = skipquotes (string, i);
cce855bc
JA
457 /* This could be a line that contains a single quote character,
458 in which case skipquotes () terminates with string[i] == '\0'
459 (the end of the string). Check for that here. */
460 if (string[i] == '\0')
461 break;
462
726f6388
JA
463 /* Now string[i] is the matching quote character, and the
464 quoted portion of the token has been scanned. */
465 continue;
466 }
467 }
468 return (i);
469}
470
471/* Return a new line, with any aliases substituted. */
472char *
473alias_expand (string)
474 char *string;
475{
726f6388 476 register int i, j, start;
bb70624e
JA
477 char *line, *token;
478 int line_len, tl, real_start, expand_next, expand_this_token;
ccc6cda3 479 alias_t *alias;
726f6388 480
bb70624e 481 line_len = strlen (string) + 1;
f73dda09
JA
482 line = (char *)xmalloc (line_len);
483 token = (char *)xmalloc (line_len);
bb70624e 484
726f6388
JA
485 line[0] = i = 0;
486 expand_next = 0;
487 command_word = 1; /* initialized to expand the first word on the line */
488
489 /* Each time through the loop we find the next word in line. If it
bb70624e
JA
490 has an alias, substitute the alias value. If the value ends in ` ',
491 then try again with the next word. Else, if there is no value, or if
726f6388
JA
492 the value does not end in space, we are done. */
493
494 for (;;)
495 {
496
497 token[0] = 0;
498 start = i;
499
500 /* Skip white space and quoted characters */
501 i = skipws (string, start);
502
503 if (start == i && string[i] == '\0')
504 {
505 free (token);
506 return (line);
507 }
508
509 /* copy the just-skipped characters into the output string,
510 expanding it if there is not enough room. */
511 j = strlen (line);
512 tl = i - start; /* number of characters just skipped */
ccc6cda3 513 RESIZE_MALLOCED_BUFFER (line, j, (tl + 1), line_len, (tl + 50));
726f6388
JA
514 strncpy (line + j, string + start, tl);
515 line[j + tl] = '\0';
516
517 real_start = i;
518
519 command_word = command_word || (command_separator (string[i]));
520 expand_this_token = (command_word || expand_next);
521 expand_next = 0;
522
523 /* Read the next token, and copy it into TOKEN. */
524 start = i;
525 i = rd_token (string, start);
526
527 tl = i - start; /* token length */
528
529 /* If tl == 0, but we're not at the end of the string, then we have a
530 single-character token, probably a delimiter */
531 if (tl == 0 && string[i] != '\0')
532 {
533 tl = 1;
534 i++; /* move past it */
535 }
536
537 strncpy (token, string + start, tl);
538 token [tl] = '\0';
539
540 /* If there is a backslash-escaped character quoted in TOKEN,
541 then we don't do alias expansion. This should check for all
542 other quoting characters, too. */
0001803f 543 if (mbschr (token, '\\'))
726f6388
JA
544 expand_this_token = 0;
545
546 /* If we should be expanding here, if we are expanding all words, or if
547 we are in a location in the string where an expansion is supposed to
548 take place, see if this word has a substitution. If it does, then do
549 the expansion. Note that we defer the alias value lookup until we
550 are sure we are expanding this token. */
551
552 if ((token[0]) &&
553 (expand_this_token || alias_expand_all) &&
554 (alias = find_alias (token)))
555 {
ccc6cda3
JA
556 char *v;
557 int vlen, llen;
558
559 v = alias->value;
560 vlen = strlen (v);
561 llen = strlen (line);
562
726f6388 563 /* +3 because we possibly add one more character below. */
ccc6cda3 564 RESIZE_MALLOCED_BUFFER (line, llen, (vlen + 3), line_len, (vlen + 50));
726f6388 565
ccc6cda3 566 strcpy (line + llen, v);
726f6388 567
ccc6cda3 568 if ((expand_this_token && vlen && whitespace (v[vlen - 1])) ||
726f6388
JA
569 alias_expand_all)
570 expand_next = 1;
571 }
572 else
573 {
ccc6cda3
JA
574 int llen, tlen;
575
576 llen = strlen (line);
577 tlen = i - real_start; /* tlen == strlen(token) */
726f6388 578
ccc6cda3 579 RESIZE_MALLOCED_BUFFER (line, llen, (tlen + 1), line_len, (llen + tlen + 50));
726f6388 580
ccc6cda3
JA
581 strncpy (line + llen, string + real_start, tlen);
582 line[llen + tlen] = '\0';
726f6388
JA
583 }
584 command_word = 0;
585 }
586}
d166f048 587#endif /* READLINE */
ccc6cda3 588#endif /* ALIAS */