]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/common.c
Imported from ../bash-2.05a.tar.gz.
[thirdparty/bash.git] / builtins / common.c
CommitLineData
726f6388
JA
1/* Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
2
3 This file is part of GNU Bash, the Bourne Again SHell.
4
5 Bash is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free
bb70624e 7 Software Foundation; either version 2, or (at your option) any later
726f6388
JA
8 version.
9
10 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with Bash; see the file COPYING. If not, write to the Free Software
bb70624e 17 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
726f6388 18
ccc6cda3
JA
19#include <config.h>
20
21#if defined (HAVE_UNISTD_H)
cce855bc
JA
22# ifdef _MINIX
23# include <sys/types.h>
24# endif
ccc6cda3
JA
25# include <unistd.h>
26#endif
27
726f6388 28#include <stdio.h>
f73dda09 29#include <chartypes.h>
d166f048 30#include "../bashtypes.h"
bb70624e 31#include "posixstat.h"
ccc6cda3
JA
32#include <signal.h>
33
cce855bc
JA
34#include <errno.h>
35
ccc6cda3
JA
36#if defined (PREFER_STDARG)
37# include <stdarg.h>
38#else
39# if defined (PREFER_VARARGS)
40# include <varargs.h>
41# endif
42#endif
726f6388 43
ccc6cda3 44#include "../bashansi.h"
726f6388
JA
45
46#include "../shell.h"
bb70624e 47#include "maxpath.h"
ccc6cda3 48#include "../flags.h"
726f6388
JA
49#include "../jobs.h"
50#include "../builtins.h"
51#include "../input.h"
52#include "../execute_cmd.h"
ccc6cda3 53#include "../trap.h"
ccc6cda3 54#include "bashgetopt.h"
726f6388 55#include "common.h"
d166f048 56#include "builtext.h"
726f6388
JA
57#include <tilde/tilde.h>
58
59#if defined (HISTORY)
60# include "../bashhist.h"
61#endif
62
cce855bc
JA
63#if !defined (errno)
64extern int errno;
65#endif /* !errno */
66
f73dda09 67extern int no_symbolic_links;
ccc6cda3
JA
68extern int indirection_level, startup_state, subshell_environment;
69extern int line_number;
726f6388 70extern int last_command_exit_value;
ccc6cda3 71extern int running_trap;
ccc6cda3 72extern int posixly_correct;
726f6388 73extern char *this_command_name, *shell_name;
ccc6cda3 74extern char *bash_getcwd_errstr;
726f6388 75
d166f048 76/* Used by some builtins and the mainline code. */
f73dda09
JA
77sh_builtin_func_t *last_shell_builtin = (sh_builtin_func_t *)NULL;
78sh_builtin_func_t *this_shell_builtin = (sh_builtin_func_t *)NULL;
d166f048 79
ccc6cda3
JA
80/* **************************************************************** */
81/* */
82/* Error reporting, usage, and option processing */
83/* */
84/* **************************************************************** */
726f6388
JA
85
86/* This is a lot like report_error (), but it is for shell builtins
87 instead of shell control structures, and it won't ever exit the
88 shell. */
ccc6cda3 89#if defined (USE_VARARGS)
726f6388 90void
ccc6cda3
JA
91#if defined (PREFER_STDARG)
92builtin_error (const char *format, ...)
93#else
94builtin_error (format, va_alist)
95 const char *format;
726f6388 96 va_dcl
ccc6cda3 97#endif
726f6388 98{
726f6388 99 va_list args;
ccc6cda3
JA
100 char *name;
101
102 name = get_name_for_error ();
103 fprintf (stderr, "%s: ", name);
726f6388
JA
104
105 if (this_command_name && *this_command_name)
106 fprintf (stderr, "%s: ", this_command_name);
107
ccc6cda3
JA
108#if defined (PREFER_STDARG)
109 va_start (args, format);
110#else
726f6388 111 va_start (args);
ccc6cda3
JA
112#endif
113
726f6388
JA
114 vfprintf (stderr, format, args);
115 va_end (args);
116 fprintf (stderr, "\n");
117}
ccc6cda3 118#else /* !USE_VARARGS */
726f6388
JA
119void
120builtin_error (format, arg1, arg2, arg3, arg4, arg5)
121 char *format, *arg1, *arg2, *arg3, *arg4, *arg5;
122{
123 if (this_command_name && *this_command_name)
124 fprintf (stderr, "%s: ", this_command_name);
125
126 fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
127 fprintf (stderr, "\n");
128 fflush (stderr);
129}
ccc6cda3
JA
130#endif /* !USE_VARARGS */
131
132/* Print a usage summary for the currently-executing builtin command. */
133void
134builtin_usage ()
135{
136 if (this_command_name && *this_command_name)
137 fprintf (stderr, "%s: usage: ", this_command_name);
138 fprintf (stderr, "%s\n", current_builtin->short_doc);
139 fflush (stderr);
140}
141
142/* Return if LIST is NULL else barf and jump to top_level. Used by some
143 builtins that do not accept arguments. */
144void
145no_args (list)
146 WORD_LIST *list;
147{
148 if (list)
149 {
150 builtin_error ("too many arguments");
151 jump_to_top_level (DISCARD);
152 }
153}
154
155/* Function called when one of the builtin commands detects a bad
156 option. */
157void
158bad_option (s)
159 char *s;
160{
161 builtin_error ("unknown option: %s", s);
162}
163
164/* Check that no options were given to the currently-executing builtin,
165 and return 0 if there were options. */
166int
167no_options (list)
168 WORD_LIST *list;
169{
170 reset_internal_getopt ();
171 if (internal_getopt (list, "") != -1)
172 {
173 builtin_usage ();
174 return (1);
175 }
176 return (0);
177}
178
179/* **************************************************************** */
180/* */
181/* Shell positional parameter manipulation */
182/* */
183/* **************************************************************** */
184
185/* Convert a WORD_LIST into a C-style argv. Return the number of elements
186 in the list in *IP, if IP is non-null. A convenience function for
187 loadable builtins; also used by `test'. */
188char **
189make_builtin_argv (list, ip)
190 WORD_LIST *list;
191 int *ip;
192{
193 char **argv;
194
195 argv = word_list_to_argv (list, 0, 1, ip);
196 argv[0] = this_command_name;
197 return argv;
198}
726f6388
JA
199
200/* Remember LIST in $0 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is
201 non-zero, then discard whatever the existing arguments are, else
202 only discard the ones that are to be replaced. */
203void
204remember_args (list, destructive)
205 WORD_LIST *list;
206 int destructive;
207{
208 register int i;
209
210 for (i = 1; i < 10; i++)
211 {
ccc6cda3 212 if ((destructive || list) && dollar_vars[i])
726f6388
JA
213 {
214 free (dollar_vars[i]);
215 dollar_vars[i] = (char *)NULL;
216 }
217
218 if (list)
219 {
726f6388
JA
220 dollar_vars[i] = savestring (list->word->word);
221 list = list->next;
222 }
223 }
224
225 /* If arguments remain, assign them to REST_OF_ARGS.
226 Note that copy_word_list (NULL) returns NULL, and
227 that dispose_words (NULL) does nothing. */
228 if (destructive || list)
229 {
230 dispose_words (rest_of_args);
231 rest_of_args = copy_word_list (list);
232 }
233
234 if (destructive)
235 set_dollar_vars_changed ();
236}
237
726f6388
JA
238/* **************************************************************** */
239/* */
ccc6cda3 240/* Pushing and Popping variable contexts */
726f6388
JA
241/* */
242/* **************************************************************** */
243
244static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
ccc6cda3
JA
245static int dollar_arg_stack_slots;
246static int dollar_arg_stack_index;
726f6388
JA
247
248void
249push_context ()
250{
251 push_dollar_vars ();
252 variable_context++;
253}
254
255void
256pop_context ()
257{
258 pop_dollar_vars ();
259 kill_all_local_variables ();
260 variable_context--;
261}
262
263/* Save the existing positional parameters on a stack. */
264void
265push_dollar_vars ()
266{
267 if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
268 {
269 dollar_arg_stack = (WORD_LIST **)
270 xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
271 * sizeof (WORD_LIST **));
272 }
ccc6cda3
JA
273 dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args ();
274 dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
726f6388
JA
275}
276
277/* Restore the positional parameters from our stack. */
278void
279pop_dollar_vars ()
280{
ccc6cda3 281 if (!dollar_arg_stack || dollar_arg_stack_index == 0)
726f6388
JA
282 return;
283
284 remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
285 dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
286 dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
287}
288
289void
290dispose_saved_dollar_vars ()
291{
ccc6cda3 292 if (!dollar_arg_stack || dollar_arg_stack_index == 0)
726f6388
JA
293 return;
294
295 dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
296 dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
297}
298
ccc6cda3 299static int changed_dollar_vars;
726f6388
JA
300
301/* Have the dollar variables been reset to new values since we last
302 checked? */
ccc6cda3 303int
726f6388
JA
304dollar_vars_changed ()
305{
306 return (changed_dollar_vars);
307}
308
309void
310set_dollar_vars_unchanged ()
311{
312 changed_dollar_vars = 0;
313}
314
315void
316set_dollar_vars_changed ()
317{
ccc6cda3 318 changed_dollar_vars = 1;
726f6388
JA
319}
320
ccc6cda3
JA
321/* **************************************************************** */
322/* */
28ef6c31 323/* Validating numeric input and arguments */
ccc6cda3
JA
324/* */
325/* **************************************************************** */
326
327/* Read a numeric arg for this_command_name, the name of the shell builtin
328 that wants it. LIST is the word list that the arg is to come from.
329 Accept only the numeric argument; report an error if other arguments
d166f048
JA
330 follow. If FATAL is true, call throw_to_top_level, which exits the
331 shell; if not, call jump_to_top_level (DISCARD), which aborts the
332 current command. */
f73dda09 333long
d166f048 334get_numeric_arg (list, fatal)
ccc6cda3 335 WORD_LIST *list;
d166f048 336 int fatal;
726f6388 337{
ccc6cda3
JA
338 long count = 1;
339
340 if (list)
341 {
342 register char *arg;
343
344 arg = list->word->word;
345 if (!arg || (legal_number (arg, &count) == 0))
346 {
347 builtin_error ("bad non-numeric arg `%s'", list->word->word);
d166f048
JA
348 if (fatal)
349 throw_to_top_level ();
350 else
351 jump_to_top_level (DISCARD);
ccc6cda3
JA
352 }
353 no_args (list->next);
354 }
f73dda09 355
ccc6cda3
JA
356 return (count);
357}
358
f73dda09
JA
359/* Get an eight-bit status value from LIST */
360int
361get_exitstat (list)
362 WORD_LIST *list;
363{
364 int status;
365 long sval;
366 char *arg;
367
368 arg = list->word->word;
369 if (arg == 0 || legal_number (arg, &sval) == 0)
370 {
371 builtin_error ("bad non-numeric arg `%s'", list->word->word);
372 return 255;
373 }
374 no_args (list->next);
375
376 status = sval & 255;
377 return status;
378}
379
ccc6cda3
JA
380/* Return the octal number parsed from STRING, or -1 to indicate
381 that the string contained a bad number. */
382int
383read_octal (string)
384 char *string;
385{
386 int result, digits;
387
388 result = digits = 0;
28ef6c31 389 while (*string && ISOCTAL (*string))
ccc6cda3
JA
390 {
391 digits++;
28ef6c31 392 result = (result * 8) + (*string++ - '0');
f73dda09
JA
393 if (result > 0777)
394 return -1;
ccc6cda3
JA
395 }
396
f73dda09 397 if (digits == 0 || *string)
ccc6cda3
JA
398 result = -1;
399
400 return (result);
401}
402
ccc6cda3
JA
403/* **************************************************************** */
404/* */
405/* Manipulating the current working directory */
406/* */
407/* **************************************************************** */
408
726f6388
JA
409/* Return a consed string which is the current working directory.
410 FOR_WHOM is the name of the caller for error printing. */
411char *the_current_working_directory = (char *)NULL;
412
413char *
414get_working_directory (for_whom)
415 char *for_whom;
416{
ccc6cda3
JA
417 char *directory;
418
726f6388
JA
419 if (no_symbolic_links)
420 {
421 if (the_current_working_directory)
422 free (the_current_working_directory);
423
424 the_current_working_directory = (char *)NULL;
425 }
426
ccc6cda3 427 if (the_current_working_directory == 0)
726f6388 428 {
f73dda09 429 the_current_working_directory = (char *)xmalloc (PATH_MAX);
ccc6cda3
JA
430 the_current_working_directory[0] = '\0';
431 directory = getcwd (the_current_working_directory, PATH_MAX);
432 if (directory == 0)
726f6388 433 {
cce855bc 434 fprintf (stderr, "%s: could not get current directory: %s: %s\n",
ccc6cda3 435 (for_whom && *for_whom) ? for_whom : get_name_for_error (),
28ef6c31 436 bash_getcwd_errstr, strerror (errno));
726f6388
JA
437
438 free (the_current_working_directory);
439 the_current_working_directory = (char *)NULL;
440 return (char *)NULL;
441 }
442 }
443
444 return (savestring (the_current_working_directory));
445}
446
447/* Make NAME our internal idea of the current working directory. */
448void
449set_working_directory (name)
450 char *name;
451{
ccc6cda3 452 FREE (the_current_working_directory);
726f6388
JA
453 the_current_working_directory = savestring (name);
454}
455
ccc6cda3
JA
456/* **************************************************************** */
457/* */
458/* Job control support functions */
459/* */
460/* **************************************************************** */
461
726f6388
JA
462#if defined (JOB_CONTROL)
463/* Return the job spec found in LIST. */
ccc6cda3 464int
726f6388
JA
465get_job_spec (list)
466 WORD_LIST *list;
467{
468 register char *word;
f73dda09 469 int job, substring_search;
726f6388 470
ccc6cda3 471 if (list == 0)
726f6388
JA
472 return (current_job);
473
474 word = list->word->word;
475
ccc6cda3 476 if (*word == '\0')
726f6388
JA
477 return (current_job);
478
479 if (*word == '%')
480 word++;
481
f73dda09 482 if (DIGIT (*word) && all_digits (word))
ccc6cda3
JA
483 {
484 job = atoi (word);
bb70624e 485 return (job >= job_slots ? NO_JOB : job - 1);
ccc6cda3 486 }
726f6388 487
f73dda09 488 substring_search = 0;
726f6388
JA
489 switch (*word)
490 {
491 case 0:
492 case '%':
493 case '+':
494 return (current_job);
495
496 case '-':
497 return (previous_job);
498
499 case '?': /* Substring search requested. */
f73dda09 500 substring_search++;
726f6388 501 word++;
ccc6cda3 502 /* FALLTHROUGH */
726f6388
JA
503
504 default:
726f6388 505 {
ccc6cda3
JA
506 register int i, wl;
507
508 job = NO_JOB;
509 wl = strlen (word);
726f6388
JA
510 for (i = 0; i < job_slots; i++)
511 {
512 if (jobs[i])
513 {
ccc6cda3
JA
514 register PROCESS *p;
515 p = jobs[i]->pipe;
726f6388
JA
516 do
517 {
f73dda09 518 if ((substring_search && strindex (p->command, word)) ||
ccc6cda3 519 (STREQN (p->command, word, wl)))
f73dda09
JA
520 {
521 if (job != NO_JOB)
522 {
523 builtin_error ("ambigious job spec: %s", word);
524 return (DUP_JOB);
525 }
526 else
527 job = i;
528 }
726f6388
JA
529
530 p = p->next;
531 }
532 while (p != jobs[i]->pipe);
533 }
534 }
535 return (job);
536 }
537 }
538}
539#endif /* JOB_CONTROL */
540
726f6388 541int
ccc6cda3
JA
542display_signal_list (list, forcecols)
543 WORD_LIST *list;
544 int forcecols;
726f6388 545{
ccc6cda3
JA
546 register int i, column;
547 char *name;
548 int result;
549 long signum;
726f6388 550
ccc6cda3
JA
551 result = EXECUTION_SUCCESS;
552 if (!list)
726f6388 553 {
ccc6cda3
JA
554 for (i = 1, column = 0; i < NSIG; i++)
555 {
556 name = signal_name (i);
557 if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
558 continue;
726f6388 559
ccc6cda3
JA
560 if (posixly_correct && !forcecols)
561 printf ("%s%s", name, (i == NSIG - 1) ? "" : " ");
562 else
563 {
564 printf ("%2d) %s", i, name);
565
566 if (++column < 4)
567 printf ("\t");
568 else
569 {
570 printf ("\n");
571 column = 0;
572 }
573 }
574 }
726f6388 575
ccc6cda3
JA
576 if ((posixly_correct && !forcecols) || column != 0)
577 printf ("\n");
578 return result;
579 }
726f6388 580
ccc6cda3
JA
581 /* List individual signal names or numbers. */
582 while (list)
726f6388 583 {
ccc6cda3
JA
584 if (legal_number (list->word->word, &signum))
585 {
586 /* This is specified by Posix.2 so that exit statuses can be
587 mapped into signal numbers. */
588 if (signum > 128)
589 signum -= 128;
590 if (signum < 0 || signum >= NSIG)
591 {
592 builtin_error ("bad signal number: %s", list->word->word);
593 result = EXECUTION_FAILURE;
594 list = list->next;
595 continue;
596 }
597
598 name = signal_name (signum);
599 if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
600 {
601 list = list->next;
602 continue;
603 }
d166f048
JA
604#if defined (JOB_CONTROL)
605 /* POSIX.2 says that `kill -l signum' prints the signal name without
606 the `SIG' prefix. */
607 printf ("%s\n", (this_shell_builtin == kill_builtin) ? name + 3 : name);
608#else
ccc6cda3 609 printf ("%s\n", name);
d166f048 610#endif
ccc6cda3
JA
611 }
612 else
613 {
614 signum = decode_signal (list->word->word);
615 if (signum == NO_SIG)
616 {
617 builtin_error ("%s: not a signal specification", list->word->word);
618 result = EXECUTION_FAILURE;
619 list = list->next;
620 continue;
621 }
622 printf ("%ld\n", signum);
623 }
624 list = list->next;
726f6388 625 }
ccc6cda3 626 return (result);
726f6388
JA
627}
628
ccc6cda3
JA
629/* **************************************************************** */
630/* */
631/* Finding builtin commands and their functions */
632/* */
633/* **************************************************************** */
634
635/* Perform a binary search and return the address of the builtin function
636 whose name is NAME. If the function couldn't be found, or the builtin
637 is disabled or has no function associated with it, return NULL.
638 Return the address of the builtin.
726f6388 639 DISABLED_OKAY means find it even if the builtin is disabled. */
ccc6cda3 640struct builtin *
726f6388
JA
641builtin_address_internal (name, disabled_okay)
642 char *name;
643 int disabled_okay;
644{
645 int hi, lo, mid, j;
646
647 hi = num_shell_builtins - 1;
648 lo = 0;
649
650 while (lo <= hi)
651 {
652 mid = (lo + hi) / 2;
653
654 j = shell_builtins[mid].name[0] - name[0];
655
656 if (j == 0)
657 j = strcmp (shell_builtins[mid].name, name);
658
659 if (j == 0)
660 {
661 /* It must have a function pointer. It must be enabled, or we
ccc6cda3
JA
662 must have explicitly allowed disabled functions to be found,
663 and it must not have been deleted. */
726f6388 664 if (shell_builtins[mid].function &&
ccc6cda3 665 ((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) &&
726f6388 666 ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay))
ccc6cda3 667 return (&shell_builtins[mid]);
726f6388 668 else
ccc6cda3 669 return ((struct builtin *)NULL);
726f6388
JA
670 }
671 if (j > 0)
672 hi = mid - 1;
673 else
674 lo = mid + 1;
675 }
ccc6cda3 676 return ((struct builtin *)NULL);
726f6388
JA
677}
678
ccc6cda3 679/* Return the pointer to the function implementing builtin command NAME. */
f73dda09 680sh_builtin_func_t *
726f6388 681find_shell_builtin (name)
ccc6cda3 682 char *name;
726f6388 683{
ccc6cda3 684 current_builtin = builtin_address_internal (name, 0);
f73dda09 685 return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
726f6388
JA
686}
687
ccc6cda3 688/* Return the address of builtin with NAME, whether it is enabled or not. */
f73dda09 689sh_builtin_func_t *
726f6388
JA
690builtin_address (name)
691 char *name;
692{
ccc6cda3 693 current_builtin = builtin_address_internal (name, 1);
f73dda09 694 return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
726f6388
JA
695}
696
ccc6cda3
JA
697/* Return the function implementing the builtin NAME, but only if it is a
698 POSIX.2 special builtin. */
f73dda09 699sh_builtin_func_t *
ccc6cda3
JA
700find_special_builtin (name)
701 char *name;
702{
703 current_builtin = builtin_address_internal (name, 0);
704 return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ?
705 current_builtin->function :
f73dda09 706 (sh_builtin_func_t *)NULL);
ccc6cda3
JA
707}
708
726f6388
JA
709static int
710shell_builtin_compare (sbp1, sbp2)
711 struct builtin *sbp1, *sbp2;
712{
713 int result;
714
715 if ((result = sbp1->name[0] - sbp2->name[0]) == 0)
716 result = strcmp (sbp1->name, sbp2->name);
717
718 return (result);
719}
720
721/* Sort the table of shell builtins so that the binary search will work
722 in find_shell_builtin. */
723void
724initialize_shell_builtins ()
725{
726 qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
bb70624e 727 (QSFUNC *)shell_builtin_compare);
726f6388 728}