]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/common.c
Imported from ../bash-2.0.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
7 Software Foundation; either version 1, or (at your option) any later
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
17 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
18
ccc6cda3
JA
19#include <config.h>
20
21#if defined (HAVE_UNISTD_H)
22# include <unistd.h>
23#endif
24
726f6388
JA
25#include <stdio.h>
26#include <sys/types.h>
27#include "../posixstat.h"
ccc6cda3
JA
28#include <signal.h>
29
30#if defined (PREFER_STDARG)
31# include <stdarg.h>
32#else
33# if defined (PREFER_VARARGS)
34# include <varargs.h>
35# endif
36#endif
726f6388 37
ccc6cda3 38#include "../bashansi.h"
726f6388
JA
39
40#include "../shell.h"
726f6388 41#include "../maxpath.h"
ccc6cda3 42#include "../flags.h"
726f6388
JA
43#include "../jobs.h"
44#include "../builtins.h"
45#include "../input.h"
46#include "../execute_cmd.h"
ccc6cda3 47#include "../trap.h"
726f6388 48#include "hashcom.h"
ccc6cda3 49#include "bashgetopt.h"
726f6388
JA
50#include "common.h"
51#include <tilde/tilde.h>
52
53#if defined (HISTORY)
54# include "../bashhist.h"
55#endif
56
57extern int no_symbolic_links, interactive, interactive_shell;
ccc6cda3
JA
58extern int indirection_level, startup_state, subshell_environment;
59extern int line_number;
726f6388 60extern int last_command_exit_value;
ccc6cda3
JA
61extern int running_trap;
62extern int hashing_enabled;
726f6388 63extern int variable_context;
ccc6cda3 64extern int posixly_correct;
726f6388
JA
65extern char *this_command_name, *shell_name;
66extern COMMAND *global_command;
67extern HASH_TABLE *hashed_filenames;
ccc6cda3 68extern char *bash_getcwd_errstr;
726f6388 69
ccc6cda3
JA
70/* **************************************************************** */
71/* */
72/* Error reporting, usage, and option processing */
73/* */
74/* **************************************************************** */
726f6388
JA
75
76/* This is a lot like report_error (), but it is for shell builtins
77 instead of shell control structures, and it won't ever exit the
78 shell. */
ccc6cda3 79#if defined (USE_VARARGS)
726f6388 80void
ccc6cda3
JA
81#if defined (PREFER_STDARG)
82builtin_error (const char *format, ...)
83#else
84builtin_error (format, va_alist)
85 const char *format;
726f6388 86 va_dcl
ccc6cda3 87#endif
726f6388 88{
726f6388 89 va_list args;
ccc6cda3
JA
90 char *name;
91
92 name = get_name_for_error ();
93 fprintf (stderr, "%s: ", name);
726f6388
JA
94
95 if (this_command_name && *this_command_name)
96 fprintf (stderr, "%s: ", this_command_name);
97
ccc6cda3
JA
98#if defined (PREFER_STDARG)
99 va_start (args, format);
100#else
726f6388 101 va_start (args);
ccc6cda3
JA
102#endif
103
726f6388
JA
104 vfprintf (stderr, format, args);
105 va_end (args);
106 fprintf (stderr, "\n");
107}
ccc6cda3 108#else /* !USE_VARARGS */
726f6388
JA
109void
110builtin_error (format, arg1, arg2, arg3, arg4, arg5)
111 char *format, *arg1, *arg2, *arg3, *arg4, *arg5;
112{
113 if (this_command_name && *this_command_name)
114 fprintf (stderr, "%s: ", this_command_name);
115
116 fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
117 fprintf (stderr, "\n");
118 fflush (stderr);
119}
ccc6cda3
JA
120#endif /* !USE_VARARGS */
121
122/* Print a usage summary for the currently-executing builtin command. */
123void
124builtin_usage ()
125{
126 if (this_command_name && *this_command_name)
127 fprintf (stderr, "%s: usage: ", this_command_name);
128 fprintf (stderr, "%s\n", current_builtin->short_doc);
129 fflush (stderr);
130}
131
132/* Return if LIST is NULL else barf and jump to top_level. Used by some
133 builtins that do not accept arguments. */
134void
135no_args (list)
136 WORD_LIST *list;
137{
138 if (list)
139 {
140 builtin_error ("too many arguments");
141 jump_to_top_level (DISCARD);
142 }
143}
144
145/* Function called when one of the builtin commands detects a bad
146 option. */
147void
148bad_option (s)
149 char *s;
150{
151 builtin_error ("unknown option: %s", s);
152}
153
154/* Check that no options were given to the currently-executing builtin,
155 and return 0 if there were options. */
156int
157no_options (list)
158 WORD_LIST *list;
159{
160 reset_internal_getopt ();
161 if (internal_getopt (list, "") != -1)
162 {
163 builtin_usage ();
164 return (1);
165 }
166 return (0);
167}
168
169/* **************************************************************** */
170/* */
171/* Shell positional parameter manipulation */
172/* */
173/* **************************************************************** */
174
175/* Convert a WORD_LIST into a C-style argv. Return the number of elements
176 in the list in *IP, if IP is non-null. A convenience function for
177 loadable builtins; also used by `test'. */
178char **
179make_builtin_argv (list, ip)
180 WORD_LIST *list;
181 int *ip;
182{
183 char **argv;
184
185 argv = word_list_to_argv (list, 0, 1, ip);
186 argv[0] = this_command_name;
187 return argv;
188}
726f6388
JA
189
190/* Remember LIST in $0 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is
191 non-zero, then discard whatever the existing arguments are, else
192 only discard the ones that are to be replaced. */
193void
194remember_args (list, destructive)
195 WORD_LIST *list;
196 int destructive;
197{
198 register int i;
199
200 for (i = 1; i < 10; i++)
201 {
ccc6cda3 202 if ((destructive || list) && dollar_vars[i])
726f6388
JA
203 {
204 free (dollar_vars[i]);
205 dollar_vars[i] = (char *)NULL;
206 }
207
208 if (list)
209 {
726f6388
JA
210 dollar_vars[i] = savestring (list->word->word);
211 list = list->next;
212 }
213 }
214
215 /* If arguments remain, assign them to REST_OF_ARGS.
216 Note that copy_word_list (NULL) returns NULL, and
217 that dispose_words (NULL) does nothing. */
218 if (destructive || list)
219 {
220 dispose_words (rest_of_args);
221 rest_of_args = copy_word_list (list);
222 }
223
224 if (destructive)
225 set_dollar_vars_changed ();
226}
227
726f6388
JA
228/* **************************************************************** */
229/* */
ccc6cda3 230/* Pushing and Popping variable contexts */
726f6388
JA
231/* */
232/* **************************************************************** */
233
234static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
ccc6cda3
JA
235static int dollar_arg_stack_slots;
236static int dollar_arg_stack_index;
726f6388
JA
237
238void
239push_context ()
240{
241 push_dollar_vars ();
242 variable_context++;
243}
244
245void
246pop_context ()
247{
248 pop_dollar_vars ();
249 kill_all_local_variables ();
250 variable_context--;
251}
252
253/* Save the existing positional parameters on a stack. */
254void
255push_dollar_vars ()
256{
257 if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
258 {
259 dollar_arg_stack = (WORD_LIST **)
260 xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
261 * sizeof (WORD_LIST **));
262 }
ccc6cda3
JA
263 dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args ();
264 dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
726f6388
JA
265}
266
267/* Restore the positional parameters from our stack. */
268void
269pop_dollar_vars ()
270{
ccc6cda3 271 if (!dollar_arg_stack || dollar_arg_stack_index == 0)
726f6388
JA
272 return;
273
274 remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
275 dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
276 dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
277}
278
279void
280dispose_saved_dollar_vars ()
281{
ccc6cda3 282 if (!dollar_arg_stack || dollar_arg_stack_index == 0)
726f6388
JA
283 return;
284
285 dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
286 dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
287}
288
ccc6cda3 289static int changed_dollar_vars;
726f6388
JA
290
291/* Have the dollar variables been reset to new values since we last
292 checked? */
ccc6cda3 293int
726f6388
JA
294dollar_vars_changed ()
295{
296 return (changed_dollar_vars);
297}
298
299void
300set_dollar_vars_unchanged ()
301{
302 changed_dollar_vars = 0;
303}
304
305void
306set_dollar_vars_changed ()
307{
ccc6cda3 308 changed_dollar_vars = 1;
726f6388
JA
309}
310
ccc6cda3
JA
311/* **************************************************************** */
312/* */
313/* Validating numeric input and arguments */
314/* */
315/* **************************************************************** */
316
317/* Read a numeric arg for this_command_name, the name of the shell builtin
318 that wants it. LIST is the word list that the arg is to come from.
319 Accept only the numeric argument; report an error if other arguments
320 follow. */
321int
322get_numeric_arg (list)
323 WORD_LIST *list;
726f6388 324{
ccc6cda3
JA
325 long count = 1;
326
327 if (list)
328 {
329 register char *arg;
330
331 arg = list->word->word;
332 if (!arg || (legal_number (arg, &count) == 0))
333 {
334 builtin_error ("bad non-numeric arg `%s'", list->word->word);
335 throw_to_top_level ();
336 }
337 no_args (list->next);
338 }
339 return (count);
340}
341
342/* Return the octal number parsed from STRING, or -1 to indicate
343 that the string contained a bad number. */
344int
345read_octal (string)
346 char *string;
347{
348 int result, digits;
349
350 result = digits = 0;
351 while (*string && *string >= '0' && *string < '8')
352 {
353 digits++;
354 result = (result * 8) + *string++ - '0';
355 }
356
357 if (!digits || result > 0777 || *string)
358 result = -1;
359
360 return (result);
361}
362
363/* **************************************************************** */
364/* */
365/* Command name hashing */
366/* */
367/* **************************************************************** */
368
369/* Return the full pathname that FILENAME hashes to. If FILENAME
370 is hashed, but (data->flags & HASH_CHKDOT) is non-zero, check
371 ./FILENAME and return that if it is executable. */
372char *
373find_hashed_filename (filename)
374 char *filename;
375{
376 register BUCKET_CONTENTS *item;
377 char *path, *dotted_filename, *tail;
378 int same;
379
380 if (hashing_enabled == 0)
381 return ((char *)NULL);
382
383 item = find_hash_item (filename, hashed_filenames);
384
385 if (item == NULL)
386 return ((char *)NULL);
387
388 /* If this filename is hashed, but `.' comes before it in the path,
389 see if ./filename is executable. If the hashed value is not an
390 absolute pathname, see if ./`hashed-value' exists. */
391 path = pathdata(item)->path;
392 if (pathdata(item)->flags & (HASH_CHKDOT|HASH_RELPATH))
393 {
394 tail = (pathdata(item)->flags & HASH_RELPATH) ? path : filename;
395 dotted_filename = xmalloc (3 + strlen (tail));
396 dotted_filename[0] = '.'; dotted_filename[1] = '/';
397 strcpy (dotted_filename + 2, tail);
398
399 if (executable_file (dotted_filename))
400 return (dotted_filename);
401
402 free (dotted_filename);
403
404#if 0
405 if (pathdata(item)->flags & HASH_RELPATH)
406 return ((char *)NULL);
407#endif
408
409 /* Watch out. If this file was hashed to "./filename", and
410 "./filename" is not executable, then return NULL. */
411
412 /* Since we already know "./filename" is not executable, what
413 we're really interested in is whether or not the `path'
414 portion of the hashed filename is equivalent to the current
415 directory, but only if it starts with a `.'. (This catches
416 ./. and so on.) same_file () tests general Unix file
417 equivalence -- same device and inode. */
418 if (*path == '.')
419 {
420 same = 0;
421 tail = (char *)strrchr (path, '/');
422
423 if (tail)
424 {
425 *tail = '\0';
426 same = same_file (".", path, (struct stat *)NULL, (struct stat *)NULL);
427 *tail = '/';
428 }
429
430 return same ? (char *)NULL : path;
431 }
432 }
433
434 return (path);
726f6388
JA
435}
436
ccc6cda3
JA
437/* **************************************************************** */
438/* */
439/* Manipulating the current working directory */
440/* */
441/* **************************************************************** */
442
726f6388
JA
443/* Return a consed string which is the current working directory.
444 FOR_WHOM is the name of the caller for error printing. */
445char *the_current_working_directory = (char *)NULL;
446
447char *
448get_working_directory (for_whom)
449 char *for_whom;
450{
ccc6cda3
JA
451 char *directory;
452
726f6388
JA
453 if (no_symbolic_links)
454 {
455 if (the_current_working_directory)
456 free (the_current_working_directory);
457
458 the_current_working_directory = (char *)NULL;
459 }
460
ccc6cda3 461 if (the_current_working_directory == 0)
726f6388 462 {
ccc6cda3
JA
463 the_current_working_directory = xmalloc (PATH_MAX);
464 the_current_working_directory[0] = '\0';
465 directory = getcwd (the_current_working_directory, PATH_MAX);
466 if (directory == 0)
726f6388 467 {
ccc6cda3
JA
468 fprintf (stderr, "%s: could not get current directory: %s\n",
469 (for_whom && *for_whom) ? for_whom : get_name_for_error (),
470 the_current_working_directory[0]
471 ? the_current_working_directory
472 : bash_getcwd_errstr);
726f6388
JA
473
474 free (the_current_working_directory);
475 the_current_working_directory = (char *)NULL;
476 return (char *)NULL;
477 }
478 }
479
480 return (savestring (the_current_working_directory));
481}
482
483/* Make NAME our internal idea of the current working directory. */
484void
485set_working_directory (name)
486 char *name;
487{
ccc6cda3 488 FREE (the_current_working_directory);
726f6388
JA
489 the_current_working_directory = savestring (name);
490}
491
ccc6cda3
JA
492/* **************************************************************** */
493/* */
494/* Job control support functions */
495/* */
496/* **************************************************************** */
497
726f6388
JA
498#if defined (JOB_CONTROL)
499/* Return the job spec found in LIST. */
ccc6cda3 500int
726f6388
JA
501get_job_spec (list)
502 WORD_LIST *list;
503{
504 register char *word;
ccc6cda3 505 int job, substring;
726f6388 506
ccc6cda3 507 if (list == 0)
726f6388
JA
508 return (current_job);
509
510 word = list->word->word;
511
ccc6cda3 512 if (*word == '\0')
726f6388
JA
513 return (current_job);
514
515 if (*word == '%')
516 word++;
517
ccc6cda3
JA
518 if (digit (*word) && all_digits (word))
519 {
520 job = atoi (word);
521 return (job - 1);
522 }
726f6388 523
ccc6cda3 524 substring = 0;
726f6388
JA
525 switch (*word)
526 {
527 case 0:
528 case '%':
529 case '+':
530 return (current_job);
531
532 case '-':
533 return (previous_job);
534
535 case '?': /* Substring search requested. */
536 substring++;
537 word++;
ccc6cda3 538 /* FALLTHROUGH */
726f6388
JA
539
540 default:
726f6388 541 {
ccc6cda3
JA
542 register int i, wl;
543
544 job = NO_JOB;
545 wl = strlen (word);
726f6388
JA
546 for (i = 0; i < job_slots; i++)
547 {
548 if (jobs[i])
549 {
ccc6cda3
JA
550 register PROCESS *p;
551 p = jobs[i]->pipe;
726f6388
JA
552 do
553 {
554 if ((substring && strindex (p->command, word)) ||
ccc6cda3 555 (STREQN (p->command, word, wl)))
726f6388
JA
556 if (job != NO_JOB)
557 {
558 builtin_error ("ambigious job spec: %s", word);
559 return (DUP_JOB);
560 }
561 else
562 job = i;
563
564 p = p->next;
565 }
566 while (p != jobs[i]->pipe);
567 }
568 }
569 return (job);
570 }
571 }
572}
573#endif /* JOB_CONTROL */
574
726f6388 575int
ccc6cda3
JA
576display_signal_list (list, forcecols)
577 WORD_LIST *list;
578 int forcecols;
726f6388 579{
ccc6cda3
JA
580 register int i, column;
581 char *name;
582 int result;
583 long signum;
726f6388 584
ccc6cda3
JA
585 result = EXECUTION_SUCCESS;
586 if (!list)
726f6388 587 {
ccc6cda3
JA
588 for (i = 1, column = 0; i < NSIG; i++)
589 {
590 name = signal_name (i);
591 if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
592 continue;
726f6388 593
ccc6cda3
JA
594 if (posixly_correct && !forcecols)
595 printf ("%s%s", name, (i == NSIG - 1) ? "" : " ");
596 else
597 {
598 printf ("%2d) %s", i, name);
599
600 if (++column < 4)
601 printf ("\t");
602 else
603 {
604 printf ("\n");
605 column = 0;
606 }
607 }
608 }
726f6388 609
ccc6cda3
JA
610 if ((posixly_correct && !forcecols) || column != 0)
611 printf ("\n");
612 return result;
613 }
726f6388 614
ccc6cda3
JA
615 /* List individual signal names or numbers. */
616 while (list)
726f6388 617 {
ccc6cda3
JA
618 if (legal_number (list->word->word, &signum))
619 {
620 /* This is specified by Posix.2 so that exit statuses can be
621 mapped into signal numbers. */
622 if (signum > 128)
623 signum -= 128;
624 if (signum < 0 || signum >= NSIG)
625 {
626 builtin_error ("bad signal number: %s", list->word->word);
627 result = EXECUTION_FAILURE;
628 list = list->next;
629 continue;
630 }
631
632 name = signal_name (signum);
633 if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
634 {
635 list = list->next;
636 continue;
637 }
638 printf ("%s\n", name);
639 }
640 else
641 {
642 signum = decode_signal (list->word->word);
643 if (signum == NO_SIG)
644 {
645 builtin_error ("%s: not a signal specification", list->word->word);
646 result = EXECUTION_FAILURE;
647 list = list->next;
648 continue;
649 }
650 printf ("%ld\n", signum);
651 }
652 list = list->next;
726f6388 653 }
ccc6cda3 654 return (result);
726f6388
JA
655}
656
ccc6cda3
JA
657/* **************************************************************** */
658/* */
659/* Finding builtin commands and their functions */
660/* */
661/* **************************************************************** */
662
663/* Perform a binary search and return the address of the builtin function
664 whose name is NAME. If the function couldn't be found, or the builtin
665 is disabled or has no function associated with it, return NULL.
666 Return the address of the builtin.
726f6388 667 DISABLED_OKAY means find it even if the builtin is disabled. */
ccc6cda3 668struct builtin *
726f6388
JA
669builtin_address_internal (name, disabled_okay)
670 char *name;
671 int disabled_okay;
672{
673 int hi, lo, mid, j;
674
675 hi = num_shell_builtins - 1;
676 lo = 0;
677
678 while (lo <= hi)
679 {
680 mid = (lo + hi) / 2;
681
682 j = shell_builtins[mid].name[0] - name[0];
683
684 if (j == 0)
685 j = strcmp (shell_builtins[mid].name, name);
686
687 if (j == 0)
688 {
689 /* It must have a function pointer. It must be enabled, or we
ccc6cda3
JA
690 must have explicitly allowed disabled functions to be found,
691 and it must not have been deleted. */
726f6388 692 if (shell_builtins[mid].function &&
ccc6cda3 693 ((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) &&
726f6388 694 ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay))
ccc6cda3 695 return (&shell_builtins[mid]);
726f6388 696 else
ccc6cda3 697 return ((struct builtin *)NULL);
726f6388
JA
698 }
699 if (j > 0)
700 hi = mid - 1;
701 else
702 lo = mid + 1;
703 }
ccc6cda3 704 return ((struct builtin *)NULL);
726f6388
JA
705}
706
ccc6cda3 707/* Return the pointer to the function implementing builtin command NAME. */
726f6388
JA
708Function *
709find_shell_builtin (name)
ccc6cda3 710 char *name;
726f6388 711{
ccc6cda3
JA
712 current_builtin = builtin_address_internal (name, 0);
713 return (current_builtin ? current_builtin->function : (Function *)NULL);
726f6388
JA
714}
715
ccc6cda3 716/* Return the address of builtin with NAME, whether it is enabled or not. */
726f6388
JA
717Function *
718builtin_address (name)
719 char *name;
720{
ccc6cda3
JA
721 current_builtin = builtin_address_internal (name, 1);
722 return (current_builtin ? current_builtin->function : (Function *)NULL);
726f6388
JA
723}
724
ccc6cda3
JA
725/* Return the function implementing the builtin NAME, but only if it is a
726 POSIX.2 special builtin. */
727Function *
728find_special_builtin (name)
729 char *name;
730{
731 current_builtin = builtin_address_internal (name, 0);
732 return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ?
733 current_builtin->function :
734 (Function *)NULL);
735}
736
726f6388
JA
737static int
738shell_builtin_compare (sbp1, sbp2)
739 struct builtin *sbp1, *sbp2;
740{
741 int result;
742
743 if ((result = sbp1->name[0] - sbp2->name[0]) == 0)
744 result = strcmp (sbp1->name, sbp2->name);
745
746 return (result);
747}
748
749/* Sort the table of shell builtins so that the binary search will work
750 in find_shell_builtin. */
751void
752initialize_shell_builtins ()
753{
754 qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
755 shell_builtin_compare);
756}
757
ccc6cda3
JA
758/* **************************************************************** */
759/* */
760/* Functions for quoting strings to be re-read as input */
761/* */
762/* **************************************************************** */
763
764/* Return a new string which is the single-quoted version of STRING.
765 Used by alias and trap, among others. */
726f6388
JA
766char *
767single_quote (string)
768 char *string;
769{
ccc6cda3
JA
770 register int c;
771 char *result, *r, *s;
726f6388 772
ccc6cda3
JA
773 result = (char *)xmalloc (3 + (4 * strlen (string)));
774 r = result;
775 *r++ = '\'';
726f6388 776
ccc6cda3 777 for (s = string; s && (c = *s); s++)
726f6388 778 {
ccc6cda3 779 *r++ = c;
726f6388
JA
780
781 if (c == '\'')
782 {
ccc6cda3
JA
783 *r++ = '\\'; /* insert escaped single quote */
784 *r++ = '\'';
785 *r++ = '\''; /* start new quoted string */
726f6388
JA
786 }
787 }
788
ccc6cda3
JA
789 *r++ = '\'';
790 *r = '\0';
726f6388
JA
791
792 return (result);
793}
794
ccc6cda3 795/* Quote STRING using double quotes. Return a new string. */
726f6388
JA
796char *
797double_quote (string)
798 char *string;
799{
ccc6cda3
JA
800 register int c;
801 char *result, *r, *s;
726f6388 802
ccc6cda3
JA
803 result = (char *)xmalloc (3 + (2 * strlen (string)));
804 r = result;
805 *r++ = '"';
726f6388 806
ccc6cda3 807 for (s = string; s && (c = *s); s++)
726f6388
JA
808 {
809 switch (c)
810 {
811 case '"':
812 case '$':
813 case '`':
814 case '\\':
ccc6cda3 815 *r++ = '\\';
726f6388 816 default:
ccc6cda3 817 *r++ = c;
726f6388
JA
818 break;
819 }
820 }
821
ccc6cda3
JA
822 *r++ = '"';
823 *r = '\0';
726f6388
JA
824
825 return (result);
826}
ccc6cda3
JA
827
828/* Quote special characters in STRING using backslashes. Return a new
829 string. */
830char *
831backslash_quote (string)
832 char *string;
833{
834 int c;
835 char *result, *r, *s;
836
837 result = xmalloc (2 * strlen (string) + 1);
838
839 for (r = result, s = string; s && (c = *s); s++)
840 {
841 switch (c)
842 {
843 case ' ': case '\t': case '\n': /* IFS white space */
844 case '\'': case '"': case '\\': /* quoting chars */
845 case '|': case '&': case ';': /* shell metacharacters */
846 case '(': case ')': case '<': case '>':
847 case '!': case '{': case '}': /* reserved words */
848 case '*': case '[': case '?': case ']': /* globbing chars */
849 case '^':
850 case '$': case '`': /* expansion chars */
851 *r++ = '\\';
852 *r++ = c;
853 break;
854 case '#': /* comment char */
855 if (s == string)
856 *r++ = '\\';
857 /* FALLTHROUGH */
858 default:
859 *r++ = c;
860 break;
861 }
862 }
863
864 *r = '\0';
865 return (result);
866}
867
868int
869contains_shell_metas (string)
870 char *string;
871{
872 char *s;
873
874 for (s = string; s && *s; s++)
875 {
876 switch (*s)
877 {
878 case ' ': case '\t': case '\n': /* IFS white space */
879 case '\'': case '"': case '\\': /* quoting chars */
880 case '|': case '&': case ';': /* shell metacharacters */
881 case '(': case ')': case '<': case '>':
882 case '!': case '{': case '}': /* reserved words */
883 case '*': case '[': case '?': case ']': /* globbing chars */
884 case '^':
885 case '$': case '`': /* expansion chars */
886 return (1);
887 case '#':
888 if (s == string) /* comment char */
889 return (1);
890 /* FALLTHROUGH */
891 default:
892 break;
893 }
894 }
895
896 return (0);
897}