]> git.ipfire.org Git - thirdparty/bash.git/blob - alias.c
fix for SIGINT in sourced script
[thirdparty/bash.git] / alias.c
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
4 /* Copyright (C) 1987-2015 Free Software Foundation, Inc.
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
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.
12
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.
17
18 You should have received a copy of the GNU General Public License
19 along with Bash. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "config.h"
23
24 #if defined (ALIAS)
25
26 #if defined (HAVE_UNISTD_H)
27 # ifdef _MINIX
28 # include <sys/types.h>
29 # endif
30 # include <unistd.h>
31 #endif
32
33 #include <stdio.h>
34 #include "chartypes.h"
35 #include "bashansi.h"
36 #include "command.h"
37 #include "general.h"
38 #include "externs.h"
39 #include "alias.h"
40
41 #if defined (PROGRAMMABLE_COMPLETION)
42 # include "pcomplete.h"
43 #endif
44
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 */
50
51 typedef int sh_alias_map_func_t __P((alias_t *));
52
53 static void free_alias_data __P((PTR_T));
54 static alias_t **map_over_aliases __P((sh_alias_map_func_t *));
55 static void sort_aliases __P((alias_t **));
56 static int qsort_alias_compare __P((alias_t **, alias_t **));
57
58 #if defined (READLINE)
59 static int skipquotes __P((char *, int));
60 static int skipws __P((char *, int));
61 static int rd_token __P((char *, int));
62 #endif
63
64 /* Non-zero means expand all words on the line. Otherwise, expand
65 after first expansion if the expansion ends in a space. */
66 int alias_expand_all = 0;
67
68 /* The list of aliases that we have. */
69 HASH_TABLE *aliases = (HASH_TABLE *)NULL;
70
71 void
72 initialize_aliases ()
73 {
74 if (aliases == 0)
75 aliases = hash_create (ALIAS_HASH_BUCKETS);
76 }
77
78 /* Scan the list of aliases looking for one with NAME. Return NULL
79 if the alias doesn't exist, else a pointer to the alias_t. */
80 alias_t *
81 find_alias (name)
82 char *name;
83 {
84 BUCKET_CONTENTS *al;
85
86 if (aliases == 0)
87 return ((alias_t *)NULL);
88
89 al = hash_search (name, aliases, 0);
90 return (al ? (alias_t *)al->data : (alias_t *)NULL);
91 }
92
93 /* Return the value of the alias for NAME, or NULL if there is none. */
94 char *
95 get_alias_value (name)
96 char *name;
97 {
98 alias_t *alias;
99
100 if (aliases == 0)
101 return ((char *)NULL);
102
103 alias = find_alias (name);
104 return (alias ? alias->value : (char *)NULL);
105 }
106
107 /* Make a new alias from NAME and VALUE. If NAME can be found,
108 then replace its value. */
109 void
110 add_alias (name, value)
111 char *name, *value;
112 {
113 BUCKET_CONTENTS *elt;
114 alias_t *temp;
115 int n;
116
117 if (aliases == 0)
118 {
119 initialize_aliases ();
120 temp = (alias_t *)NULL;
121 }
122 else
123 temp = find_alias (name);
124
125 if (temp)
126 {
127 free (temp->value);
128 temp->value = savestring (value);
129 temp->flags &= ~AL_EXPANDNEXT;
130 n = value[strlen (value) - 1];
131 if (n == ' ' || n == '\t')
132 temp->flags |= AL_EXPANDNEXT;
133 }
134 else
135 {
136 temp = (alias_t *)xmalloc (sizeof (alias_t));
137 temp->name = savestring (name);
138 temp->value = savestring (value);
139 temp->flags = 0;
140
141 n = value[strlen (value) - 1];
142 if (n == ' ' || n == '\t')
143 temp->flags |= AL_EXPANDNEXT;
144
145 elt = hash_insert (savestring (name), aliases, HASH_NOSRCH);
146 elt->data = temp;
147 #if defined (PROGRAMMABLE_COMPLETION)
148 set_itemlist_dirty (&it_aliases);
149 #endif
150 }
151 }
152
153 /* Delete a single alias structure. */
154 static void
155 free_alias_data (data)
156 PTR_T data;
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
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. */
169 int
170 remove_alias (name)
171 char *name;
172 {
173 BUCKET_CONTENTS *elt;
174
175 if (aliases == 0)
176 return (-1);
177
178 elt = hash_remove (name, aliases, 0);
179 if (elt)
180 {
181 free_alias_data (elt->data);
182 free (elt->key); /* alias name */
183 free (elt); /* XXX */
184 #if defined (PROGRAMMABLE_COMPLETION)
185 set_itemlist_dirty (&it_aliases);
186 #endif
187 return (aliases->nentries);
188 }
189 return (-1);
190 }
191
192 /* Delete all aliases. */
193 void
194 delete_all_aliases ()
195 {
196 if (aliases == 0)
197 return;
198
199 hash_flush (aliases, free_alias_data);
200 hash_dispose (aliases);
201 aliases = (HASH_TABLE *)NULL;
202 #if defined (PROGRAMMABLE_COMPLETION)
203 set_itemlist_dirty (&it_aliases);
204 #endif
205 }
206
207 /* Return an array of aliases that satisfy the conditions tested by FUNCTION.
208 If FUNCTION is NULL, return all aliases. */
209 static alias_t **
210 map_over_aliases (function)
211 sh_alias_map_func_t *function;
212 {
213 register int i;
214 register BUCKET_CONTENTS *tlist;
215 alias_t *alias, **list;
216 int list_index;
217
218 i = HASH_ENTRIES (aliases);
219 if (i == 0)
220 return ((alias_t **)NULL);
221
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)
226 {
227 alias = (alias_t *)tlist->data;
228
229 if (!function || (*function) (alias))
230 {
231 list[list_index++] = alias;
232 list[list_index] = (alias_t *)NULL;
233 }
234 }
235 }
236 return (list);
237 }
238
239 static void
240 sort_aliases (array)
241 alias_t **array;
242 {
243 qsort (array, strvec_len ((char **)array), sizeof (alias_t *), (QSFUNC *)qsort_alias_compare);
244 }
245
246 static int
247 qsort_alias_compare (as1, as2)
248 alias_t **as1, **as2;
249 {
250 int result;
251
252 if ((result = (*as1)->name[0] - (*as2)->name[0]) == 0)
253 result = strcmp ((*as1)->name, (*as2)->name);
254
255 return (result);
256 }
257
258 /* Return a sorted list of all defined aliases */
259 alias_t **
260 all_aliases ()
261 {
262 alias_t **list;
263
264 if (aliases == 0 || HASH_ENTRIES (aliases) == 0)
265 return ((alias_t **)NULL);
266
267 list = map_over_aliases ((sh_alias_map_func_t *)NULL);
268 if (list)
269 sort_aliases (list);
270 return (list);
271 }
272
273 char *
274 alias_expand_word (s)
275 char *s;
276 {
277 alias_t *r;
278
279 r = find_alias (s);
280 return (r ? savestring (r->value) : (char *)NULL);
281 }
282
283 /* Readline support functions -- expand all aliases in a line. */
284
285 #if defined (READLINE)
286
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. */
298 static 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
311 static int
312 skipquotes (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 */
326 if (string[i] == 0)
327 break;
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. */
340 static int
341 skipws (string, start)
342 char *string;
343 int start;
344 {
345 register int i;
346 int pass_next, backslash_quoted_word;
347 unsigned char peekc;
348
349 /* skip quoted strings, in ' or ", and words in which a character is quoted
350 with a `\'. */
351 i = backslash_quoted_word = pass_next = 0;
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];
373 if (peekc == 0)
374 break;
375 if (ISLETTER (peekc))
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];
396 if (ISLETTER (peekc))
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) */
427 static int
428 rd_token (string, start)
429 char *string;
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 */
440 if (string[i] == 0)
441 break;
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
448 have. The presence of the quotes in the token serves then to
449 inhibit expansion. */
450 if (quote_char (string[i]))
451 {
452 i = skipquotes (string, i);
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
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. */
468 char *
469 alias_expand (string)
470 char *string;
471 {
472 register int i, j, start;
473 char *line, *token;
474 int line_len, tl, real_start, expand_next, expand_this_token;
475 alias_t *alias;
476
477 line_len = strlen (string) + 1;
478 line = (char *)xmalloc (line_len);
479 token = (char *)xmalloc (line_len);
480
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
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
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 */
509 RESIZE_MALLOCED_BUFFER (line, j, (tl + 1), line_len, (tl + 50));
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. */
539 if (mbschr (token, '\\'))
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 {
552 char *v;
553 int vlen, llen;
554
555 v = alias->value;
556 vlen = strlen (v);
557 llen = strlen (line);
558
559 /* +3 because we possibly add one more character below. */
560 RESIZE_MALLOCED_BUFFER (line, llen, (vlen + 3), line_len, (vlen + 50));
561
562 strcpy (line + llen, v);
563
564 if ((expand_this_token && vlen && whitespace (v[vlen - 1])) ||
565 alias_expand_all)
566 expand_next = 1;
567 }
568 else
569 {
570 int llen, tlen;
571
572 llen = strlen (line);
573 tlen = i - real_start; /* tlen == strlen(token) */
574
575 RESIZE_MALLOCED_BUFFER (line, llen, (tlen + 1), line_len, (llen + tlen + 50));
576
577 strncpy (line + llen, string + real_start, tlen);
578 line[llen + tlen] = '\0';
579 }
580 command_word = 0;
581 }
582 }
583 #endif /* READLINE */
584 #endif /* ALIAS */