Line data Source code
1 : /* common.c - utility functions for all builtins */
2 :
3 : /* Copyright (C) 1987-2016 Free Software Foundation, Inc.
4 :
5 : This file is part of GNU Bash, the Bourne Again SHell.
6 :
7 : Bash is free software: you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation, either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : Bash is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with Bash. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <config.h>
22 :
23 : #if defined (HAVE_UNISTD_H)
24 : # ifdef _MINIX
25 : # include <sys/types.h>
26 : # endif
27 : # include <unistd.h>
28 : #endif
29 :
30 : #include <stdio.h>
31 : #include <chartypes.h>
32 : #include "../bashtypes.h"
33 : #include "posixstat.h"
34 : #include <signal.h>
35 :
36 : #include <errno.h>
37 :
38 : #if defined (PREFER_STDARG)
39 : # include <stdarg.h>
40 : #else
41 : # include <varargs.h>
42 : #endif
43 :
44 : #include "../bashansi.h"
45 : #include "../bashintl.h"
46 :
47 : #define NEED_FPURGE_DECL
48 :
49 : #include "../shell.h"
50 : #include "maxpath.h"
51 : #include "../flags.h"
52 : #include "../jobs.h"
53 : #include "../builtins.h"
54 : #include "../input.h"
55 : #include "../execute_cmd.h"
56 : #include "../trap.h"
57 : #include "bashgetopt.h"
58 : #include "common.h"
59 : #include "builtext.h"
60 : #include <tilde/tilde.h>
61 :
62 : #if defined (HISTORY)
63 : # include "../bashhist.h"
64 : #endif
65 :
66 : #if !defined (errno)
67 : extern int errno;
68 : #endif /* !errno */
69 :
70 : extern int indirection_level, subshell_environment;
71 : extern int line_number;
72 : extern int last_command_exit_value;
73 : extern int trap_saved_exit_value;
74 : extern int running_trap;
75 : extern int posixly_correct;
76 : extern char *this_command_name, *shell_name;
77 : extern const char * const bash_getcwd_errstr;
78 :
79 : /* Used by some builtins and the mainline code. */
80 : sh_builtin_func_t *last_shell_builtin = (sh_builtin_func_t *)NULL;
81 : sh_builtin_func_t *this_shell_builtin = (sh_builtin_func_t *)NULL;
82 :
83 : /* **************************************************************** */
84 : /* */
85 : /* Error reporting, usage, and option processing */
86 : /* */
87 : /* **************************************************************** */
88 :
89 : /* This is a lot like report_error (), but it is for shell builtins
90 : instead of shell control structures, and it won't ever exit the
91 : shell. */
92 :
93 : static void
94 113792 : builtin_error_prolog ()
95 : {
96 113792 : char *name;
97 :
98 113792 : name = get_name_for_error ();
99 113792 : fprintf (stderr, "%s: ", name);
100 :
101 113792 : if (interactive_shell == 0)
102 113792 : fprintf (stderr, _("line %d: "), executing_line_number ());
103 :
104 113792 : if (this_command_name && *this_command_name)
105 113792 : fprintf (stderr, "%s: ", this_command_name);
106 113792 : }
107 :
108 : void
109 : #if defined (PREFER_STDARG)
110 113792 : builtin_error (const char *format, ...)
111 : #else
112 : builtin_error (format, va_alist)
113 : const char *format;
114 : va_dcl
115 : #endif
116 : {
117 113792 : va_list args;
118 :
119 113792 : builtin_error_prolog ();
120 :
121 113792 : SH_VA_START (args, format);
122 :
123 113792 : vfprintf (stderr, format, args);
124 113792 : va_end (args);
125 113792 : fprintf (stderr, "\n");
126 113792 : }
127 :
128 : void
129 : #if defined (PREFER_STDARG)
130 0 : builtin_warning (const char *format, ...)
131 : #else
132 : builtin_warning (format, va_alist)
133 : const char *format;
134 : va_dcl
135 : #endif
136 : {
137 0 : va_list args;
138 :
139 0 : builtin_error_prolog ();
140 0 : fprintf (stderr, _("warning: "));
141 :
142 0 : SH_VA_START (args, format);
143 :
144 0 : vfprintf (stderr, format, args);
145 0 : va_end (args);
146 0 : fprintf (stderr, "\n");
147 0 : }
148 :
149 : /* Print a usage summary for the currently-executing builtin command. */
150 : void
151 644 : builtin_usage ()
152 : {
153 644 : if (this_command_name && *this_command_name)
154 644 : fprintf (stderr, _("%s: usage: "), this_command_name);
155 644 : fprintf (stderr, "%s\n", _(current_builtin->short_doc));
156 644 : fflush (stderr);
157 644 : }
158 :
159 : /* Return if LIST is NULL else barf and jump to top_level. Used by some
160 : builtins that do not accept arguments. */
161 : void
162 7210327 : no_args (list)
163 : WORD_LIST *list;
164 : {
165 7210327 : if (list)
166 : {
167 154 : builtin_error (_("too many arguments"));
168 154 : top_level_cleanup ();
169 154 : jump_to_top_level (DISCARD);
170 : }
171 7210173 : }
172 :
173 : /* Check that no options were given to the currently-executing builtin,
174 : and return 0 if there were options. */
175 : int
176 17797641 : no_options (list)
177 : WORD_LIST *list;
178 : {
179 17797641 : int opt;
180 :
181 17797641 : reset_internal_getopt ();
182 17797641 : if ((opt = internal_getopt (list, "")) != -1)
183 : {
184 99 : if (opt == GETOPT_HELP)
185 : {
186 0 : builtin_help ();
187 0 : return (2);
188 : }
189 99 : builtin_usage ();
190 99 : return (1);
191 : }
192 : return (0);
193 : }
194 :
195 : void
196 0 : sh_needarg (s)
197 : char *s;
198 : {
199 0 : builtin_error (_("%s: option requires an argument"), s);
200 0 : }
201 :
202 : void
203 30274 : sh_neednumarg (s)
204 : char *s;
205 : {
206 30274 : builtin_error (_("%s: numeric argument required"), s);
207 30274 : }
208 :
209 : void
210 174 : sh_notfound (s)
211 : char *s;
212 : {
213 174 : builtin_error (_("%s: not found"), s);
214 174 : }
215 :
216 : /* Function called when one of the builtin commands detects an invalid
217 : option. */
218 : void
219 99 : sh_invalidopt (s)
220 : char *s;
221 : {
222 99 : builtin_error (_("%s: invalid option"), s);
223 99 : }
224 :
225 : void
226 0 : sh_invalidoptname (s)
227 : char *s;
228 : {
229 0 : builtin_error (_("%s: invalid option name"), s);
230 0 : }
231 :
232 : void
233 134 : sh_invalidid (s)
234 : char *s;
235 : {
236 134 : builtin_error (_("`%s': not a valid identifier"), s);
237 134 : }
238 :
239 : void
240 0 : sh_invalidnum (s)
241 : char *s;
242 : {
243 0 : char *msg;
244 :
245 0 : if (*s == '0' && isdigit ((unsigned char)s[1]))
246 0 : msg = _("invalid octal number");
247 0 : else if (*s == '0' && s[1] == 'x')
248 0 : msg = _("invalid hex number");
249 : else
250 0 : msg = _("invalid number");
251 0 : builtin_error ("%s: %s", s, msg);
252 0 : }
253 :
254 : void
255 12 : sh_invalidsig (s)
256 : char *s;
257 : {
258 12 : builtin_error (_("%s: invalid signal specification"), s);
259 12 : }
260 :
261 : void
262 46 : sh_badpid (s)
263 : char *s;
264 : {
265 46 : builtin_error (_("`%s': not a pid or valid job spec"), s);
266 46 : }
267 :
268 : void
269 0 : sh_readonly (s)
270 : const char *s;
271 : {
272 0 : builtin_error (_("%s: readonly variable"), s);
273 0 : }
274 :
275 : void
276 0 : sh_erange (s, desc)
277 : char *s, *desc;
278 : {
279 0 : if (s)
280 0 : builtin_error (_("%s: %s out of range"), s, desc ? desc : _("argument"));
281 : else
282 0 : builtin_error (_("%s out of range"), desc ? desc : _("argument"));
283 0 : }
284 :
285 : #if defined (JOB_CONTROL)
286 : void
287 741 : sh_badjob (s)
288 : char *s;
289 : {
290 741 : builtin_error (_("%s: no such job"), s);
291 741 : }
292 :
293 : void
294 641 : sh_nojobs (s)
295 : char *s;
296 : {
297 641 : if (s)
298 69 : builtin_error (_("%s: no job control"), s);
299 : else
300 572 : builtin_error (_("no job control"));
301 641 : }
302 : #endif
303 :
304 : #if defined (RESTRICTED_SHELL)
305 : void
306 : sh_restricted (s)
307 : char *s;
308 : {
309 : if (s)
310 : builtin_error (_("%s: restricted"), s);
311 : else
312 : builtin_error (_("restricted"));
313 : }
314 : #endif
315 :
316 : void
317 139 : sh_notbuiltin (s)
318 : char *s;
319 : {
320 139 : builtin_error (_("%s: not a shell builtin"), s);
321 139 : }
322 :
323 : void
324 99 : sh_wrerror ()
325 : {
326 : #if defined (DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS) && defined (EPIPE)
327 : if (errno != EPIPE)
328 : #endif /* DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS && EPIPE */
329 99 : builtin_error (_("write error: %s"), strerror (errno));
330 99 : }
331 :
332 : void
333 0 : sh_ttyerror (set)
334 : int set;
335 : {
336 0 : if (set)
337 0 : builtin_error (_("error setting terminal attributes: %s"), strerror (errno));
338 : else
339 0 : builtin_error (_("error getting terminal attributes: %s"), strerror (errno));
340 0 : }
341 :
342 : int
343 1911794 : sh_chkwrite (s)
344 : int s;
345 : {
346 1911794 : QUIT;
347 1911794 : fflush (stdout);
348 1911794 : QUIT;
349 1911794 : if (ferror (stdout))
350 : {
351 99 : sh_wrerror ();
352 99 : fpurge (stdout);
353 99 : clearerr (stdout);
354 99 : return (EXECUTION_FAILURE);
355 : }
356 : return (s);
357 : }
358 :
359 : /* **************************************************************** */
360 : /* */
361 : /* Shell positional parameter manipulation */
362 : /* */
363 : /* **************************************************************** */
364 :
365 : /* Convert a WORD_LIST into a C-style argv. Return the number of elements
366 : in the list in *IP, if IP is non-null. A convenience function for
367 : loadable builtins; also used by `test'. */
368 : char **
369 24808088 : make_builtin_argv (list, ip)
370 : WORD_LIST *list;
371 : int *ip;
372 : {
373 24808088 : char **argv;
374 :
375 24808088 : argv = strvec_from_word_list (list, 0, 1, ip);
376 24808088 : argv[0] = this_command_name;
377 24808088 : return argv;
378 : }
379 :
380 : /* Remember LIST in $1 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is
381 : non-zero, then discard whatever the existing arguments are, else
382 : only discard the ones that are to be replaced. */
383 : void
384 33057 : remember_args (list, destructive)
385 : WORD_LIST *list;
386 : int destructive;
387 : {
388 33057 : register int i;
389 :
390 330570 : for (i = 1; i < 10; i++)
391 : {
392 297513 : if ((destructive || list) && dollar_vars[i])
393 : {
394 18175 : free (dollar_vars[i]);
395 18175 : dollar_vars[i] = (char *)NULL;
396 : }
397 :
398 297513 : if (list)
399 : {
400 18193 : dollar_vars[i] = savestring (list->word->word);
401 18193 : list = list->next;
402 : }
403 : }
404 :
405 : /* If arguments remain, assign them to REST_OF_ARGS.
406 : Note that copy_word_list (NULL) returns NULL, and
407 : that dispose_words (NULL) does nothing. */
408 33057 : if (destructive || list)
409 : {
410 33057 : dispose_words (rest_of_args);
411 33057 : rest_of_args = copy_word_list (list);
412 : }
413 :
414 33057 : if (destructive)
415 33057 : set_dollar_vars_changed ();
416 :
417 33057 : invalidate_cached_quoted_dollar_at ();
418 33057 : }
419 :
420 : static int changed_dollar_vars;
421 :
422 : /* Have the dollar variables been reset to new values since we last
423 : checked? */
424 : int
425 7074 : dollar_vars_changed ()
426 : {
427 7074 : return (changed_dollar_vars);
428 : }
429 :
430 : void
431 17819751 : set_dollar_vars_unchanged ()
432 : {
433 17819751 : changed_dollar_vars = 0;
434 17819751 : }
435 :
436 : void
437 0 : set_dollar_vars_changed ()
438 : {
439 33057 : if (variable_context)
440 18891 : changed_dollar_vars |= ARGS_FUNC;
441 14166 : else if (this_shell_builtin == set_builtin)
442 0 : changed_dollar_vars |= ARGS_SETBLTIN;
443 : else
444 14166 : changed_dollar_vars |= ARGS_INVOC;
445 0 : }
446 :
447 : /* **************************************************************** */
448 : /* */
449 : /* Validating numeric input and arguments */
450 : /* */
451 : /* **************************************************************** */
452 :
453 : /* Read a numeric arg for this_command_name, the name of the shell builtin
454 : that wants it. LIST is the word list that the arg is to come from.
455 : Accept only the numeric argument; report an error if other arguments
456 : follow. If FATAL is 1, call throw_to_top_level, which exits the
457 : shell; if it's 2, call jump_to_top_level (DISCARD), which aborts the
458 : current command; if FATAL is 0, return an indication of an invalid
459 : number by setting *NUMOK == 0 and return -1. */
460 : int
461 77 : get_numeric_arg (list, fatal, count)
462 : WORD_LIST *list;
463 : int fatal;
464 : intmax_t *count;
465 : {
466 77 : char *arg;
467 :
468 77 : if (count)
469 77 : *count = 1;
470 :
471 77 : if (list && list->word && ISOPTION (list->word->word, '-'))
472 0 : list = list->next;
473 :
474 77 : if (list)
475 : {
476 18 : arg = list->word->word;
477 18 : if (arg == 0 || (legal_number (arg, count) == 0))
478 : {
479 36 : sh_neednumarg (list->word->word ? list->word->word : "`'");
480 18 : if (fatal == 0)
481 : return 0;
482 0 : else if (fatal == 1) /* fatal == 1; abort */
483 0 : throw_to_top_level ();
484 : else /* fatal == 2; discard current command */
485 : {
486 0 : top_level_cleanup ();
487 0 : jump_to_top_level (DISCARD);
488 : }
489 : }
490 0 : no_args (list->next);
491 : }
492 :
493 : return (1);
494 : }
495 :
496 : /* Get an eight-bit status value from LIST */
497 : int
498 7350987 : get_exitstat (list)
499 : WORD_LIST *list;
500 : {
501 7350987 : int status;
502 7350987 : intmax_t sval;
503 7350987 : char *arg;
504 :
505 7350987 : if (list && list->word && ISOPTION (list->word->word, '-'))
506 0 : list = list->next;
507 :
508 7350987 : if (list == 0)
509 : {
510 : /* If we're not running the DEBUG trap, the return builtin, when not
511 : given any arguments, uses the value of $? before the trap ran. If
512 : given an argument, return uses it. This means that the trap can't
513 : change $?. The DEBUG trap gets to change $?, though, since that is
514 : part of its reason for existing, and because the extended debug mode
515 : does things with the return value. */
516 110404 : if (this_shell_builtin == return_builtin && running_trap > 0 && running_trap != DEBUG_TRAP+1)
517 0 : return (trap_saved_exit_value);
518 110404 : return (last_command_exit_value);
519 : }
520 :
521 7240583 : arg = list->word->word;
522 7240583 : if (arg == 0 || legal_number (arg, &sval) == 0)
523 : {
524 30256 : sh_neednumarg (list->word->word ? list->word->word : "`'");
525 30256 : return EX_BADUSAGE;
526 : }
527 7210327 : no_args (list->next);
528 :
529 7210173 : status = sval & 255;
530 7210173 : return status;
531 : }
532 :
533 : /* Return the octal number parsed from STRING, or -1 to indicate
534 : that the string contained a bad number. */
535 : int
536 0 : read_octal (string)
537 : char *string;
538 : {
539 0 : int result, digits;
540 :
541 0 : result = digits = 0;
542 0 : while (*string && ISOCTAL (*string))
543 : {
544 0 : digits++;
545 0 : result = (result * 8) + (*string++ - '0');
546 0 : if (result > 0777)
547 : return -1;
548 : }
549 :
550 0 : if (digits == 0 || *string)
551 0 : result = -1;
552 :
553 : return (result);
554 : }
555 :
556 : /* **************************************************************** */
557 : /* */
558 : /* Manipulating the current working directory */
559 : /* */
560 : /* **************************************************************** */
561 :
562 : /* Return a consed string which is the current working directory.
563 : FOR_WHOM is the name of the caller for error printing. */
564 : char *the_current_working_directory = (char *)NULL;
565 :
566 : char *
567 0 : get_working_directory (for_whom)
568 : char *for_whom;
569 : {
570 0 : if (no_symbolic_links)
571 : {
572 0 : FREE (the_current_working_directory);
573 0 : the_current_working_directory = (char *)NULL;
574 : }
575 :
576 0 : if (the_current_working_directory == 0)
577 : {
578 : #if defined (GETCWD_BROKEN)
579 : the_current_working_directory = getcwd (0, PATH_MAX);
580 : #else
581 0 : the_current_working_directory = getcwd (0, 0);
582 : #endif
583 0 : if (the_current_working_directory == 0)
584 : {
585 0 : fprintf (stderr, _("%s: error retrieving current directory: %s: %s\n"),
586 0 : (for_whom && *for_whom) ? for_whom : get_name_for_error (),
587 0 : _(bash_getcwd_errstr), strerror (errno));
588 0 : return (char *)NULL;
589 : }
590 : }
591 :
592 0 : return (savestring (the_current_working_directory));
593 : }
594 :
595 : /* Make NAME our internal idea of the current working directory. */
596 : void
597 9542940 : set_working_directory (name)
598 : char *name;
599 : {
600 9542940 : FREE (the_current_working_directory);
601 9542940 : the_current_working_directory = savestring (name);
602 9542940 : }
603 :
604 : /* **************************************************************** */
605 : /* */
606 : /* Job control support functions */
607 : /* */
608 : /* **************************************************************** */
609 :
610 : #if defined (JOB_CONTROL)
611 : int
612 713 : get_job_by_name (name, flags)
613 : const char *name;
614 : int flags;
615 : {
616 713 : register int i, wl, cl, match, job;
617 713 : register PROCESS *p;
618 713 : register JOB *j;
619 :
620 713 : job = NO_JOB;
621 713 : wl = strlen (name);
622 3473 : for (i = js.j_jobslots - 1; i >= 0; i--)
623 : {
624 2760 : j = get_job_by_jid (i);
625 2760 : if (j == 0 || ((flags & JM_STOPPED) && J_JOBSTATE(j) != JSTOPPED))
626 : continue;
627 :
628 0 : p = j->pipe;
629 0 : do
630 : {
631 0 : if (flags & JM_EXACT)
632 : {
633 0 : cl = strlen (p->command);
634 0 : match = STREQN (p->command, name, cl);
635 : }
636 0 : else if (flags & JM_SUBSTRING)
637 0 : match = strcasestr (p->command, name) != (char *)0;
638 : else
639 0 : match = STREQN (p->command, name, wl);
640 :
641 0 : if (match == 0)
642 : {
643 0 : p = p->next;
644 0 : continue;
645 : }
646 0 : else if (flags & JM_FIRSTMATCH)
647 0 : return i; /* return first match */
648 0 : else if (job != NO_JOB)
649 : {
650 0 : if (this_shell_builtin)
651 0 : builtin_error (_("%s: ambiguous job spec"), name);
652 : else
653 0 : internal_error (_("%s: ambiguous job spec"), name);
654 0 : return (DUP_JOB);
655 : }
656 : else
657 : job = i;
658 : }
659 0 : while (p != j->pipe);
660 : }
661 :
662 : return (job);
663 : }
664 :
665 : /* Return the job spec found in LIST. */
666 : int
667 741 : get_job_spec (list)
668 : WORD_LIST *list;
669 : {
670 741 : register char *word;
671 741 : int job, jflags;
672 :
673 741 : if (list == 0)
674 0 : return (js.j_current);
675 :
676 741 : word = list->word->word;
677 :
678 741 : if (*word == '\0')
679 : return (NO_JOB);
680 :
681 732 : if (*word == '%')
682 0 : word++;
683 :
684 732 : if (DIGIT (*word) && all_digits (word))
685 : {
686 19 : job = atoi (word);
687 19 : return (job > js.j_jobslots ? NO_JOB : job - 1);
688 : }
689 :
690 713 : jflags = 0;
691 713 : switch (*word)
692 : {
693 0 : case 0:
694 : case '%':
695 : case '+':
696 0 : return (js.j_current);
697 :
698 0 : case '-':
699 0 : return (js.j_previous);
700 :
701 0 : case '?': /* Substring search requested. */
702 0 : jflags |= JM_SUBSTRING;
703 0 : word++;
704 : /* FALLTHROUGH */
705 :
706 713 : default:
707 713 : return get_job_by_name (word, jflags);
708 : }
709 : }
710 : #endif /* JOB_CONTROL */
711 :
712 : /*
713 : * NOTE: `kill' calls this function with forcecols == 0
714 : */
715 : int
716 0 : display_signal_list (list, forcecols)
717 : WORD_LIST *list;
718 : int forcecols;
719 : {
720 0 : register int i, column;
721 0 : char *name;
722 0 : int result, signum, dflags;
723 0 : intmax_t lsignum;
724 :
725 0 : result = EXECUTION_SUCCESS;
726 0 : if (!list)
727 : {
728 0 : for (i = 1, column = 0; i < NSIG; i++)
729 : {
730 0 : name = signal_name (i);
731 0 : if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
732 : continue;
733 :
734 0 : if (posixly_correct && !forcecols)
735 : {
736 : /* This is for the kill builtin. POSIX.2 says the signal names
737 : are displayed without the `SIG' prefix. */
738 0 : if (STREQN (name, "SIG", 3))
739 0 : name += 3;
740 0 : printf ("%s%s", name, (i == NSIG - 1) ? "" : " ");
741 : }
742 : else
743 : {
744 0 : printf ("%2d) %s", i, name);
745 :
746 0 : if (++column < 5)
747 0 : printf ("\t");
748 : else
749 : {
750 0 : printf ("\n");
751 0 : column = 0;
752 : }
753 : }
754 : }
755 :
756 0 : if ((posixly_correct && !forcecols) || column != 0)
757 0 : printf ("\n");
758 0 : return result;
759 : }
760 :
761 : /* List individual signal names or numbers. */
762 0 : while (list)
763 : {
764 0 : if (legal_number (list->word->word, &lsignum))
765 : {
766 : /* This is specified by Posix.2 so that exit statuses can be
767 : mapped into signal numbers. */
768 0 : if (lsignum > 128)
769 0 : lsignum -= 128;
770 0 : if (lsignum < 0 || lsignum >= NSIG)
771 : {
772 0 : sh_invalidsig (list->word->word);
773 0 : result = EXECUTION_FAILURE;
774 0 : list = list->next;
775 0 : continue;
776 : }
777 :
778 0 : signum = lsignum;
779 0 : name = signal_name (signum);
780 0 : if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
781 : {
782 0 : list = list->next;
783 0 : continue;
784 : }
785 : #if defined (JOB_CONTROL)
786 : /* POSIX.2 says that `kill -l signum' prints the signal name without
787 : the `SIG' prefix. */
788 0 : printf ("%s\n", (this_shell_builtin == kill_builtin) ? name + 3 : name);
789 : #else
790 : printf ("%s\n", name);
791 : #endif
792 : }
793 : else
794 : {
795 0 : dflags = DSIG_NOCASE;
796 0 : if (posixly_correct == 0 || this_shell_builtin != kill_builtin)
797 0 : dflags |= DSIG_SIGPREFIX;
798 0 : signum = decode_signal (list->word->word, dflags);
799 0 : if (signum == NO_SIG)
800 : {
801 0 : sh_invalidsig (list->word->word);
802 0 : result = EXECUTION_FAILURE;
803 0 : list = list->next;
804 0 : continue;
805 : }
806 0 : printf ("%d\n", signum);
807 : }
808 0 : list = list->next;
809 : }
810 : return (result);
811 : }
812 :
813 : /* **************************************************************** */
814 : /* */
815 : /* Finding builtin commands and their functions */
816 : /* */
817 : /* **************************************************************** */
818 :
819 : /* Perform a binary search and return the address of the builtin function
820 : whose name is NAME. If the function couldn't be found, or the builtin
821 : is disabled or has no function associated with it, return NULL.
822 : Return the address of the builtin.
823 : DISABLED_OKAY means find it even if the builtin is disabled. */
824 : struct builtin *
825 437104433 : builtin_address_internal (name, disabled_okay)
826 : const char *name;
827 : int disabled_okay;
828 : {
829 437104433 : int hi, lo, mid, j;
830 :
831 437104433 : hi = num_shell_builtins - 1;
832 437104433 : lo = 0;
833 :
834 2835697661 : while (lo <= hi)
835 : {
836 2595709304 : mid = (lo + hi) / 2;
837 :
838 2595709304 : j = shell_builtins[mid].name[0] - name[0];
839 :
840 2595709304 : if (j == 0)
841 676410707 : j = strcmp (shell_builtins[mid].name, name);
842 :
843 2595709304 : if (j == 0)
844 : {
845 : /* It must have a function pointer. It must be enabled, or we
846 : must have explicitly allowed disabled functions to be found,
847 : and it must not have been deleted. */
848 197116076 : if (shell_builtins[mid].function &&
849 197109865 : ((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) &&
850 197109865 : ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay))
851 : return (&shell_builtins[mid]);
852 : else
853 6211 : return ((struct builtin *)NULL);
854 : }
855 2398593228 : if (j > 0)
856 1656698038 : hi = mid - 1;
857 : else
858 741895190 : lo = mid + 1;
859 : }
860 : return ((struct builtin *)NULL);
861 : }
862 :
863 : /* Return the pointer to the function implementing builtin command NAME. */
864 : sh_builtin_func_t *
865 61420224 : find_shell_builtin (name)
866 : char *name;
867 : {
868 61420224 : current_builtin = builtin_address_internal (name, 0);
869 61420224 : return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
870 : }
871 :
872 : /* Return the address of builtin with NAME, whether it is enabled or not. */
873 : sh_builtin_func_t *
874 560 : builtin_address (name)
875 : char *name;
876 : {
877 560 : current_builtin = builtin_address_internal (name, 1);
878 560 : return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
879 : }
880 :
881 : /* Return the function implementing the builtin NAME, but only if it is a
882 : POSIX.2 special builtin. */
883 : sh_builtin_func_t *
884 0 : find_special_builtin (name)
885 : char *name;
886 : {
887 0 : current_builtin = builtin_address_internal (name, 0);
888 0 : return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ?
889 0 : current_builtin->function :
890 : (sh_builtin_func_t *)NULL);
891 : }
892 :
893 : static int
894 3158710161 : shell_builtin_compare (sbp1, sbp2)
895 : struct builtin *sbp1, *sbp2;
896 : {
897 3158710161 : int result;
898 :
899 3158710161 : if ((result = sbp1->name[0] - sbp2->name[0]) == 0)
900 734805687 : result = strcmp (sbp1->name, sbp2->name);
901 :
902 3158710161 : return (result);
903 : }
904 :
905 : /* Sort the table of shell builtins so that the binary search will work
906 : in find_shell_builtin. */
907 : void
908 9542931 : initialize_shell_builtins ()
909 : {
910 9542931 : qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
911 : (QSFUNC *)shell_builtin_compare);
912 9542931 : }
913 :
914 : #if !defined (HELP_BUILTIN)
915 : void
916 0 : builtin_help ()
917 : {
918 0 : printf ("%s: %s\n", this_command_name, _("help not available in this version"));
919 0 : }
920 : #endif
|