]> git.ipfire.org Git - thirdparty/bash.git/blame_incremental - builtins/common.c
updated translations; remove unneeded files
[thirdparty/bash.git] / builtins / common.c
... / ...
CommitLineData
1/* common.c - utility functions for all builtins */
2
3/* Copyright (C) 1987-2021 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 "../parser.h"
53#include "../jobs.h"
54#include "../builtins.h"
55#include "../input.h"
56#include "../execute_cmd.h"
57#include "../trap.h"
58#include "bashgetopt.h"
59#include "common.h"
60#include "builtext.h"
61#include <tilde/tilde.h>
62
63#if defined (HISTORY)
64# include "../bashhist.h"
65#endif
66
67#if !defined (errno)
68extern int errno;
69#endif /* !errno */
70
71extern const char * const bash_getcwd_errstr;
72
73/* Used by some builtins and the mainline code. */
74sh_builtin_func_t *last_shell_builtin = (sh_builtin_func_t *)NULL;
75sh_builtin_func_t *this_shell_builtin = (sh_builtin_func_t *)NULL;
76
77/* **************************************************************** */
78/* */
79/* Error reporting, usage, and option processing */
80/* */
81/* **************************************************************** */
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. */
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
102void
103#if defined (PREFER_STDARG)
104builtin_error (const char *format, ...)
105#else
106builtin_error (format, va_alist)
107 const char *format;
108 va_dcl
109#endif
110{
111 va_list args;
112
113 builtin_error_prolog ();
114
115 SH_VA_START (args, format);
116
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: "));
135
136 SH_VA_START (args, format);
137
138 vfprintf (stderr, format, args);
139 va_end (args);
140 fprintf (stderr, "\n");
141}
142
143/* Print a usage summary for the currently-executing builtin command. */
144void
145builtin_usage ()
146{
147 if (this_command_name && *this_command_name)
148 fprintf (stderr, _("%s: usage: "), this_command_name);
149 fprintf (stderr, "%s\n", _(current_builtin->short_doc));
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 {
161 builtin_error (_("too many arguments"));
162 top_level_cleanup ();
163 jump_to_top_level (DISCARD);
164 }
165}
166
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{
173 int opt;
174
175 reset_internal_getopt ();
176 if ((opt = internal_getopt (list, "")) != -1)
177 {
178 if (opt == GETOPT_HELP)
179 {
180 builtin_help ();
181 return (2);
182 }
183 builtin_usage ();
184 return (1);
185 }
186 return (0);
187}
188
189void
190sh_needarg (s)
191 char *s;
192{
193 builtin_error (_("%s: option requires an argument"), s);
194}
195
196void
197sh_neednumarg (s)
198 char *s;
199{
200 builtin_error (_("%s: numeric argument required"), s);
201}
202
203void
204sh_notfound (s)
205 char *s;
206{
207 builtin_error (_("%s: not found"), s);
208}
209
210/* Function called when one of the builtin commands detects an invalid
211 option. */
212void
213sh_invalidopt (s)
214 char *s;
215{
216 builtin_error (_("%s: invalid option"), s);
217}
218
219void
220sh_invalidoptname (s)
221 char *s;
222{
223 builtin_error (_("%s: invalid option name"), s);
224}
225
226void
227sh_invalidid (s)
228 char *s;
229{
230 builtin_error (_("`%s': not a valid identifier"), s);
231}
232
233void
234sh_invalidnum (s)
235 char *s;
236{
237 char *msg;
238
239 if (*s == '0' && isdigit ((unsigned char)s[1]))
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);
246}
247
248void
249sh_invalidsig (s)
250 char *s;
251{
252 builtin_error (_("%s: invalid signal specification"), s);
253}
254
255void
256sh_badpid (s)
257 char *s;
258{
259 builtin_error (_("`%s': not a pid or valid job spec"), s);
260}
261
262void
263sh_readonly (s)
264 const char *s;
265{
266 builtin_error (_("%s: readonly variable"), s);
267}
268
269void
270sh_noassign (s)
271 const char *s;
272{
273 internal_error (_("%s: cannot assign"), s); /* XXX */
274}
275
276void
277sh_erange (s, desc)
278 char *s, *desc;
279{
280 if (s)
281 builtin_error (_("%s: %s out of range"), s, desc ? desc : _("argument"));
282 else
283 builtin_error (_("%s out of range"), desc ? desc : _("argument"));
284}
285
286#if defined (JOB_CONTROL)
287void
288sh_badjob (s)
289 char *s;
290{
291 builtin_error (_("%s: no such job"), s);
292}
293
294void
295sh_nojobs (s)
296 char *s;
297{
298 if (s)
299 builtin_error (_("%s: no job control"), s);
300 else
301 builtin_error (_("no job control"));
302}
303#endif
304
305#if defined (RESTRICTED_SHELL)
306void
307sh_restricted (s)
308 char *s;
309{
310 if (s)
311 builtin_error (_("%s: restricted"), s);
312 else
313 builtin_error (_("restricted"));
314}
315#endif
316
317void
318sh_notbuiltin (s)
319 char *s;
320{
321 builtin_error (_("%s: not a shell builtin"), s);
322}
323
324void
325sh_wrerror ()
326{
327#if defined (DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS) && defined (EPIPE)
328 if (errno != EPIPE)
329#endif /* DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS && EPIPE */
330 builtin_error (_("write error: %s"), strerror (errno));
331}
332
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
343int
344sh_chkwrite (s)
345 int s;
346{
347 QUIT;
348 fflush (stdout);
349 QUIT;
350 if (ferror (stdout))
351 {
352 sh_wrerror ();
353 fpurge (stdout);
354 clearerr (stdout);
355 return (EXECUTION_FAILURE);
356 }
357 return (s);
358}
359
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
376 argv = strvec_from_word_list (list, 0, 1, ip);
377 argv[0] = this_command_name;
378 return argv;
379}
380
381/* Remember LIST in $1 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is
382 non-zero, then discard whatever the existing arguments are, else
383 only discard the ones that are to be replaced. Set POSPARAM_COUNT
384 to the number of args assigned (length of LIST). */
385void
386remember_args (list, destructive)
387 WORD_LIST *list;
388 int destructive;
389{
390 register int i;
391
392 posparam_count = 0;
393
394 for (i = 1; i < 10; i++)
395 {
396 if ((destructive || list) && dollar_vars[i])
397 {
398 free (dollar_vars[i]);
399 dollar_vars[i] = (char *)NULL;
400 }
401
402 if (list)
403 {
404 dollar_vars[posparam_count = i] = savestring (list->word->word);
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);
416 posparam_count += list_length (list);
417 }
418
419 if (destructive)
420 set_dollar_vars_changed ();
421
422 invalidate_cached_quoted_dollar_at ();
423}
424
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{
461#if 0
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);
472#else
473 return posparam_count;
474#endif
475}
476
477static int changed_dollar_vars;
478
479/* Have the dollar variables been reset to new values since we last
480 checked? */
481int
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{
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;
502}
503
504/* **************************************************************** */
505/* */
506/* Validating numeric input and arguments */
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
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)
519 WORD_LIST *list;
520 int fatal;
521 intmax_t *count;
522{
523 char *arg;
524
525 if (count)
526 *count = 1;
527
528 if (list && list->word && ISOPTION (list->word->word, '-'))
529 list = list->next;
530
531 if (list)
532 {
533 arg = list->word->word;
534 if (arg == 0 || (legal_number (arg, count) == 0))
535 {
536 sh_neednumarg (list->word->word ? list->word->word : "`'");
537 if (fatal == 0)
538 return 0;
539 else if (fatal == 1) /* fatal == 1; abort */
540 throw_to_top_level ();
541 else /* fatal == 2; discard current command */
542 {
543 top_level_cleanup ();
544 jump_to_top_level (DISCARD);
545 }
546 }
547 no_args (list->next);
548 }
549
550 return (1);
551}
552
553/* Get an eight-bit status value from LIST */
554int
555get_exitstat (list)
556 WORD_LIST *list;
557{
558 int status;
559 intmax_t sval;
560 char *arg;
561
562 if (list && list->word && ISOPTION (list->word->word, '-'))
563 list = list->next;
564
565 if (list == 0)
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 }
577
578 arg = list->word->word;
579 if (arg == 0 || legal_number (arg, &sval) == 0)
580 {
581 sh_neednumarg (list->word->word ? list->word->word : "`'");
582 return EX_BADUSAGE;
583 }
584 no_args (list->next);
585
586 status = sval & 255;
587 return status;
588}
589
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;
599 while (*string && ISOCTAL (*string))
600 {
601 digits++;
602 result = (result * 8) + (*string++ - '0');
603 if (result > 07777)
604 return -1;
605 }
606
607 if (digits == 0 || *string)
608 result = -1;
609
610 return (result);
611}
612
613/* **************************************************************** */
614/* */
615/* Manipulating the current working directory */
616/* */
617/* **************************************************************** */
618
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 {
629 FREE (the_current_working_directory);
630 the_current_working_directory = (char *)NULL;
631 }
632
633 if (the_current_working_directory == 0)
634 {
635#if defined (GETCWD_BROKEN)
636 the_current_working_directory = getcwd (0, PATH_MAX);
637#else
638 the_current_working_directory = getcwd (0, 0);
639#endif
640 if (the_current_working_directory == 0)
641 {
642 fprintf (stderr, _("%s: error retrieving current directory: %s: %s\n"),
643 (for_whom && *for_whom) ? for_whom : get_name_for_error (),
644 _(bash_getcwd_errstr), strerror (errno));
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{
657 FREE (the_current_working_directory);
658 the_current_working_directory = savestring (name);
659}
660
661/* **************************************************************** */
662/* */
663/* Job control support functions */
664/* */
665/* **************************************************************** */
666
667#if defined (JOB_CONTROL)
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;
675 register JOB *j;
676
677 job = NO_JOB;
678 wl = strlen (name);
679 for (i = js.j_jobslots - 1; i >= 0; i--)
680 {
681 j = get_job_by_jid (i);
682 if (j == 0 || ((flags & JM_STOPPED) && J_JOBSTATE(j) != JSTOPPED))
683 continue;
684
685 p = j->pipe;
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)
694 match = strcasestr (p->command, name) != (char *)0;
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)
708 builtin_error (_("%s: ambiguous job spec"), name);
709 else
710 internal_error (_("%s: ambiguous job spec"), name);
711 return (DUP_JOB);
712 }
713 else
714 job = i;
715 }
716 while (p != j->pipe);
717 }
718
719 return (job);
720}
721
722/* Return the job spec found in LIST. */
723int
724get_job_spec (list)
725 WORD_LIST *list;
726{
727 register char *word;
728 int job, jflags;
729
730 if (list == 0)
731 return (js.j_current);
732
733 word = list->word->word;
734
735 if (*word == '\0')
736 return (NO_JOB);
737
738 if (*word == '%')
739 word++;
740
741 if (DIGIT (*word) && all_digits (word))
742 {
743 job = atoi (word);
744 return ((job < 0 || job > js.j_jobslots) ? NO_JOB : job - 1);
745 }
746
747 jflags = 0;
748 switch (*word)
749 {
750 case 0:
751 case '%':
752 case '+':
753 return (js.j_current);
754
755 case '-':
756 return (js.j_previous);
757
758 case '?': /* Substring search requested. */
759 jflags |= JM_SUBSTRING;
760 word++;
761 /* FALLTHROUGH */
762
763 default:
764 return get_job_by_name (word, jflags);
765 }
766}
767#endif /* JOB_CONTROL */
768
769/*
770 * NOTE: `kill' calls this function with forcecols == 0
771 */
772int
773display_signal_list (list, forcecols)
774 WORD_LIST *list;
775 int forcecols;
776{
777 register int i, column;
778 char *name;
779 int result, signum, dflags;
780 intmax_t lsignum;
781
782 result = EXECUTION_SUCCESS;
783 if (!list)
784 {
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;
790
791 if (posixly_correct && !forcecols)
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 }
799 else
800 {
801 printf ("%2d) %s", i, name);
802
803 if (++column < 5)
804 printf ("\t");
805 else
806 {
807 printf ("\n");
808 column = 0;
809 }
810 }
811 }
812
813 if ((posixly_correct && !forcecols) || column != 0)
814 printf ("\n");
815 return result;
816 }
817
818 /* List individual signal names or numbers. */
819 while (list)
820 {
821 if (legal_number (list->word->word, &lsignum))
822 {
823 /* This is specified by Posix.2 so that exit statuses can be
824 mapped into signal numbers. */
825 if (lsignum > 128)
826 lsignum -= 128;
827 if (lsignum < 0 || lsignum >= NSIG)
828 {
829 sh_invalidsig (list->word->word);
830 result = EXECUTION_FAILURE;
831 list = list->next;
832 continue;
833 }
834
835 signum = lsignum;
836 name = signal_name (signum);
837 if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
838 {
839 list = list->next;
840 continue;
841 }
842 /* POSIX.2 says that `kill -l signum' prints the signal name without
843 the `SIG' prefix. */
844 printf ("%s\n", (this_shell_builtin == kill_builtin && signum > 0) ? name + 3 : name);
845 }
846 else
847 {
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);
852 if (signum == NO_SIG)
853 {
854 sh_invalidsig (list->word->word);
855 result = EXECUTION_FAILURE;
856 list = list->next;
857 continue;
858 }
859 printf ("%d\n", signum);
860 }
861 list = list->next;
862 }
863 return (result);
864}
865
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.
876 DISABLED_OKAY means find it even if the builtin is disabled. */
877struct builtin *
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
899 must have explicitly allowed disabled functions to be found,
900 and it must not have been deleted. */
901 if (shell_builtins[mid].function &&
902 ((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) &&
903 ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay))
904 return (&shell_builtins[mid]);
905 else
906 return ((struct builtin *)NULL);
907 }
908 if (j > 0)
909 hi = mid - 1;
910 else
911 lo = mid + 1;
912 }
913 return ((struct builtin *)NULL);
914}
915
916/* Return the pointer to the function implementing builtin command NAME. */
917sh_builtin_func_t *
918find_shell_builtin (name)
919 char *name;
920{
921 current_builtin = builtin_address_internal (name, 0);
922 return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
923}
924
925/* Return the address of builtin with NAME, whether it is enabled or not. */
926sh_builtin_func_t *
927builtin_address (name)
928 char *name;
929{
930 current_builtin = builtin_address_internal (name, 1);
931 return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
932}
933
934/* Return the function implementing the builtin NAME, but only if it is a
935 POSIX.2 special builtin. */
936sh_builtin_func_t *
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 :
943 (sh_builtin_func_t *)NULL);
944}
945
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),
964 (QSFUNC *)shell_builtin_compare);
965}
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
974
975/* **************************************************************** */
976/* */
977/* Variable assignments during builtin commands */
978/* */
979/* **************************************************************** */
980
981/* Assign NAME=VALUE, passing FLAGS to the assignment functions. */
982SHELL_VAR *
983builtin_bind_variable (name, value, flags)
984 char *name;
985 char *value;
986 int flags;
987{
988 SHELL_VAR *v;
989 int vflags, bindflags;
990
991#if defined (ARRAY_VARS)
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)
1002 v = bind_variable (name, value, flags);
1003 else
1004 v = assign_array_element (name, value, bindflags, (array_eltstate_t *)0);
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
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
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}
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