]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/common.c
Bash-5.2 patch 26: fix typo when specifying readline's custom color prefix
[thirdparty/bash.git] / builtins / common.c
CommitLineData
3185942a
JA
1/* common.c - utility functions for all builtins */
2
74091dd4 3/* Copyright (C) 1987-2021 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"
d233b485 52#include "../parser.h"
726f6388
JA
53#include "../jobs.h"
54#include "../builtins.h"
55#include "../input.h"
56#include "../execute_cmd.h"
ccc6cda3 57#include "../trap.h"
ccc6cda3 58#include "bashgetopt.h"
726f6388 59#include "common.h"
d166f048 60#include "builtext.h"
726f6388
JA
61#include <tilde/tilde.h>
62
63#if defined (HISTORY)
64# include "../bashhist.h"
65#endif
66
cce855bc
JA
67#if !defined (errno)
68extern int errno;
69#endif /* !errno */
70
3185942a 71extern const char * const bash_getcwd_errstr;
726f6388 72
d166f048 73/* Used by some builtins and the mainline code. */
f73dda09
JA
74sh_builtin_func_t *last_shell_builtin = (sh_builtin_func_t *)NULL;
75sh_builtin_func_t *this_shell_builtin = (sh_builtin_func_t *)NULL;
d166f048 76
ccc6cda3
JA
77/* **************************************************************** */
78/* */
79/* Error reporting, usage, and option processing */
80/* */
81/* **************************************************************** */
726f6388
JA
82
83/* This is a lot like report_error (), but it is for shell builtins
84 instead of shell control structures, and it won't ever exit the
85 shell. */
3185942a
JA
86
87static void
88builtin_error_prolog ()
89{
90 char *name;
91
92 name = get_name_for_error ();
93 fprintf (stderr, "%s: ", name);
94
95 if (interactive_shell == 0)
96 fprintf (stderr, _("line %d: "), executing_line_number ());
97
98 if (this_command_name && *this_command_name)
99 fprintf (stderr, "%s: ", this_command_name);
100}
101
726f6388 102void
ccc6cda3
JA
103#if defined (PREFER_STDARG)
104builtin_error (const char *format, ...)
105#else
106builtin_error (format, va_alist)
107 const char *format;
726f6388 108 va_dcl
ccc6cda3 109#endif
726f6388 110{
726f6388 111 va_list args;
ccc6cda3 112
3185942a 113 builtin_error_prolog ();
726f6388 114
3185942a 115 SH_VA_START (args, format);
7117c2d2 116
3185942a
JA
117 vfprintf (stderr, format, args);
118 va_end (args);
119 fprintf (stderr, "\n");
120}
121
122void
123#if defined (PREFER_STDARG)
124builtin_warning (const char *format, ...)
125#else
126builtin_warning (format, va_alist)
127 const char *format;
128 va_dcl
129#endif
130{
131 va_list args;
132
133 builtin_error_prolog ();
134 fprintf (stderr, _("warning: "));
726f6388 135
7117c2d2 136 SH_VA_START (args, format);
ccc6cda3 137
726f6388
JA
138 vfprintf (stderr, format, args);
139 va_end (args);
140 fprintf (stderr, "\n");
141}
ccc6cda3
JA
142
143/* Print a usage summary for the currently-executing builtin command. */
144void
145builtin_usage ()
146{
147 if (this_command_name && *this_command_name)
3185942a 148 fprintf (stderr, _("%s: usage: "), this_command_name);
495aee44 149 fprintf (stderr, "%s\n", _(current_builtin->short_doc));
ccc6cda3
JA
150 fflush (stderr);
151}
152
153/* Return if LIST is NULL else barf and jump to top_level. Used by some
154 builtins that do not accept arguments. */
155void
156no_args (list)
157 WORD_LIST *list;
158{
159 if (list)
160 {
b80f6443 161 builtin_error (_("too many arguments"));
f1be666c 162 top_level_cleanup ();
ccc6cda3
JA
163 jump_to_top_level (DISCARD);
164 }
165}
166
ccc6cda3
JA
167/* Check that no options were given to the currently-executing builtin,
168 and return 0 if there were options. */
169int
170no_options (list)
171 WORD_LIST *list;
172{
a0c0a00f
CR
173 int opt;
174
ccc6cda3 175 reset_internal_getopt ();
a0c0a00f 176 if ((opt = internal_getopt (list, "")) != -1)
ccc6cda3 177 {
a0c0a00f
CR
178 if (opt == GETOPT_HELP)
179 {
180 builtin_help ();
181 return (2);
182 }
ccc6cda3
JA
183 builtin_usage ();
184 return (1);
185 }
186 return (0);
187}
188
7117c2d2
JA
189void
190sh_needarg (s)
191 char *s;
192{
b80f6443 193 builtin_error (_("%s: option requires an argument"), s);
7117c2d2
JA
194}
195
196void
197sh_neednumarg (s)
198 char *s;
199{
b80f6443 200 builtin_error (_("%s: numeric argument required"), s);
7117c2d2
JA
201}
202
203void
204sh_notfound (s)
205 char *s;
206{
b80f6443 207 builtin_error (_("%s: not found"), s);
7117c2d2
JA
208}
209
210/* Function called when one of the builtin commands detects an invalid
211 option. */
212void
213sh_invalidopt (s)
214 char *s;
215{
b80f6443 216 builtin_error (_("%s: invalid option"), s);
7117c2d2
JA
217}
218
219void
220sh_invalidoptname (s)
221 char *s;
222{
b80f6443 223 builtin_error (_("%s: invalid option name"), s);
7117c2d2
JA
224}
225
226void
227sh_invalidid (s)
228 char *s;
229{
b80f6443 230 builtin_error (_("`%s': not a valid identifier"), s);
7117c2d2
JA
231}
232
233void
234sh_invalidnum (s)
235 char *s;
236{
3185942a
JA
237 char *msg;
238
a0c0a00f 239 if (*s == '0' && isdigit ((unsigned char)s[1]))
3185942a
JA
240 msg = _("invalid octal number");
241 else if (*s == '0' && s[1] == 'x')
242 msg = _("invalid hex number");
243 else
244 msg = _("invalid number");
245 builtin_error ("%s: %s", s, msg);
7117c2d2
JA
246}
247
248void
249sh_invalidsig (s)
250 char *s;
251{
b80f6443 252 builtin_error (_("%s: invalid signal specification"), s);
7117c2d2
JA
253}
254
255void
256sh_badpid (s)
257 char *s;
258{
b80f6443 259 builtin_error (_("`%s': not a pid or valid job spec"), s);
7117c2d2
JA
260}
261
262void
263sh_readonly (s)
264 const char *s;
265{
b80f6443 266 builtin_error (_("%s: readonly variable"), s);
7117c2d2
JA
267}
268
74091dd4
CR
269void
270sh_noassign (s)
271 const char *s;
272{
273 internal_error (_("%s: cannot assign"), s); /* XXX */
274}
275
7117c2d2
JA
276void
277sh_erange (s, desc)
278 char *s, *desc;
279{
280 if (s)
b80f6443 281 builtin_error (_("%s: %s out of range"), s, desc ? desc : _("argument"));
7117c2d2 282 else
b80f6443 283 builtin_error (_("%s out of range"), desc ? desc : _("argument"));
7117c2d2
JA
284}
285
286#if defined (JOB_CONTROL)
287void
288sh_badjob (s)
289 char *s;
290{
b80f6443 291 builtin_error (_("%s: no such job"), s);
7117c2d2
JA
292}
293
294void
295sh_nojobs (s)
296 char *s;
297{
298 if (s)
b80f6443 299 builtin_error (_("%s: no job control"), s);
7117c2d2 300 else
b80f6443 301 builtin_error (_("no job control"));
7117c2d2
JA
302}
303#endif
304
305#if defined (RESTRICTED_SHELL)
306void
307sh_restricted (s)
308 char *s;
309{
310 if (s)
b80f6443 311 builtin_error (_("%s: restricted"), s);
7117c2d2 312 else
b80f6443 313 builtin_error (_("restricted"));
7117c2d2
JA
314}
315#endif
316
b80f6443
JA
317void
318sh_notbuiltin (s)
319 char *s;
320{
321 builtin_error (_("%s: not a shell builtin"), s);
322}
323
95732b49
JA
324void
325sh_wrerror ()
326{
3185942a
JA
327#if defined (DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS) && defined (EPIPE)
328 if (errno != EPIPE)
329#endif /* DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS && EPIPE */
95732b49
JA
330 builtin_error (_("write error: %s"), strerror (errno));
331}
332
17345e5a
JA
333void
334sh_ttyerror (set)
335 int set;
336{
337 if (set)
338 builtin_error (_("error setting terminal attributes: %s"), strerror (errno));
339 else
340 builtin_error (_("error getting terminal attributes: %s"), strerror (errno));
341}
342
3185942a
JA
343int
344sh_chkwrite (s)
345 int s;
346{
a0c0a00f 347 QUIT;
3185942a 348 fflush (stdout);
a0c0a00f 349 QUIT;
3185942a
JA
350 if (ferror (stdout))
351 {
352 sh_wrerror ();
353 fpurge (stdout);
354 clearerr (stdout);
355 return (EXECUTION_FAILURE);
356 }
357 return (s);
358}
359
ccc6cda3
JA
360/* **************************************************************** */
361/* */
362/* Shell positional parameter manipulation */
363/* */
364/* **************************************************************** */
365
366/* Convert a WORD_LIST into a C-style argv. Return the number of elements
367 in the list in *IP, if IP is non-null. A convenience function for
368 loadable builtins; also used by `test'. */
369char **
370make_builtin_argv (list, ip)
371 WORD_LIST *list;
372 int *ip;
373{
374 char **argv;
375
7117c2d2 376 argv = strvec_from_word_list (list, 0, 1, ip);
ccc6cda3
JA
377 argv[0] = this_command_name;
378 return argv;
379}
726f6388 380
495aee44 381/* Remember LIST in $1 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is
726f6388 382 non-zero, then discard whatever the existing arguments are, else
8868edaf
CR
383 only discard the ones that are to be replaced. Set POSPARAM_COUNT
384 to the number of args assigned (length of LIST). */
726f6388
JA
385void
386remember_args (list, destructive)
387 WORD_LIST *list;
388 int destructive;
389{
390 register int i;
391
8868edaf
CR
392 posparam_count = 0;
393
726f6388
JA
394 for (i = 1; i < 10; i++)
395 {
ccc6cda3 396 if ((destructive || list) && dollar_vars[i])
726f6388
JA
397 {
398 free (dollar_vars[i]);
399 dollar_vars[i] = (char *)NULL;
400 }
401
402 if (list)
403 {
8868edaf 404 dollar_vars[posparam_count = i] = savestring (list->word->word);
726f6388
JA
405 list = list->next;
406 }
407 }
408
409 /* If arguments remain, assign them to REST_OF_ARGS.
410 Note that copy_word_list (NULL) returns NULL, and
411 that dispose_words (NULL) does nothing. */
412 if (destructive || list)
413 {
414 dispose_words (rest_of_args);
415 rest_of_args = copy_word_list (list);
8868edaf 416 posparam_count += list_length (list);
726f6388
JA
417 }
418
419 if (destructive)
420 set_dollar_vars_changed ();
a0c0a00f
CR
421
422 invalidate_cached_quoted_dollar_at ();
726f6388
JA
423}
424
8868edaf
CR
425void
426shift_args (times)
427 int times;
428{
429 WORD_LIST *temp;
430 int count;
431
432 if (times <= 0) /* caller should check */
433 return;
434
435 while (times-- > 0)
436 {
437 if (dollar_vars[1])
438 free (dollar_vars[1]);
439
440 for (count = 1; count < 9; count++)
441 dollar_vars[count] = dollar_vars[count + 1];
442
443 if (rest_of_args)
444 {
445 temp = rest_of_args;
446 dollar_vars[9] = savestring (temp->word->word);
447 rest_of_args = rest_of_args->next;
448 temp->next = (WORD_LIST *)NULL;
449 dispose_words (temp);
450 }
451 else
452 dollar_vars[9] = (char *)NULL;
453
454 posparam_count--;
455 }
456}
457
458int
459number_of_args ()
460{
74091dd4 461#if 0
8868edaf
CR
462 register WORD_LIST *list;
463 int n;
464
465 for (n = 0; n < 9 && dollar_vars[n+1]; n++)
466 ;
467 for (list = rest_of_args; list; list = list->next)
468 n++;
469
470if (n != posparam_count)
471 itrace("number_of_args: n (%d) != posparam_count (%d)", n, posparam_count);
74091dd4 472#else
8868edaf 473 return posparam_count;
74091dd4 474#endif
8868edaf
CR
475}
476
ccc6cda3 477static int changed_dollar_vars;
726f6388
JA
478
479/* Have the dollar variables been reset to new values since we last
480 checked? */
ccc6cda3 481int
726f6388
JA
482dollar_vars_changed ()
483{
484 return (changed_dollar_vars);
485}
486
487void
488set_dollar_vars_unchanged ()
489{
490 changed_dollar_vars = 0;
491}
492
493void
494set_dollar_vars_changed ()
495{
7117c2d2
JA
496 if (variable_context)
497 changed_dollar_vars |= ARGS_FUNC;
498 else if (this_shell_builtin == set_builtin)
499 changed_dollar_vars |= ARGS_SETBLTIN;
500 else
501 changed_dollar_vars |= ARGS_INVOC;
726f6388
JA
502}
503
ccc6cda3
JA
504/* **************************************************************** */
505/* */
28ef6c31 506/* Validating numeric input and arguments */
ccc6cda3
JA
507/* */
508/* **************************************************************** */
509
510/* Read a numeric arg for this_command_name, the name of the shell builtin
511 that wants it. LIST is the word list that the arg is to come from.
512 Accept only the numeric argument; report an error if other arguments
3185942a
JA
513 follow. If FATAL is 1, call throw_to_top_level, which exits the
514 shell; if it's 2, call jump_to_top_level (DISCARD), which aborts the
515 current command; if FATAL is 0, return an indication of an invalid
516 number by setting *NUMOK == 0 and return -1. */
517int
518get_numeric_arg (list, fatal, count)
ccc6cda3 519 WORD_LIST *list;
d166f048 520 int fatal;
3185942a 521 intmax_t *count;
726f6388 522{
3185942a
JA
523 char *arg;
524
525 if (count)
526 *count = 1;
7117c2d2
JA
527
528 if (list && list->word && ISOPTION (list->word->word, '-'))
529 list = list->next;
ccc6cda3
JA
530
531 if (list)
532 {
ccc6cda3 533 arg = list->word->word;
3185942a 534 if (arg == 0 || (legal_number (arg, count) == 0))
ccc6cda3 535 {
3185942a
JA
536 sh_neednumarg (list->word->word ? list->word->word : "`'");
537 if (fatal == 0)
538 return 0;
539 else if (fatal == 1) /* fatal == 1; abort */
d166f048 540 throw_to_top_level ();
3185942a 541 else /* fatal == 2; discard current command */
f1be666c
JA
542 {
543 top_level_cleanup ();
544 jump_to_top_level (DISCARD);
545 }
ccc6cda3
JA
546 }
547 no_args (list->next);
548 }
f73dda09 549
3185942a 550 return (1);
ccc6cda3
JA
551}
552
f73dda09
JA
553/* Get an eight-bit status value from LIST */
554int
555get_exitstat (list)
556 WORD_LIST *list;
557{
558 int status;
7117c2d2 559 intmax_t sval;
f73dda09
JA
560 char *arg;
561
7117c2d2
JA
562 if (list && list->word && ISOPTION (list->word->word, '-'))
563 list = list->next;
564
565 if (list == 0)
a0c0a00f
CR
566 {
567 /* If we're not running the DEBUG trap, the return builtin, when not
568 given any arguments, uses the value of $? before the trap ran. If
569 given an argument, return uses it. This means that the trap can't
570 change $?. The DEBUG trap gets to change $?, though, since that is
571 part of its reason for existing, and because the extended debug mode
572 does things with the return value. */
573 if (this_shell_builtin == return_builtin && running_trap > 0 && running_trap != DEBUG_TRAP+1)
574 return (trap_saved_exit_value);
575 return (last_command_exit_value);
576 }
7117c2d2 577
f73dda09
JA
578 arg = list->word->word;
579 if (arg == 0 || legal_number (arg, &sval) == 0)
580 {
7117c2d2 581 sh_neednumarg (list->word->word ? list->word->word : "`'");
ac50fbac 582 return EX_BADUSAGE;
f73dda09
JA
583 }
584 no_args (list->next);
585
586 status = sval & 255;
587 return status;
588}
589
ccc6cda3
JA
590/* Return the octal number parsed from STRING, or -1 to indicate
591 that the string contained a bad number. */
592int
593read_octal (string)
594 char *string;
595{
596 int result, digits;
597
598 result = digits = 0;
28ef6c31 599 while (*string && ISOCTAL (*string))
ccc6cda3
JA
600 {
601 digits++;
28ef6c31 602 result = (result * 8) + (*string++ - '0');
d233b485 603 if (result > 07777)
f73dda09 604 return -1;
ccc6cda3
JA
605 }
606
f73dda09 607 if (digits == 0 || *string)
ccc6cda3
JA
608 result = -1;
609
610 return (result);
611}
612
ccc6cda3
JA
613/* **************************************************************** */
614/* */
615/* Manipulating the current working directory */
616/* */
617/* **************************************************************** */
618
726f6388
JA
619/* Return a consed string which is the current working directory.
620 FOR_WHOM is the name of the caller for error printing. */
621char *the_current_working_directory = (char *)NULL;
622
623char *
624get_working_directory (for_whom)
625 char *for_whom;
626{
627 if (no_symbolic_links)
628 {
b80f6443 629 FREE (the_current_working_directory);
726f6388
JA
630 the_current_working_directory = (char *)NULL;
631 }
632
ccc6cda3 633 if (the_current_working_directory == 0)
726f6388 634 {
f1be666c
JA
635#if defined (GETCWD_BROKEN)
636 the_current_working_directory = getcwd (0, PATH_MAX);
637#else
b80f6443 638 the_current_working_directory = getcwd (0, 0);
f1be666c 639#endif
b80f6443 640 if (the_current_working_directory == 0)
726f6388 641 {
b80f6443 642 fprintf (stderr, _("%s: error retrieving current directory: %s: %s\n"),
ccc6cda3 643 (for_whom && *for_whom) ? for_whom : get_name_for_error (),
b80f6443 644 _(bash_getcwd_errstr), strerror (errno));
726f6388
JA
645 return (char *)NULL;
646 }
647 }
648
649 return (savestring (the_current_working_directory));
650}
651
652/* Make NAME our internal idea of the current working directory. */
653void
654set_working_directory (name)
655 char *name;
656{
ccc6cda3 657 FREE (the_current_working_directory);
726f6388
JA
658 the_current_working_directory = savestring (name);
659}
660
ccc6cda3
JA
661/* **************************************************************** */
662/* */
663/* Job control support functions */
664/* */
665/* **************************************************************** */
666
726f6388 667#if defined (JOB_CONTROL)
7117c2d2
JA
668int
669get_job_by_name (name, flags)
670 const char *name;
671 int flags;
672{
673 register int i, wl, cl, match, job;
674 register PROCESS *p;
95732b49 675 register JOB *j;
7117c2d2
JA
676
677 job = NO_JOB;
678 wl = strlen (name);
95732b49 679 for (i = js.j_jobslots - 1; i >= 0; i--)
7117c2d2 680 {
95732b49
JA
681 j = get_job_by_jid (i);
682 if (j == 0 || ((flags & JM_STOPPED) && J_JOBSTATE(j) != JSTOPPED))
7117c2d2
JA
683 continue;
684
95732b49 685 p = j->pipe;
7117c2d2
JA
686 do
687 {
688 if (flags & JM_EXACT)
689 {
690 cl = strlen (p->command);
691 match = STREQN (p->command, name, cl);
692 }
693 else if (flags & JM_SUBSTRING)
0001803f 694 match = strcasestr (p->command, name) != (char *)0;
7117c2d2
JA
695 else
696 match = STREQN (p->command, name, wl);
697
698 if (match == 0)
699 {
700 p = p->next;
701 continue;
702 }
703 else if (flags & JM_FIRSTMATCH)
704 return i; /* return first match */
705 else if (job != NO_JOB)
706 {
707 if (this_shell_builtin)
b80f6443 708 builtin_error (_("%s: ambiguous job spec"), name);
7117c2d2 709 else
ac50fbac 710 internal_error (_("%s: ambiguous job spec"), name);
7117c2d2
JA
711 return (DUP_JOB);
712 }
713 else
714 job = i;
715 }
95732b49 716 while (p != j->pipe);
7117c2d2
JA
717 }
718
719 return (job);
720}
721
726f6388 722/* Return the job spec found in LIST. */
ccc6cda3 723int
726f6388
JA
724get_job_spec (list)
725 WORD_LIST *list;
726{
727 register char *word;
7117c2d2 728 int job, jflags;
726f6388 729
ccc6cda3 730 if (list == 0)
95732b49 731 return (js.j_current);
726f6388
JA
732
733 word = list->word->word;
734
ccc6cda3 735 if (*word == '\0')
b80f6443 736 return (NO_JOB);
726f6388
JA
737
738 if (*word == '%')
739 word++;
740
f73dda09 741 if (DIGIT (*word) && all_digits (word))
ccc6cda3
JA
742 {
743 job = atoi (word);
d233b485 744 return ((job < 0 || job > js.j_jobslots) ? NO_JOB : job - 1);
ccc6cda3 745 }
726f6388 746
7117c2d2 747 jflags = 0;
726f6388
JA
748 switch (*word)
749 {
750 case 0:
751 case '%':
752 case '+':
95732b49 753 return (js.j_current);
726f6388
JA
754
755 case '-':
95732b49 756 return (js.j_previous);
726f6388
JA
757
758 case '?': /* Substring search requested. */
7117c2d2 759 jflags |= JM_SUBSTRING;
726f6388 760 word++;
ccc6cda3 761 /* FALLTHROUGH */
726f6388
JA
762
763 default:
7117c2d2 764 return get_job_by_name (word, jflags);
726f6388
JA
765 }
766}
767#endif /* JOB_CONTROL */
768
b80f6443
JA
769/*
770 * NOTE: `kill' calls this function with forcecols == 0
771 */
726f6388 772int
ccc6cda3
JA
773display_signal_list (list, forcecols)
774 WORD_LIST *list;
775 int forcecols;
726f6388 776{
ccc6cda3
JA
777 register int i, column;
778 char *name;
b80f6443 779 int result, signum, dflags;
7117c2d2 780 intmax_t lsignum;
726f6388 781
ccc6cda3
JA
782 result = EXECUTION_SUCCESS;
783 if (!list)
726f6388 784 {
ccc6cda3
JA
785 for (i = 1, column = 0; i < NSIG; i++)
786 {
787 name = signal_name (i);
788 if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
789 continue;
726f6388 790
ccc6cda3 791 if (posixly_correct && !forcecols)
b80f6443
JA
792 {
793 /* This is for the kill builtin. POSIX.2 says the signal names
794 are displayed without the `SIG' prefix. */
795 if (STREQN (name, "SIG", 3))
796 name += 3;
797 printf ("%s%s", name, (i == NSIG - 1) ? "" : " ");
798 }
ccc6cda3
JA
799 else
800 {
801 printf ("%2d) %s", i, name);
802
3185942a 803 if (++column < 5)
ccc6cda3
JA
804 printf ("\t");
805 else
806 {
807 printf ("\n");
808 column = 0;
809 }
810 }
811 }
726f6388 812
ccc6cda3
JA
813 if ((posixly_correct && !forcecols) || column != 0)
814 printf ("\n");
815 return result;
816 }
726f6388 817
ccc6cda3
JA
818 /* List individual signal names or numbers. */
819 while (list)
726f6388 820 {
7117c2d2 821 if (legal_number (list->word->word, &lsignum))
ccc6cda3
JA
822 {
823 /* This is specified by Posix.2 so that exit statuses can be
824 mapped into signal numbers. */
7117c2d2
JA
825 if (lsignum > 128)
826 lsignum -= 128;
827 if (lsignum < 0 || lsignum >= NSIG)
ccc6cda3 828 {
7117c2d2 829 sh_invalidsig (list->word->word);
ccc6cda3
JA
830 result = EXECUTION_FAILURE;
831 list = list->next;
832 continue;
833 }
834
7117c2d2 835 signum = lsignum;
ccc6cda3
JA
836 name = signal_name (signum);
837 if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
838 {
839 list = list->next;
840 continue;
841 }
d166f048
JA
842 /* POSIX.2 says that `kill -l signum' prints the signal name without
843 the `SIG' prefix. */
d233b485 844 printf ("%s\n", (this_shell_builtin == kill_builtin && signum > 0) ? name + 3 : name);
ccc6cda3
JA
845 }
846 else
847 {
b80f6443
JA
848 dflags = DSIG_NOCASE;
849 if (posixly_correct == 0 || this_shell_builtin != kill_builtin)
850 dflags |= DSIG_SIGPREFIX;
851 signum = decode_signal (list->word->word, dflags);
ccc6cda3
JA
852 if (signum == NO_SIG)
853 {
7117c2d2 854 sh_invalidsig (list->word->word);
ccc6cda3
JA
855 result = EXECUTION_FAILURE;
856 list = list->next;
857 continue;
858 }
7117c2d2 859 printf ("%d\n", signum);
ccc6cda3
JA
860 }
861 list = list->next;
726f6388 862 }
ccc6cda3 863 return (result);
726f6388
JA
864}
865
ccc6cda3
JA
866/* **************************************************************** */
867/* */
868/* Finding builtin commands and their functions */
869/* */
870/* **************************************************************** */
871
872/* Perform a binary search and return the address of the builtin function
873 whose name is NAME. If the function couldn't be found, or the builtin
874 is disabled or has no function associated with it, return NULL.
875 Return the address of the builtin.
726f6388 876 DISABLED_OKAY means find it even if the builtin is disabled. */
ccc6cda3 877struct builtin *
726f6388
JA
878builtin_address_internal (name, disabled_okay)
879 char *name;
880 int disabled_okay;
881{
882 int hi, lo, mid, j;
883
884 hi = num_shell_builtins - 1;
885 lo = 0;
886
887 while (lo <= hi)
888 {
889 mid = (lo + hi) / 2;
890
891 j = shell_builtins[mid].name[0] - name[0];
892
893 if (j == 0)
894 j = strcmp (shell_builtins[mid].name, name);
895
896 if (j == 0)
897 {
898 /* It must have a function pointer. It must be enabled, or we
ccc6cda3
JA
899 must have explicitly allowed disabled functions to be found,
900 and it must not have been deleted. */
726f6388 901 if (shell_builtins[mid].function &&
ccc6cda3 902 ((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) &&
726f6388 903 ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay))
ccc6cda3 904 return (&shell_builtins[mid]);
726f6388 905 else
ccc6cda3 906 return ((struct builtin *)NULL);
726f6388
JA
907 }
908 if (j > 0)
909 hi = mid - 1;
910 else
911 lo = mid + 1;
912 }
ccc6cda3 913 return ((struct builtin *)NULL);
726f6388
JA
914}
915
ccc6cda3 916/* Return the pointer to the function implementing builtin command NAME. */
f73dda09 917sh_builtin_func_t *
726f6388 918find_shell_builtin (name)
ccc6cda3 919 char *name;
726f6388 920{
ccc6cda3 921 current_builtin = builtin_address_internal (name, 0);
f73dda09 922 return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
726f6388
JA
923}
924
ccc6cda3 925/* Return the address of builtin with NAME, whether it is enabled or not. */
f73dda09 926sh_builtin_func_t *
726f6388
JA
927builtin_address (name)
928 char *name;
929{
ccc6cda3 930 current_builtin = builtin_address_internal (name, 1);
f73dda09 931 return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
726f6388
JA
932}
933
ccc6cda3
JA
934/* Return the function implementing the builtin NAME, but only if it is a
935 POSIX.2 special builtin. */
f73dda09 936sh_builtin_func_t *
ccc6cda3
JA
937find_special_builtin (name)
938 char *name;
939{
940 current_builtin = builtin_address_internal (name, 0);
941 return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ?
942 current_builtin->function :
f73dda09 943 (sh_builtin_func_t *)NULL);
ccc6cda3 944}
74091dd4 945
726f6388
JA
946static int
947shell_builtin_compare (sbp1, sbp2)
948 struct builtin *sbp1, *sbp2;
949{
950 int result;
951
952 if ((result = sbp1->name[0] - sbp2->name[0]) == 0)
953 result = strcmp (sbp1->name, sbp2->name);
954
955 return (result);
956}
957
958/* Sort the table of shell builtins so that the binary search will work
959 in find_shell_builtin. */
960void
961initialize_shell_builtins ()
962{
963 qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
bb70624e 964 (QSFUNC *)shell_builtin_compare);
726f6388 965}
a0c0a00f
CR
966
967#if !defined (HELP_BUILTIN)
968void
969builtin_help ()
970{
971 printf ("%s: %s\n", this_command_name, _("help not available in this version"));
972}
973#endif
8868edaf
CR
974
975/* **************************************************************** */
976/* */
977/* Variable assignments during builtin commands */
978/* */
979/* **************************************************************** */
980
74091dd4 981/* Assign NAME=VALUE, passing FLAGS to the assignment functions. */
8868edaf
CR
982SHELL_VAR *
983builtin_bind_variable (name, value, flags)
984 char *name;
985 char *value;
986 int flags;
987{
988 SHELL_VAR *v;
74091dd4 989 int vflags, bindflags;
8868edaf
CR
990
991#if defined (ARRAY_VARS)
74091dd4
CR
992 /* Callers are responsible for calling this with array references that have
993 already undergone valid_array_reference checks (read, printf). */
994 vflags = assoc_expand_once ? (VA_NOEXPAND|VA_ONEWORD) : 0;
995 bindflags = flags | (assoc_expand_once ? ASS_NOEXPAND : 0) | ASS_ALLOWALLSUB;
996 if (flags & ASS_NOEXPAND)
997 vflags |= VA_NOEXPAND;
998 if (flags & ASS_ONEWORD)
999 vflags |= VA_ONEWORD;
1000
1001 if (valid_array_reference (name, vflags) == 0)
8868edaf
CR
1002 v = bind_variable (name, value, flags);
1003 else
74091dd4 1004 v = assign_array_element (name, value, bindflags, (array_eltstate_t *)0);
8868edaf
CR
1005#else /* !ARRAY_VARS */
1006 v = bind_variable (name, value, flags);
1007#endif /* !ARRAY_VARS */
1008
1009 if (v && readonly_p (v) == 0 && noassign_p (v) == 0)
1010 VUNSETATTR (v, att_invisible);
1011
1012 return v;
1013}
1014
74091dd4
CR
1015SHELL_VAR *
1016builtin_bind_var_to_int (name, val, flags)
1017 char *name;
1018 intmax_t val;
1019 int flags;
1020{
1021 SHELL_VAR *v;
1022
1023 v = bind_var_to_int (name, val, flags|ASS_ALLOWALLSUB);
1024 return v;
1025}
1026
1027#if defined (ARRAY_VARS)
1028SHELL_VAR *
1029builtin_find_indexed_array (array_name, flags)
1030 char *array_name;
1031 int flags;
1032{
1033 SHELL_VAR *entry;
1034
1035 if ((flags & 2) && legal_identifier (array_name) == 0)
1036 {
1037 sh_invalidid (array_name);
1038 return (SHELL_VAR *)NULL;
1039 }
1040
1041 entry = find_or_make_array_variable (array_name, 1);
1042 /* With flags argument & 1, find_or_make_array_variable checks for readonly
1043 and noassign variables and prints error messages. */
1044 if (entry == 0)
1045 return entry;
1046 else if (array_p (entry) == 0)
1047 {
1048 builtin_error (_("%s: not an indexed array"), array_name);
1049 return (SHELL_VAR *)NULL;
1050 }
1051 else if (invisible_p (entry))
1052 VUNSETATTR (entry, att_invisible); /* no longer invisible */
1053
1054 if (flags & 1)
1055 array_flush (array_cell (entry));
1056
1057 return entry;
1058}
1059#endif /* ARRAY_VARS */
1060
8868edaf
CR
1061/* Like check_unbind_variable, but for use by builtins (only matters for
1062 error messages). */
1063int
1064builtin_unbind_variable (vname)
1065 const char *vname;
1066{
1067 SHELL_VAR *v;
1068
1069 v = find_variable (vname);
1070 if (v && readonly_p (v))
1071 {
1072 builtin_error (_("%s: cannot unset: readonly %s"), vname, "variable");
1073 return -2;
1074 }
1075 else if (v && non_unsettable_p (v))
1076 {
1077 builtin_error (_("%s: cannot unset"), vname);
1078 return -2;
1079 }
1080 return (unbind_variable (vname));
1081}
74091dd4
CR
1082
1083int
1084builtin_arrayref_flags (w, baseflags)
1085 WORD_DESC *w;
1086 int baseflags;
1087{
1088 char *t;
1089 int vflags;
1090
1091 vflags = baseflags;
1092
1093 /* Don't require assoc_expand_once if we have an argument that's already
1094 passed through valid_array_reference and been expanded once. That
1095 doesn't protect it from normal expansions like word splitting, so
1096 proper quoting is still required. */
1097 if (w->flags & W_ARRAYREF)
1098 vflags |= VA_ONEWORD|VA_NOEXPAND;
1099
1100# if 0
1101 /* This is a little sketchier but handles quoted arguments. */
1102 if (assoc_expand_once && (t = strchr (w->word, '[')) && t[strlen(t) - 1] == ']')
1103 vflags |= VA_ONEWORD|VA_NOEXPAND;
1104# endif
1105
1106 return vflags;
1107}
1108
1109/* **************************************************************** */
1110/* */
1111/* External interface to manipulate shell options */
1112/* */
1113/* **************************************************************** */
1114
1115#if defined (ARRAY_VARS)
1116int
1117set_expand_once (nval, uwp)
1118 int nval, uwp;
1119{
1120 int oa;
1121
1122 oa = assoc_expand_once;
1123 if (shell_compatibility_level > 51) /* XXX - internal */
1124 {
1125 if (uwp)
1126 unwind_protect_int (assoc_expand_once);
1127 assoc_expand_once = nval;
1128 }
1129 return oa;
1130}
1131#endif