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