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 113377 : builtin_error_prolog ()
95 : {
96 113377 : char *name;
97 :
98 113377 : name = get_name_for_error ();
99 113377 : fprintf (stderr, "%s: ", name);
100 :
101 113377 : if (interactive_shell == 0)
102 113377 : fprintf (stderr, _("line %d: "), executing_line_number ());
103 :
104 113377 : if (this_command_name && *this_command_name)
105 113377 : fprintf (stderr, "%s: ", this_command_name);
106 113377 : }
107 :
108 : void
109 : #if defined (PREFER_STDARG)
110 113302 : builtin_error (const char *format, ...)
111 : #else
112 : builtin_error (format, va_alist)
113 : const char *format;
114 : va_dcl
115 : #endif
116 : {
117 113302 : va_list args;
118 :
119 113302 : builtin_error_prolog ();
120 :
121 113302 : SH_VA_START (args, format);
122 :
123 113302 : vfprintf (stderr, format, args);
124 113302 : va_end (args);
125 113302 : fprintf (stderr, "\n");
126 113302 : }
127 :
128 : void
129 : #if defined (PREFER_STDARG)
130 75 : builtin_warning (const char *format, ...)
131 : #else
132 : builtin_warning (format, va_alist)
133 : const char *format;
134 : va_dcl
135 : #endif
136 : {
137 75 : va_list args;
138 :
139 75 : builtin_error_prolog ();
140 75 : fprintf (stderr, _("warning: "));
141 :
142 75 : SH_VA_START (args, format);
143 :
144 75 : vfprintf (stderr, format, args);
145 75 : va_end (args);
146 75 : fprintf (stderr, "\n");
147 75 : }
148 :
149 : /* Print a usage summary for the currently-executing builtin command. */
150 : void
151 523 : builtin_usage ()
152 : {
153 523 : if (this_command_name && *this_command_name)
154 523 : fprintf (stderr, _("%s: usage: "), this_command_name);
155 523 : fprintf (stderr, "%s\n", _(current_builtin->short_doc));
156 523 : fflush (stderr);
157 523 : }
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 6741113 : no_args (list)
163 : WORD_LIST *list;
164 : {
165 6741113 : if (list)
166 : {
167 169 : builtin_error (_("too many arguments"));
168 169 : top_level_cleanup ();
169 169 : jump_to_top_level (DISCARD);
170 : }
171 6740944 : }
172 :
173 : /* Check that no options were given to the currently-executing builtin,
174 : and return 0 if there were options. */
175 : int
176 16846898 : no_options (list)
177 : WORD_LIST *list;
178 : {
179 16846898 : int opt;
180 :
181 16846898 : reset_internal_getopt ();
182 16846898 : if ((opt = internal_getopt (list, "")) != -1)
183 : {
184 87 : if (opt == GETOPT_HELP)
185 : {
186 0 : builtin_help ();
187 0 : return (2);
188 : }
189 87 : builtin_usage ();
190 87 : 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 30341 : sh_neednumarg (s)
204 : char *s;
205 : {
206 30341 : builtin_error (_("%s: numeric argument required"), s);
207 30341 : }
208 :
209 : void
210 182 : sh_notfound (s)
211 : char *s;
212 : {
213 182 : builtin_error (_("%s: not found"), s);
214 182 : }
215 :
216 : /* Function called when one of the builtin commands detects an invalid
217 : option. */
218 : void
219 87 : sh_invalidopt (s)
220 : char *s;
221 : {
222 87 : builtin_error (_("%s: invalid option"), s);
223 87 : }
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 153 : sh_invalidid (s)
234 : char *s;
235 : {
236 153 : builtin_error (_("`%s': not a valid identifier"), s);
237 153 : }
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 75 : sh_invalidsig (s)
256 : char *s;
257 : {
258 75 : builtin_error (_("%s: invalid signal specification"), s);
259 75 : }
260 :
261 : void
262 45 : sh_badpid (s)
263 : char *s;
264 : {
265 45 : builtin_error (_("`%s': not a pid or valid job spec"), s);
266 45 : }
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 678 : sh_badjob (s)
288 : char *s;
289 : {
290 678 : builtin_error (_("%s: no such job"), s);
291 678 : }
292 :
293 : void
294 595 : sh_nojobs (s)
295 : char *s;
296 : {
297 595 : if (s)
298 50 : builtin_error (_("%s: no job control"), s);
299 : else
300 545 : builtin_error (_("no job control"));
301 595 : }
302 : #endif
303 :
304 : #if defined (RESTRICTED_SHELL)
305 : void
306 0 : sh_restricted (s)
307 : char *s;
308 : {
309 0 : if (s)
310 0 : builtin_error (_("%s: restricted"), s);
311 : else
312 0 : builtin_error (_("restricted"));
313 0 : }
314 : #endif
315 :
316 : void
317 66 : sh_notbuiltin (s)
318 : char *s;
319 : {
320 66 : builtin_error (_("%s: not a shell builtin"), s);
321 66 : }
322 :
323 : void
324 106 : 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 106 : builtin_error (_("write error: %s"), strerror (errno));
330 106 : }
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 1910114 : sh_chkwrite (s)
344 : int s;
345 : {
346 1910114 : QUIT;
347 1910114 : fflush (stdout);
348 1910114 : QUIT;
349 1910114 : if (ferror (stdout))
350 : {
351 106 : sh_wrerror ();
352 106 : fpurge (stdout);
353 106 : clearerr (stdout);
354 106 : 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 24005772 : make_builtin_argv (list, ip)
370 : WORD_LIST *list;
371 : int *ip;
372 : {
373 24005772 : char **argv;
374 :
375 24005772 : argv = strvec_from_word_list (list, 0, 1, ip);
376 24005772 : argv[0] = this_command_name;
377 24005772 : 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 28414 : remember_args (list, destructive)
385 : WORD_LIST *list;
386 : int destructive;
387 : {
388 28414 : register int i;
389 :
390 284140 : for (i = 1; i < 10; i++)
391 : {
392 255726 : if ((destructive || list) && dollar_vars[i])
393 : {
394 17708 : free (dollar_vars[i]);
395 17708 : dollar_vars[i] = (char *)NULL;
396 : }
397 :
398 255726 : if (list)
399 : {
400 17789 : dollar_vars[i] = savestring (list->word->word);
401 17789 : 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 28414 : if (destructive || list)
409 : {
410 28414 : dispose_words (rest_of_args);
411 28414 : rest_of_args = copy_word_list (list);
412 : }
413 :
414 28414 : if (destructive)
415 28414 : set_dollar_vars_changed ();
416 :
417 28414 : invalidate_cached_quoted_dollar_at ();
418 28414 : }
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 6790 : dollar_vars_changed ()
426 : {
427 6790 : return (changed_dollar_vars);
428 : }
429 :
430 : void
431 16867063 : set_dollar_vars_unchanged ()
432 : {
433 16867063 : changed_dollar_vars = 0;
434 16867063 : }
435 :
436 : void
437 0 : set_dollar_vars_changed ()
438 : {
439 28414 : if (variable_context)
440 14807 : changed_dollar_vars |= ARGS_FUNC;
441 13607 : else if (this_shell_builtin == set_builtin)
442 0 : changed_dollar_vars |= ARGS_SETBLTIN;
443 : else
444 13607 : 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 101 : get_numeric_arg (list, fatal, count)
462 : WORD_LIST *list;
463 : int fatal;
464 : intmax_t *count;
465 : {
466 101 : char *arg;
467 :
468 101 : if (count)
469 101 : *count = 1;
470 :
471 101 : if (list && list->word && ISOPTION (list->word->word, '-'))
472 0 : list = list->next;
473 :
474 101 : if (list)
475 : {
476 45 : arg = list->word->word;
477 45 : if (arg == 0 || (legal_number (arg, count) == 0))
478 : {
479 70 : sh_neednumarg (list->word->word ? list->word->word : "`'");
480 35 : 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 10 : no_args (list->next);
491 : }
492 :
493 : return (1);
494 : }
495 :
496 : /* Get an eight-bit status value from LIST */
497 : int
498 6881805 : get_exitstat (list)
499 : WORD_LIST *list;
500 : {
501 6881805 : int status;
502 6881805 : intmax_t sval;
503 6881805 : char *arg;
504 :
505 6881805 : if (list && list->word && ISOPTION (list->word->word, '-'))
506 9 : list = list->next;
507 :
508 6881805 : 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 110396 : if (this_shell_builtin == return_builtin && running_trap > 0 && running_trap != DEBUG_TRAP+1)
517 0 : return (trap_saved_exit_value);
518 110396 : return (last_command_exit_value);
519 : }
520 :
521 6771409 : arg = list->word->word;
522 6771409 : if (arg == 0 || legal_number (arg, &sval) == 0)
523 : {
524 30306 : sh_neednumarg (list->word->word ? list->word->word : "`'");
525 30306 : return EX_BADUSAGE;
526 : }
527 6741103 : no_args (list->next);
528 :
529 6740934 : status = sval & 255;
530 6740934 : 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 9143282 : set_working_directory (name)
598 : char *name;
599 : {
600 9143282 : FREE (the_current_working_directory);
601 9143282 : the_current_working_directory = savestring (name);
602 9143282 : }
603 :
604 : /* **************************************************************** */
605 : /* */
606 : /* Job control support functions */
607 : /* */
608 : /* **************************************************************** */
609 :
610 : #if defined (JOB_CONTROL)
611 : int
612 660 : get_job_by_name (name, flags)
613 : const char *name;
614 : int flags;
615 : {
616 660 : register int i, wl, cl, match, job;
617 660 : register PROCESS *p;
618 660 : register JOB *j;
619 :
620 660 : job = NO_JOB;
621 660 : wl = strlen (name);
622 1660 : for (i = js.j_jobslots - 1; i >= 0; i--)
623 : {
624 1000 : j = get_job_by_jid (i);
625 1000 : 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 678 : get_job_spec (list)
668 : WORD_LIST *list;
669 : {
670 678 : register char *word;
671 678 : int job, jflags;
672 :
673 678 : if (list == 0)
674 0 : return (js.j_current);
675 :
676 678 : word = list->word->word;
677 :
678 678 : if (*word == '\0')
679 : return (NO_JOB);
680 :
681 678 : if (*word == '%')
682 0 : word++;
683 :
684 678 : if (DIGIT (*word) && all_digits (word))
685 : {
686 18 : job = atoi (word);
687 18 : return (job > js.j_jobslots ? NO_JOB : job - 1);
688 : }
689 :
690 660 : jflags = 0;
691 660 : 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 660 : default:
707 660 : 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 408730381 : builtin_address_internal (name, disabled_okay)
826 : const char *name;
827 : int disabled_okay;
828 : {
829 408730381 : int hi, lo, mid, j;
830 :
831 408730381 : hi = num_shell_builtins - 1;
832 408730381 : lo = 0;
833 :
834 2654551723 : while (lo <= hi)
835 : {
836 2434577175 : mid = (lo + hi) / 2;
837 :
838 2434577175 : j = shell_builtins[mid].name[0] - name[0];
839 :
840 2434577175 : if (j == 0)
841 718262788 : j = strcmp (shell_builtins[mid].name, name);
842 :
843 2434577175 : 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 188755833 : if (shell_builtins[mid].function &&
849 188749758 : ((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) &&
850 188749758 : ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay))
851 : return (&shell_builtins[mid]);
852 : else
853 6075 : return ((struct builtin *)NULL);
854 : }
855 2245821342 : if (j > 0)
856 1429077945 : hi = mid - 1;
857 : else
858 816743397 : 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 56778785 : find_shell_builtin (name)
866 : char *name;
867 : {
868 56778785 : current_builtin = builtin_address_internal (name, 0);
869 56778785 : 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 534 : builtin_address (name)
875 : char *name;
876 : {
877 534 : current_builtin = builtin_address_internal (name, 1);
878 534 : 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 3337296661 : shell_builtin_compare (sbp1, sbp2)
895 : struct builtin *sbp1, *sbp2;
896 : {
897 3337296661 : int result;
898 :
899 3337296661 : if ((result = sbp1->name[0] - sbp2->name[0]) == 0)
900 859468427 : result = strcmp (sbp1->name, sbp2->name);
901 :
902 3337296661 : 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 9143282 : initialize_shell_builtins ()
909 : {
910 9143282 : qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
911 : (QSFUNC *)shell_builtin_compare);
912 9143282 : }
913 :
914 : #if !defined (HELP_BUILTIN)
915 : void
916 : builtin_help ()
917 : {
918 : printf ("%s: %s\n", this_command_name, _("help not available in this version"));
919 : }
920 : #endif
|