]> git.ipfire.org Git - thirdparty/bash.git/blame - alias.c
fix for SIGINT in sourced script
[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;
161 free (a->value);
162 free (a->name);
163 free (data);
164}
165
726f6388
JA
166/* Remove the alias with name NAME from the alias table. Returns
167 the number of aliases left in the table, or -1 if the alias didn't
168 exist. */
169int
170remove_alias (name)
171 char *name;
172{
173 BUCKET_CONTENTS *elt;
174
ccc6cda3 175 if (aliases == 0)
726f6388
JA
176 return (-1);
177
7117c2d2 178 elt = hash_remove (name, aliases, 0);
726f6388
JA
179 if (elt)
180 {
ccc6cda3 181 free_alias_data (elt->data);
726f6388 182 free (elt->key); /* alias name */
d166f048 183 free (elt); /* XXX */
bb70624e
JA
184#if defined (PROGRAMMABLE_COMPLETION)
185 set_itemlist_dirty (&it_aliases);
186#endif
726f6388
JA
187 return (aliases->nentries);
188 }
189 return (-1);
190}
191
726f6388
JA
192/* Delete all aliases. */
193void
194delete_all_aliases ()
195{
ccc6cda3 196 if (aliases == 0)
726f6388
JA
197 return;
198
7117c2d2
JA
199 hash_flush (aliases, free_alias_data);
200 hash_dispose (aliases);
726f6388 201 aliases = (HASH_TABLE *)NULL;
bb70624e
JA
202#if defined (PROGRAMMABLE_COMPLETION)
203 set_itemlist_dirty (&it_aliases);
204#endif
726f6388
JA
205}
206
207/* Return an array of aliases that satisfy the conditions tested by FUNCTION.
208 If FUNCTION is NULL, return all aliases. */
ccc6cda3 209static alias_t **
726f6388 210map_over_aliases (function)
f73dda09 211 sh_alias_map_func_t *function;
726f6388
JA
212{
213 register int i;
214 register BUCKET_CONTENTS *tlist;
ccc6cda3 215 alias_t *alias, **list;
7117c2d2 216 int list_index;
726f6388 217
7117c2d2
JA
218 i = HASH_ENTRIES (aliases);
219 if (i == 0)
220 return ((alias_t **)NULL);
726f6388 221
7117c2d2
JA
222 list = (alias_t **)xmalloc ((i + 1) * sizeof (alias_t *));
223 for (i = list_index = 0; i < aliases->nbuckets; i++)
224 {
225 for (tlist = hash_items (i, aliases); tlist; tlist = tlist->next)
726f6388 226 {
ccc6cda3 227 alias = (alias_t *)tlist->data;
726f6388
JA
228
229 if (!function || (*function) (alias))
230 {
726f6388 231 list[list_index++] = alias;
ccc6cda3 232 list[list_index] = (alias_t *)NULL;
726f6388 233 }
726f6388
JA
234 }
235 }
236 return (list);
237}
238
239static void
240sort_aliases (array)
ccc6cda3 241 alias_t **array;
726f6388 242{
7117c2d2 243 qsort (array, strvec_len ((char **)array), sizeof (alias_t *), (QSFUNC *)qsort_alias_compare);
726f6388
JA
244}
245
246static int
247qsort_alias_compare (as1, as2)
ccc6cda3 248 alias_t **as1, **as2;
726f6388
JA
249{
250 int result;
ccc6cda3 251
726f6388
JA
252 if ((result = (*as1)->name[0] - (*as2)->name[0]) == 0)
253 result = strcmp ((*as1)->name, (*as2)->name);
254
255 return (result);
256}
ccc6cda3
JA
257
258/* Return a sorted list of all defined aliases */
259alias_t **
726f6388
JA
260all_aliases ()
261{
ccc6cda3 262 alias_t **list;
726f6388 263
7117c2d2 264 if (aliases == 0 || HASH_ENTRIES (aliases) == 0)
ccc6cda3 265 return ((alias_t **)NULL);
726f6388 266
f73dda09 267 list = map_over_aliases ((sh_alias_map_func_t *)NULL);
726f6388
JA
268 if (list)
269 sort_aliases (list);
270 return (list);
271}
272
273char *
274alias_expand_word (s)
275 char *s;
276{
ccc6cda3 277 alias_t *r;
726f6388 278
ccc6cda3
JA
279 r = find_alias (s);
280 return (r ? savestring (r->value) : (char *)NULL);
726f6388
JA
281}
282
d166f048
JA
283/* Readline support functions -- expand all aliases in a line. */
284
285#if defined (READLINE)
286
726f6388
JA
287/* Return non-zero if CHARACTER is a member of the class of characters
288 that are self-delimiting in the shell (this really means that these
289 characters delimit tokens). */
290#define self_delimiting(character) (member ((character), " \t\n\r;|&()"))
291
292/* Return non-zero if CHARACTER is a member of the class of characters
293 that delimit commands in the shell. */
294#define command_separator(character) (member ((character), "\r\n;|&("))
295
296/* If this is 1, we are checking the next token read for alias expansion
297 because it is the first word in a command. */
298static int command_word;
299
300/* This is for skipping quoted strings in alias expansions. */
301#define quote_char(c) (((c) == '\'') || ((c) == '"'))
302
303/* Consume a quoted string from STRING, starting at string[START] (so
304 string[START] is the opening quote character), and return the index
305 of the closing quote character matching the opening quote character.
306 This handles single matching pairs of unquoted quotes; it could afford
307 to be a little smarter... This skips words between balanced pairs of
308 quotes, words where the first character is quoted with a `\', and other
309 backslash-escaped characters. */
310
311static int
312skipquotes (string, start)
313 char *string;
314 int start;
315{
316 register int i;
317 int delimiter = string[start];
318
319 /* i starts at START + 1 because string[START] is the opening quote
320 character. */
321 for (i = start + 1 ; string[i] ; i++)
322 {
323 if (string[i] == '\\')
324 {
325 i++; /* skip backslash-quoted quote characters, too */
495aee44
CR
326 if (string[i] == 0)
327 break;
726f6388
JA
328 continue;
329 }
330
331 if (string[i] == delimiter)
332 return i;
333 }
334 return (i);
335}
336
337/* Skip the white space and any quoted characters in STRING, starting at
338 START. Return the new index into STRING, after zero or more characters
339 have been skipped. */
340static int
341skipws (string, start)
342 char *string;
343 int start;
344{
f73dda09
JA
345 register int i;
346 int pass_next, backslash_quoted_word;
347 unsigned char peekc;
726f6388
JA
348
349 /* skip quoted strings, in ' or ", and words in which a character is quoted
350 with a `\'. */
f73dda09 351 i = backslash_quoted_word = pass_next = 0;
726f6388
JA
352
353 /* Skip leading whitespace (or separator characters), and quoted words.
354 But save it in the output. */
355
356 for (i = start; string[i]; i++)
357 {
358 if (pass_next)
359 {
360 pass_next = 0;
361 continue;
362 }
363
364 if (whitespace (string[i]))
365 {
366 backslash_quoted_word = 0; /* we are no longer in a backslash-quoted word */
367 continue;
368 }
369
370 if (string[i] == '\\')
371 {
372 peekc = string[i+1];
495aee44
CR
373 if (peekc == 0)
374 break;
f73dda09 375 if (ISLETTER (peekc))
726f6388
JA
376 backslash_quoted_word++; /* this is a backslash-quoted word */
377 else
378 pass_next++;
379 continue;
380 }
381
382 /* This only handles single pairs of non-escaped quotes. This
383 overloads backslash_quoted_word to also mean that a word like
384 ""f is being scanned, so that the quotes will inhibit any expansion
385 of the word. */
386 if (quote_char(string[i]))
387 {
388 i = skipquotes (string, i);
389 /* This could be a line that contains a single quote character,
390 in which case skipquotes () terminates with string[i] == '\0'
391 (the end of the string). Check for that here. */
392 if (string[i] == '\0')
393 break;
394
395 peekc = string[i + 1];
f73dda09 396 if (ISLETTER (peekc))
726f6388
JA
397 backslash_quoted_word++;
398 continue;
399 }
400
401 /* If we're in the middle of some kind of quoted word, let it
402 pass through. */
403 if (backslash_quoted_word)
404 continue;
405
406 /* If this character is a shell command separator, then set a hint for
407 alias_expand that the next token is the first word in a command. */
408
409 if (command_separator (string[i]))
410 {
411 command_word++;
412 continue;
413 }
414 break;
415 }
416 return (i);
417}
418
419/* Characters that may appear in a token. Basically, anything except white
420 space and a token separator. */
421#define token_char(c) (!((whitespace (string[i]) || self_delimiting (string[i]))))
422
423/* Read from START in STRING until the next separator character, and return
424 the index of that separator. Skip backslash-quoted characters. Call
425 skipquotes () for quoted strings in the middle or at the end of tokens,
426 so all characters show up (e.g. foo'' and foo""bar) */
427static int
428rd_token (string, start)
ccc6cda3 429 char *string;
726f6388
JA
430 int start;
431{
432 register int i;
433
434 /* From here to next separator character is a token. */
435 for (i = start; string[i] && token_char (string[i]); i++)
436 {
437 if (string[i] == '\\')
438 {
439 i++; /* skip backslash-escaped character */
495aee44
CR
440 if (string[i] == 0)
441 break;
726f6388
JA
442 continue;
443 }
444
445 /* If this character is a quote character, we want to call skipquotes
446 to get the whole quoted portion as part of this word. That word
447 will not generally match an alias, even if te unquoted word would
ccc6cda3 448 have. The presence of the quotes in the token serves then to
726f6388
JA
449 inhibit expansion. */
450 if (quote_char (string[i]))
451 {
452 i = skipquotes (string, i);
cce855bc
JA
453 /* This could be a line that contains a single quote character,
454 in which case skipquotes () terminates with string[i] == '\0'
455 (the end of the string). Check for that here. */
456 if (string[i] == '\0')
457 break;
458
726f6388
JA
459 /* Now string[i] is the matching quote character, and the
460 quoted portion of the token has been scanned. */
461 continue;
462 }
463 }
464 return (i);
465}
466
467/* Return a new line, with any aliases substituted. */
468char *
469alias_expand (string)
470 char *string;
471{
726f6388 472 register int i, j, start;
bb70624e
JA
473 char *line, *token;
474 int line_len, tl, real_start, expand_next, expand_this_token;
ccc6cda3 475 alias_t *alias;
726f6388 476
bb70624e 477 line_len = strlen (string) + 1;
f73dda09
JA
478 line = (char *)xmalloc (line_len);
479 token = (char *)xmalloc (line_len);
bb70624e 480
726f6388
JA
481 line[0] = i = 0;
482 expand_next = 0;
483 command_word = 1; /* initialized to expand the first word on the line */
484
485 /* Each time through the loop we find the next word in line. If it
bb70624e
JA
486 has an alias, substitute the alias value. If the value ends in ` ',
487 then try again with the next word. Else, if there is no value, or if
726f6388
JA
488 the value does not end in space, we are done. */
489
490 for (;;)
491 {
492
493 token[0] = 0;
494 start = i;
495
496 /* Skip white space and quoted characters */
497 i = skipws (string, start);
498
499 if (start == i && string[i] == '\0')
500 {
501 free (token);
502 return (line);
503 }
504
505 /* copy the just-skipped characters into the output string,
506 expanding it if there is not enough room. */
507 j = strlen (line);
508 tl = i - start; /* number of characters just skipped */
ccc6cda3 509 RESIZE_MALLOCED_BUFFER (line, j, (tl + 1), line_len, (tl + 50));
726f6388
JA
510 strncpy (line + j, string + start, tl);
511 line[j + tl] = '\0';
512
513 real_start = i;
514
515 command_word = command_word || (command_separator (string[i]));
516 expand_this_token = (command_word || expand_next);
517 expand_next = 0;
518
519 /* Read the next token, and copy it into TOKEN. */
520 start = i;
521 i = rd_token (string, start);
522
523 tl = i - start; /* token length */
524
525 /* If tl == 0, but we're not at the end of the string, then we have a
526 single-character token, probably a delimiter */
527 if (tl == 0 && string[i] != '\0')
528 {
529 tl = 1;
530 i++; /* move past it */
531 }
532
533 strncpy (token, string + start, tl);
534 token [tl] = '\0';
535
536 /* If there is a backslash-escaped character quoted in TOKEN,
537 then we don't do alias expansion. This should check for all
538 other quoting characters, too. */
0001803f 539 if (mbschr (token, '\\'))
726f6388
JA
540 expand_this_token = 0;
541
542 /* If we should be expanding here, if we are expanding all words, or if
543 we are in a location in the string where an expansion is supposed to
544 take place, see if this word has a substitution. If it does, then do
545 the expansion. Note that we defer the alias value lookup until we
546 are sure we are expanding this token. */
547
548 if ((token[0]) &&
549 (expand_this_token || alias_expand_all) &&
550 (alias = find_alias (token)))
551 {
ccc6cda3
JA
552 char *v;
553 int vlen, llen;
554
555 v = alias->value;
556 vlen = strlen (v);
557 llen = strlen (line);
558
726f6388 559 /* +3 because we possibly add one more character below. */
ccc6cda3 560 RESIZE_MALLOCED_BUFFER (line, llen, (vlen + 3), line_len, (vlen + 50));
726f6388 561
ccc6cda3 562 strcpy (line + llen, v);
726f6388 563
ccc6cda3 564 if ((expand_this_token && vlen && whitespace (v[vlen - 1])) ||
726f6388
JA
565 alias_expand_all)
566 expand_next = 1;
567 }
568 else
569 {
ccc6cda3
JA
570 int llen, tlen;
571
572 llen = strlen (line);
573 tlen = i - real_start; /* tlen == strlen(token) */
726f6388 574
ccc6cda3 575 RESIZE_MALLOCED_BUFFER (line, llen, (tlen + 1), line_len, (llen + tlen + 50));
726f6388 576
ccc6cda3
JA
577 strncpy (line + llen, string + real_start, tlen);
578 line[llen + tlen] = '\0';
726f6388
JA
579 }
580 command_word = 0;
581 }
582}
d166f048 583#endif /* READLINE */
ccc6cda3 584#endif /* ALIAS */