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