i-bash/builtins/common.c

898 lines
21 KiB
C
Raw Normal View History

1996-08-26 18:22:31 +00:00
/* Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
1996-12-23 17:02:34 +00:00
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
1996-08-26 18:22:31 +00:00
#include <stdio.h>
#include <sys/types.h>
#include "../posixstat.h"
1996-12-23 17:02:34 +00:00
#include <signal.h>
#if defined (PREFER_STDARG)
# include <stdarg.h>
#else
# if defined (PREFER_VARARGS)
# include <varargs.h>
# endif
#endif
1996-08-26 18:22:31 +00:00
1996-12-23 17:02:34 +00:00
#include "../bashansi.h"
1996-08-26 18:22:31 +00:00
#include "../shell.h"
#include "../maxpath.h"
1996-12-23 17:02:34 +00:00
#include "../flags.h"
1996-08-26 18:22:31 +00:00
#include "../jobs.h"
#include "../builtins.h"
#include "../input.h"
#include "../execute_cmd.h"
1996-12-23 17:02:34 +00:00
#include "../trap.h"
1996-08-26 18:22:31 +00:00
#include "hashcom.h"
1996-12-23 17:02:34 +00:00
#include "bashgetopt.h"
1996-08-26 18:22:31 +00:00
#include "common.h"
#include <tilde/tilde.h>
#if defined (HISTORY)
# include "../bashhist.h"
#endif
extern int no_symbolic_links, interactive, interactive_shell;
1996-12-23 17:02:34 +00:00
extern int indirection_level, startup_state, subshell_environment;
extern int line_number;
1996-08-26 18:22:31 +00:00
extern int last_command_exit_value;
1996-12-23 17:02:34 +00:00
extern int running_trap;
extern int hashing_enabled;
1996-08-26 18:22:31 +00:00
extern int variable_context;
1996-12-23 17:02:34 +00:00
extern int posixly_correct;
1996-08-26 18:22:31 +00:00
extern char *this_command_name, *shell_name;
extern COMMAND *global_command;
extern HASH_TABLE *hashed_filenames;
1996-12-23 17:02:34 +00:00
extern char *bash_getcwd_errstr;
1996-08-26 18:22:31 +00:00
1996-12-23 17:02:34 +00:00
/* **************************************************************** */
/* */
/* Error reporting, usage, and option processing */
/* */
/* **************************************************************** */
1996-08-26 18:22:31 +00:00
/* This is a lot like report_error (), but it is for shell builtins
instead of shell control structures, and it won't ever exit the
shell. */
1996-12-23 17:02:34 +00:00
#if defined (USE_VARARGS)
1996-08-26 18:22:31 +00:00
void
1996-12-23 17:02:34 +00:00
#if defined (PREFER_STDARG)
builtin_error (const char *format, ...)
#else
builtin_error (format, va_alist)
const char *format;
1996-08-26 18:22:31 +00:00
va_dcl
1996-12-23 17:02:34 +00:00
#endif
1996-08-26 18:22:31 +00:00
{
va_list args;
1996-12-23 17:02:34 +00:00
char *name;
name = get_name_for_error ();
fprintf (stderr, "%s: ", name);
1996-08-26 18:22:31 +00:00
if (this_command_name && *this_command_name)
fprintf (stderr, "%s: ", this_command_name);
1996-12-23 17:02:34 +00:00
#if defined (PREFER_STDARG)
va_start (args, format);
#else
1996-08-26 18:22:31 +00:00
va_start (args);
1996-12-23 17:02:34 +00:00
#endif
1996-08-26 18:22:31 +00:00
vfprintf (stderr, format, args);
va_end (args);
fprintf (stderr, "\n");
}
1996-12-23 17:02:34 +00:00
#else /* !USE_VARARGS */
1996-08-26 18:22:31 +00:00
void
builtin_error (format, arg1, arg2, arg3, arg4, arg5)
char *format, *arg1, *arg2, *arg3, *arg4, *arg5;
{
if (this_command_name && *this_command_name)
fprintf (stderr, "%s: ", this_command_name);
fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
fprintf (stderr, "\n");
fflush (stderr);
}
1996-12-23 17:02:34 +00:00
#endif /* !USE_VARARGS */
/* Print a usage summary for the currently-executing builtin command. */
void
builtin_usage ()
{
if (this_command_name && *this_command_name)
fprintf (stderr, "%s: usage: ", this_command_name);
fprintf (stderr, "%s\n", current_builtin->short_doc);
fflush (stderr);
}
/* Return if LIST is NULL else barf and jump to top_level. Used by some
builtins that do not accept arguments. */
void
no_args (list)
WORD_LIST *list;
{
if (list)
{
builtin_error ("too many arguments");
jump_to_top_level (DISCARD);
}
}
/* Function called when one of the builtin commands detects a bad
option. */
void
bad_option (s)
char *s;
{
builtin_error ("unknown option: %s", s);
}
/* Check that no options were given to the currently-executing builtin,
and return 0 if there were options. */
int
no_options (list)
WORD_LIST *list;
{
reset_internal_getopt ();
if (internal_getopt (list, "") != -1)
{
builtin_usage ();
return (1);
}
return (0);
}
/* **************************************************************** */
/* */
/* Shell positional parameter manipulation */
/* */
/* **************************************************************** */
/* Convert a WORD_LIST into a C-style argv. Return the number of elements
in the list in *IP, if IP is non-null. A convenience function for
loadable builtins; also used by `test'. */
char **
make_builtin_argv (list, ip)
WORD_LIST *list;
int *ip;
{
char **argv;
argv = word_list_to_argv (list, 0, 1, ip);
argv[0] = this_command_name;
return argv;
}
1996-08-26 18:22:31 +00:00
/* Remember LIST in $0 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is
non-zero, then discard whatever the existing arguments are, else
only discard the ones that are to be replaced. */
void
remember_args (list, destructive)
WORD_LIST *list;
int destructive;
{
register int i;
for (i = 1; i < 10; i++)
{
1996-12-23 17:02:34 +00:00
if ((destructive || list) && dollar_vars[i])
1996-08-26 18:22:31 +00:00
{
free (dollar_vars[i]);
dollar_vars[i] = (char *)NULL;
}
if (list)
{
dollar_vars[i] = savestring (list->word->word);
list = list->next;
}
}
/* If arguments remain, assign them to REST_OF_ARGS.
Note that copy_word_list (NULL) returns NULL, and
that dispose_words (NULL) does nothing. */
if (destructive || list)
{
dispose_words (rest_of_args);
rest_of_args = copy_word_list (list);
}
if (destructive)
set_dollar_vars_changed ();
}
/* **************************************************************** */
/* */
1996-12-23 17:02:34 +00:00
/* Pushing and Popping variable contexts */
1996-08-26 18:22:31 +00:00
/* */
/* **************************************************************** */
static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
1996-12-23 17:02:34 +00:00
static int dollar_arg_stack_slots;
static int dollar_arg_stack_index;
1996-08-26 18:22:31 +00:00
void
push_context ()
{
push_dollar_vars ();
variable_context++;
}
void
pop_context ()
{
pop_dollar_vars ();
kill_all_local_variables ();
variable_context--;
}
/* Save the existing positional parameters on a stack. */
void
push_dollar_vars ()
{
if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
{
dollar_arg_stack = (WORD_LIST **)
xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
* sizeof (WORD_LIST **));
}
1996-12-23 17:02:34 +00:00
dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args ();
dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
1996-08-26 18:22:31 +00:00
}
/* Restore the positional parameters from our stack. */
void
pop_dollar_vars ()
{
1996-12-23 17:02:34 +00:00
if (!dollar_arg_stack || dollar_arg_stack_index == 0)
1996-08-26 18:22:31 +00:00
return;
remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
}
void
dispose_saved_dollar_vars ()
{
1996-12-23 17:02:34 +00:00
if (!dollar_arg_stack || dollar_arg_stack_index == 0)
1996-08-26 18:22:31 +00:00
return;
dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
}
1996-12-23 17:02:34 +00:00
static int changed_dollar_vars;
1996-08-26 18:22:31 +00:00
/* Have the dollar variables been reset to new values since we last
checked? */
1996-12-23 17:02:34 +00:00
int
1996-08-26 18:22:31 +00:00
dollar_vars_changed ()
{
return (changed_dollar_vars);
}
void
set_dollar_vars_unchanged ()
{
changed_dollar_vars = 0;
}
void
set_dollar_vars_changed ()
{
1996-12-23 17:02:34 +00:00
changed_dollar_vars = 1;
1996-08-26 18:22:31 +00:00
}
1996-12-23 17:02:34 +00:00
/* **************************************************************** */
/* */
/* Validating numeric input and arguments */
/* */
/* **************************************************************** */
/* Read a numeric arg for this_command_name, the name of the shell builtin
that wants it. LIST is the word list that the arg is to come from.
Accept only the numeric argument; report an error if other arguments
follow. */
int
get_numeric_arg (list)
WORD_LIST *list;
1996-08-26 18:22:31 +00:00
{
1996-12-23 17:02:34 +00:00
long count = 1;
if (list)
{
register char *arg;
arg = list->word->word;
if (!arg || (legal_number (arg, &count) == 0))
{
builtin_error ("bad non-numeric arg `%s'", list->word->word);
throw_to_top_level ();
}
no_args (list->next);
}
return (count);
}
/* Return the octal number parsed from STRING, or -1 to indicate
that the string contained a bad number. */
int
read_octal (string)
char *string;
{
int result, digits;
result = digits = 0;
while (*string && *string >= '0' && *string < '8')
{
digits++;
result = (result * 8) + *string++ - '0';
}
if (!digits || result > 0777 || *string)
result = -1;
return (result);
}
/* **************************************************************** */
/* */
/* Command name hashing */
/* */
/* **************************************************************** */
/* Return the full pathname that FILENAME hashes to. If FILENAME
is hashed, but (data->flags & HASH_CHKDOT) is non-zero, check
./FILENAME and return that if it is executable. */
char *
find_hashed_filename (filename)
char *filename;
{
register BUCKET_CONTENTS *item;
char *path, *dotted_filename, *tail;
int same;
if (hashing_enabled == 0)
return ((char *)NULL);
item = find_hash_item (filename, hashed_filenames);
if (item == NULL)
return ((char *)NULL);
/* If this filename is hashed, but `.' comes before it in the path,
see if ./filename is executable. If the hashed value is not an
absolute pathname, see if ./`hashed-value' exists. */
path = pathdata(item)->path;
if (pathdata(item)->flags & (HASH_CHKDOT|HASH_RELPATH))
{
tail = (pathdata(item)->flags & HASH_RELPATH) ? path : filename;
dotted_filename = xmalloc (3 + strlen (tail));
dotted_filename[0] = '.'; dotted_filename[1] = '/';
strcpy (dotted_filename + 2, tail);
if (executable_file (dotted_filename))
return (dotted_filename);
free (dotted_filename);
#if 0
if (pathdata(item)->flags & HASH_RELPATH)
return ((char *)NULL);
#endif
/* Watch out. If this file was hashed to "./filename", and
"./filename" is not executable, then return NULL. */
/* Since we already know "./filename" is not executable, what
we're really interested in is whether or not the `path'
portion of the hashed filename is equivalent to the current
directory, but only if it starts with a `.'. (This catches
./. and so on.) same_file () tests general Unix file
equivalence -- same device and inode. */
if (*path == '.')
{
same = 0;
tail = (char *)strrchr (path, '/');
if (tail)
{
*tail = '\0';
same = same_file (".", path, (struct stat *)NULL, (struct stat *)NULL);
*tail = '/';
}
return same ? (char *)NULL : path;
}
}
return (path);
1996-08-26 18:22:31 +00:00
}
1996-12-23 17:02:34 +00:00
/* **************************************************************** */
/* */
/* Manipulating the current working directory */
/* */
/* **************************************************************** */
1996-08-26 18:22:31 +00:00
/* Return a consed string which is the current working directory.
FOR_WHOM is the name of the caller for error printing. */
char *the_current_working_directory = (char *)NULL;
char *
get_working_directory (for_whom)
char *for_whom;
{
1996-12-23 17:02:34 +00:00
char *directory;
1996-08-26 18:22:31 +00:00
if (no_symbolic_links)
{
if (the_current_working_directory)
free (the_current_working_directory);
the_current_working_directory = (char *)NULL;
}
1996-12-23 17:02:34 +00:00
if (the_current_working_directory == 0)
1996-08-26 18:22:31 +00:00
{
1996-12-23 17:02:34 +00:00
the_current_working_directory = xmalloc (PATH_MAX);
the_current_working_directory[0] = '\0';
directory = getcwd (the_current_working_directory, PATH_MAX);
if (directory == 0)
1996-08-26 18:22:31 +00:00
{
1996-12-23 17:02:34 +00:00
fprintf (stderr, "%s: could not get current directory: %s\n",
(for_whom && *for_whom) ? for_whom : get_name_for_error (),
the_current_working_directory[0]
? the_current_working_directory
: bash_getcwd_errstr);
1996-08-26 18:22:31 +00:00
free (the_current_working_directory);
the_current_working_directory = (char *)NULL;
return (char *)NULL;
}
}
return (savestring (the_current_working_directory));
}
/* Make NAME our internal idea of the current working directory. */
void
set_working_directory (name)
char *name;
{
1996-12-23 17:02:34 +00:00
FREE (the_current_working_directory);
1996-08-26 18:22:31 +00:00
the_current_working_directory = savestring (name);
}
1996-12-23 17:02:34 +00:00
/* **************************************************************** */
/* */
/* Job control support functions */
/* */
/* **************************************************************** */
1996-08-26 18:22:31 +00:00
#if defined (JOB_CONTROL)
/* Return the job spec found in LIST. */
1996-12-23 17:02:34 +00:00
int
1996-08-26 18:22:31 +00:00
get_job_spec (list)
WORD_LIST *list;
{
register char *word;
1996-12-23 17:02:34 +00:00
int job, substring;
1996-08-26 18:22:31 +00:00
1996-12-23 17:02:34 +00:00
if (list == 0)
1996-08-26 18:22:31 +00:00
return (current_job);
word = list->word->word;
1996-12-23 17:02:34 +00:00
if (*word == '\0')
1996-08-26 18:22:31 +00:00
return (current_job);
if (*word == '%')
word++;
1996-12-23 17:02:34 +00:00
if (digit (*word) && all_digits (word))
{
job = atoi (word);
return (job - 1);
}
1996-08-26 18:22:31 +00:00
1996-12-23 17:02:34 +00:00
substring = 0;
1996-08-26 18:22:31 +00:00
switch (*word)
{
case 0:
case '%':
case '+':
return (current_job);
case '-':
return (previous_job);
case '?': /* Substring search requested. */
substring++;
word++;
1996-12-23 17:02:34 +00:00
/* FALLTHROUGH */
1996-08-26 18:22:31 +00:00
default:
{
1996-12-23 17:02:34 +00:00
register int i, wl;
job = NO_JOB;
wl = strlen (word);
1996-08-26 18:22:31 +00:00
for (i = 0; i < job_slots; i++)
{
if (jobs[i])
{
1996-12-23 17:02:34 +00:00
register PROCESS *p;
p = jobs[i]->pipe;
1996-08-26 18:22:31 +00:00
do
{
if ((substring && strindex (p->command, word)) ||
1996-12-23 17:02:34 +00:00
(STREQN (p->command, word, wl)))
1996-08-26 18:22:31 +00:00
if (job != NO_JOB)
{
builtin_error ("ambigious job spec: %s", word);
return (DUP_JOB);
}
else
job = i;
p = p->next;
}
while (p != jobs[i]->pipe);
}
}
return (job);
}
}
}
#endif /* JOB_CONTROL */
int
1996-12-23 17:02:34 +00:00
display_signal_list (list, forcecols)
WORD_LIST *list;
int forcecols;
1996-08-26 18:22:31 +00:00
{
1996-12-23 17:02:34 +00:00
register int i, column;
char *name;
int result;
long signum;
1996-08-26 18:22:31 +00:00
1996-12-23 17:02:34 +00:00
result = EXECUTION_SUCCESS;
if (!list)
1996-08-26 18:22:31 +00:00
{
1996-12-23 17:02:34 +00:00
for (i = 1, column = 0; i < NSIG; i++)
{
name = signal_name (i);
if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
continue;
1996-08-26 18:22:31 +00:00
1996-12-23 17:02:34 +00:00
if (posixly_correct && !forcecols)
printf ("%s%s", name, (i == NSIG - 1) ? "" : " ");
else
{
printf ("%2d) %s", i, name);
if (++column < 4)
printf ("\t");
else
{
printf ("\n");
column = 0;
}
}
}
1996-08-26 18:22:31 +00:00
1996-12-23 17:02:34 +00:00
if ((posixly_correct && !forcecols) || column != 0)
printf ("\n");
return result;
}
1996-08-26 18:22:31 +00:00
1996-12-23 17:02:34 +00:00
/* List individual signal names or numbers. */
while (list)
1996-08-26 18:22:31 +00:00
{
1996-12-23 17:02:34 +00:00
if (legal_number (list->word->word, &signum))
{
/* This is specified by Posix.2 so that exit statuses can be
mapped into signal numbers. */
if (signum > 128)
signum -= 128;
if (signum < 0 || signum >= NSIG)
{
builtin_error ("bad signal number: %s", list->word->word);
result = EXECUTION_FAILURE;
list = list->next;
continue;
}
name = signal_name (signum);
if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
{
list = list->next;
continue;
}
printf ("%s\n", name);
}
else
{
signum = decode_signal (list->word->word);
if (signum == NO_SIG)
{
builtin_error ("%s: not a signal specification", list->word->word);
result = EXECUTION_FAILURE;
list = list->next;
continue;
}
printf ("%ld\n", signum);
}
list = list->next;
1996-08-26 18:22:31 +00:00
}
1996-12-23 17:02:34 +00:00
return (result);
1996-08-26 18:22:31 +00:00
}
1996-12-23 17:02:34 +00:00
/* **************************************************************** */
/* */
/* Finding builtin commands and their functions */
/* */
/* **************************************************************** */
/* Perform a binary search and return the address of the builtin function
whose name is NAME. If the function couldn't be found, or the builtin
is disabled or has no function associated with it, return NULL.
Return the address of the builtin.
1996-08-26 18:22:31 +00:00
DISABLED_OKAY means find it even if the builtin is disabled. */
1996-12-23 17:02:34 +00:00
struct builtin *
1996-08-26 18:22:31 +00:00
builtin_address_internal (name, disabled_okay)
char *name;
int disabled_okay;
{
int hi, lo, mid, j;
hi = num_shell_builtins - 1;
lo = 0;
while (lo <= hi)
{
mid = (lo + hi) / 2;
j = shell_builtins[mid].name[0] - name[0];
if (j == 0)
j = strcmp (shell_builtins[mid].name, name);
if (j == 0)
{
/* It must have a function pointer. It must be enabled, or we
1996-12-23 17:02:34 +00:00
must have explicitly allowed disabled functions to be found,
and it must not have been deleted. */
1996-08-26 18:22:31 +00:00
if (shell_builtins[mid].function &&
1996-12-23 17:02:34 +00:00
((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) &&
1996-08-26 18:22:31 +00:00
((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay))
1996-12-23 17:02:34 +00:00
return (&shell_builtins[mid]);
1996-08-26 18:22:31 +00:00
else
1996-12-23 17:02:34 +00:00
return ((struct builtin *)NULL);
1996-08-26 18:22:31 +00:00
}
if (j > 0)
hi = mid - 1;
else
lo = mid + 1;
}
1996-12-23 17:02:34 +00:00
return ((struct builtin *)NULL);
1996-08-26 18:22:31 +00:00
}
1996-12-23 17:02:34 +00:00
/* Return the pointer to the function implementing builtin command NAME. */
1996-08-26 18:22:31 +00:00
Function *
find_shell_builtin (name)
1996-12-23 17:02:34 +00:00
char *name;
1996-08-26 18:22:31 +00:00
{
1996-12-23 17:02:34 +00:00
current_builtin = builtin_address_internal (name, 0);
return (current_builtin ? current_builtin->function : (Function *)NULL);
1996-08-26 18:22:31 +00:00
}
1996-12-23 17:02:34 +00:00
/* Return the address of builtin with NAME, whether it is enabled or not. */
1996-08-26 18:22:31 +00:00
Function *
builtin_address (name)
char *name;
{
1996-12-23 17:02:34 +00:00
current_builtin = builtin_address_internal (name, 1);
return (current_builtin ? current_builtin->function : (Function *)NULL);
1996-08-26 18:22:31 +00:00
}
1996-12-23 17:02:34 +00:00
/* Return the function implementing the builtin NAME, but only if it is a
POSIX.2 special builtin. */
Function *
find_special_builtin (name)
char *name;
{
current_builtin = builtin_address_internal (name, 0);
return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ?
current_builtin->function :
(Function *)NULL);
}
1996-08-26 18:22:31 +00:00
static int
shell_builtin_compare (sbp1, sbp2)
struct builtin *sbp1, *sbp2;
{
int result;
if ((result = sbp1->name[0] - sbp2->name[0]) == 0)
result = strcmp (sbp1->name, sbp2->name);
return (result);
}
/* Sort the table of shell builtins so that the binary search will work
in find_shell_builtin. */
void
initialize_shell_builtins ()
{
qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
shell_builtin_compare);
}
1996-12-23 17:02:34 +00:00
/* **************************************************************** */
/* */
/* Functions for quoting strings to be re-read as input */
/* */
/* **************************************************************** */
/* Return a new string which is the single-quoted version of STRING.
Used by alias and trap, among others. */
1996-08-26 18:22:31 +00:00
char *
single_quote (string)
char *string;
{
1996-12-23 17:02:34 +00:00
register int c;
char *result, *r, *s;
1996-08-26 18:22:31 +00:00
1996-12-23 17:02:34 +00:00
result = (char *)xmalloc (3 + (4 * strlen (string)));
r = result;
*r++ = '\'';
1996-08-26 18:22:31 +00:00
1996-12-23 17:02:34 +00:00
for (s = string; s && (c = *s); s++)
1996-08-26 18:22:31 +00:00
{
1996-12-23 17:02:34 +00:00
*r++ = c;
1996-08-26 18:22:31 +00:00
if (c == '\'')
{
1996-12-23 17:02:34 +00:00
*r++ = '\\'; /* insert escaped single quote */
*r++ = '\'';
*r++ = '\''; /* start new quoted string */
1996-08-26 18:22:31 +00:00
}
}
1996-12-23 17:02:34 +00:00
*r++ = '\'';
*r = '\0';
1996-08-26 18:22:31 +00:00
return (result);
}
1996-12-23 17:02:34 +00:00
/* Quote STRING using double quotes. Return a new string. */
1996-08-26 18:22:31 +00:00
char *
double_quote (string)
char *string;
{
1996-12-23 17:02:34 +00:00
register int c;
char *result, *r, *s;
1996-08-26 18:22:31 +00:00
1996-12-23 17:02:34 +00:00
result = (char *)xmalloc (3 + (2 * strlen (string)));
r = result;
*r++ = '"';
1996-08-26 18:22:31 +00:00
1996-12-23 17:02:34 +00:00
for (s = string; s && (c = *s); s++)
1996-08-26 18:22:31 +00:00
{
switch (c)
{
case '"':
case '$':
case '`':
case '\\':
1996-12-23 17:02:34 +00:00
*r++ = '\\';
1996-08-26 18:22:31 +00:00
default:
1996-12-23 17:02:34 +00:00
*r++ = c;
1996-08-26 18:22:31 +00:00
break;
}
}
1996-12-23 17:02:34 +00:00
*r++ = '"';
*r = '\0';
1996-08-26 18:22:31 +00:00
return (result);
}
1996-12-23 17:02:34 +00:00
/* Quote special characters in STRING using backslashes. Return a new
string. */
char *
backslash_quote (string)
char *string;
{
int c;
char *result, *r, *s;
result = xmalloc (2 * strlen (string) + 1);
for (r = result, s = string; s && (c = *s); s++)
{
switch (c)
{
case ' ': case '\t': case '\n': /* IFS white space */
case '\'': case '"': case '\\': /* quoting chars */
case '|': case '&': case ';': /* shell metacharacters */
case '(': case ')': case '<': case '>':
case '!': case '{': case '}': /* reserved words */
case '*': case '[': case '?': case ']': /* globbing chars */
case '^':
case '$': case '`': /* expansion chars */
*r++ = '\\';
*r++ = c;
break;
case '#': /* comment char */
if (s == string)
*r++ = '\\';
/* FALLTHROUGH */
default:
*r++ = c;
break;
}
}
*r = '\0';
return (result);
}
int
contains_shell_metas (string)
char *string;
{
char *s;
for (s = string; s && *s; s++)
{
switch (*s)
{
case ' ': case '\t': case '\n': /* IFS white space */
case '\'': case '"': case '\\': /* quoting chars */
case '|': case '&': case ';': /* shell metacharacters */
case '(': case ')': case '<': case '>':
case '!': case '{': case '}': /* reserved words */
case '*': case '[': case '?': case ']': /* globbing chars */
case '^':
case '$': case '`': /* expansion chars */
return (1);
case '#':
if (s == string) /* comment char */
return (1);
/* FALLTHROUGH */
default:
break;
}
}
return (0);
}