mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-23 22:07:58 +02:00
bash-20120629 remove leftover and stray files
This commit is contained in:
-14137
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
Starting bash with the `--posix' command-line option or executing
|
||||
`set -o posix' while bash is running will cause bash to conform more
|
||||
closely to the Posix.2 standard by changing the behavior to match that
|
||||
specified by Posix.2 in areas where the bash default differs.
|
||||
|
||||
The following list is what's changed when `posix mode' is in effect:
|
||||
|
||||
1. When a command in the hash table no longer exists, bash will re-search
|
||||
$PATH to find the new location. This is also available with
|
||||
`shopt -s checkhash'.
|
||||
|
||||
2. The >& redirection does not redirect stdout and stderr.
|
||||
|
||||
3. The message printed by the job control code and builtins when a job
|
||||
exits with a non-zero status is `Done(status)'.
|
||||
|
||||
4. Reserved words may not be aliased.
|
||||
|
||||
5. The Posix.2 PS1 and PS2 expansions of `!' -> history number and
|
||||
`!!' -> `!' are enabled, and parameter expansion is performed on
|
||||
the value regardless of the setting of the `promptvars' option.
|
||||
|
||||
6. Interactive comments are enabled by default. (Note that bash has
|
||||
them on by default anyway.)
|
||||
|
||||
7. The Posix.2 startup files are executed ($ENV) rather than the normal
|
||||
bash files.
|
||||
|
||||
8. Tilde expansion is only performed on assignments preceding a command
|
||||
name, rather than on all assignment statements on the line.
|
||||
|
||||
9. The default history file is ~/.sh_history (default value of $HISTFILE).
|
||||
|
||||
10. The output of `kill -l' prints all the signal names on a single line,
|
||||
separated by spaces.
|
||||
|
||||
11. Non-interactive shells exit if `file' in `. file' is not found.
|
||||
|
||||
12. Redirection operators do not perform pathname expansion on the word
|
||||
in the redirection unless the shell is interactive
|
||||
|
||||
13. Function names must be valid shell identifiers. That is, they may not
|
||||
contain characters other than letters, digits, and underscores, and
|
||||
may not start with a digit. Declaring a function with an illegal name
|
||||
causes a fatal syntax error in non-interactive shells.
|
||||
|
||||
14. Posix.2 `special' builtins are found before shell functions during command
|
||||
lookup.
|
||||
|
||||
15. If a Posix.2 special builtin returns an error status, a non-interactive
|
||||
shell exits. The fatal errors are those listed in the POSIX.2 standard,
|
||||
and include things like passing incorrect options, redirection errors,
|
||||
variable assignment errors for assignments preceding the command name,
|
||||
and so on.
|
||||
|
||||
16. The environment passed to executed commands is not sorted. Neither is
|
||||
the output of `set'. This is not strictly Posix.2 behavior, but sh
|
||||
does it this way. Ksh does not. It's not necessary to sort the
|
||||
environment; no program should rely on it being sorted.
|
||||
|
||||
17. If the `cd' builtin finds a directory to change to using $CDPATH, the
|
||||
value it assigns to $PWD does not contain any symbolic links, as if
|
||||
`cd -P' had been executed.
|
||||
|
||||
18. A non-interactive shell exits with an error status if a variable
|
||||
assignment error occurs when no command name follows the assignment
|
||||
statements. A variable assignment error occurs, for example, when
|
||||
trying to assign a value to a read-only variable.
|
||||
|
||||
19. A non-interactive shell exits with an error status if the iteration
|
||||
variable in a for statement or the selection variable in a select
|
||||
statement is a read-only variable.
|
||||
|
||||
20. Process substitution is not available.
|
||||
|
||||
21. Assignment statements preceding POSIX.2 `special' builtins persist in
|
||||
the shell environment after the builtin completes.
|
||||
|
||||
There is other Posix.2 behavior that bash does not implement. Specifically:
|
||||
|
||||
1. Assignment statements affect the execution environment of all builtins,
|
||||
not just special ones.
|
||||
@@ -1,544 +0,0 @@
|
||||
This file is set.def, from which is created set.c.
|
||||
It implements the "set" and "unset" builtins in Bash.
|
||||
|
||||
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.
|
||||
|
||||
$PRODUCES set.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../shell.h"
|
||||
#include "../flags.h"
|
||||
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int interactive;
|
||||
extern int noclobber, posixly_correct;
|
||||
#if defined (READLINE)
|
||||
extern int rl_editing_mode, no_line_editing;
|
||||
#endif /* READLINE */
|
||||
|
||||
$BUILTIN set
|
||||
$FUNCTION set_builtin
|
||||
$SHORT_DOC set [--abefhkmnptuvxldBCHP] [-o option] [arg ...]
|
||||
-a Mark variables which are modified or created for export.
|
||||
-b Notify of job termination immediately.
|
||||
-e Exit immediately if a command exits with a non-zero status.
|
||||
-f Disable file name generation (globbing).
|
||||
-h Locate and remember function commands as functions are
|
||||
defined. Function commands are normally looked up when
|
||||
the function is executed.
|
||||
-i Force the shell to be an "interactive" one. Interactive shells
|
||||
always read `~/.bashrc' on startup.
|
||||
-k All keyword arguments are placed in the environment for a
|
||||
command, not just those that precede the command name.
|
||||
-m Job control is enabled.
|
||||
-n Read commands but do not execute them.
|
||||
-o option-name
|
||||
Set the variable corresponding to option-name:
|
||||
allexport same as -a
|
||||
braceexpand same as -B
|
||||
#if defined (READLINE)
|
||||
emacs use an emacs-style line editing interface
|
||||
#endif /* READLINE */
|
||||
errexit same as -e
|
||||
histexpand same as -H
|
||||
ignoreeof the shell will not exit upon reading EOF
|
||||
interactive-comments
|
||||
allow comments to appear in interactive commands
|
||||
monitor same as -m
|
||||
noclobber disallow redirection to existing files
|
||||
noexec same as -n
|
||||
noglob same as -f
|
||||
nohash same as -d
|
||||
notify save as -b
|
||||
nounset same as -u
|
||||
physical same as -P
|
||||
posix change the behavior of bash where the default
|
||||
operation differs from the 1003.2 standard to
|
||||
match the standard
|
||||
privileged same as -p
|
||||
verbose same as -v
|
||||
#if defined (READLINE)
|
||||
vi use a vi-style line editing interface
|
||||
#endif /* READLINE */
|
||||
xtrace same as -x
|
||||
-p Turned on whenever the real and effective user ids do not match.
|
||||
Disables processing of the $ENV file and importing of shell
|
||||
functions. Turning this option off causes the effective uid and
|
||||
gid to be set to the real uid and gid.
|
||||
-t Exit after reading and executing one command.
|
||||
-u Treat unset variables as an error when substituting.
|
||||
-v Print shell input lines as they are read.
|
||||
-x Print commands and their arguments as they are executed.
|
||||
-l Save and restore the binding of the NAME in a FOR command.
|
||||
-d Disable the hashing of commands that are looked up for execution.
|
||||
Normally, commands are remembered in a hash table, and once
|
||||
found, do not have to be looked up again.
|
||||
#if defined (BRACE_EXPANSION)
|
||||
-B the shell will perform brace expansion
|
||||
#endif /* BRACE_EXPANSION */
|
||||
#if defined (BANG_HISTORY)
|
||||
-H Enable ! style history substitution. This flag is on
|
||||
by default.
|
||||
#endif /* BANG_HISTORY */
|
||||
-C If set, disallow existing regular files to be overwritten
|
||||
by redirection of output.
|
||||
-P If set, do not follow symbolic links when executing commands
|
||||
such as cd which change the current directory.
|
||||
|
||||
Using + rather than - causes these flags to be turned off. The
|
||||
flags can also be used upon invocation of the shell. The current
|
||||
set of flags may be found in $-. The remaining n ARGs are positional
|
||||
parameters and are assigned, in order, to $1, $2, .. $n. If no
|
||||
ARGs are given, all shell variables are printed.
|
||||
$END
|
||||
|
||||
/* An a-list used to match long options for set -o to the corresponding
|
||||
option letter. */
|
||||
struct {
|
||||
char *name;
|
||||
int letter;
|
||||
} o_options[] = {
|
||||
{ "allexport", 'a' },
|
||||
#if defined (BRACE_EXPANSION)
|
||||
{ "braceexpand",'B' },
|
||||
#endif
|
||||
{ "errexit", 'e' },
|
||||
{ "histexpand", 'H' },
|
||||
{ "monitor", 'm' },
|
||||
{ "noexec", 'n' },
|
||||
{ "noglob", 'f' },
|
||||
{ "nohash", 'd' },
|
||||
#if defined (JOB_CONTROL)
|
||||
{ "notify", 'b' },
|
||||
#endif /* JOB_CONTROL */
|
||||
{"nounset", 'u' },
|
||||
{"physical", 'P' },
|
||||
{"privileged", 'p' },
|
||||
{"verbose", 'v' },
|
||||
{"xtrace", 'x' },
|
||||
{(char *)NULL, 0},
|
||||
};
|
||||
|
||||
#define MINUS_O_FORMAT "%-15s\t%s\n"
|
||||
|
||||
void
|
||||
list_minus_o_opts ()
|
||||
{
|
||||
register int i;
|
||||
char *on = "on", *off = "off";
|
||||
|
||||
printf (MINUS_O_FORMAT, "noclobber", (noclobber == 1) ? on : off);
|
||||
|
||||
if (find_variable ("ignoreeof") || find_variable ("IGNOREEOF"))
|
||||
printf (MINUS_O_FORMAT, "ignoreeof", on);
|
||||
else
|
||||
printf (MINUS_O_FORMAT, "ignoreeof", off);
|
||||
|
||||
printf (MINUS_O_FORMAT, "interactive-comments",
|
||||
interactive_comments ? on : off);
|
||||
|
||||
printf (MINUS_O_FORMAT, "posix", posixly_correct ? on : off);
|
||||
|
||||
#if defined (READLINE)
|
||||
if (no_line_editing)
|
||||
{
|
||||
printf (MINUS_O_FORMAT, "emacs", off);
|
||||
printf (MINUS_O_FORMAT, "vi", off);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Magic. This code `knows' how readline handles rl_editing_mode. */
|
||||
printf (MINUS_O_FORMAT, "emacs", (rl_editing_mode == 1) ? on : off);
|
||||
printf (MINUS_O_FORMAT, "vi", (rl_editing_mode == 0) ? on : off);
|
||||
}
|
||||
#endif /* READLINE */
|
||||
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
int *on_or_off, zero = 0;
|
||||
|
||||
on_or_off = find_flag (o_options[i].letter);
|
||||
if (on_or_off == FLAG_UNKNOWN)
|
||||
on_or_off = &zero;
|
||||
printf (MINUS_O_FORMAT, o_options[i].name, (*on_or_off == 1) ? on : off);
|
||||
}
|
||||
}
|
||||
|
||||
set_minus_o_option (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
int option_char = -1;
|
||||
|
||||
if (STREQ (option_name, "noclobber"))
|
||||
{
|
||||
if (on_or_off == FLAG_ON)
|
||||
bind_variable ("noclobber", "");
|
||||
else
|
||||
unbind_variable ("noclobber");
|
||||
stupidly_hack_special_variables ("noclobber");
|
||||
}
|
||||
else if (STREQ (option_name, "ignoreeof"))
|
||||
{
|
||||
unbind_variable ("ignoreeof");
|
||||
unbind_variable ("IGNOREEOF");
|
||||
if (on_or_off == FLAG_ON)
|
||||
bind_variable ("IGNOREEOF", "10");
|
||||
stupidly_hack_special_variables ("IGNOREEOF");
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
else if ((STREQ (option_name, "emacs")) || (STREQ (option_name, "vi")))
|
||||
{
|
||||
if (on_or_off == FLAG_ON)
|
||||
{
|
||||
rl_variable_bind ("editing-mode", option_name);
|
||||
|
||||
if (interactive)
|
||||
with_input_from_stdin ();
|
||||
no_line_editing = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int isemacs = (rl_editing_mode == 1);
|
||||
if ((isemacs && STREQ (option_name, "emacs")) ||
|
||||
(!isemacs && STREQ (option_name, "vi")))
|
||||
{
|
||||
if (interactive)
|
||||
with_input_from_stream (stdin, "stdin");
|
||||
no_line_editing = 1;
|
||||
}
|
||||
else
|
||||
builtin_error ("not in %s editing mode", option_name);
|
||||
}
|
||||
}
|
||||
#endif /* READLINE */
|
||||
else if (STREQ (option_name, "interactive-comments"))
|
||||
interactive_comments = (on_or_off == FLAG_ON);
|
||||
else if (STREQ (option_name, "posix"))
|
||||
{
|
||||
posixly_correct = (on_or_off == FLAG_ON);
|
||||
unbind_variable ("POSIXLY_CORRECT");
|
||||
unbind_variable ("POSIX_PEDANTIC");
|
||||
if (on_or_off == FLAG_ON)
|
||||
{
|
||||
bind_variable ("POSIXLY_CORRECT", "");
|
||||
stupidly_hack_special_variables ("POSIXLY_CORRECT");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
register int i;
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (STREQ (option_name, o_options[i].name))
|
||||
{
|
||||
option_char = o_options[i].letter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (option_char == -1)
|
||||
{
|
||||
builtin_error ("%s: unknown option name", option_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (change_flag (option_char, on_or_off) == FLAG_ERROR)
|
||||
{
|
||||
bad_option (option_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Set some flags from the word values in the input list. If LIST is empty,
|
||||
then print out the values of the variables instead. If LIST contains
|
||||
non-flags, then set $1 - $9 to the successive words of LIST. */
|
||||
set_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int on_or_off, flag_name, force_assignment = 0;
|
||||
|
||||
if (!list)
|
||||
{
|
||||
SHELL_VAR **vars;
|
||||
|
||||
vars = all_shell_variables ();
|
||||
if (vars)
|
||||
{
|
||||
print_var_list (vars);
|
||||
free (vars);
|
||||
}
|
||||
|
||||
vars = all_shell_functions ();
|
||||
if (vars)
|
||||
{
|
||||
print_var_list (vars);
|
||||
free (vars);
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Check validity of flag arguments. */
|
||||
if (*list->word->word == '-' || *list->word->word == '+')
|
||||
{
|
||||
register char *arg;
|
||||
WORD_LIST *save_list = list;
|
||||
|
||||
while (list && (arg = list->word->word))
|
||||
{
|
||||
char c;
|
||||
|
||||
if (arg[0] != '-' && arg[0] != '+')
|
||||
break;
|
||||
|
||||
/* `-' or `--' signifies end of flag arguments. */
|
||||
if (arg[0] == '-' &&
|
||||
(!arg[1] || (arg[1] == '-' && !arg[2])))
|
||||
break;
|
||||
|
||||
while (c = *++arg)
|
||||
{
|
||||
if (find_flag (c) == FLAG_UNKNOWN && c != 'o')
|
||||
{
|
||||
char s[2];
|
||||
s[0] = c; s[1] = '\0';
|
||||
bad_option (s);
|
||||
if (c == '?')
|
||||
builtin_usage ();
|
||||
return (c == '?' ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
list = save_list;
|
||||
}
|
||||
|
||||
/* Do the set command. While the list consists of words starting with
|
||||
'-' or '+' treat them as flags, otherwise, start assigning them to
|
||||
$1 ... $n. */
|
||||
while (list)
|
||||
{
|
||||
char *string = list->word->word;
|
||||
|
||||
/* If the argument is `--' or `-' then signal the end of the list
|
||||
and remember the remaining arguments. */
|
||||
if (string[0] == '-' && (!string[1] || (string[1] == '-' && !string[2])))
|
||||
{
|
||||
list = list->next;
|
||||
|
||||
/* `set --' unsets the positional parameters. */
|
||||
if (string[1] == '-')
|
||||
force_assignment = 1;
|
||||
|
||||
/* Until told differently, the old shell behaviour of
|
||||
`set - [arg ...]' being equivalent to `set +xv [arg ...]'
|
||||
stands. Posix.2 says the behaviour is marked as obsolescent. */
|
||||
else
|
||||
{
|
||||
change_flag ('x', '+');
|
||||
change_flag ('v', '+');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((on_or_off = *string) &&
|
||||
(on_or_off == '-' || on_or_off == '+'))
|
||||
{
|
||||
int i = 1;
|
||||
while (flag_name = string[i++])
|
||||
{
|
||||
if (flag_name == '?')
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else if (flag_name == 'o') /* -+o option-name */
|
||||
{
|
||||
char *option_name;
|
||||
WORD_LIST *opt;
|
||||
|
||||
opt = list->next;
|
||||
|
||||
if (!opt)
|
||||
{
|
||||
list_minus_o_opts ();
|
||||
continue;
|
||||
}
|
||||
|
||||
option_name = opt->word->word;
|
||||
|
||||
if (!option_name || !*option_name || (*option_name == '-'))
|
||||
{
|
||||
list_minus_o_opts ();
|
||||
continue;
|
||||
}
|
||||
list = list->next; /* Skip over option name. */
|
||||
|
||||
if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS)
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
|
||||
{
|
||||
char opt[3];
|
||||
opt[0] = on_or_off;
|
||||
opt[1] = flag_name;
|
||||
opt[2] = '\0';
|
||||
bad_option (opt);
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* Assigning $1 ... $n */
|
||||
if (list || force_assignment)
|
||||
remember_args (list, 1);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
$BUILTIN unset
|
||||
$FUNCTION unset_builtin
|
||||
$SHORT_DOC unset [-f] [-v] [name ...]
|
||||
For each NAME, remove the corresponding variable or function. Given
|
||||
the `-v', unset will only act on variables. Given the `-f' flag,
|
||||
unset will only act on functions. With neither flag, unset first
|
||||
tries to unset a variable, and if that fails, then tries to unset a
|
||||
function. Some variables (such as PATH and IFS) cannot be unset; also
|
||||
see readonly.
|
||||
$END
|
||||
|
||||
#define NEXT_VARIABLE() any_failed++; list = list->next; continue;
|
||||
|
||||
unset_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int unset_function, unset_variable, unset_array, opt, any_failed;
|
||||
char *name;
|
||||
|
||||
unset_function = unset_variable = unset_array = any_failed = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "fv")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
unset_function = 1;
|
||||
break;
|
||||
case 'v':
|
||||
unset_variable = 1;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (unset_function && unset_variable)
|
||||
{
|
||||
builtin_error ("cannot simultaneously unset a function and a variable");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
int tem;
|
||||
#if defined (ARRAY_VARS)
|
||||
char *t;
|
||||
#endif
|
||||
|
||||
name = list->word->word;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (!unset_function && valid_array_reference (name))
|
||||
{
|
||||
t = strchr (name, '[');
|
||||
*t++ = '\0';
|
||||
unset_array++;
|
||||
}
|
||||
#endif
|
||||
|
||||
var = unset_function ? find_function (name) : find_variable (name);
|
||||
|
||||
if (var && !unset_function && non_unsettable_p (var))
|
||||
{
|
||||
builtin_error ("%s: cannot unset", name);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* Posix.2 says that unsetting readonly variables is an error. */
|
||||
if (var && readonly_p (var))
|
||||
{
|
||||
builtin_error ("%s: cannot unset: readonly %s",
|
||||
name, unset_function ? "function" : "variable");
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* Unless the -f option is supplied, the name refers to a variable. */
|
||||
#if defined (ARRAY_VARS)
|
||||
if (var && unset_array)
|
||||
{
|
||||
if (array_p (var) == 0)
|
||||
{
|
||||
builtin_error ("%s: not an array variable", name);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
else
|
||||
tem = unbind_array_element (var, t);
|
||||
}
|
||||
else
|
||||
#endif /* ARRAY_VARS */
|
||||
tem = makunbound (name, unset_function ? shell_functions : shell_variables);
|
||||
|
||||
/* This is what Posix.2 draft 11+ says. ``If neither -f nor -v
|
||||
is specified, the name refers to a variable; if a variable by
|
||||
that name does not exist, a function by that name, if any,
|
||||
shall be unset.'' */
|
||||
if ((tem == -1) && !unset_function && !unset_variable)
|
||||
tem = makunbound (name, shell_functions);
|
||||
|
||||
if (tem == -1)
|
||||
any_failed++;
|
||||
else if (!unset_function)
|
||||
stupidly_hack_special_variables (name);
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if (any_failed)
|
||||
return (EXECUTION_FAILURE);
|
||||
else
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/* unwind_prot.h - Macros and functions for hacking unwind protection. */
|
||||
|
||||
/* Copyright (C) 1993 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 2, 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. */
|
||||
|
||||
#if !defined (_UNWIND_PROT_H)
|
||||
#define _UNWIND_PROT_H
|
||||
|
||||
/* Run a function without interrupts. */
|
||||
extern void begin_unwind_frame ();
|
||||
extern void discard_unwind_frame ();
|
||||
extern void run_unwind_frame ();
|
||||
extern void add_unwind_protect ();
|
||||
extern void remove_unwind_protect ();
|
||||
extern void run_unwind_protects ();
|
||||
extern void unwind_protect_var ();
|
||||
|
||||
/* Define for people who like their code to look a certain way. */
|
||||
#define end_unwind_frame()
|
||||
|
||||
/* How to protect an integer. */
|
||||
#define unwind_protect_int(X) unwind_protect_var (&(X), (char *)(X), sizeof (int))
|
||||
|
||||
/* How to protect a pointer to a string. */
|
||||
#define unwind_protect_string(X) \
|
||||
unwind_protect_var ((int *)&(X), (X), sizeof (char *))
|
||||
|
||||
/* How to protect any old pointer. */
|
||||
#define unwind_protect_pointer(X) unwind_protect_string (X)
|
||||
|
||||
/* How to protect the contents of a jmp_buf. */
|
||||
#define unwind_protect_jmp_buf(X) \
|
||||
unwind_protect_var ((int *)(X), (char *)(X), sizeof (procenv_t))
|
||||
|
||||
#endif /* _UNWIND_PROT_H */
|
||||
-1121
File diff suppressed because it is too large
Load Diff
-923
@@ -1,923 +0,0 @@
|
||||
/* bashhist.c -- bash interface to the GNU history library. */
|
||||
|
||||
/* Copyright (C) 1993-2011 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HISTORY)
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "bashansi.h"
|
||||
#include "posixstat.h"
|
||||
#include "filecntl.h"
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#if defined (SYSLOG_HISTORY)
|
||||
# include <syslog.h>
|
||||
#endif
|
||||
|
||||
#include "shell.h"
|
||||
#include "flags.h"
|
||||
#include "input.h"
|
||||
#include "parser.h" /* for the struct dstack stuff. */
|
||||
#include "pathexp.h" /* for the struct ignorevar stuff */
|
||||
#include "bashhist.h" /* matching prototypes and declarations */
|
||||
#include "builtins/common.h"
|
||||
|
||||
#include <readline/history.h>
|
||||
#include <glob/glob.h>
|
||||
#include <glob/strmatch.h>
|
||||
|
||||
#if defined (READLINE)
|
||||
# include "bashline.h"
|
||||
extern int rl_done, rl_dispatching; /* should really include readline.h */
|
||||
#endif
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
static int histignore_item_func __P((struct ign *));
|
||||
static int check_history_control __P((char *));
|
||||
static void hc_erasedups __P((char *));
|
||||
static void really_add_history __P((char *));
|
||||
|
||||
static struct ignorevar histignore =
|
||||
{
|
||||
"HISTIGNORE",
|
||||
(struct ign *)0,
|
||||
0,
|
||||
(char *)0,
|
||||
(sh_iv_item_func_t *)histignore_item_func,
|
||||
};
|
||||
|
||||
#define HIGN_EXPAND 0x01
|
||||
|
||||
/* Declarations of bash history variables. */
|
||||
/* Non-zero means to remember lines typed to the shell on the history
|
||||
list. This is different than the user-controlled behaviour; this
|
||||
becomes zero when we read lines from a file, for example. */
|
||||
int remember_on_history = 1;
|
||||
int enable_history_list = 1; /* value for `set -o history' */
|
||||
|
||||
/* The number of lines that Bash has added to this history session. The
|
||||
difference between the number of the top element in the history list
|
||||
(offset from history_base) and the number of lines in the history file.
|
||||
Appending this session's history to the history file resets this to 0. */
|
||||
int history_lines_this_session;
|
||||
|
||||
/* The number of lines that Bash has read from the history file. */
|
||||
int history_lines_in_file;
|
||||
|
||||
#if defined (BANG_HISTORY)
|
||||
/* Non-zero means do no history expansion on this line, regardless
|
||||
of what history_expansion says. */
|
||||
int history_expansion_inhibited;
|
||||
#endif
|
||||
|
||||
/* With the old default, every line was saved in the history individually.
|
||||
I.e., if the user enters:
|
||||
bash$ for i in a b c
|
||||
> do
|
||||
> echo $i
|
||||
> done
|
||||
Each line will be individually saved in the history.
|
||||
bash$ history
|
||||
10 for i in a b c
|
||||
11 do
|
||||
12 echo $i
|
||||
13 done
|
||||
14 history
|
||||
If the variable command_oriented_history is set, multiple lines
|
||||
which form one command will be saved as one history entry.
|
||||
bash$ for i in a b c
|
||||
> do
|
||||
> echo $i
|
||||
> done
|
||||
bash$ history
|
||||
10 for i in a b c
|
||||
do
|
||||
echo $i
|
||||
done
|
||||
11 history
|
||||
The user can then recall the whole command all at once instead
|
||||
of just being able to recall one line at a time.
|
||||
|
||||
This is now enabled by default.
|
||||
*/
|
||||
int command_oriented_history = 1;
|
||||
|
||||
/* Set to 1 if the first line of a possibly-multi-line command was saved
|
||||
in the history list. Managed by maybe_add_history(), but global so
|
||||
the history-manipluating builtins can see it. */
|
||||
int current_command_first_line_saved = 0;
|
||||
|
||||
/* Non-zero means to store newlines in the history list when using
|
||||
command_oriented_history rather than trying to use semicolons. */
|
||||
int literal_history;
|
||||
|
||||
/* Non-zero means to append the history to the history file at shell
|
||||
exit, even if the history has been stifled. */
|
||||
int force_append_history;
|
||||
|
||||
/* A nit for picking at history saving. Flags have the following values:
|
||||
|
||||
Value == 0 means save all lines parsed by the shell on the history.
|
||||
Value & HC_IGNSPACE means save all lines that do not start with a space.
|
||||
Value & HC_IGNDUPS means save all lines that do not match the last
|
||||
line saved.
|
||||
Value & HC_ERASEDUPS means to remove all other matching lines from the
|
||||
history list before saving the latest line. */
|
||||
int history_control;
|
||||
|
||||
/* Set to 1 if the last command was added to the history list successfully
|
||||
as a separate history entry; set to 0 if the line was ignored or added
|
||||
to a previous entry as part of command-oriented-history processing. */
|
||||
int hist_last_line_added;
|
||||
|
||||
/* Set to 1 if builtins/history.def:push_history added the last history
|
||||
entry. */
|
||||
int hist_last_line_pushed;
|
||||
|
||||
#if defined (READLINE)
|
||||
/* If non-zero, and readline is being used, the user is offered the
|
||||
chance to re-edit a failed history expansion. */
|
||||
int history_reediting;
|
||||
|
||||
/* If non-zero, and readline is being used, don't directly execute a
|
||||
line with history substitution. Reload it into the editing buffer
|
||||
instead and let the user further edit and confirm with a newline. */
|
||||
int hist_verify;
|
||||
|
||||
#endif /* READLINE */
|
||||
|
||||
/* Non-zero means to not save function definitions in the history list. */
|
||||
int dont_save_function_defs;
|
||||
|
||||
/* Variables declared in other files used here. */
|
||||
extern int current_command_line_count;
|
||||
|
||||
extern struct dstack dstack;
|
||||
extern int parser_state;
|
||||
|
||||
static int bash_history_inhibit_expansion __P((char *, int));
|
||||
#if defined (READLINE)
|
||||
static void re_edit __P((char *));
|
||||
#endif
|
||||
static int history_expansion_p __P((char *));
|
||||
static int shell_comment __P((char *));
|
||||
static int should_expand __P((char *));
|
||||
static HIST_ENTRY *last_history_entry __P((void));
|
||||
static char *expand_histignore_pattern __P((char *));
|
||||
static int history_should_ignore __P((char *));
|
||||
|
||||
/* Is the history expansion starting at string[i] one that should not
|
||||
be expanded? */
|
||||
static int
|
||||
bash_history_inhibit_expansion (string, i)
|
||||
char *string;
|
||||
int i;
|
||||
{
|
||||
/* The shell uses ! as a pattern negation character in globbing [...]
|
||||
expressions, so let those pass without expansion. */
|
||||
if (i > 0 && (string[i - 1] == '[') && member (']', string + i + 1))
|
||||
return (1);
|
||||
/* The shell uses ! as the indirect expansion character, so let those
|
||||
expansions pass as well. */
|
||||
else if (i > 1 && string[i - 1] == '{' && string[i - 2] == '$' &&
|
||||
member ('}', string + i + 1))
|
||||
return (1);
|
||||
/* The shell uses $! as a defined parameter expansion. */
|
||||
else if (i > 1 && string[i - 1] == '$' && string[i] == '!')
|
||||
return (1);
|
||||
#if defined (EXTENDED_GLOB)
|
||||
else if (extended_glob && i > 1 && string[i+1] == '(' && member (')', string + i + 2))
|
||||
return (1);
|
||||
#endif
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
bash_initialize_history ()
|
||||
{
|
||||
history_quotes_inhibit_expansion = 1;
|
||||
history_search_delimiter_chars = ";&()|<>";
|
||||
history_inhibit_expansion_function = bash_history_inhibit_expansion;
|
||||
#if defined (BANG_HISTORY)
|
||||
sv_histchars ("histchars");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
bash_history_reinit (interact)
|
||||
int interact;
|
||||
{
|
||||
#if defined (BANG_HISTORY)
|
||||
history_expansion = interact != 0;
|
||||
history_expansion_inhibited = 1;
|
||||
#endif
|
||||
remember_on_history = enable_history_list = interact != 0;
|
||||
history_inhibit_expansion_function = bash_history_inhibit_expansion;
|
||||
}
|
||||
|
||||
void
|
||||
bash_history_disable ()
|
||||
{
|
||||
remember_on_history = 0;
|
||||
#if defined (BANG_HISTORY)
|
||||
history_expansion_inhibited = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
bash_history_enable ()
|
||||
{
|
||||
remember_on_history = 1;
|
||||
#if defined (BANG_HISTORY)
|
||||
history_expansion_inhibited = 0;
|
||||
#endif
|
||||
history_inhibit_expansion_function = bash_history_inhibit_expansion;
|
||||
sv_history_control ("HISTCONTROL");
|
||||
sv_histignore ("HISTIGNORE");
|
||||
}
|
||||
|
||||
/* Load the history list from the history file. */
|
||||
void
|
||||
load_history ()
|
||||
{
|
||||
char *hf;
|
||||
|
||||
/* Truncate history file for interactive shells which desire it.
|
||||
Note that the history file is automatically truncated to the
|
||||
size of HISTSIZE if the user does not explicitly set the size
|
||||
differently. */
|
||||
set_if_not ("HISTSIZE", "500");
|
||||
sv_histsize ("HISTSIZE");
|
||||
|
||||
set_if_not ("HISTFILESIZE", get_string_value ("HISTSIZE"));
|
||||
sv_histsize ("HISTFILESIZE");
|
||||
|
||||
/* Read the history in HISTFILE into the history list. */
|
||||
hf = get_string_value ("HISTFILE");
|
||||
|
||||
if (hf && *hf && file_exists (hf))
|
||||
{
|
||||
read_history (hf);
|
||||
using_history ();
|
||||
history_lines_in_file = where_history ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bash_clear_history ()
|
||||
{
|
||||
clear_history ();
|
||||
history_lines_this_session = 0;
|
||||
}
|
||||
|
||||
/* Delete and free the history list entry at offset I. */
|
||||
int
|
||||
bash_delete_histent (i)
|
||||
int i;
|
||||
{
|
||||
HIST_ENTRY *discard;
|
||||
|
||||
discard = remove_history (i);
|
||||
if (discard)
|
||||
free_history_entry (discard);
|
||||
history_lines_this_session--;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
bash_delete_last_history ()
|
||||
{
|
||||
register int i;
|
||||
HIST_ENTRY **hlist, *histent;
|
||||
int r;
|
||||
|
||||
hlist = history_list ();
|
||||
if (hlist == NULL)
|
||||
return 0;
|
||||
|
||||
for (i = 0; hlist[i]; i++)
|
||||
;
|
||||
i--;
|
||||
|
||||
/* History_get () takes a parameter that must be offset by history_base. */
|
||||
histent = history_get (history_base + i); /* Don't free this */
|
||||
if (histent == NULL)
|
||||
return 0;
|
||||
|
||||
r = bash_delete_histent (i);
|
||||
|
||||
if (where_history () > history_length)
|
||||
history_set_pos (history_length);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Write the existing history out to the history file. */
|
||||
void
|
||||
save_history ()
|
||||
{
|
||||
char *hf;
|
||||
int r;
|
||||
|
||||
hf = get_string_value ("HISTFILE");
|
||||
if (hf && *hf && file_exists (hf))
|
||||
{
|
||||
/* Append only the lines that occurred this session to
|
||||
the history file. */
|
||||
using_history ();
|
||||
|
||||
if (history_lines_this_session <= where_history () || force_append_history)
|
||||
r = append_history (history_lines_this_session, hf);
|
||||
else
|
||||
r = write_history (hf);
|
||||
sv_histsize ("HISTFILESIZE");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
maybe_append_history (filename)
|
||||
char *filename;
|
||||
{
|
||||
int fd, result;
|
||||
struct stat buf;
|
||||
|
||||
result = EXECUTION_SUCCESS;
|
||||
if (history_lines_this_session && (history_lines_this_session <= where_history ()))
|
||||
{
|
||||
/* If the filename was supplied, then create it if necessary. */
|
||||
if (stat (filename, &buf) == -1 && errno == ENOENT)
|
||||
{
|
||||
fd = open (filename, O_WRONLY|O_CREAT, 0600);
|
||||
if (fd < 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot create: %s"), filename, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
close (fd);
|
||||
}
|
||||
result = append_history (history_lines_this_session, filename);
|
||||
history_lines_in_file += history_lines_this_session;
|
||||
history_lines_this_session = 0;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* If this is an interactive shell, then append the lines executed
|
||||
this session to the history file. */
|
||||
int
|
||||
maybe_save_shell_history ()
|
||||
{
|
||||
int result;
|
||||
char *hf;
|
||||
|
||||
result = 0;
|
||||
if (history_lines_this_session)
|
||||
{
|
||||
hf = get_string_value ("HISTFILE");
|
||||
|
||||
if (hf && *hf)
|
||||
{
|
||||
/* If the file doesn't exist, then create it. */
|
||||
if (file_exists (hf) == 0)
|
||||
{
|
||||
int file;
|
||||
file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||
if (file != -1)
|
||||
close (file);
|
||||
}
|
||||
|
||||
/* Now actually append the lines if the history hasn't been
|
||||
stifled. If the history has been stifled, rewrite the
|
||||
history file. */
|
||||
using_history ();
|
||||
if (history_lines_this_session <= where_history () || force_append_history)
|
||||
{
|
||||
result = append_history (history_lines_this_session, hf);
|
||||
history_lines_in_file += history_lines_this_session;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = write_history (hf);
|
||||
history_lines_in_file = history_lines_this_session;
|
||||
}
|
||||
history_lines_this_session = 0;
|
||||
|
||||
sv_histsize ("HISTFILESIZE");
|
||||
}
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
/* Tell readline () that we have some text for it to edit. */
|
||||
static void
|
||||
re_edit (text)
|
||||
char *text;
|
||||
{
|
||||
if (bash_input.type == st_stdin)
|
||||
bash_re_edit (text);
|
||||
}
|
||||
#endif /* READLINE */
|
||||
|
||||
/* Return 1 if this line needs history expansion. */
|
||||
static int
|
||||
history_expansion_p (line)
|
||||
char *line;
|
||||
{
|
||||
register char *s;
|
||||
|
||||
for (s = line; *s; s++)
|
||||
if (*s == history_expansion_char || *s == history_subst_char)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do pre-processing on LINE. If PRINT_CHANGES is non-zero, then
|
||||
print the results of expanding the line if there were any changes.
|
||||
If there is an error, return NULL, otherwise the expanded line is
|
||||
returned. If ADDIT is non-zero the line is added to the history
|
||||
list after history expansion. ADDIT is just a suggestion;
|
||||
REMEMBER_ON_HISTORY can veto, and does.
|
||||
Right now this does history expansion. */
|
||||
char *
|
||||
pre_process_line (line, print_changes, addit)
|
||||
char *line;
|
||||
int print_changes, addit;
|
||||
{
|
||||
char *history_value;
|
||||
char *return_value;
|
||||
int expanded;
|
||||
|
||||
return_value = line;
|
||||
expanded = 0;
|
||||
|
||||
# if defined (BANG_HISTORY)
|
||||
/* History expand the line. If this results in no errors, then
|
||||
add that line to the history if ADDIT is non-zero. */
|
||||
if (!history_expansion_inhibited && history_expansion && history_expansion_p (line))
|
||||
{
|
||||
expanded = history_expand (line, &history_value);
|
||||
|
||||
if (expanded)
|
||||
{
|
||||
if (print_changes)
|
||||
{
|
||||
if (expanded < 0)
|
||||
internal_error ("%s", history_value);
|
||||
#if defined (READLINE)
|
||||
else if (hist_verify == 0 || expanded == 2)
|
||||
#else
|
||||
else
|
||||
#endif
|
||||
fprintf (stderr, "%s\n", history_value);
|
||||
}
|
||||
|
||||
/* If there was an error, return NULL. */
|
||||
if (expanded < 0 || expanded == 2) /* 2 == print only */
|
||||
{
|
||||
# if defined (READLINE)
|
||||
if (expanded == 2 && rl_dispatching == 0 && *history_value)
|
||||
# else
|
||||
if (expanded == 2 && *history_value)
|
||||
# endif /* !READLINE */
|
||||
maybe_add_history (history_value);
|
||||
|
||||
free (history_value);
|
||||
|
||||
# if defined (READLINE)
|
||||
/* New hack. We can allow the user to edit the
|
||||
failed history expansion. */
|
||||
if (history_reediting && expanded < 0 && rl_done)
|
||||
re_edit (line);
|
||||
# endif /* READLINE */
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
# if defined (READLINE)
|
||||
if (hist_verify && expanded == 1)
|
||||
{
|
||||
re_edit (history_value);
|
||||
return ((char *)NULL);
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
/* Let other expansions know that return_value can be free'ed,
|
||||
and that a line has been added to the history list. Note
|
||||
that we only add lines that have something in them. */
|
||||
expanded = 1;
|
||||
return_value = history_value;
|
||||
}
|
||||
# endif /* BANG_HISTORY */
|
||||
|
||||
if (addit && remember_on_history && *return_value)
|
||||
maybe_add_history (return_value);
|
||||
|
||||
#if 0
|
||||
if (expanded == 0)
|
||||
return_value = savestring (line);
|
||||
#endif
|
||||
|
||||
return (return_value);
|
||||
}
|
||||
|
||||
/* Return 1 if the first non-whitespace character in LINE is a `#', indicating
|
||||
* that the line is a shell comment. */
|
||||
static int
|
||||
shell_comment (line)
|
||||
char *line;
|
||||
{
|
||||
char *p;
|
||||
|
||||
for (p = line; p && *p && whitespace (*p); p++)
|
||||
;
|
||||
return (p && *p == '#');
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Remove shell comments from LINE. A `#' and anything after it is a comment.
|
||||
This isn't really useful yet, since it doesn't handle quoting. */
|
||||
static char *
|
||||
filter_comments (line)
|
||||
char *line;
|
||||
{
|
||||
char *p;
|
||||
|
||||
for (p = line; p && *p && *p != '#'; p++)
|
||||
;
|
||||
if (p && *p == '#')
|
||||
*p = '\0';
|
||||
return (line);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check LINE against what HISTCONTROL says to do. Returns 1 if the line
|
||||
should be saved; 0 if it should be discarded. */
|
||||
static int
|
||||
check_history_control (line)
|
||||
char *line;
|
||||
{
|
||||
HIST_ENTRY *temp;
|
||||
int r;
|
||||
|
||||
if (history_control == 0)
|
||||
return 1;
|
||||
|
||||
/* ignorespace or ignoreboth */
|
||||
if ((history_control & HC_IGNSPACE) && *line == ' ')
|
||||
return 0;
|
||||
|
||||
/* ignoredups or ignoreboth */
|
||||
if (history_control & HC_IGNDUPS)
|
||||
{
|
||||
using_history ();
|
||||
temp = previous_history ();
|
||||
|
||||
r = (temp == 0 || STREQ (temp->line, line) == 0);
|
||||
|
||||
using_history ();
|
||||
|
||||
if (r == 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Remove all entries matching LINE from the history list. Triggered when
|
||||
HISTCONTROL includes `erasedups'. */
|
||||
static void
|
||||
hc_erasedups (line)
|
||||
char *line;
|
||||
{
|
||||
HIST_ENTRY *temp;
|
||||
int r;
|
||||
|
||||
using_history ();
|
||||
while (temp = previous_history ())
|
||||
{
|
||||
if (STREQ (temp->line, line))
|
||||
{
|
||||
r = where_history ();
|
||||
remove_history (r);
|
||||
}
|
||||
}
|
||||
using_history ();
|
||||
}
|
||||
|
||||
/* Add LINE to the history list, handling possibly multi-line compound
|
||||
commands. We note whether or not we save the first line of each command
|
||||
(which is usually the entire command and history entry), and don't add
|
||||
the second and subsequent lines of a multi-line compound command if we
|
||||
didn't save the first line. We don't usually save shell comment lines in
|
||||
compound commands in the history, because they could have the effect of
|
||||
commenting out the rest of the command when the entire command is saved as
|
||||
a single history entry (when COMMAND_ORIENTED_HISTORY is enabled). If
|
||||
LITERAL_HISTORY is set, we're saving lines in the history with embedded
|
||||
newlines, so it's OK to save comment lines. If we're collecting the body
|
||||
of a here-document, we should act as if literal_history is enabled, because
|
||||
we want to save the entire contents of the here-document as it was
|
||||
entered. We also make sure to save multiple-line quoted strings or other
|
||||
constructs. */
|
||||
void
|
||||
maybe_add_history (line)
|
||||
char *line;
|
||||
{
|
||||
hist_last_line_added = 0;
|
||||
|
||||
/* Don't use the value of history_control to affect the second
|
||||
and subsequent lines of a multi-line command (old code did
|
||||
this only when command_oriented_history is enabled). */
|
||||
if (current_command_line_count > 1)
|
||||
{
|
||||
if (current_command_first_line_saved &&
|
||||
((parser_state & PST_HEREDOC) || literal_history || dstack.delimiter_depth != 0 || shell_comment (line) == 0))
|
||||
bash_add_history (line);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is the first line of a (possible multi-line) command. Note whether
|
||||
or not we should save the first line and remember it. */
|
||||
current_command_first_line_saved = check_add_history (line, 0);
|
||||
}
|
||||
|
||||
/* Just check LINE against HISTCONTROL and HISTIGNORE and add it to the
|
||||
history if it's OK. Used by `history -s' as well as maybe_add_history().
|
||||
Returns 1 if the line was saved in the history, 0 otherwise. */
|
||||
int
|
||||
check_add_history (line, force)
|
||||
char *line;
|
||||
int force;
|
||||
{
|
||||
if (check_history_control (line) && history_should_ignore (line) == 0)
|
||||
{
|
||||
/* We're committed to saving the line. If the user has requested it,
|
||||
remove other matching lines from the history. */
|
||||
if (history_control & HC_ERASEDUPS)
|
||||
hc_erasedups (line);
|
||||
|
||||
if (force)
|
||||
{
|
||||
really_add_history (line);
|
||||
using_history ();
|
||||
}
|
||||
else
|
||||
bash_add_history (line);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined (SYSLOG_HISTORY)
|
||||
#define SYSLOG_MAXLEN 600
|
||||
|
||||
void
|
||||
bash_syslog_history (line)
|
||||
const char *line;
|
||||
{
|
||||
char trunc[SYSLOG_MAXLEN];
|
||||
|
||||
if (strlen(line) < SYSLOG_MAXLEN)
|
||||
syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY: PID=%d UID=%d %s", getpid(), current_user.uid, line);
|
||||
else
|
||||
{
|
||||
strncpy (trunc, line, SYSLOG_MAXLEN);
|
||||
trunc[SYSLOG_MAXLEN - 1] = '\0';
|
||||
syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY (TRUNCATED): PID=%d UID=%d %s", getpid(), current_user.uid, trunc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Add a line to the history list.
|
||||
The variable COMMAND_ORIENTED_HISTORY controls the style of history
|
||||
remembering; when non-zero, and LINE is not the first line of a
|
||||
complete parser construct, append LINE to the last history line instead
|
||||
of adding it as a new line. */
|
||||
void
|
||||
bash_add_history (line)
|
||||
char *line;
|
||||
{
|
||||
int add_it, offset, curlen;
|
||||
HIST_ENTRY *current, *old;
|
||||
char *chars_to_add, *new_line;
|
||||
|
||||
add_it = 1;
|
||||
if (command_oriented_history && current_command_line_count > 1)
|
||||
{
|
||||
/* The second and subsequent lines of a here document have the trailing
|
||||
newline preserved. We don't want to add extra newlines here, but we
|
||||
do want to add one after the first line (which is the command that
|
||||
contains the here-doc specifier). parse.y:history_delimiting_chars()
|
||||
does the right thing to take care of this for us. We don't want to
|
||||
add extra newlines if the user chooses to enable literal_history,
|
||||
so we have to duplicate some of what that function does here. */
|
||||
if ((parser_state & PST_HEREDOC) && literal_history && current_command_line_count > 2 && line[strlen (line) - 1] == '\n')
|
||||
chars_to_add = "";
|
||||
else
|
||||
chars_to_add = literal_history ? "\n" : history_delimiting_chars (line);
|
||||
|
||||
using_history ();
|
||||
current = previous_history ();
|
||||
|
||||
if (current)
|
||||
{
|
||||
/* If the previous line ended with an escaped newline (escaped
|
||||
with backslash, but otherwise unquoted), then remove the quoted
|
||||
newline, since that is what happens when the line is parsed. */
|
||||
curlen = strlen (current->line);
|
||||
|
||||
if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\\' &&
|
||||
current->line[curlen - 2] != '\\')
|
||||
{
|
||||
current->line[curlen - 1] = '\0';
|
||||
curlen--;
|
||||
chars_to_add = "";
|
||||
}
|
||||
|
||||
/* If we're not in some kind of quoted construct, the current history
|
||||
entry ends with a newline, and we're going to add a semicolon,
|
||||
don't. In some cases, it results in a syntax error (e.g., before
|
||||
a close brace), and it should not be needed. */
|
||||
if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\n' && *chars_to_add == ';')
|
||||
chars_to_add++;
|
||||
|
||||
new_line = (char *)xmalloc (1
|
||||
+ curlen
|
||||
+ strlen (line)
|
||||
+ strlen (chars_to_add));
|
||||
sprintf (new_line, "%s%s%s", current->line, chars_to_add, line);
|
||||
offset = where_history ();
|
||||
old = replace_history_entry (offset, new_line, current->data);
|
||||
free (new_line);
|
||||
|
||||
if (old)
|
||||
free_history_entry (old);
|
||||
|
||||
add_it = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (add_it)
|
||||
really_add_history (line);
|
||||
|
||||
#if defined (SYSLOG_HISTORY)
|
||||
bash_syslog_history (line);
|
||||
#endif
|
||||
|
||||
using_history ();
|
||||
}
|
||||
|
||||
static void
|
||||
really_add_history (line)
|
||||
char *line;
|
||||
{
|
||||
hist_last_line_added = 1;
|
||||
hist_last_line_pushed = 0;
|
||||
add_history (line);
|
||||
history_lines_this_session++;
|
||||
}
|
||||
|
||||
int
|
||||
history_number ()
|
||||
{
|
||||
using_history ();
|
||||
return (remember_on_history ? history_base + where_history () : 1);
|
||||
}
|
||||
|
||||
static int
|
||||
should_expand (s)
|
||||
char *s;
|
||||
{
|
||||
char *p;
|
||||
|
||||
for (p = s; p && *p; p++)
|
||||
{
|
||||
if (*p == '\\')
|
||||
p++;
|
||||
else if (*p == '&')
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
histignore_item_func (ign)
|
||||
struct ign *ign;
|
||||
{
|
||||
if (should_expand (ign->val))
|
||||
ign->flags |= HIGN_EXPAND;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
setup_history_ignore (varname)
|
||||
char *varname;
|
||||
{
|
||||
setup_ignore_patterns (&histignore);
|
||||
}
|
||||
|
||||
static HIST_ENTRY *
|
||||
last_history_entry ()
|
||||
{
|
||||
HIST_ENTRY *he;
|
||||
|
||||
using_history ();
|
||||
he = previous_history ();
|
||||
using_history ();
|
||||
return he;
|
||||
}
|
||||
|
||||
char *
|
||||
last_history_line ()
|
||||
{
|
||||
HIST_ENTRY *he;
|
||||
|
||||
he = last_history_entry ();
|
||||
if (he == 0)
|
||||
return ((char *)NULL);
|
||||
return he->line;
|
||||
}
|
||||
|
||||
static char *
|
||||
expand_histignore_pattern (pat)
|
||||
char *pat;
|
||||
{
|
||||
HIST_ENTRY *phe;
|
||||
char *ret;
|
||||
|
||||
phe = last_history_entry ();
|
||||
|
||||
if (phe == (HIST_ENTRY *)0)
|
||||
return (savestring (pat));
|
||||
|
||||
ret = strcreplace (pat, '&', phe->line, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return 1 if we should not put LINE into the history according to the
|
||||
patterns in HISTIGNORE. */
|
||||
static int
|
||||
history_should_ignore (line)
|
||||
char *line;
|
||||
{
|
||||
register int i, match;
|
||||
char *npat;
|
||||
|
||||
if (histignore.num_ignores == 0)
|
||||
return 0;
|
||||
|
||||
for (i = match = 0; i < histignore.num_ignores; i++)
|
||||
{
|
||||
if (histignore.ignores[i].flags & HIGN_EXPAND)
|
||||
npat = expand_histignore_pattern (histignore.ignores[i].val);
|
||||
else
|
||||
npat = histignore.ignores[i].val;
|
||||
|
||||
match = strmatch (npat, line, FNMATCH_EXTFLAG) != FNM_NOMATCH;
|
||||
|
||||
if (histignore.ignores[i].flags & HIGN_EXPAND)
|
||||
free (npat);
|
||||
|
||||
if (match)
|
||||
break;
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
#endif /* HISTORY */
|
||||
-4122
File diff suppressed because it is too large
Load Diff
-221
@@ -1,221 +0,0 @@
|
||||
/* bracecomp.c -- Complete a filename with the possible completions enclosed
|
||||
in csh-style braces such that the list of completions is available to the
|
||||
shell. */
|
||||
|
||||
/* Original version by tromey@cns.caltech.edu, Fri Feb 7 1992. */
|
||||
|
||||
/* Copyright (C) 1993-2009 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (BRACE_EXPANSION) && defined (READLINE)
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shmbutil.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include <readline/readline.h>
|
||||
|
||||
static int _strcompare __P((char **, char **));
|
||||
|
||||
/* Find greatest common prefix of two strings. */
|
||||
static int
|
||||
string_gcd (s1, s2)
|
||||
char *s1, *s2;
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (s1 == NULL || s2 == NULL)
|
||||
return (0);
|
||||
|
||||
for (i = 0; *s1 && *s2; ++s1, ++s2, ++i)
|
||||
{
|
||||
if (*s1 != *s2)
|
||||
break;
|
||||
}
|
||||
|
||||
return (i);
|
||||
}
|
||||
|
||||
static char *
|
||||
really_munge_braces (array, real_start, real_end, gcd_zero)
|
||||
char **array;
|
||||
int real_start, real_end, gcd_zero;
|
||||
{
|
||||
int start, end, gcd;
|
||||
char *result, *subterm, *x;
|
||||
int result_size, flag, tlen;
|
||||
|
||||
flag = 0;
|
||||
|
||||
if (real_start == real_end)
|
||||
{
|
||||
x = array[real_start] ? sh_backslash_quote (array[real_start] + gcd_zero, 0)
|
||||
: sh_backslash_quote (array[0], 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
result = (char *)xmalloc (result_size = 16);
|
||||
*result = '\0';
|
||||
|
||||
for (start = real_start; start < real_end; start = end + 1)
|
||||
{
|
||||
gcd = strlen (array[start]);
|
||||
for (end = start + 1; end < real_end; end++)
|
||||
{
|
||||
int temp;
|
||||
|
||||
temp = string_gcd (array[start], array[end]);
|
||||
|
||||
if (temp <= gcd_zero)
|
||||
break;
|
||||
|
||||
gcd = temp;
|
||||
}
|
||||
end--;
|
||||
|
||||
if (gcd_zero == 0 && start == real_start && end != (real_end - 1))
|
||||
{
|
||||
/* In this case, add in a leading '{', because we are at
|
||||
top level, and there isn't a consistent prefix. */
|
||||
result_size += 1;
|
||||
result = (char *)xrealloc (result, result_size);
|
||||
result[0] = '{'; result[1] = '\0';
|
||||
flag++;
|
||||
}
|
||||
|
||||
/* Make sure we backslash quote every substring we insert into the
|
||||
resultant brace expression. This is so the default filename
|
||||
quoting function won't inappropriately quote the braces. */
|
||||
if (start == end)
|
||||
{
|
||||
x = savestring (array[start] + gcd_zero);
|
||||
subterm = sh_backslash_quote (x, 0);
|
||||
free (x);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If there is more than one element in the subarray,
|
||||
insert the (quoted) prefix and an opening brace. */
|
||||
tlen = gcd - gcd_zero;
|
||||
x = (char *)xmalloc (tlen + 1);
|
||||
strncpy (x, array[start] + gcd_zero, tlen);
|
||||
x[tlen] = '\0';
|
||||
subterm = sh_backslash_quote (x, 0);
|
||||
free (x);
|
||||
result_size += strlen (subterm) + 1;
|
||||
result = (char *)xrealloc (result, result_size);
|
||||
strcat (result, subterm);
|
||||
free (subterm);
|
||||
strcat (result, "{");
|
||||
subterm = really_munge_braces (array, start, end + 1, gcd);
|
||||
subterm[strlen (subterm) - 1] = '}';
|
||||
}
|
||||
|
||||
result_size += strlen (subterm) + 1;
|
||||
result = (char *)xrealloc (result, result_size);
|
||||
strcat (result, subterm);
|
||||
strcat (result, ",");
|
||||
free (subterm);
|
||||
}
|
||||
|
||||
if (gcd_zero == 0)
|
||||
result[strlen (result) - 1] = flag ? '}' : '\0';
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
_strcompare (s1, s2)
|
||||
char **s1, **s2;
|
||||
{
|
||||
int result;
|
||||
|
||||
result = **s1 - **s2;
|
||||
if (result == 0)
|
||||
result = strcmp (*s1, *s2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
hack_braces_completion (names)
|
||||
char **names;
|
||||
{
|
||||
register int i;
|
||||
char *temp;
|
||||
|
||||
i = strvec_len (names);
|
||||
if (MB_CUR_MAX > 1 && i > 2)
|
||||
qsort (names+1, i-1, sizeof (char *), (QSFUNC *)_strcompare);
|
||||
|
||||
temp = really_munge_braces (names, 1, i, 0);
|
||||
|
||||
for (i = 0; names[i]; ++i)
|
||||
{
|
||||
free (names[i]);
|
||||
names[i] = NULL;
|
||||
}
|
||||
names[0] = temp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We handle quoting ourselves within hack_braces_completion, so we turn off
|
||||
rl_filename_quoting_desired and rl_filename_quoting_function. */
|
||||
int
|
||||
bash_brace_completion (count, ignore)
|
||||
int count, ignore;
|
||||
{
|
||||
rl_compignore_func_t *orig_ignore_func;
|
||||
rl_compentry_func_t *orig_entry_func;
|
||||
rl_quote_func_t *orig_quoting_func;
|
||||
rl_completion_func_t *orig_attempt_func;
|
||||
int orig_quoting_desired, r;
|
||||
|
||||
orig_ignore_func = rl_ignore_some_completions_function;
|
||||
orig_attempt_func = rl_attempted_completion_function;
|
||||
orig_entry_func = rl_completion_entry_function;
|
||||
orig_quoting_func = rl_filename_quoting_function;
|
||||
orig_quoting_desired = rl_filename_quoting_desired;
|
||||
|
||||
rl_completion_entry_function = rl_filename_completion_function;
|
||||
rl_attempted_completion_function = (rl_completion_func_t *)NULL;
|
||||
rl_ignore_some_completions_function = hack_braces_completion;
|
||||
rl_filename_quoting_function = (rl_quote_func_t *)NULL;
|
||||
rl_filename_quoting_desired = 0;
|
||||
|
||||
r = rl_complete_internal (TAB);
|
||||
|
||||
rl_ignore_some_completions_function = orig_ignore_func;
|
||||
rl_attempted_completion_function = orig_attempt_func;
|
||||
rl_completion_entry_function = orig_entry_func;
|
||||
rl_filename_quoting_function = orig_quoting_func;
|
||||
rl_filename_quoting_desired = orig_quoting_desired;
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif /* BRACE_EXPANSION && READLINE */
|
||||
@@ -1,786 +0,0 @@
|
||||
/* braces.c -- code for doing word expansion in curly braces. */
|
||||
|
||||
/* Copyright (C) 1987-2012 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Stuff in curly braces gets expanded before all other shell expansions. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (BRACE_EXPANSION)
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#if defined (SHELL)
|
||||
# include "shell.h"
|
||||
#endif /* SHELL */
|
||||
|
||||
#include "general.h"
|
||||
#include "shmbutil.h"
|
||||
#include "chartypes.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
|
||||
|
||||
#define BRACE_SEQ_SPECIFIER ".."
|
||||
|
||||
extern int asprintf __P((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
|
||||
|
||||
extern int last_command_exit_value;
|
||||
|
||||
/* Basic idea:
|
||||
|
||||
Segregate the text into 3 sections: preamble (stuff before an open brace),
|
||||
postamble (stuff after the matching close brace) and amble (stuff after
|
||||
preamble, and before postamble). Expand amble, and then tack on the
|
||||
expansions to preamble. Expand postamble, and tack on the expansions to
|
||||
the result so far.
|
||||
*/
|
||||
|
||||
/* The character which is used to separate arguments. */
|
||||
static const int brace_arg_separator = ',';
|
||||
|
||||
#if defined (__P)
|
||||
static int brace_gobbler __P((char *, size_t, int *, int));
|
||||
static char **expand_amble __P((char *, size_t, int));
|
||||
static char **expand_seqterm __P((char *, size_t));
|
||||
static char **mkseq __P((intmax_t, intmax_t, intmax_t, int, int));
|
||||
static char **array_concat __P((char **, char **));
|
||||
#else
|
||||
static int brace_gobbler ();
|
||||
static char **expand_amble ();
|
||||
static char **expand_seqterm ();
|
||||
static char **mkseq();
|
||||
static char **array_concat ();
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static void
|
||||
dump_result (a)
|
||||
char **a;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; a[i]; i++)
|
||||
printf ("dump_result: a[%d] = -%s-\n", i, a[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return an array of strings; the brace expansion of TEXT. */
|
||||
char **
|
||||
brace_expand (text)
|
||||
char *text;
|
||||
{
|
||||
register int start;
|
||||
size_t tlen;
|
||||
char *preamble, *postamble, *amble;
|
||||
size_t alen;
|
||||
char **tack, **result;
|
||||
int i, j, c, c1;
|
||||
|
||||
DECLARE_MBSTATE;
|
||||
|
||||
/* Find the text of the preamble. */
|
||||
tlen = strlen (text);
|
||||
i = 0;
|
||||
#if defined (CSH_BRACE_COMPAT)
|
||||
c = brace_gobbler (text, tlen, &i, '{'); /* } */
|
||||
#else
|
||||
/* Make sure that when we exit this loop, c == 0 or text[i] begins a
|
||||
valid brace expansion sequence. */
|
||||
do
|
||||
{
|
||||
c = brace_gobbler (text, tlen, &i, '{'); /* } */
|
||||
c1 = c;
|
||||
/* Verify that c begins a valid brace expansion word. If it doesn't, we
|
||||
go on. Loop stops when there are no more open braces in the word. */
|
||||
if (c)
|
||||
{
|
||||
start = j = i + 1; /* { */
|
||||
c = brace_gobbler (text, tlen, &j, '}');
|
||||
if (c == 0) /* it's not */
|
||||
{
|
||||
i++;
|
||||
c = c1;
|
||||
continue;
|
||||
}
|
||||
else /* it is */
|
||||
{
|
||||
c = c1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
while (c);
|
||||
#endif /* !CSH_BRACE_COMPAT */
|
||||
|
||||
preamble = (char *)xmalloc (i + 1);
|
||||
if (i > 0)
|
||||
strncpy (preamble, text, i);
|
||||
preamble[i] = '\0';
|
||||
|
||||
result = (char **)xmalloc (2 * sizeof (char *));
|
||||
result[0] = preamble;
|
||||
result[1] = (char *)NULL;
|
||||
|
||||
/* Special case. If we never found an exciting character, then
|
||||
the preamble is all of the text, so just return that. */
|
||||
if (c != '{')
|
||||
return (result);
|
||||
|
||||
/* Find the amble. This is the stuff inside this set of braces. */
|
||||
start = ++i;
|
||||
c = brace_gobbler (text, tlen, &i, '}');
|
||||
|
||||
/* What if there isn't a matching close brace? */
|
||||
if (c == 0)
|
||||
{
|
||||
#if defined (NOTDEF)
|
||||
/* Well, if we found an unquoted BRACE_ARG_SEPARATOR between START
|
||||
and I, then this should be an error. Otherwise, it isn't. */
|
||||
j = start;
|
||||
while (j < i)
|
||||
{
|
||||
if (text[j] == '\\')
|
||||
{
|
||||
j++;
|
||||
ADVANCE_CHAR (text, tlen, j);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (text[j] == brace_arg_separator)
|
||||
{ /* { */
|
||||
strvec_dispose (result);
|
||||
last_command_exit_value = 1;
|
||||
report_error ("no closing `%c' in %s", '}', text);
|
||||
throw_to_top_level ();
|
||||
}
|
||||
ADVANCE_CHAR (text, tlen, j);
|
||||
}
|
||||
#endif
|
||||
free (preamble); /* Same as result[0]; see initialization. */
|
||||
result[0] = savestring (text);
|
||||
return (result);
|
||||
}
|
||||
|
||||
#if defined (SHELL)
|
||||
amble = substring (text, start, i);
|
||||
alen = i - start;
|
||||
#else
|
||||
amble = (char *)xmalloc (1 + (i - start));
|
||||
strncpy (amble, &text[start], (i - start));
|
||||
alen = i - start;
|
||||
amble[alen] = '\0';
|
||||
#endif
|
||||
|
||||
#if defined (SHELL)
|
||||
INITIALIZE_MBSTATE;
|
||||
|
||||
/* If the amble does not contain an unquoted BRACE_ARG_SEPARATOR, then
|
||||
just return without doing any expansion. */
|
||||
j = 0;
|
||||
while (amble[j])
|
||||
{
|
||||
if (amble[j] == '\\')
|
||||
{
|
||||
j++;
|
||||
ADVANCE_CHAR (amble, alen, j);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (amble[j] == brace_arg_separator)
|
||||
break;
|
||||
|
||||
ADVANCE_CHAR (amble, alen, j);
|
||||
}
|
||||
|
||||
if (amble[j] == 0)
|
||||
{
|
||||
tack = expand_seqterm (amble, alen);
|
||||
if (tack)
|
||||
goto add_tack;
|
||||
else
|
||||
{
|
||||
free (amble);
|
||||
free (preamble);
|
||||
result[0] = savestring (text);
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
#endif /* SHELL */
|
||||
|
||||
tack = expand_amble (amble, alen, 0);
|
||||
add_tack:
|
||||
result = array_concat (result, tack);
|
||||
free (amble);
|
||||
if (tack != result)
|
||||
strvec_dispose (tack);
|
||||
|
||||
postamble = text + i + 1;
|
||||
|
||||
if (postamble && *postamble)
|
||||
{
|
||||
tack = brace_expand (postamble);
|
||||
result = array_concat (result, tack);
|
||||
if (tack != result)
|
||||
strvec_dispose (tack);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Expand the text found inside of braces. We simply try to split the
|
||||
text at BRACE_ARG_SEPARATORs into separate strings. We then brace
|
||||
expand each slot which needs it, until there are no more slots which
|
||||
need it. */
|
||||
static char **
|
||||
expand_amble (text, tlen, flags)
|
||||
char *text;
|
||||
size_t tlen;
|
||||
int flags;
|
||||
{
|
||||
char **result, **partial;
|
||||
char *tem;
|
||||
int start, i, c;
|
||||
|
||||
DECLARE_MBSTATE;
|
||||
|
||||
result = (char **)NULL;
|
||||
|
||||
start = i = 0;
|
||||
c = 1;
|
||||
while (c)
|
||||
{
|
||||
c = brace_gobbler (text, tlen, &i, brace_arg_separator);
|
||||
#if defined (SHELL)
|
||||
tem = substring (text, start, i);
|
||||
#else
|
||||
tem = (char *)xmalloc (1 + (i - start));
|
||||
strncpy (tem, &text[start], (i - start));
|
||||
tem[i- start] = '\0';
|
||||
#endif
|
||||
|
||||
partial = brace_expand (tem);
|
||||
|
||||
if (!result)
|
||||
result = partial;
|
||||
else
|
||||
{
|
||||
register int lr, lp, j;
|
||||
|
||||
lr = strvec_len (result);
|
||||
lp = strvec_len (partial);
|
||||
|
||||
result = strvec_resize (result, lp + lr + 1);
|
||||
|
||||
for (j = 0; j < lp; j++)
|
||||
result[lr + j] = partial[j];
|
||||
|
||||
result[lr + j] = (char *)NULL;
|
||||
free (partial);
|
||||
}
|
||||
free (tem);
|
||||
ADVANCE_CHAR (text, tlen, i);
|
||||
start = i;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
#define ST_BAD 0
|
||||
#define ST_INT 1
|
||||
#define ST_CHAR 2
|
||||
#define ST_ZINT 3
|
||||
|
||||
#ifndef sh_imaxabs
|
||||
# define sh_imaxabs(x) (((x) >= 0) ? (x) : -(x))
|
||||
#endif
|
||||
|
||||
/* Handle signed arithmetic overflow and underflow. Have to do it this way
|
||||
to avoid compilers optimizing out simpler overflow checks. */
|
||||
|
||||
/* Make sure that a+b does not exceed MAXV or is smaller than MINV (if b < 0).
|
||||
Assumes that b > 0 if a > 0 and b < 0 if a < 0 */
|
||||
#define ADDOVERFLOW(a,b,minv,maxv) \
|
||||
((((a) > 0) && ((b) > ((maxv) - (a)))) || \
|
||||
(((a) < 0) && ((b) < ((minv) - (a)))))
|
||||
|
||||
/* Make sure that a-b is not smaller than MINV or exceeds MAXV (if b < 0).
|
||||
Assumes that b > 0 if a > 0 and b < 0 if a < 0 */
|
||||
#define SUBOVERFLOW(a,b,minv,maxv) \
|
||||
((((b) > 0) && ((a) < ((minv) + (b)))) || \
|
||||
(((b) < 0) && ((a) > ((maxv) + (b)))))
|
||||
|
||||
static char **
|
||||
mkseq (start, end, incr, type, width)
|
||||
intmax_t start, end, incr;
|
||||
int type, width;
|
||||
{
|
||||
intmax_t n, prevn;
|
||||
int i, nelem;
|
||||
char **result, *t;
|
||||
|
||||
if (incr == 0)
|
||||
incr = 1;
|
||||
|
||||
if (start > end && incr > 0)
|
||||
incr = -incr;
|
||||
else if (start < end && incr < 0)
|
||||
{
|
||||
if (incr == INTMAX_MIN) /* Don't use -INTMAX_MIN */
|
||||
return ((char **)NULL);
|
||||
incr = -incr;
|
||||
}
|
||||
|
||||
/* Check that end-start will not overflow INTMAX_MIN, INTMAX_MAX. The +3
|
||||
and -2, not strictly necessary, are there because of the way the number
|
||||
of elements and value passed to strvec_create() are calculated below. */
|
||||
if (SUBOVERFLOW (end, start, INTMAX_MIN+3, INTMAX_MAX-2))
|
||||
return ((char **)NULL);
|
||||
|
||||
prevn = sh_imaxabs (end - start);
|
||||
/* Need to check this way in case INT_MAX == INTMAX_MAX */
|
||||
if (INT_MAX == INTMAX_MAX && (ADDOVERFLOW (prevn, 2, INT_MIN, INT_MAX)))
|
||||
return ((char **)NULL);
|
||||
else if (ADDOVERFLOW ((prevn/sh_imaxabs(incr)), 1, INTMAX_MIN, INTMAX_MAX))
|
||||
return ((char **)NULL);
|
||||
|
||||
/* XXX - TOFIX: potentially allocating a lot of extra memory if
|
||||
imaxabs(incr) != 1 */
|
||||
/* Instead of a simple nelem = prevn + 1, something like:
|
||||
nelem = (prevn / imaxabs(incr)) + 1;
|
||||
would work */
|
||||
nelem = (prevn / sh_imaxabs(incr)) + 1;
|
||||
if (nelem > INT_MAX - 2) /* Don't overflow int */
|
||||
return ((char **)NULL);
|
||||
result = strvec_create (nelem + 1);
|
||||
|
||||
/* Make sure we go through the loop at least once, so {3..3} prints `3' */
|
||||
i = 0;
|
||||
n = start;
|
||||
do
|
||||
{
|
||||
#if defined (SHELL)
|
||||
QUIT; /* XXX - memory leak here */
|
||||
#endif
|
||||
if (type == ST_INT)
|
||||
result[i++] = itos (n);
|
||||
else if (type == ST_ZINT)
|
||||
{
|
||||
int len, arg;
|
||||
arg = n;
|
||||
len = asprintf (&t, "%0*d", width, arg);
|
||||
result[i++] = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = (char *)xmalloc (2);
|
||||
t[0] = n;
|
||||
t[1] = '\0';
|
||||
result[i++] = t;
|
||||
}
|
||||
|
||||
/* Handle overflow and underflow of n+incr */
|
||||
if (ADDOVERFLOW (n, incr, INTMAX_MIN, INTMAX_MAX))
|
||||
break;
|
||||
|
||||
n += incr;
|
||||
|
||||
if ((incr < 0 && n < end) || (incr > 0 && n > end))
|
||||
break;
|
||||
}
|
||||
while (1);
|
||||
|
||||
result[i] = (char *)0;
|
||||
return (result);
|
||||
}
|
||||
|
||||
static char **
|
||||
expand_seqterm (text, tlen)
|
||||
char *text;
|
||||
size_t tlen;
|
||||
{
|
||||
char *t, *lhs, *rhs;
|
||||
int i, lhs_t, rhs_t, lhs_l, rhs_l, width;
|
||||
intmax_t lhs_v, rhs_v, incr;
|
||||
intmax_t tl, tr;
|
||||
char **result, *ep, *oep;
|
||||
|
||||
t = strstr (text, BRACE_SEQ_SPECIFIER);
|
||||
if (t == 0)
|
||||
return ((char **)NULL);
|
||||
|
||||
lhs_l = t - text; /* index of start of BRACE_SEQ_SPECIFIER */
|
||||
lhs = substring (text, 0, lhs_l);
|
||||
rhs = substring (text, lhs_l + sizeof(BRACE_SEQ_SPECIFIER) - 1, tlen);
|
||||
|
||||
if (lhs[0] == 0 || rhs[0] == 0)
|
||||
{
|
||||
free (lhs);
|
||||
free (rhs);
|
||||
return ((char **)NULL);
|
||||
}
|
||||
|
||||
/* Now figure out whether LHS and RHS are integers or letters. Both
|
||||
sides have to match. */
|
||||
lhs_t = (legal_number (lhs, &tl)) ? ST_INT :
|
||||
((ISALPHA (lhs[0]) && lhs[1] == 0) ? ST_CHAR : ST_BAD);
|
||||
|
||||
/* Decide on rhs and whether or not it looks like the user specified
|
||||
an increment */
|
||||
ep = 0;
|
||||
if (ISDIGIT (rhs[0]) || ((rhs[0] == '+' || rhs[0] == '-') && ISDIGIT (rhs[1])))
|
||||
{
|
||||
rhs_t = ST_INT;
|
||||
errno == 0;
|
||||
tr = strtoimax (rhs, &ep, 10);
|
||||
if (errno == ERANGE || (ep && *ep != 0 && *ep != '.'))
|
||||
rhs_t = ST_BAD; /* invalid */
|
||||
}
|
||||
else if (ISALPHA (rhs[0]) && (rhs[1] == 0 || rhs[1] == '.'))
|
||||
{
|
||||
rhs_t = ST_CHAR;
|
||||
ep = rhs + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rhs_t = ST_BAD;
|
||||
ep = 0;
|
||||
}
|
||||
|
||||
incr = 1;
|
||||
if (rhs_t != ST_BAD)
|
||||
{
|
||||
oep = ep;
|
||||
errno = 0;
|
||||
if (ep && *ep == '.' && ep[1] == '.' && ep[2])
|
||||
incr = strtoimax (ep + 2, &ep, 10);
|
||||
if (*ep != 0 || errno == ERANGE)
|
||||
rhs_t = ST_BAD; /* invalid incr or overflow */
|
||||
tlen -= ep - oep;
|
||||
}
|
||||
|
||||
if (lhs_t != rhs_t || lhs_t == ST_BAD || rhs_t == ST_BAD)
|
||||
{
|
||||
free (lhs);
|
||||
free (rhs);
|
||||
return ((char **)NULL);
|
||||
}
|
||||
|
||||
/* OK, we have something. It's either a sequence of integers, ascending
|
||||
or descending, or a sequence or letters, ditto. Generate the sequence,
|
||||
put it into a string vector, and return it. */
|
||||
|
||||
if (lhs_t == ST_CHAR)
|
||||
{
|
||||
lhs_v = (unsigned char)lhs[0];
|
||||
rhs_v = (unsigned char)rhs[0];
|
||||
width = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lhs_v = tl; /* integer truncation */
|
||||
rhs_v = tr;
|
||||
|
||||
/* Decide whether or not the terms need zero-padding */
|
||||
rhs_l = tlen - lhs_l - sizeof (BRACE_SEQ_SPECIFIER) + 1;
|
||||
width = 0;
|
||||
if (lhs_l > 1 && lhs[0] == '0')
|
||||
width = lhs_l, lhs_t = ST_ZINT;
|
||||
if (lhs_l > 2 && lhs[0] == '-' && lhs[1] == '0')
|
||||
width = lhs_l, lhs_t = ST_ZINT;
|
||||
if (rhs_l > 1 && rhs[0] == '0' && width < rhs_l)
|
||||
width = rhs_l, lhs_t = ST_ZINT;
|
||||
if (rhs_l > 2 && rhs[0] == '-' && rhs[1] == '0' && width < rhs_l)
|
||||
width = rhs_l, lhs_t = ST_ZINT;
|
||||
|
||||
if (width < lhs_l && lhs_t == ST_ZINT)
|
||||
width = lhs_l;
|
||||
if (width < rhs_l && lhs_t == ST_ZINT)
|
||||
width = rhs_l;
|
||||
}
|
||||
|
||||
result = mkseq (lhs_v, rhs_v, incr, lhs_t, width);
|
||||
|
||||
free (lhs);
|
||||
free (rhs);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Start at INDEX, and skip characters in TEXT. Set INDEX to the
|
||||
index of the character matching SATISFY. This understands about
|
||||
quoting. Return the character that caused us to stop searching;
|
||||
this is either the same as SATISFY, or 0. */
|
||||
/* If SATISFY is `}', we are looking for a brace expression, so we
|
||||
should enforce the rules that govern valid brace expansions:
|
||||
1) to count as an arg separator, a comma or `..' has to be outside
|
||||
an inner set of braces.
|
||||
*/
|
||||
static int
|
||||
brace_gobbler (text, tlen, indx, satisfy)
|
||||
char *text;
|
||||
size_t tlen;
|
||||
int *indx;
|
||||
int satisfy;
|
||||
{
|
||||
register int i, c, quoted, level, commas, pass_next;
|
||||
#if defined (SHELL)
|
||||
int si;
|
||||
char *t;
|
||||
#endif
|
||||
DECLARE_MBSTATE;
|
||||
|
||||
level = quoted = pass_next = 0;
|
||||
#if defined (CSH_BRACE_COMPAT)
|
||||
commas = 1;
|
||||
#else
|
||||
commas = (satisfy == '}') ? 0 : 1;
|
||||
#endif
|
||||
|
||||
i = *indx;
|
||||
while (c = text[i])
|
||||
{
|
||||
if (pass_next)
|
||||
{
|
||||
pass_next = 0;
|
||||
ADVANCE_CHAR (text, tlen, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* A backslash escapes the next character. This allows backslash to
|
||||
escape the quote character in a double-quoted string. */
|
||||
if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
|
||||
{
|
||||
pass_next = 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined (SHELL)
|
||||
/* If compiling for the shell, treat ${...} like \{...} */
|
||||
if (c == '$' && text[i+1] == '{' && quoted != '\'') /* } */
|
||||
{
|
||||
pass_next = 1;
|
||||
i++;
|
||||
if (quoted == 0)
|
||||
level++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (quoted)
|
||||
{
|
||||
if (c == quoted)
|
||||
quoted = 0;
|
||||
#if defined (SHELL)
|
||||
/* The shell allows quoted command substitutions */
|
||||
if (quoted == '"' && c == '$' && text[i+1] == '(') /*)*/
|
||||
goto comsub;
|
||||
#endif
|
||||
ADVANCE_CHAR (text, tlen, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '"' || c == '\'' || c == '`')
|
||||
{
|
||||
quoted = c;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined (SHELL)
|
||||
/* Pass new-style command and process substitutions through unchanged. */
|
||||
if ((c == '$' || c == '<' || c == '>') && text[i+1] == '(') /* ) */
|
||||
{
|
||||
comsub:
|
||||
si = i + 2;
|
||||
t = extract_command_subst (text, &si, 0);
|
||||
i = si;
|
||||
free (t);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (c == satisfy && level == 0 && quoted == 0 && commas > 0)
|
||||
{
|
||||
/* We ignore an open brace surrounded by whitespace, and also
|
||||
an open brace followed immediately by a close brace preceded
|
||||
by whitespace. */
|
||||
if (c == '{' &&
|
||||
((!i || brace_whitespace (text[i - 1])) &&
|
||||
(brace_whitespace (text[i + 1]) || text[i + 1] == '}')))
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '{')
|
||||
level++;
|
||||
else if (c == '}' && level)
|
||||
level--;
|
||||
#if !defined (CSH_BRACE_COMPAT)
|
||||
else if (satisfy == '}' && c == brace_arg_separator && level == 0)
|
||||
commas++;
|
||||
else if (satisfy == '}' && STREQN (text+i, BRACE_SEQ_SPECIFIER, 2) &&
|
||||
text[i+2] != satisfy && level == 0)
|
||||
commas++;
|
||||
#endif
|
||||
|
||||
ADVANCE_CHAR (text, tlen, i);
|
||||
}
|
||||
|
||||
*indx = i;
|
||||
return (c);
|
||||
}
|
||||
|
||||
/* Return 1 if ARR has any non-empty-string members. Used to short-circuit
|
||||
in array_concat() below. */
|
||||
static int
|
||||
degenerate_array (arr)
|
||||
char **arr;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; arr[i]; i++)
|
||||
if (arr[i][0] != '\0')
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return a new array of strings which is the result of appending each
|
||||
string in ARR2 to each string in ARR1. The resultant array is
|
||||
len (arr1) * len (arr2) long. For convenience, ARR1 (and its contents)
|
||||
are free ()'ed. ARR1 can be NULL, in that case, a new version of ARR2
|
||||
is returned. */
|
||||
static char **
|
||||
array_concat (arr1, arr2)
|
||||
char **arr1, **arr2;
|
||||
{
|
||||
register int i, j, len, len1, len2;
|
||||
register char **result;
|
||||
|
||||
if (arr1 == 0)
|
||||
return (arr2); /* XXX - see if we can get away without copying? */
|
||||
|
||||
if (arr2 == 0)
|
||||
return (arr1); /* XXX - caller expects us to free arr1 */
|
||||
|
||||
if (degenerate_array (arr1))
|
||||
{
|
||||
strvec_dispose (arr1);
|
||||
return (arr2); /* XXX - use flags to see if we can avoid copying here */
|
||||
}
|
||||
|
||||
if (degenerate_array (arr2))
|
||||
return (arr1); /* XXX - rather than copying and freeing it */
|
||||
|
||||
len1 = strvec_len (arr1);
|
||||
len2 = strvec_len (arr2);
|
||||
|
||||
result = (char **)xmalloc ((1 + (len1 * len2)) * sizeof (char *));
|
||||
|
||||
len = 0;
|
||||
for (i = 0; i < len1; i++)
|
||||
{
|
||||
int strlen_1 = strlen (arr1[i]);
|
||||
|
||||
for (j = 0; j < len2; j++)
|
||||
{
|
||||
result[len] = (char *)xmalloc (1 + strlen_1 + strlen (arr2[j]));
|
||||
strcpy (result[len], arr1[i]);
|
||||
strcpy (result[len] + strlen_1, arr2[j]);
|
||||
len++;
|
||||
}
|
||||
free (arr1[i]);
|
||||
}
|
||||
free (arr1);
|
||||
|
||||
result[len] = (char *)NULL;
|
||||
return (result);
|
||||
}
|
||||
|
||||
#if defined (TEST)
|
||||
#include <stdio.h>
|
||||
|
||||
fatal_error (format, arg1, arg2)
|
||||
char *format, *arg1, *arg2;
|
||||
{
|
||||
report_error (format, arg1, arg2);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
report_error (format, arg1, arg2)
|
||||
char *format, *arg1, *arg2;
|
||||
{
|
||||
fprintf (stderr, format, arg1, arg2);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
main ()
|
||||
{
|
||||
char example[256];
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char **result;
|
||||
int i;
|
||||
|
||||
fprintf (stderr, "brace_expand> ");
|
||||
|
||||
if ((!fgets (example, 256, stdin)) ||
|
||||
(strncmp (example, "quit", 4) == 0))
|
||||
break;
|
||||
|
||||
if (strlen (example))
|
||||
example[strlen (example) - 1] = '\0';
|
||||
|
||||
result = brace_expand (example);
|
||||
|
||||
for (i = 0; result[i]; i++)
|
||||
printf ("%s\n", result[i]);
|
||||
|
||||
free_array (result);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* compile-command: "gcc -g -Bstatic -DTEST -o brace_expand braces.c general.o"
|
||||
* end:
|
||||
*/
|
||||
|
||||
#endif /* TEST */
|
||||
#endif /* BRACE_EXPANSION */
|
||||
@@ -1,659 +0,0 @@
|
||||
This file is declare.def, from which is created declare.c.
|
||||
It implements the builtins "declare" and "local" in Bash.
|
||||
|
||||
Copyright (C) 1987-2012 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$PRODUCES declare.c
|
||||
|
||||
$BUILTIN declare
|
||||
$FUNCTION declare_builtin
|
||||
$SHORT_DOC declare [-aAfFgilnrtux] [-p] [name[=value] ...]
|
||||
Set variable values and attributes.
|
||||
|
||||
Declare variables and give them attributes. If no NAMEs are given,
|
||||
display the attributes and values of all variables.
|
||||
|
||||
Options:
|
||||
-f restrict action or display to function names and definitions
|
||||
-F restrict display to function names only (plus line number and
|
||||
source file when debugging)
|
||||
-g create global variables when used in a shell function; otherwise
|
||||
ignored
|
||||
-p display the attributes and value of each NAME
|
||||
|
||||
Options which set attributes:
|
||||
-a to make NAMEs indexed arrays (if supported)
|
||||
-A to make NAMEs associative arrays (if supported)
|
||||
-i to make NAMEs have the `integer' attribute
|
||||
-l to convert NAMEs to lower case on assignment
|
||||
-n make NAME a reference to the variable named by its value
|
||||
-r to make NAMEs readonly
|
||||
-t to make NAMEs have the `trace' attribute
|
||||
-u to convert NAMEs to upper case on assignment
|
||||
-x to make NAMEs export
|
||||
|
||||
Using `+' instead of `-' turns off the given attribute.
|
||||
|
||||
Variables with the integer attribute have arithmetic evaluation (see
|
||||
the `let' command) performed when the variable is assigned a value.
|
||||
|
||||
When used in a function, `declare' makes NAMEs local, as with the `local'
|
||||
command. The `-g' option suppresses this behavior.
|
||||
|
||||
Exit Status:
|
||||
Returns success unless an invalid option is supplied or an error occurs.
|
||||
$END
|
||||
|
||||
$BUILTIN typeset
|
||||
$FUNCTION declare_builtin
|
||||
$SHORT_DOC typeset [-aAfFgilrtux] [-p] name[=value] ...
|
||||
Set variable values and attributes.
|
||||
|
||||
Obsolete. See `help declare'.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "common.h"
|
||||
#include "builtext.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int array_needs_making;
|
||||
extern int posixly_correct;
|
||||
|
||||
static int declare_internal __P((register WORD_LIST *, int));
|
||||
|
||||
/* Declare or change variable attributes. */
|
||||
int
|
||||
declare_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
return (declare_internal (list, 0));
|
||||
}
|
||||
|
||||
$BUILTIN local
|
||||
$FUNCTION local_builtin
|
||||
$SHORT_DOC local [option] name[=value] ...
|
||||
Define local variables.
|
||||
|
||||
Create a local variable called NAME, and give it VALUE. OPTION can
|
||||
be any option accepted by `declare'.
|
||||
|
||||
Local variables can only be used within a function; they are visible
|
||||
only to the function where they are defined and its children.
|
||||
|
||||
Exit Status:
|
||||
Returns success unless an invalid option is supplied, an error occurs,
|
||||
or the shell is not executing a function.
|
||||
$END
|
||||
int
|
||||
local_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
if (variable_context)
|
||||
return (declare_internal (list, 1));
|
||||
else
|
||||
{
|
||||
builtin_error (_("can only be used in a function"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
# define DECLARE_OPTS "+acfgilnprtuxAF"
|
||||
#else
|
||||
# define DECLARE_OPTS "+cfgilnprtuxF"
|
||||
#endif
|
||||
|
||||
/* The workhorse function. */
|
||||
static int
|
||||
declare_internal (list, local_var)
|
||||
register WORD_LIST *list;
|
||||
int local_var;
|
||||
{
|
||||
int flags_on, flags_off, *flags;
|
||||
int any_failed, assign_error, pflag, nodefs, opt, mkglobal, onref, offref;
|
||||
char *t, *subscript_start;
|
||||
SHELL_VAR *var, *refvar;
|
||||
FUNCTION_DEF *shell_fn;
|
||||
|
||||
flags_on = flags_off = any_failed = assign_error = pflag = nodefs = mkglobal = 0;
|
||||
refvar = (SHELL_VAR *)NULL;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, DECLARE_OPTS)) != EOF)
|
||||
{
|
||||
flags = list_opttype == '+' ? &flags_off : &flags_on;
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
#if defined (ARRAY_VARS)
|
||||
*flags |= att_array;
|
||||
break;
|
||||
#else
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
#endif
|
||||
case 'A':
|
||||
#if defined (ARRAY_VARS)
|
||||
*flags |= att_assoc;
|
||||
break;
|
||||
#else
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
#endif
|
||||
case 'p':
|
||||
if (local_var == 0)
|
||||
pflag++;
|
||||
break;
|
||||
case 'F':
|
||||
nodefs++;
|
||||
*flags |= att_function;
|
||||
break;
|
||||
case 'f':
|
||||
*flags |= att_function;
|
||||
break;
|
||||
case 'g':
|
||||
if (flags == &flags_on)
|
||||
mkglobal = 1;
|
||||
break;
|
||||
case 'i':
|
||||
*flags |= att_integer;
|
||||
break;
|
||||
case 'n':
|
||||
*flags |= att_nameref;
|
||||
break;
|
||||
case 'r':
|
||||
*flags |= att_readonly;
|
||||
break;
|
||||
case 't':
|
||||
*flags |= att_trace;
|
||||
break;
|
||||
case 'x':
|
||||
*flags |= att_exported;
|
||||
array_needs_making = 1;
|
||||
break;
|
||||
#if defined (CASEMOD_ATTRS)
|
||||
# if defined (CASEMOD_CAPCASE)
|
||||
case 'c':
|
||||
*flags |= att_capcase;
|
||||
if (flags == &flags_on)
|
||||
flags_off |= att_uppercase|att_lowercase;
|
||||
break;
|
||||
# endif
|
||||
case 'l':
|
||||
*flags |= att_lowercase;
|
||||
if (flags == &flags_on)
|
||||
flags_off |= att_capcase|att_uppercase;
|
||||
break;
|
||||
case 'u':
|
||||
*flags |= att_uppercase;
|
||||
if (flags == &flags_on)
|
||||
flags_off |= att_capcase|att_lowercase;
|
||||
break;
|
||||
#endif /* CASEMOD_ATTRS */
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
/* If there are no more arguments left, then we just want to show
|
||||
some variables. */
|
||||
if (list == 0) /* declare -[aAfFirtx] */
|
||||
{
|
||||
/* Show local variables defined at this context level if this is
|
||||
the `local' builtin. */
|
||||
if (local_var)
|
||||
{
|
||||
register SHELL_VAR **vlist;
|
||||
register int i;
|
||||
|
||||
vlist = all_local_variables ();
|
||||
|
||||
if (vlist)
|
||||
{
|
||||
for (i = 0; vlist[i]; i++)
|
||||
print_assignment (vlist[i]);
|
||||
|
||||
free (vlist);
|
||||
}
|
||||
}
|
||||
else if (pflag && (flags_on == 0 || flags_on == att_function))
|
||||
show_all_var_attributes (flags_on == 0, nodefs);
|
||||
else if (flags_on == 0)
|
||||
return (set_builtin ((WORD_LIST *)NULL));
|
||||
else
|
||||
set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
|
||||
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
if (pflag) /* declare -p [-aAfFirtx] name [name...] */
|
||||
{
|
||||
for (any_failed = 0; list; list = list->next)
|
||||
{
|
||||
pflag = show_name_attributes (list->word->word, nodefs);
|
||||
if (pflag)
|
||||
{
|
||||
sh_notfound (list->word->word);
|
||||
any_failed++;
|
||||
}
|
||||
}
|
||||
return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
#define NEXT_VARIABLE() free (name); list = list->next; continue
|
||||
|
||||
/* There are arguments left, so we are making variables. */
|
||||
while (list) /* declare [-aAfFirx] name [name ...] */
|
||||
{
|
||||
char *value, *name;
|
||||
int offset, aflags;
|
||||
#if defined (ARRAY_VARS)
|
||||
int making_array_special, compound_array_assign, simple_array_assign;
|
||||
#endif
|
||||
|
||||
name = savestring (list->word->word);
|
||||
offset = assignment (name, 0);
|
||||
aflags = 0;
|
||||
|
||||
if (offset) /* declare [-aAfFirx] name=value */
|
||||
{
|
||||
name[offset] = '\0';
|
||||
value = name + offset + 1;
|
||||
if (name[offset - 1] == '+')
|
||||
{
|
||||
aflags |= ASS_APPEND;
|
||||
name[offset - 1] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
value = "";
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
compound_array_assign = simple_array_assign = 0;
|
||||
subscript_start = (char *)NULL;
|
||||
if (t = strchr (name, '[')) /* ] */
|
||||
{
|
||||
/* If offset != 0 we have already validated any array reference */
|
||||
if (offset == 0 && valid_array_reference (name) == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
assign_error++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
subscript_start = t;
|
||||
*t = '\0';
|
||||
making_array_special = 1;
|
||||
}
|
||||
else
|
||||
making_array_special = 0;
|
||||
#endif
|
||||
|
||||
/* If we're in posix mode or not looking for a shell function (since
|
||||
shell function names don't have to be valid identifiers when the
|
||||
shell's not in posix mode), check whether or not the argument is a
|
||||
valid, well-formed shell identifier. */
|
||||
if ((posixly_correct || (flags_on & att_function) == 0) && legal_identifier (name) == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
assign_error++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* If VARIABLE_CONTEXT has a non-zero value, then we are executing
|
||||
inside of a function. This means we should make local variables,
|
||||
not global ones. */
|
||||
|
||||
/* XXX - this has consequences when we're making a local copy of a
|
||||
variable that was in the temporary environment. Watch out
|
||||
for this. */
|
||||
refvar = (SHELL_VAR *)NULL;
|
||||
if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0))
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (flags_on & att_assoc)
|
||||
var = make_local_assoc_variable (name);
|
||||
else if ((flags_on & att_array) || making_array_special)
|
||||
var = make_local_array_variable (name, making_array_special);
|
||||
else
|
||||
#endif
|
||||
#if 0
|
||||
/* XXX - this doesn't work right yet. */
|
||||
/* See below for rationale for doing this. */
|
||||
if (flags_on & att_nameref)
|
||||
{
|
||||
/* See if we are trying to modify an existing nameref variable */
|
||||
var = find_variable_last_nameref (name);
|
||||
if (var && nameref_p (var) == 0)
|
||||
var = make_local_variable (name);
|
||||
}
|
||||
else if (flags_off & att_nameref)
|
||||
{
|
||||
var = (SHELL_VAR *)NULL;
|
||||
/* See if we are trying to modify an existing nameref variable */
|
||||
refvar = find_variable_last_nameref (name);
|
||||
if (refvar && nameref_p (refvar) == 0)
|
||||
refvar = 0;
|
||||
if (refvar)
|
||||
var = make_local_variable (nameref_cell (refvar));
|
||||
if (var == 0)
|
||||
var = make_local_variable (name);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
var = make_local_variable (name);
|
||||
if (var == 0)
|
||||
{
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
}
|
||||
else
|
||||
var = (SHELL_VAR *)NULL;
|
||||
|
||||
/* If we are declaring a function, then complain about it in some way.
|
||||
We don't let people make functions by saying `typeset -f foo=bar'. */
|
||||
|
||||
/* There should be a way, however, to let people look at a particular
|
||||
function definition by saying `typeset -f foo'. */
|
||||
|
||||
if (flags_on & att_function)
|
||||
{
|
||||
if (offset) /* declare -f [-rix] foo=bar */
|
||||
{
|
||||
builtin_error (_("cannot use `-f' to make functions"));
|
||||
free (name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else /* declare -f [-rx] name [name...] */
|
||||
{
|
||||
var = find_function (name);
|
||||
|
||||
if (var)
|
||||
{
|
||||
if (readonly_p (var) && (flags_off & att_readonly))
|
||||
{
|
||||
builtin_error (_("%s: readonly function"), name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* declare -[Ff] name [name...] */
|
||||
if (flags_on == att_function && flags_off == 0)
|
||||
{
|
||||
#if defined (DEBUGGER)
|
||||
if (nodefs && debugging_mode)
|
||||
{
|
||||
shell_fn = find_function_def (var->name);
|
||||
if (shell_fn)
|
||||
printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file);
|
||||
else
|
||||
printf ("%s\n", var->name);
|
||||
}
|
||||
else
|
||||
#endif /* DEBUGGER */
|
||||
{
|
||||
t = nodefs ? var->name
|
||||
: named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL);
|
||||
printf ("%s\n", t);
|
||||
any_failed = sh_chkwrite (any_failed);
|
||||
}
|
||||
}
|
||||
else /* declare -[fF] -[rx] name [name...] */
|
||||
{
|
||||
VSETATTR (var, flags_on);
|
||||
VUNSETATTR (var, flags_off);
|
||||
}
|
||||
}
|
||||
else
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
}
|
||||
else /* declare -[aAirx] name [name...] */
|
||||
{
|
||||
/* Non-null if we just created or fetched a local variable. */
|
||||
/* Here's what ksh93 seems to do. If we are modifying an existing
|
||||
nameref variable, we don't follow the nameref chain past the last
|
||||
nameref, and we set the nameref variable's value so future
|
||||
references to that variable will return the value of the variable
|
||||
we're assigning right now. */
|
||||
if (var == 0 && (flags_on & att_nameref))
|
||||
{
|
||||
/* See if we are trying to modify an existing nameref variable */
|
||||
var = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name);
|
||||
if (var && nameref_p (var) == 0)
|
||||
var = 0;
|
||||
}
|
||||
/* However, if we're turning off the nameref attribute on an existing
|
||||
nameref variable, we first follow the nameref chain to the end,
|
||||
modify the value of the variable this nameref variable references,
|
||||
*CHANGING ITS VALUE AS A SIDE EFFECT* then turn off the nameref
|
||||
flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */
|
||||
else if (var == 0 && (flags_off & att_nameref))
|
||||
{
|
||||
/* See if we are trying to modify an existing nameref variable */
|
||||
refvar = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name);
|
||||
if (refvar && nameref_p (refvar) == 0)
|
||||
refvar = 0;
|
||||
if (refvar)
|
||||
var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
|
||||
}
|
||||
|
||||
if (var == 0)
|
||||
var = mkglobal ? find_global_variable (name) : find_variable (name);
|
||||
|
||||
if (var == 0)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (flags_on & att_assoc)
|
||||
var = make_new_assoc_variable (name);
|
||||
else if ((flags_on & att_array) || making_array_special)
|
||||
var = make_new_array_variable (name);
|
||||
else
|
||||
#endif
|
||||
|
||||
if (offset)
|
||||
var = bind_variable (name, "", 0);
|
||||
else
|
||||
{
|
||||
var = bind_variable (name, (char *)NULL, 0);
|
||||
VSETATTR (var, att_invisible);
|
||||
}
|
||||
}
|
||||
|
||||
/* Cannot use declare +r to turn off readonly attribute. */
|
||||
if (readonly_p (var) && (flags_off & att_readonly))
|
||||
{
|
||||
sh_readonly (name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* Cannot use declare to assign value to readonly or noassign
|
||||
variable. */
|
||||
if ((readonly_p (var) || noassign_p (var)) && offset)
|
||||
{
|
||||
if (readonly_p (var))
|
||||
sh_readonly (name);
|
||||
assign_error++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if ((making_array_special || (flags_on & (att_array|att_assoc)) || array_p (var) || assoc_p (var)) && offset)
|
||||
{
|
||||
int vlen;
|
||||
vlen = STRLEN (value);
|
||||
|
||||
if (value[0] == '(' && value[vlen-1] == ')')
|
||||
compound_array_assign = 1;
|
||||
else
|
||||
simple_array_assign = 1;
|
||||
}
|
||||
|
||||
/* Cannot use declare +a name or declare +A name to remove an
|
||||
array variable. */
|
||||
if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var)))
|
||||
{
|
||||
builtin_error (_("%s: cannot destroy array variables in this way"), name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
if ((flags_on & att_array) && assoc_p (var))
|
||||
{
|
||||
builtin_error (_("%s: cannot convert associative to indexed array"), name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
if ((flags_on & att_assoc) && array_p (var))
|
||||
{
|
||||
builtin_error (_("%s: cannot convert indexed to associative array"), name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* declare -A name[[n]] makes name an associative array variable. */
|
||||
if (flags_on & att_assoc)
|
||||
{
|
||||
if (assoc_p (var) == 0)
|
||||
var = convert_var_to_assoc (var);
|
||||
}
|
||||
/* declare -a name[[n]] or declare name[n] makes name an indexed
|
||||
array variable. */
|
||||
else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0)
|
||||
var = convert_var_to_array (var);
|
||||
#endif /* ARRAY_VARS */
|
||||
|
||||
/* XXX - we note that we are turning on nameref attribute and defer
|
||||
setting it until the assignment has been made so we don't do an
|
||||
inadvertent nameref lookup. Might have to do the same thing for
|
||||
flags_off&att_nameref. */
|
||||
/* XXX - ksh93 makes it an error to have a readonly nameref variable */
|
||||
onref = (flags_on & att_nameref);
|
||||
flags_on &= ~att_nameref;
|
||||
if (array_p (var) || assoc_p (var)
|
||||
|| (offset && compound_array_assign)
|
||||
|| simple_array_assign)
|
||||
onref = 0; /* array variables may not be namerefs */
|
||||
|
||||
/* ksh93 seems to do this */
|
||||
offref = (flags_off & att_nameref);
|
||||
flags_off &= ~att_nameref;
|
||||
|
||||
VSETATTR (var, flags_on);
|
||||
VUNSETATTR (var, flags_off);
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (offset && compound_array_assign)
|
||||
assign_array_var_from_string (var, value, aflags);
|
||||
else if (simple_array_assign && subscript_start)
|
||||
{
|
||||
/* declare [-aA] name[N]=value */
|
||||
*subscript_start = '['; /* ] */
|
||||
var = assign_array_element (name, value, 0); /* XXX - not aflags */
|
||||
*subscript_start = '\0';
|
||||
if (var == 0) /* some kind of assignment error */
|
||||
{
|
||||
assign_error++;
|
||||
flags_on |= onref;
|
||||
flags_off |= offref;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
}
|
||||
else if (simple_array_assign)
|
||||
{
|
||||
/* let bind_{array,assoc}_variable take care of this. */
|
||||
if (assoc_p (var))
|
||||
bind_assoc_variable (var, name, savestring ("0"), value, aflags);
|
||||
else
|
||||
bind_array_variable (name, 0, value, aflags);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* bind_variable_value duplicates the essential internals of
|
||||
bind_variable() */
|
||||
if (offset)
|
||||
bind_variable_value (var, value, aflags);
|
||||
|
||||
/* If we found this variable in the temporary environment, as with
|
||||
`var=value declare -x var', make sure it is treated identically
|
||||
to `var=value export var'. Do the same for `declare -r' and
|
||||
`readonly'. Preserve the attributes, except for att_tempvar. */
|
||||
/* XXX -- should this create a variable in the global scope, or
|
||||
modify the local variable flags? ksh93 has it modify the
|
||||
global scope.
|
||||
Need to handle case like in set_var_attribute where a temporary
|
||||
variable is in the same table as the function local vars. */
|
||||
if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
|
||||
{
|
||||
SHELL_VAR *tv;
|
||||
char *tvalue;
|
||||
|
||||
tv = find_tempenv_variable (var->name);
|
||||
if (tv)
|
||||
{
|
||||
tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
|
||||
tv = bind_variable (var->name, tvalue, 0);
|
||||
tv->attributes |= var->attributes & ~att_tempvar;
|
||||
if (tv->context > 0)
|
||||
VSETATTR (tv, att_propagate);
|
||||
free (tvalue);
|
||||
}
|
||||
VSETATTR (var, att_propagate);
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn on nameref attribute we deferred above. */
|
||||
/* XXX - should we turn on the noassign attribute for consistency with
|
||||
ksh93 when we turn on the nameref attribute? */
|
||||
VSETATTR (var, onref);
|
||||
flags_on |= onref;
|
||||
VUNSETATTR (var, offref);
|
||||
flags_off |= offref;
|
||||
/* Yuck. ksh93 compatibility */
|
||||
if (refvar)
|
||||
VUNSETATTR (refvar, flags_off);
|
||||
|
||||
stupidly_hack_special_variables (name);
|
||||
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
return (assign_error ? EX_BADASSIGN
|
||||
: ((any_failed == 0) ? EXECUTION_SUCCESS
|
||||
: EXECUTION_FAILURE));
|
||||
}
|
||||
@@ -1,349 +0,0 @@
|
||||
/* evalfile.c - read and evaluate commands from a file or file descriptor */
|
||||
|
||||
/* Copyright (C) 1996-2009 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
#include "filecntl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../jobs.h"
|
||||
#include "../builtins.h"
|
||||
#include "../flags.h"
|
||||
#include "../input.h"
|
||||
#include "../execute_cmd.h"
|
||||
#include "../trap.h"
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "../bashhist.h"
|
||||
#endif
|
||||
|
||||
#include <typemax.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
/* Flags for _evalfile() */
|
||||
#define FEVAL_ENOENTOK 0x001
|
||||
#define FEVAL_BUILTIN 0x002
|
||||
#define FEVAL_UNWINDPROT 0x004
|
||||
#define FEVAL_NONINT 0x008
|
||||
#define FEVAL_LONGJMP 0x010
|
||||
#define FEVAL_HISTORY 0x020
|
||||
#define FEVAL_CHECKBINARY 0x040
|
||||
#define FEVAL_REGFILE 0x080
|
||||
#define FEVAL_NOPUSHARGS 0x100
|
||||
|
||||
extern int posixly_correct;
|
||||
extern int indirection_level, subshell_environment;
|
||||
extern int return_catch_flag, return_catch_value;
|
||||
extern int last_command_exit_value;
|
||||
extern int executing_command_builtin;
|
||||
|
||||
/* How many `levels' of sourced files we have. */
|
||||
int sourcelevel = 0;
|
||||
|
||||
static int
|
||||
_evalfile (filename, flags)
|
||||
const char *filename;
|
||||
int flags;
|
||||
{
|
||||
volatile int old_interactive;
|
||||
procenv_t old_return_catch;
|
||||
int return_val, fd, result, pflags, i, nnull;
|
||||
ssize_t nr; /* return value from read(2) */
|
||||
char *string;
|
||||
struct stat finfo;
|
||||
size_t file_size;
|
||||
sh_vmsg_func_t *errfunc;
|
||||
#if defined (ARRAY_VARS)
|
||||
SHELL_VAR *funcname_v, *nfv, *bash_source_v, *bash_lineno_v;
|
||||
ARRAY *funcname_a, *bash_source_a, *bash_lineno_a;
|
||||
# if defined (DEBUGGER)
|
||||
SHELL_VAR *bash_argv_v, *bash_argc_v;
|
||||
ARRAY *bash_argv_a, *bash_argc_a;
|
||||
# endif
|
||||
char *t, tt[2];
|
||||
#endif
|
||||
char *lastcom;
|
||||
|
||||
USE_VAR(pflags);
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
|
||||
GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
|
||||
GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a);
|
||||
# if defined (DEBUGGER)
|
||||
GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
|
||||
GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
fd = open (filename, O_RDONLY);
|
||||
|
||||
if (fd < 0 || (fstat (fd, &finfo) == -1))
|
||||
{
|
||||
file_error_and_exit:
|
||||
if (((flags & FEVAL_ENOENTOK) == 0) || errno != ENOENT)
|
||||
file_error (filename);
|
||||
|
||||
if (flags & FEVAL_LONGJMP)
|
||||
{
|
||||
last_command_exit_value = 1;
|
||||
jump_to_top_level (EXITPROG);
|
||||
}
|
||||
|
||||
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE
|
||||
: ((errno == ENOENT) ? 0 : -1));
|
||||
}
|
||||
|
||||
errfunc = ((flags & FEVAL_BUILTIN) ? builtin_error : internal_error);
|
||||
|
||||
if (S_ISDIR (finfo.st_mode))
|
||||
{
|
||||
(*errfunc) (_("%s: is a directory"), filename);
|
||||
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1);
|
||||
}
|
||||
else if ((flags & FEVAL_REGFILE) && S_ISREG (finfo.st_mode) == 0)
|
||||
{
|
||||
(*errfunc) (_("%s: not a regular file"), filename);
|
||||
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1);
|
||||
}
|
||||
|
||||
file_size = (size_t)finfo.st_size;
|
||||
/* Check for overflow with large files. */
|
||||
if (file_size != finfo.st_size || file_size + 1 < file_size)
|
||||
{
|
||||
(*errfunc) (_("%s: file is too large"), filename);
|
||||
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1);
|
||||
}
|
||||
|
||||
if (S_ISREG (finfo.st_mode) && file_size <= SSIZE_MAX)
|
||||
{
|
||||
string = (char *)xmalloc (1 + file_size);
|
||||
nr = read (fd, string, file_size);
|
||||
if (nr >= 0)
|
||||
string[nr] = '\0';
|
||||
}
|
||||
else
|
||||
nr = zmapfd (fd, &string, 0);
|
||||
|
||||
return_val = errno;
|
||||
close (fd);
|
||||
errno = return_val;
|
||||
|
||||
if (nr < 0) /* XXX was != file_size, not < 0 */
|
||||
{
|
||||
free (string);
|
||||
goto file_error_and_exit;
|
||||
}
|
||||
|
||||
if (nr == 0)
|
||||
{
|
||||
free (string);
|
||||
return ((flags & FEVAL_BUILTIN) ? EXECUTION_SUCCESS : 1);
|
||||
}
|
||||
|
||||
if ((flags & FEVAL_CHECKBINARY) &&
|
||||
check_binary_file (string, (nr > 80) ? 80 : nr))
|
||||
{
|
||||
free (string);
|
||||
(*errfunc) (_("%s: cannot execute binary file"), filename);
|
||||
return ((flags & FEVAL_BUILTIN) ? EX_BINARY_FILE : -1);
|
||||
}
|
||||
|
||||
i = strlen (string);
|
||||
if (i < nr)
|
||||
{
|
||||
for (nnull = i = 0; i < nr; i++)
|
||||
if (string[i] == '\0')
|
||||
{
|
||||
memmove (string+i, string+i+1, nr - i);
|
||||
nr--;
|
||||
/* Even if the `check binary' flag is not set, we want to avoid
|
||||
sourcing files with more than 256 null characters -- that
|
||||
probably indicates a binary file. */
|
||||
if ((flags & FEVAL_BUILTIN) && ++nnull > 256)
|
||||
{
|
||||
free (string);
|
||||
(*errfunc) (_("%s: cannot execute binary file"), filename);
|
||||
return ((flags & FEVAL_BUILTIN) ? EX_BINARY_FILE : -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FEVAL_UNWINDPROT)
|
||||
{
|
||||
begin_unwind_frame ("_evalfile");
|
||||
|
||||
unwind_protect_int (return_catch_flag);
|
||||
unwind_protect_jmp_buf (return_catch);
|
||||
if (flags & FEVAL_NONINT)
|
||||
unwind_protect_int (interactive);
|
||||
unwind_protect_int (sourcelevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
COPY_PROCENV (return_catch, old_return_catch);
|
||||
if (flags & FEVAL_NONINT)
|
||||
old_interactive = interactive;
|
||||
}
|
||||
|
||||
if (flags & FEVAL_NONINT)
|
||||
interactive = 0;
|
||||
|
||||
return_catch_flag++;
|
||||
sourcelevel++;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
array_push (bash_source_a, (char *)filename);
|
||||
t = itos (executing_line_number ());
|
||||
array_push (bash_lineno_a, t);
|
||||
free (t);
|
||||
array_push (funcname_a, "source"); /* not exactly right */
|
||||
# if defined (DEBUGGER)
|
||||
/* Have to figure out a better way to do this when `source' is supplied
|
||||
arguments */
|
||||
if ((flags & FEVAL_NOPUSHARGS) == 0)
|
||||
{
|
||||
array_push (bash_argv_a, (char *)filename);
|
||||
tt[0] = '1'; tt[1] = '\0';
|
||||
array_push (bash_argc_a, tt);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* set the flags to be passed to parse_and_execute */
|
||||
pflags = SEVAL_RESETLINE;
|
||||
pflags |= (flags & FEVAL_HISTORY) ? 0 : SEVAL_NOHIST;
|
||||
|
||||
if (flags & FEVAL_BUILTIN)
|
||||
result = EXECUTION_SUCCESS;
|
||||
|
||||
return_val = setjmp (return_catch);
|
||||
|
||||
/* If `return' was seen outside of a function, but in the script, then
|
||||
force parse_and_execute () to clean up. */
|
||||
if (return_val)
|
||||
{
|
||||
parse_and_execute_cleanup ();
|
||||
result = return_catch_value;
|
||||
}
|
||||
else
|
||||
result = parse_and_execute (string, filename, pflags);
|
||||
|
||||
if (flags & FEVAL_UNWINDPROT)
|
||||
run_unwind_frame ("_evalfile");
|
||||
else
|
||||
{
|
||||
if (flags & FEVAL_NONINT)
|
||||
interactive = old_interactive;
|
||||
return_catch_flag--;
|
||||
sourcelevel--;
|
||||
COPY_PROCENV (old_return_catch, return_catch);
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
/* These two variables cannot be unset, and cannot be affected by the
|
||||
sourced file. */
|
||||
array_pop (bash_source_a);
|
||||
array_pop (bash_lineno_a);
|
||||
|
||||
/* FUNCNAME can be unset, and so can potentially be changed by the
|
||||
sourced file. */
|
||||
GET_ARRAY_FROM_VAR ("FUNCNAME", nfv, funcname_a);
|
||||
if (nfv == funcname_v)
|
||||
array_pop (funcname_a);
|
||||
# if defined (DEBUGGER)
|
||||
if ((flags & FEVAL_NOPUSHARGS) == 0)
|
||||
{
|
||||
array_pop (bash_argc_a);
|
||||
array_pop (bash_argv_a);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
return ((flags & FEVAL_BUILTIN) ? result : 1);
|
||||
}
|
||||
|
||||
int
|
||||
maybe_execute_file (fname, force_noninteractive)
|
||||
const char *fname;
|
||||
int force_noninteractive;
|
||||
{
|
||||
char *filename;
|
||||
int result, flags;
|
||||
|
||||
filename = bash_tilde_expand (fname, 0);
|
||||
flags = FEVAL_ENOENTOK;
|
||||
if (force_noninteractive)
|
||||
flags |= FEVAL_NONINT;
|
||||
result = _evalfile (filename, flags);
|
||||
free (filename);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined (HISTORY)
|
||||
int
|
||||
fc_execute_file (filename)
|
||||
const char *filename;
|
||||
{
|
||||
int flags;
|
||||
|
||||
/* We want these commands to show up in the history list if
|
||||
remember_on_history is set. */
|
||||
flags = FEVAL_ENOENTOK|FEVAL_HISTORY|FEVAL_REGFILE;
|
||||
return (_evalfile (filename, flags));
|
||||
}
|
||||
#endif /* HISTORY */
|
||||
|
||||
int
|
||||
source_file (filename, sflags)
|
||||
const char *filename;
|
||||
int sflags;
|
||||
{
|
||||
int flags, rval;
|
||||
|
||||
flags = FEVAL_BUILTIN|FEVAL_UNWINDPROT|FEVAL_NONINT;
|
||||
if (sflags)
|
||||
flags |= FEVAL_NOPUSHARGS;
|
||||
/* POSIX shells exit if non-interactive and file error. */
|
||||
if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
|
||||
flags |= FEVAL_LONGJMP;
|
||||
rval = _evalfile (filename, flags);
|
||||
|
||||
run_return_trap ();
|
||||
return rval;
|
||||
}
|
||||
@@ -1,524 +0,0 @@
|
||||
/* evalstring.c - evaluate a string as one or more shell commands. */
|
||||
|
||||
/* Copyright (C) 1996-2012 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "filecntl.h"
|
||||
#include "../bashansi.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../jobs.h"
|
||||
#include "../builtins.h"
|
||||
#include "../flags.h"
|
||||
#include "../input.h"
|
||||
#include "../execute_cmd.h"
|
||||
#include "../redir.h"
|
||||
#include "../trap.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include <y.tab.h>
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "../bashhist.h"
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "builtext.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define IS_BUILTIN(s) (builtin_address_internal(s, 0) != (struct builtin *)NULL)
|
||||
|
||||
extern int indirection_level, subshell_environment;
|
||||
extern int line_number, line_number_for_err_trap;
|
||||
extern int current_token, shell_eof_token;
|
||||
extern int last_command_exit_value;
|
||||
extern int running_trap;
|
||||
extern int loop_level;
|
||||
extern int executing_list;
|
||||
extern int comsub_ignore_return;
|
||||
extern int posixly_correct;
|
||||
extern sh_builtin_func_t *this_shell_builtin;
|
||||
extern char *the_printed_command_except_trap;
|
||||
|
||||
int parse_and_execute_level = 0;
|
||||
|
||||
static int cat_file __P((REDIRECT *));
|
||||
|
||||
#define PE_TAG "parse_and_execute top"
|
||||
#define PS_TAG "parse_string top"
|
||||
|
||||
#if defined (HISTORY)
|
||||
static void
|
||||
set_history_remembering ()
|
||||
{
|
||||
remember_on_history = enable_history_list;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
restore_lastcom (x)
|
||||
char *x;
|
||||
{
|
||||
FREE (the_printed_command_except_trap);
|
||||
the_printed_command_except_trap = x;
|
||||
}
|
||||
|
||||
/* How to force parse_and_execute () to clean up after itself. */
|
||||
void
|
||||
parse_and_execute_cleanup ()
|
||||
{
|
||||
if (running_trap)
|
||||
{
|
||||
run_trap_cleanup (running_trap - 1);
|
||||
unfreeze_jobs_list ();
|
||||
}
|
||||
|
||||
if (have_unwind_protects ())
|
||||
run_unwind_frame (PE_TAG);
|
||||
else
|
||||
parse_and_execute_level = 0; /* XXX */
|
||||
}
|
||||
|
||||
static void
|
||||
parse_prologue (string, flags, tag)
|
||||
char *string;
|
||||
int flags;
|
||||
char *tag;
|
||||
{
|
||||
char *orig_string;
|
||||
int x;
|
||||
|
||||
orig_string = string;
|
||||
/* Unwind protect this invocation of parse_and_execute (). */
|
||||
begin_unwind_frame (tag);
|
||||
unwind_protect_int (parse_and_execute_level);
|
||||
unwind_protect_jmp_buf (top_level);
|
||||
unwind_protect_int (indirection_level);
|
||||
unwind_protect_int (line_number);
|
||||
unwind_protect_int (line_number_for_err_trap);
|
||||
unwind_protect_int (loop_level);
|
||||
unwind_protect_int (executing_list);
|
||||
unwind_protect_int (comsub_ignore_return);
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
unwind_protect_int (interactive);
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (parse_and_execute_level == 0)
|
||||
add_unwind_protect (set_history_remembering, (char *)NULL);
|
||||
else
|
||||
unwind_protect_int (remember_on_history); /* can be used in scripts */
|
||||
# if defined (BANG_HISTORY)
|
||||
if (interactive_shell)
|
||||
unwind_protect_int (history_expansion_inhibited);
|
||||
# endif /* BANG_HISTORY */
|
||||
#endif /* HISTORY */
|
||||
|
||||
if (interactive_shell)
|
||||
{
|
||||
x = get_current_prompt_level ();
|
||||
add_unwind_protect (set_current_prompt_level, x);
|
||||
}
|
||||
|
||||
if (the_printed_command_except_trap)
|
||||
{
|
||||
lastcom = savestring (the_printed_command_except_trap);
|
||||
add_unwind_protect (restore_lastcom (lastcom));
|
||||
}
|
||||
|
||||
add_unwind_protect (pop_stream, (char *)NULL);
|
||||
if (orig_string && ((flags & SEVAL_NOFREE) == 0))
|
||||
add_unwind_protect (xfree, orig_string);
|
||||
end_unwind_frame ();
|
||||
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
interactive = (flags & SEVAL_NONINT) ? 0 : 1;
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (flags & SEVAL_NOHIST)
|
||||
bash_history_disable ();
|
||||
#endif /* HISTORY */
|
||||
}
|
||||
|
||||
/* Parse and execute the commands in STRING. Returns whatever
|
||||
execute_command () returns. This frees STRING. FLAGS is a
|
||||
flags word; look in common.h for the possible values. Actions
|
||||
are:
|
||||
(flags & SEVAL_NONINT) -> interactive = 0;
|
||||
(flags & SEVAL_INTERACT) -> interactive = 1;
|
||||
(flags & SEVAL_NOHIST) -> call bash_history_disable ()
|
||||
(flags & SEVAL_NOFREE) -> don't free STRING when finished
|
||||
(flags & SEVAL_RESETLINE) -> reset line_number to 1
|
||||
*/
|
||||
|
||||
int
|
||||
parse_and_execute (string, from_file, flags)
|
||||
char *string;
|
||||
const char *from_file;
|
||||
int flags;
|
||||
{
|
||||
int code, lreset;
|
||||
volatile int should_jump_to_top_level, last_result;
|
||||
COMMAND *volatile command;
|
||||
|
||||
parse_prologue (string, flags, PE_TAG);
|
||||
|
||||
parse_and_execute_level++;
|
||||
|
||||
lreset = flags & SEVAL_RESETLINE;
|
||||
|
||||
/* Reset the line number if the caller wants us to. If we don't reset the
|
||||
line number, we have to subtract one, because we will add one just
|
||||
before executing the next command (resetting the line number sets it to
|
||||
0; the first line number is 1). */
|
||||
push_stream (lreset);
|
||||
if (lreset == 0)
|
||||
line_number--;
|
||||
|
||||
indirection_level++;
|
||||
|
||||
code = should_jump_to_top_level = 0;
|
||||
last_result = EXECUTION_SUCCESS;
|
||||
|
||||
with_input_from_string (string, from_file);
|
||||
while (*(bash_input.location.string))
|
||||
{
|
||||
command = (COMMAND *)NULL;
|
||||
|
||||
if (interrupt_state)
|
||||
{
|
||||
last_result = EXECUTION_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Provide a location for functions which `longjmp (top_level)' to
|
||||
jump to. This prevents errors in substitution from restarting
|
||||
the reader loop directly, for example. */
|
||||
code = setjmp (top_level);
|
||||
|
||||
if (code)
|
||||
{
|
||||
should_jump_to_top_level = 0;
|
||||
switch (code)
|
||||
{
|
||||
case FORCE_EOF:
|
||||
case ERREXIT:
|
||||
case EXITPROG:
|
||||
if (command)
|
||||
run_unwind_frame ("pe_dispose");
|
||||
/* Remember to call longjmp (top_level) after the old
|
||||
value for it is restored. */
|
||||
should_jump_to_top_level = 1;
|
||||
goto out;
|
||||
|
||||
case DISCARD:
|
||||
if (command)
|
||||
run_unwind_frame ("pe_dispose");
|
||||
last_result = last_command_exit_value = EXECUTION_FAILURE; /* XXX */
|
||||
if (subshell_environment)
|
||||
{
|
||||
should_jump_to_top_level = 1;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
dispose_command (command); /* pe_dispose does this */
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
default:
|
||||
command_error ("parse_and_execute", CMDERR_BADJUMP, code, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_command () == 0)
|
||||
{
|
||||
if ((flags & SEVAL_PARSEONLY) || (interactive_shell == 0 && read_but_dont_execute))
|
||||
{
|
||||
last_result = EXECUTION_SUCCESS;
|
||||
dispose_command (global_command);
|
||||
global_command = (COMMAND *)NULL;
|
||||
}
|
||||
else if (command = global_command)
|
||||
{
|
||||
struct fd_bitmap *bitmap;
|
||||
|
||||
bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
|
||||
begin_unwind_frame ("pe_dispose");
|
||||
add_unwind_protect (dispose_fd_bitmap, bitmap);
|
||||
add_unwind_protect (dispose_command, command); /* XXX */
|
||||
|
||||
global_command = (COMMAND *)NULL;
|
||||
|
||||
if ((subshell_environment & SUBSHELL_COMSUB) && comsub_ignore_return)
|
||||
command->flags |= CMD_IGNORE_RETURN;
|
||||
|
||||
#if defined (ONESHOT)
|
||||
/*
|
||||
* IF
|
||||
* we were invoked as `bash -c' (startup_state == 2) AND
|
||||
* parse_and_execute has not been called recursively AND
|
||||
* we're not running a trap AND
|
||||
* we have parsed the full command (string == '\0') AND
|
||||
* we're not going to run the exit trap AND
|
||||
* we have a simple command without redirections AND
|
||||
* the command is not being timed AND
|
||||
* the command's return status is not being inverted
|
||||
* THEN
|
||||
* tell the execution code that we don't need to fork
|
||||
*/
|
||||
if (startup_state == 2 && parse_and_execute_level == 1 &&
|
||||
running_trap == 0 &&
|
||||
*bash_input.location.string == '\0' &&
|
||||
command->type == cm_simple &&
|
||||
signal_is_trapped (EXIT_TRAP) == 0 &&
|
||||
command->redirects == 0 && command->value.Simple->redirects == 0 &&
|
||||
((command->flags & CMD_TIME_PIPELINE) == 0) &&
|
||||
((command->flags & CMD_INVERT_RETURN) == 0))
|
||||
{
|
||||
command->flags |= CMD_NO_FORK;
|
||||
command->value.Simple->flags |= CMD_NO_FORK;
|
||||
}
|
||||
#endif /* ONESHOT */
|
||||
|
||||
/* See if this is a candidate for $( <file ). */
|
||||
if (startup_state == 2 &&
|
||||
(subshell_environment & SUBSHELL_COMSUB) &&
|
||||
*bash_input.location.string == '\0' &&
|
||||
command->type == cm_simple && !command->redirects &&
|
||||
(command->flags & CMD_TIME_PIPELINE) == 0 &&
|
||||
command->value.Simple->words == 0 &&
|
||||
command->value.Simple->redirects &&
|
||||
command->value.Simple->redirects->next == 0 &&
|
||||
command->value.Simple->redirects->instruction == r_input_direction &&
|
||||
command->value.Simple->redirects->redirector.dest == 0)
|
||||
{
|
||||
int r;
|
||||
r = cat_file (command->value.Simple->redirects);
|
||||
last_result = (r < 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
|
||||
}
|
||||
else
|
||||
last_result = execute_command_internal
|
||||
(command, 0, NO_PIPE, NO_PIPE, bitmap);
|
||||
dispose_command (command);
|
||||
dispose_fd_bitmap (bitmap);
|
||||
discard_unwind_frame ("pe_dispose");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
last_result = EXECUTION_FAILURE;
|
||||
|
||||
if (interactive_shell == 0 && this_shell_builtin &&
|
||||
(this_shell_builtin == source_builtin || this_shell_builtin == eval_builtin) &&
|
||||
last_command_exit_value == EX_BADSYNTAX && posixly_correct)
|
||||
{
|
||||
should_jump_to_top_level = 1;
|
||||
code = ERREXIT;
|
||||
last_command_exit_value = EX_BADUSAGE;
|
||||
}
|
||||
|
||||
/* Since we are shell compatible, syntax errors in a script
|
||||
abort the execution of the script. Right? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
run_unwind_frame (PE_TAG);
|
||||
|
||||
if (interrupt_state && parse_and_execute_level == 0)
|
||||
{
|
||||
/* An interrupt during non-interactive execution in an
|
||||
interactive shell (e.g. via $PROMPT_COMMAND) should
|
||||
not cause the shell to exit. */
|
||||
interactive = interactive_shell;
|
||||
throw_to_top_level ();
|
||||
}
|
||||
|
||||
if (should_jump_to_top_level)
|
||||
jump_to_top_level (code);
|
||||
|
||||
return (last_result);
|
||||
}
|
||||
|
||||
/* Parse a command contained in STRING according to FLAGS and return the
|
||||
number of characters consumed from the string. If non-NULL, set *ENDP
|
||||
to the position in the string where the parse ended. Used to validate
|
||||
command substitutions during parsing to obey Posix rules about finding
|
||||
the end of the command and balancing parens. */
|
||||
int
|
||||
parse_string (string, from_file, flags, endp)
|
||||
char *string;
|
||||
const char *from_file;
|
||||
int flags;
|
||||
char **endp;
|
||||
{
|
||||
int code, nc;
|
||||
volatile int should_jump_to_top_level;
|
||||
COMMAND *volatile command, *oglobal;
|
||||
char *ostring;
|
||||
|
||||
parse_prologue (string, flags, PS_TAG);
|
||||
|
||||
/* Reset the line number if the caller wants us to. If we don't reset the
|
||||
line number, we have to subtract one, because we will add one just
|
||||
before executing the next command (resetting the line number sets it to
|
||||
0; the first line number is 1). */
|
||||
push_stream (0);
|
||||
|
||||
code = should_jump_to_top_level = 0;
|
||||
oglobal = global_command;
|
||||
ostring = string;
|
||||
|
||||
with_input_from_string (string, from_file);
|
||||
while (*(bash_input.location.string))
|
||||
{
|
||||
command = (COMMAND *)NULL;
|
||||
|
||||
#if 0
|
||||
if (interrupt_state)
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* Provide a location for functions which `longjmp (top_level)' to
|
||||
jump to. */
|
||||
code = setjmp (top_level);
|
||||
|
||||
if (code)
|
||||
{
|
||||
#if defined (DEBUG)
|
||||
itrace("parse_string: longjmp executed: code = %d", code);
|
||||
#endif
|
||||
should_jump_to_top_level = 0;
|
||||
switch (code)
|
||||
{
|
||||
case FORCE_EOF:
|
||||
case ERREXIT:
|
||||
case EXITPROG:
|
||||
case DISCARD: /* XXX */
|
||||
if (command)
|
||||
dispose_command (command);
|
||||
/* Remember to call longjmp (top_level) after the old
|
||||
value for it is restored. */
|
||||
should_jump_to_top_level = 1;
|
||||
goto out;
|
||||
|
||||
default:
|
||||
command_error ("parse_string", CMDERR_BADJUMP, code, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_command () == 0)
|
||||
{
|
||||
dispose_command (global_command);
|
||||
global_command = (COMMAND *)NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((flags & SEVAL_NOLONGJMP) == 0)
|
||||
{
|
||||
should_jump_to_top_level = 1;
|
||||
code = DISCARD;
|
||||
}
|
||||
else
|
||||
reset_parser (); /* XXX - sets token_to_read */
|
||||
break;
|
||||
}
|
||||
|
||||
if (current_token == yacc_EOF || current_token == shell_eof_token)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
global_command = oglobal;
|
||||
nc = bash_input.location.string - ostring;
|
||||
if (endp)
|
||||
*endp = bash_input.location.string;
|
||||
|
||||
run_unwind_frame (PS_TAG);
|
||||
|
||||
if (should_jump_to_top_level)
|
||||
jump_to_top_level (code);
|
||||
|
||||
return (nc);
|
||||
}
|
||||
|
||||
/* Handle a $( < file ) command substitution. This expands the filename,
|
||||
returning errors as appropriate, then just cats the file to the standard
|
||||
output. */
|
||||
static int
|
||||
cat_file (r)
|
||||
REDIRECT *r;
|
||||
{
|
||||
char *fn;
|
||||
int fd, rval;
|
||||
|
||||
if (r->instruction != r_input_direction)
|
||||
return -1;
|
||||
|
||||
/* Get the filename. */
|
||||
if (posixly_correct && !interactive_shell)
|
||||
disallow_filename_globbing++;
|
||||
fn = redirection_expand (r->redirectee.filename);
|
||||
if (posixly_correct && !interactive_shell)
|
||||
disallow_filename_globbing--;
|
||||
|
||||
if (fn == 0)
|
||||
{
|
||||
redirection_error (r, AMBIGUOUS_REDIRECT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = open(fn, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
file_error (fn);
|
||||
free (fn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rval = zcatfd (fd, 1, fn);
|
||||
|
||||
free (fn);
|
||||
close (fd);
|
||||
|
||||
return (rval);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,878 +0,0 @@
|
||||
This file is set.def, from which is created set.c.
|
||||
It implements the "set" and "unset" builtins in Bash.
|
||||
|
||||
Copyright (C) 1987-2011 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$PRODUCES set.c
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../flags.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if defined (READLINE)
|
||||
# include "../input.h"
|
||||
# include "../bashline.h"
|
||||
# include <readline/readline.h>
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "../bashhist.h"
|
||||
#endif
|
||||
|
||||
extern int posixly_correct, ignoreeof, eof_encountered_limit;
|
||||
#if defined (HISTORY)
|
||||
extern int dont_save_function_defs;
|
||||
#endif
|
||||
#if defined (READLINE)
|
||||
extern int no_line_editing;
|
||||
#endif /* READLINE */
|
||||
|
||||
$BUILTIN set
|
||||
$FUNCTION set_builtin
|
||||
$SHORT_DOC set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
|
||||
Set or unset values of shell options and positional parameters.
|
||||
|
||||
Change the value of shell attributes and positional parameters, or
|
||||
display the names and values of shell variables.
|
||||
|
||||
Options:
|
||||
-a Mark variables which are modified or created for export.
|
||||
-b Notify of job termination immediately.
|
||||
-e Exit immediately if a command exits with a non-zero status.
|
||||
-f Disable file name generation (globbing).
|
||||
-h Remember the location of commands as they are looked up.
|
||||
-k All assignment arguments are placed in the environment for a
|
||||
command, not just those that precede the command name.
|
||||
-m Job control is enabled.
|
||||
-n Read commands but do not execute them.
|
||||
-o option-name
|
||||
Set the variable corresponding to option-name:
|
||||
allexport same as -a
|
||||
braceexpand same as -B
|
||||
#if defined (READLINE)
|
||||
emacs use an emacs-style line editing interface
|
||||
#endif /* READLINE */
|
||||
errexit same as -e
|
||||
errtrace same as -E
|
||||
functrace same as -T
|
||||
hashall same as -h
|
||||
#if defined (BANG_HISTORY)
|
||||
histexpand same as -H
|
||||
#endif /* BANG_HISTORY */
|
||||
#if defined (HISTORY)
|
||||
history enable command history
|
||||
#endif
|
||||
ignoreeof the shell will not exit upon reading EOF
|
||||
interactive-comments
|
||||
allow comments to appear in interactive commands
|
||||
keyword same as -k
|
||||
#if defined (JOB_CONTROL)
|
||||
monitor same as -m
|
||||
#endif
|
||||
noclobber same as -C
|
||||
noexec same as -n
|
||||
noglob same as -f
|
||||
nolog currently accepted but ignored
|
||||
#if defined (JOB_CONTROL)
|
||||
notify same as -b
|
||||
#endif
|
||||
nounset same as -u
|
||||
onecmd same as -t
|
||||
physical same as -P
|
||||
pipefail the return value of a pipeline is the status of
|
||||
the last command to exit with a non-zero status,
|
||||
or zero if no command exited with a non-zero status
|
||||
posix change the behavior of bash where the default
|
||||
operation differs from the Posix standard to
|
||||
match the standard
|
||||
privileged same as -p
|
||||
verbose same as -v
|
||||
#if defined (READLINE)
|
||||
vi use a vi-style line editing interface
|
||||
#endif /* READLINE */
|
||||
xtrace same as -x
|
||||
-p Turned on whenever the real and effective user ids do not match.
|
||||
Disables processing of the $ENV file and importing of shell
|
||||
functions. Turning this option off causes the effective uid and
|
||||
gid to be set to the real uid and gid.
|
||||
-t Exit after reading and executing one command.
|
||||
-u Treat unset variables as an error when substituting.
|
||||
-v Print shell input lines as they are read.
|
||||
-x Print commands and their arguments as they are executed.
|
||||
#if defined (BRACE_EXPANSION)
|
||||
-B the shell will perform brace expansion
|
||||
#endif /* BRACE_EXPANSION */
|
||||
-C If set, disallow existing regular files to be overwritten
|
||||
by redirection of output.
|
||||
-E If set, the ERR trap is inherited by shell functions.
|
||||
#if defined (BANG_HISTORY)
|
||||
-H Enable ! style history substitution. This flag is on
|
||||
by default when the shell is interactive.
|
||||
#endif /* BANG_HISTORY */
|
||||
-P If set, do not resolve symbolic links when executing commands
|
||||
such as cd which change the current directory.
|
||||
-T If set, the DEBUG trap is inherited by shell functions.
|
||||
-- Assign any remaining arguments to the positional parameters.
|
||||
If there are no remaining arguments, the positional parameters
|
||||
are unset.
|
||||
- Assign any remaining arguments to the positional parameters.
|
||||
The -x and -v options are turned off.
|
||||
|
||||
Using + rather than - causes these flags to be turned off. The
|
||||
flags can also be used upon invocation of the shell. The current
|
||||
set of flags may be found in $-. The remaining n ARGs are positional
|
||||
parameters and are assigned, in order, to $1, $2, .. $n. If no
|
||||
ARGs are given, all shell variables are printed.
|
||||
|
||||
Exit Status:
|
||||
Returns success unless an invalid option is given.
|
||||
$END
|
||||
|
||||
typedef int setopt_set_func_t __P((int, char *));
|
||||
typedef int setopt_get_func_t __P((char *));
|
||||
|
||||
static void print_minus_o_option __P((char *, int, int));
|
||||
static void print_all_shell_variables __P((void));
|
||||
|
||||
static int set_ignoreeof __P((int, char *));
|
||||
static int set_posix_mode __P((int, char *));
|
||||
|
||||
#if defined (READLINE)
|
||||
static int set_edit_mode __P((int, char *));
|
||||
static int get_edit_mode __P((char *));
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
static int bash_set_history __P((int, char *));
|
||||
#endif
|
||||
|
||||
static const char * const on = "on";
|
||||
static const char * const off = "off";
|
||||
|
||||
/* A struct used to match long options for set -o to the corresponding
|
||||
option letter or internal variable. The functions can be called to
|
||||
dynamically generate values. */
|
||||
const struct {
|
||||
char *name;
|
||||
int letter;
|
||||
int *variable;
|
||||
setopt_set_func_t *set_func;
|
||||
setopt_get_func_t *get_func;
|
||||
} o_options[] = {
|
||||
{ "allexport", 'a', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (BRACE_EXPANSION)
|
||||
{ "braceexpand",'B', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif
|
||||
#if defined (READLINE)
|
||||
{ "emacs", '\0', (int *)NULL, set_edit_mode, get_edit_mode },
|
||||
#endif
|
||||
{ "errexit", 'e', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "errtrace", 'E', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "functrace", 'T', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "hashall", 'h', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (BANG_HISTORY)
|
||||
{ "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif /* BANG_HISTORY */
|
||||
#if defined (HISTORY)
|
||||
{ "history", '\0', &enable_history_list, bash_set_history, (setopt_get_func_t *)NULL },
|
||||
#endif
|
||||
{ "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL },
|
||||
{ "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "keyword", 'k', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (JOB_CONTROL)
|
||||
{ "monitor", 'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif
|
||||
{ "noclobber", 'C', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "noexec", 'n', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "noglob", 'f', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (HISTORY)
|
||||
{ "nolog", '\0', &dont_save_function_defs, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif
|
||||
#if defined (JOB_CONTROL)
|
||||
{ "notify", 'b', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif /* JOB_CONTROL */
|
||||
{ "nounset", 'u', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "onecmd", 't', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "physical", 'P', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "pipefail", '\0', &pipefail_opt, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "posix", '\0', &posixly_correct, set_posix_mode, (setopt_get_func_t *)NULL },
|
||||
{ "privileged", 'p', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "verbose", 'v', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (READLINE)
|
||||
{ "vi", '\0', (int *)NULL, set_edit_mode, get_edit_mode },
|
||||
#endif
|
||||
{ "xtrace", 'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
};
|
||||
|
||||
#define N_O_OPTIONS (sizeof (o_options) / sizeof (o_options[0]))
|
||||
|
||||
#define GET_BINARY_O_OPTION_VALUE(i, name) \
|
||||
((o_options[i].get_func) ? (*o_options[i].get_func) (name) \
|
||||
: (*o_options[i].variable))
|
||||
|
||||
#define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \
|
||||
((o_options[i].set_func) ? (*o_options[i].set_func) (onoff, name) \
|
||||
: (*o_options[i].variable = (onoff == FLAG_ON)))
|
||||
|
||||
int
|
||||
minus_o_option_value (name)
|
||||
char *name;
|
||||
{
|
||||
register int i;
|
||||
int *on_or_off;
|
||||
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (STREQ (name, o_options[i].name))
|
||||
{
|
||||
if (o_options[i].letter)
|
||||
{
|
||||
on_or_off = find_flag (o_options[i].letter);
|
||||
return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off);
|
||||
}
|
||||
else
|
||||
return (GET_BINARY_O_OPTION_VALUE (i, name));
|
||||
}
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#define MINUS_O_FORMAT "%-15s\t%s\n"
|
||||
|
||||
static void
|
||||
print_minus_o_option (name, value, pflag)
|
||||
char *name;
|
||||
int value, pflag;
|
||||
{
|
||||
if (pflag == 0)
|
||||
printf (MINUS_O_FORMAT, name, value ? on : off);
|
||||
else
|
||||
printf ("set %co %s\n", value ? '-' : '+', name);
|
||||
}
|
||||
|
||||
void
|
||||
list_minus_o_opts (mode, reusable)
|
||||
int mode, reusable;
|
||||
{
|
||||
register int i;
|
||||
int *on_or_off, value;
|
||||
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (o_options[i].letter)
|
||||
{
|
||||
value = 0;
|
||||
on_or_off = find_flag (o_options[i].letter);
|
||||
if (on_or_off == FLAG_UNKNOWN)
|
||||
on_or_off = &value;
|
||||
if (mode == -1 || mode == *on_or_off)
|
||||
print_minus_o_option (o_options[i].name, *on_or_off, reusable);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
|
||||
if (mode == -1 || mode == value)
|
||||
print_minus_o_option (o_options[i].name, value, reusable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char **
|
||||
get_minus_o_opts ()
|
||||
{
|
||||
char **ret;
|
||||
int i;
|
||||
|
||||
ret = strvec_create (N_O_OPTIONS + 1);
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
ret[i] = o_options[i].name;
|
||||
ret[i] = (char *)NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
set_ignoreeof (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
ignoreeof = on_or_off == FLAG_ON;
|
||||
unbind_variable ("ignoreeof");
|
||||
if (ignoreeof)
|
||||
bind_variable ("IGNOREEOF", "10", 0);
|
||||
else
|
||||
unbind_variable ("IGNOREEOF");
|
||||
sv_ignoreeof ("IGNOREEOF");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
set_posix_mode (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
posixly_correct = on_or_off == FLAG_ON;
|
||||
if (posixly_correct == 0)
|
||||
unbind_variable ("POSIXLY_CORRECT");
|
||||
else
|
||||
bind_variable ("POSIXLY_CORRECT", "y", 0);
|
||||
sv_strict_posix ("POSIXLY_CORRECT");
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
/* Magic. This code `knows' how readline handles rl_editing_mode. */
|
||||
static int
|
||||
set_edit_mode (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
int isemacs;
|
||||
|
||||
if (on_or_off == FLAG_ON)
|
||||
{
|
||||
rl_variable_bind ("editing-mode", option_name);
|
||||
|
||||
if (interactive)
|
||||
with_input_from_stdin ();
|
||||
no_line_editing = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
isemacs = rl_editing_mode == 1;
|
||||
if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v'))
|
||||
{
|
||||
if (interactive)
|
||||
with_input_from_stream (stdin, "stdin");
|
||||
no_line_editing = 1;
|
||||
}
|
||||
}
|
||||
return 1-no_line_editing;
|
||||
}
|
||||
|
||||
static int
|
||||
get_edit_mode (name)
|
||||
char *name;
|
||||
{
|
||||
return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1
|
||||
: no_line_editing == 0 && rl_editing_mode == 0);
|
||||
}
|
||||
#endif /* READLINE */
|
||||
|
||||
#if defined (HISTORY)
|
||||
static int
|
||||
bash_set_history (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
if (on_or_off == FLAG_ON)
|
||||
{
|
||||
enable_history_list = 1;
|
||||
bash_history_enable ();
|
||||
if (history_lines_this_session == 0)
|
||||
load_history ();
|
||||
}
|
||||
else
|
||||
{
|
||||
enable_history_list = 0;
|
||||
bash_history_disable ();
|
||||
}
|
||||
return (1 - enable_history_list);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
set_minus_o_option (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (STREQ (option_name, o_options[i].name))
|
||||
{
|
||||
if (o_options[i].letter == 0)
|
||||
{
|
||||
SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (change_flag (o_options[i].letter, on_or_off) == FLAG_ERROR)
|
||||
{
|
||||
sh_invalidoptname (option_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
sh_invalidoptname (option_name);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
static void
|
||||
print_all_shell_variables ()
|
||||
{
|
||||
SHELL_VAR **vars;
|
||||
|
||||
vars = all_shell_variables ();
|
||||
if (vars)
|
||||
{
|
||||
print_var_list (vars);
|
||||
free (vars);
|
||||
}
|
||||
|
||||
/* POSIX.2 does not allow function names and definitions to be output when
|
||||
`set' is invoked without options (PASC Interp #202). */
|
||||
if (posixly_correct == 0)
|
||||
{
|
||||
vars = all_shell_functions ();
|
||||
if (vars)
|
||||
{
|
||||
print_func_list (vars);
|
||||
free (vars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
set_shellopts ()
|
||||
{
|
||||
char *value;
|
||||
char tflag[N_O_OPTIONS];
|
||||
int vsize, i, vptr, *ip, exported;
|
||||
SHELL_VAR *v;
|
||||
|
||||
for (vsize = i = 0; o_options[i].name; i++)
|
||||
{
|
||||
tflag[i] = 0;
|
||||
if (o_options[i].letter)
|
||||
{
|
||||
ip = find_flag (o_options[i].letter);
|
||||
if (ip && *ip)
|
||||
{
|
||||
vsize += strlen (o_options[i].name) + 1;
|
||||
tflag[i] = 1;
|
||||
}
|
||||
}
|
||||
else if (GET_BINARY_O_OPTION_VALUE (i, o_options[i].name))
|
||||
{
|
||||
vsize += strlen (o_options[i].name) + 1;
|
||||
tflag[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
value = (char *)xmalloc (vsize + 1);
|
||||
|
||||
for (i = vptr = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (tflag[i])
|
||||
{
|
||||
strcpy (value + vptr, o_options[i].name);
|
||||
vptr += strlen (o_options[i].name);
|
||||
value[vptr++] = ':';
|
||||
}
|
||||
}
|
||||
|
||||
if (vptr)
|
||||
vptr--; /* cut off trailing colon */
|
||||
value[vptr] = '\0';
|
||||
|
||||
v = find_variable ("SHELLOPTS");
|
||||
|
||||
/* Turn off the read-only attribute so we can bind the new value, and
|
||||
note whether or not the variable was exported. */
|
||||
if (v)
|
||||
{
|
||||
VUNSETATTR (v, att_readonly);
|
||||
exported = exported_p (v);
|
||||
}
|
||||
else
|
||||
exported = 0;
|
||||
|
||||
v = bind_variable ("SHELLOPTS", value, 0);
|
||||
|
||||
/* Turn the read-only attribute back on, and turn off the export attribute
|
||||
if it was set implicitly by mark_modified_vars and SHELLOPTS was not
|
||||
exported before we bound the new value. */
|
||||
VSETATTR (v, att_readonly);
|
||||
if (mark_modified_vars && exported == 0 && exported_p (v))
|
||||
VUNSETATTR (v, att_exported);
|
||||
|
||||
free (value);
|
||||
}
|
||||
|
||||
void
|
||||
parse_shellopts (value)
|
||||
char *value;
|
||||
{
|
||||
char *vname;
|
||||
int vptr;
|
||||
|
||||
vptr = 0;
|
||||
while (vname = extract_colon_unit (value, &vptr))
|
||||
{
|
||||
set_minus_o_option (FLAG_ON, vname);
|
||||
free (vname);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
initialize_shell_options (no_shellopts)
|
||||
int no_shellopts;
|
||||
{
|
||||
char *temp;
|
||||
SHELL_VAR *var;
|
||||
|
||||
if (no_shellopts == 0)
|
||||
{
|
||||
var = find_variable ("SHELLOPTS");
|
||||
/* set up any shell options we may have inherited. */
|
||||
if (var && imported_p (var))
|
||||
{
|
||||
temp = (array_p (var) || assoc_p (var)) ? (char *)NULL : savestring (value_cell (var));
|
||||
if (temp)
|
||||
{
|
||||
parse_shellopts (temp);
|
||||
free (temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up the $SHELLOPTS variable. */
|
||||
set_shellopts ();
|
||||
}
|
||||
|
||||
/* Reset the values of the -o options that are not also shell flags. This is
|
||||
called from execute_cmd.c:initialize_subshell() when setting up a subshell
|
||||
to run an executable shell script without a leading `#!'. */
|
||||
void
|
||||
reset_shell_options ()
|
||||
{
|
||||
#if defined (HISTORY)
|
||||
remember_on_history = enable_history_list = 1;
|
||||
#endif
|
||||
ignoreeof = 0;
|
||||
}
|
||||
|
||||
/* Set some flags from the word values in the input list. If LIST is empty,
|
||||
then print out the values of the variables instead. If LIST contains
|
||||
non-flags, then set $1 - $9 to the successive words of LIST. */
|
||||
int
|
||||
set_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int on_or_off, flag_name, force_assignment, opts_changed, rv, r;
|
||||
register char *arg;
|
||||
char s[3];
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
print_all_shell_variables ();
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
/* Check validity of flag arguments. */
|
||||
rv = EXECUTION_SUCCESS;
|
||||
reset_internal_getopt ();
|
||||
while ((flag_name = internal_getopt (list, optflags)) != -1)
|
||||
{
|
||||
switch (flag_name)
|
||||
{
|
||||
case '?':
|
||||
builtin_usage ();
|
||||
return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do the set command. While the list consists of words starting with
|
||||
'-' or '+' treat them as flags, otherwise, start assigning them to
|
||||
$1 ... $n. */
|
||||
for (force_assignment = opts_changed = 0; list; )
|
||||
{
|
||||
arg = list->word->word;
|
||||
|
||||
/* If the argument is `--' or `-' then signal the end of the list
|
||||
and remember the remaining arguments. */
|
||||
if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
|
||||
{
|
||||
list = list->next;
|
||||
|
||||
/* `set --' unsets the positional parameters. */
|
||||
if (arg[1] == '-')
|
||||
force_assignment = 1;
|
||||
|
||||
/* Until told differently, the old shell behaviour of
|
||||
`set - [arg ...]' being equivalent to `set +xv [arg ...]'
|
||||
stands. Posix.2 says the behaviour is marked as obsolescent. */
|
||||
else
|
||||
{
|
||||
change_flag ('x', '+');
|
||||
change_flag ('v', '+');
|
||||
opts_changed = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
|
||||
{
|
||||
while (flag_name = *++arg)
|
||||
{
|
||||
if (flag_name == '?')
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else if (flag_name == 'o') /* -+o option-name */
|
||||
{
|
||||
char *option_name;
|
||||
WORD_LIST *opt;
|
||||
|
||||
opt = list->next;
|
||||
|
||||
if (opt == 0)
|
||||
{
|
||||
list_minus_o_opts (-1, (on_or_off == '+'));
|
||||
rv = sh_chkwrite (rv);
|
||||
continue;
|
||||
}
|
||||
|
||||
option_name = opt->word->word;
|
||||
|
||||
if (option_name == 0 || *option_name == '\0' ||
|
||||
*option_name == '-' || *option_name == '+')
|
||||
{
|
||||
list_minus_o_opts (-1, (on_or_off == '+'));
|
||||
continue;
|
||||
}
|
||||
list = list->next; /* Skip over option name. */
|
||||
|
||||
opts_changed = 1;
|
||||
if ((r = set_minus_o_option (on_or_off, option_name)) != EXECUTION_SUCCESS)
|
||||
{
|
||||
set_shellopts ();
|
||||
return (r);
|
||||
}
|
||||
}
|
||||
else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
|
||||
{
|
||||
s[0] = on_or_off;
|
||||
s[1] = flag_name;
|
||||
s[2] = '\0';
|
||||
sh_invalidopt (s);
|
||||
builtin_usage ();
|
||||
set_shellopts ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
opts_changed = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* Assigning $1 ... $n */
|
||||
if (list || force_assignment)
|
||||
remember_args (list, 1);
|
||||
/* Set up new value of $SHELLOPTS */
|
||||
if (opts_changed)
|
||||
set_shellopts ();
|
||||
return (rv);
|
||||
}
|
||||
|
||||
$BUILTIN unset
|
||||
$FUNCTION unset_builtin
|
||||
$SHORT_DOC unset [-f] [-v] [name ...]
|
||||
Unset values and attributes of shell variables and functions.
|
||||
|
||||
For each NAME, remove the corresponding variable or function.
|
||||
|
||||
Options:
|
||||
-f treat each NAME as a shell function
|
||||
-v treat each NAME as a shell variable
|
||||
|
||||
Without options, unset first tries to unset a variable, and if that fails,
|
||||
tries to unset a function.
|
||||
|
||||
Some variables cannot be unset; also see `readonly'.
|
||||
|
||||
Exit Status:
|
||||
Returns success unless an invalid option is given or a NAME is read-only.
|
||||
$END
|
||||
|
||||
#define NEXT_VARIABLE() any_failed++; list = list->next; continue;
|
||||
|
||||
int
|
||||
unset_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int unset_function, unset_variable, unset_array, opt, any_failed;
|
||||
char *name;
|
||||
|
||||
unset_function = unset_variable = unset_array = any_failed = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "fv")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
unset_function = 1;
|
||||
break;
|
||||
case 'v':
|
||||
unset_variable = 1;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (unset_function && unset_variable)
|
||||
{
|
||||
builtin_error (_("cannot simultaneously unset a function and a variable"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
int tem;
|
||||
#if defined (ARRAY_VARS)
|
||||
char *t;
|
||||
#endif
|
||||
|
||||
name = list->word->word;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
unset_array = 0;
|
||||
if (!unset_function && valid_array_reference (name))
|
||||
{
|
||||
t = strchr (name, '[');
|
||||
*t++ = '\0';
|
||||
unset_array++;
|
||||
}
|
||||
#endif
|
||||
/* Get error checking out of the way first. The low-level functions
|
||||
just perform the unset, relying on the caller to verify. */
|
||||
|
||||
/* Bash allows functions with names which are not valid identifiers
|
||||
to be created when not in posix mode, so check only when in posix
|
||||
mode when unsetting a function. */
|
||||
if (((unset_function && posixly_correct) || !unset_function) && legal_identifier (name) == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* Only search for functions here if -f supplied. */
|
||||
var = unset_function ? find_function (name) : find_variable (name);
|
||||
|
||||
/* Some variables (but not functions yet) cannot be unset, period. */
|
||||
if (var && unset_function == 0 && non_unsettable_p (var))
|
||||
{
|
||||
builtin_error (_("%s: cannot unset"), name);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* Posix.2 says try variables first, then functions. If we would
|
||||
find a function after unsuccessfully searching for a variable,
|
||||
note that we're acting on a function now as if -f were
|
||||
supplied. The readonly check below takes care of it. */
|
||||
if (var == 0 && unset_variable == 0 && unset_function == 0)
|
||||
{
|
||||
if (var = find_function (name))
|
||||
unset_function = 1;
|
||||
}
|
||||
|
||||
/* Posix.2 says that unsetting readonly variables is an error. */
|
||||
if (var && readonly_p (var))
|
||||
{
|
||||
builtin_error (_("%s: cannot unset: readonly %s"),
|
||||
name, unset_function ? "function" : "variable");
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
|
||||
/* Unless the -f option is supplied, the name refers to a variable. */
|
||||
#if defined (ARRAY_VARS)
|
||||
if (var && unset_array)
|
||||
{
|
||||
if (array_p (var) == 0 && assoc_p (var) == 0)
|
||||
{
|
||||
builtin_error (_("%s: not an array variable"), name);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
else
|
||||
{
|
||||
tem = unbind_array_element (var, t);
|
||||
if (tem == -1)
|
||||
any_failed++;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* ARRAY_VARS */
|
||||
tem = unset_function ? unbind_func (name) : unbind_variable (name);
|
||||
|
||||
/* This is what Posix.2 says: ``If neither -f nor -v
|
||||
is specified, the name refers to a variable; if a variable by
|
||||
that name does not exist, a function by that name, if any,
|
||||
shall be unset.'' */
|
||||
if (tem == -1 && unset_function == 0 && unset_variable == 0)
|
||||
tem = unbind_func (name);
|
||||
|
||||
/* SUSv3, POSIX.1-2001 say: ``Unsetting a variable or function that
|
||||
was not previously set shall not be considered an error.'' */
|
||||
|
||||
if (unset_function == 0)
|
||||
stupidly_hack_special_variables (name);
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
@@ -1,517 +0,0 @@
|
||||
This file is setattr.def, from which is created setattr.c.
|
||||
It implements the builtins "export" and "readonly", in Bash.
|
||||
|
||||
Copyright (C) 1987-2010 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$PRODUCES setattr.c
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int posixly_correct;
|
||||
extern int array_needs_making;
|
||||
extern char *this_command_name;
|
||||
extern sh_builtin_func_t *this_shell_builtin;
|
||||
|
||||
#ifdef ARRAY_VARS
|
||||
extern int declare_builtin __P((WORD_LIST *));
|
||||
#endif
|
||||
|
||||
#define READONLY_OR_EXPORT \
|
||||
(this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin)
|
||||
|
||||
$BUILTIN export
|
||||
$FUNCTION export_builtin
|
||||
$SHORT_DOC export [-fn] [name[=value] ...] or export -p
|
||||
Set export attribute for shell variables.
|
||||
|
||||
Marks each NAME for automatic export to the environment of subsequently
|
||||
executed commands. If VALUE is supplied, assign VALUE before exporting.
|
||||
|
||||
Options:
|
||||
-f refer to shell functions
|
||||
-n remove the export property from each NAME
|
||||
-p display a list of all exported variables and functions
|
||||
|
||||
An argument of `--' disables further option processing.
|
||||
|
||||
Exit Status:
|
||||
Returns success unless an invalid option is given or NAME is invalid.
|
||||
$END
|
||||
|
||||
/* For each variable name in LIST, make that variable appear in the
|
||||
environment passed to simple commands. If there is no LIST, then
|
||||
print all such variables. An argument of `-n' says to remove the
|
||||
exported attribute from variables named in LIST. An argument of
|
||||
-f indicates that the names present in LIST refer to functions. */
|
||||
int
|
||||
export_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
return (set_or_show_attributes (list, att_exported, 0));
|
||||
}
|
||||
|
||||
$BUILTIN readonly
|
||||
$FUNCTION readonly_builtin
|
||||
$SHORT_DOC readonly [-aAf] [name[=value] ...] or readonly -p
|
||||
Mark shell variables as unchangeable.
|
||||
|
||||
Mark each NAME as read-only; the values of these NAMEs may not be
|
||||
changed by subsequent assignment. If VALUE is supplied, assign VALUE
|
||||
before marking as read-only.
|
||||
|
||||
Options:
|
||||
-a refer to indexed array variables
|
||||
-A refer to associative array variables
|
||||
-f refer to shell functions
|
||||
-p display a list of all readonly variables and functions
|
||||
|
||||
An argument of `--' disables further option processing.
|
||||
|
||||
Exit Status:
|
||||
Returns success unless an invalid option is given or NAME is invalid.
|
||||
$END
|
||||
|
||||
/* For each variable name in LIST, make that variable readonly. Given an
|
||||
empty LIST, print out all existing readonly variables. */
|
||||
int
|
||||
readonly_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
return (set_or_show_attributes (list, att_readonly, 0));
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
# define ATTROPTS "aAfnp"
|
||||
#else
|
||||
# define ATTROPTS "fnp"
|
||||
#endif
|
||||
|
||||
/* For each variable name in LIST, make that variable have the specified
|
||||
ATTRIBUTE. An arg of `-n' says to remove the attribute from the the
|
||||
remaining names in LIST (doesn't work for readonly). */
|
||||
int
|
||||
set_or_show_attributes (list, attribute, nodefs)
|
||||
register WORD_LIST *list;
|
||||
int attribute, nodefs;
|
||||
{
|
||||
register SHELL_VAR *var;
|
||||
int assign, undo, any_failed, assign_error, opt;
|
||||
int functions_only, arrays_only, assoc_only;
|
||||
int aflags;
|
||||
char *name;
|
||||
#if defined (ARRAY_VARS)
|
||||
WORD_LIST *nlist, *tlist;
|
||||
WORD_DESC *w;
|
||||
#endif
|
||||
|
||||
functions_only = arrays_only = assoc_only = 0;
|
||||
undo = any_failed = assign_error = 0;
|
||||
/* Read arguments from the front of the list. */
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, ATTROPTS)) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'n':
|
||||
undo = 1;
|
||||
break;
|
||||
case 'f':
|
||||
functions_only = 1;
|
||||
break;
|
||||
#if defined (ARRAY_VARS)
|
||||
case 'a':
|
||||
arrays_only = 1;
|
||||
break;
|
||||
case 'A':
|
||||
assoc_only = 1;
|
||||
break;
|
||||
#endif
|
||||
case 'p':
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list)
|
||||
{
|
||||
if (attribute & att_exported)
|
||||
array_needs_making = 1;
|
||||
|
||||
/* Cannot undo readonly status, silently disallowed. */
|
||||
if (undo && (attribute & att_readonly))
|
||||
attribute &= ~att_readonly;
|
||||
|
||||
while (list)
|
||||
{
|
||||
name = list->word->word;
|
||||
|
||||
if (functions_only) /* xxx -f name */
|
||||
{
|
||||
var = find_function (name);
|
||||
if (var == 0)
|
||||
{
|
||||
builtin_error (_("%s: not a function"), name);
|
||||
any_failed++;
|
||||
}
|
||||
else
|
||||
SETVARATTR (var, attribute, undo);
|
||||
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* xxx [-np] name[=value] */
|
||||
assign = assignment (name, 0);
|
||||
|
||||
aflags = 0;
|
||||
if (assign)
|
||||
{
|
||||
name[assign] = '\0';
|
||||
if (name[assign - 1] == '+')
|
||||
{
|
||||
aflags |= ASS_APPEND;
|
||||
name[assign - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (legal_identifier (name) == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
if (assign)
|
||||
assign_error++;
|
||||
else
|
||||
any_failed++;
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assign) /* xxx [-np] name=value */
|
||||
{
|
||||
name[assign] = '=';
|
||||
if (aflags & ASS_APPEND)
|
||||
name[assign - 1] = '+';
|
||||
#if defined (ARRAY_VARS)
|
||||
/* Let's try something here. Turn readonly -a xxx=yyy into
|
||||
declare -ra xxx=yyy and see what that gets us. */
|
||||
if (arrays_only || assoc_only)
|
||||
{
|
||||
tlist = list->next;
|
||||
list->next = (WORD_LIST *)NULL;
|
||||
w = arrays_only ? make_word ("-ra") : make_word ("-rA");
|
||||
nlist = make_word_list (w, list);
|
||||
opt = declare_builtin (nlist);
|
||||
if (opt != EXECUTION_SUCCESS)
|
||||
assign_error++;
|
||||
list->next = tlist;
|
||||
dispose_word (w);
|
||||
free (nlist);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* This word has already been expanded once with command
|
||||
and parameter expansion. Call do_assignment_no_expand (),
|
||||
which does not do command or parameter substitution. If
|
||||
the assignment is not performed correctly, flag an error. */
|
||||
if (do_assignment_no_expand (name) == 0)
|
||||
assign_error++;
|
||||
name[assign] = '\0';
|
||||
if (aflags & ASS_APPEND)
|
||||
name[assign - 1] = '\0';
|
||||
}
|
||||
|
||||
set_var_attribute (name, attribute, undo);
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SHELL_VAR **variable_list;
|
||||
register int i;
|
||||
|
||||
if ((attribute & att_function) || functions_only)
|
||||
{
|
||||
variable_list = all_shell_functions ();
|
||||
if (attribute != att_function)
|
||||
attribute &= ~att_function; /* so declare -xf works, for example */
|
||||
}
|
||||
else
|
||||
variable_list = all_shell_variables ();
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (attribute & att_array)
|
||||
{
|
||||
arrays_only++;
|
||||
if (attribute != att_array)
|
||||
attribute &= ~att_array;
|
||||
}
|
||||
else if (attribute & att_assoc)
|
||||
{
|
||||
assoc_only++;
|
||||
if (attribute != att_assoc)
|
||||
attribute &= ~att_assoc;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (variable_list)
|
||||
{
|
||||
for (i = 0; var = variable_list[i]; i++)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (arrays_only && array_p (var) == 0)
|
||||
continue;
|
||||
else if (assoc_only && assoc_p (var) == 0)
|
||||
continue;
|
||||
#endif
|
||||
if ((var->attributes & attribute))
|
||||
{
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
if (any_failed = sh_chkwrite (any_failed))
|
||||
break;
|
||||
}
|
||||
}
|
||||
free (variable_list);
|
||||
}
|
||||
}
|
||||
|
||||
return (assign_error ? EX_BADASSIGN
|
||||
: ((any_failed == 0) ? EXECUTION_SUCCESS
|
||||
: EXECUTION_FAILURE));
|
||||
}
|
||||
|
||||
/* Show all variable variables (v == 1) or functions (v == 0) with
|
||||
attributes. */
|
||||
int
|
||||
show_all_var_attributes (v, nodefs)
|
||||
int v, nodefs;
|
||||
{
|
||||
SHELL_VAR **variable_list, *var;
|
||||
int any_failed;
|
||||
register int i;
|
||||
|
||||
variable_list = v ? all_shell_variables () : all_shell_functions ();
|
||||
if (variable_list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
for (i = any_failed = 0; var = variable_list[i]; i++)
|
||||
{
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
if (any_failed = sh_chkwrite (any_failed))
|
||||
break;
|
||||
}
|
||||
free (variable_list);
|
||||
return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Show the attributes for shell variable VAR. If NODEFS is non-zero,
|
||||
don't show function definitions along with the name. If PATTR is
|
||||
non-zero, it indicates we're being called from `export' or `readonly'.
|
||||
In POSIX mode, this prints the name of the calling builtin (`export'
|
||||
or `readonly') instead of `declare', and doesn't print function defs
|
||||
when called by `export' or `readonly'. */
|
||||
int
|
||||
show_var_attributes (var, pattr, nodefs)
|
||||
SHELL_VAR *var;
|
||||
int pattr, nodefs;
|
||||
{
|
||||
char flags[16], *x;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
|
||||
/* pattr == 0 means we are called from `declare'. */
|
||||
if (pattr == 0 || posixly_correct == 0)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (var))
|
||||
flags[i++] = 'a';
|
||||
|
||||
if (assoc_p (var))
|
||||
flags[i++] = 'A';
|
||||
#endif
|
||||
|
||||
if (function_p (var))
|
||||
flags[i++] = 'f';
|
||||
|
||||
if (integer_p (var))
|
||||
flags[i++] = 'i';
|
||||
|
||||
if (nameref_p (var))
|
||||
flags[i++] = 'n';
|
||||
|
||||
if (readonly_p (var))
|
||||
flags[i++] = 'r';
|
||||
|
||||
if (trace_p (var))
|
||||
flags[i++] = 't';
|
||||
|
||||
if (exported_p (var))
|
||||
flags[i++] = 'x';
|
||||
|
||||
if (capcase_p (var))
|
||||
flags[i++] = 'c';
|
||||
|
||||
if (lowercase_p (var))
|
||||
flags[i++] = 'l';
|
||||
|
||||
if (uppercase_p (var))
|
||||
flags[i++] = 'u';
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (var))
|
||||
flags[i++] = 'a';
|
||||
|
||||
if (assoc_p (var))
|
||||
flags[i++] = 'A';
|
||||
#endif
|
||||
|
||||
if (function_p (var))
|
||||
flags[i++] = 'f';
|
||||
}
|
||||
|
||||
flags[i] = '\0';
|
||||
|
||||
/* If we're printing functions with definitions, print the function def
|
||||
first, then the attributes, instead of printing output that can't be
|
||||
reused as input to recreate the current state. */
|
||||
if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0))
|
||||
{
|
||||
printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
|
||||
nodefs++;
|
||||
if (pattr == 0 && i == 1 && flags[0] == 'f')
|
||||
return 0; /* don't print `declare -f name' */
|
||||
}
|
||||
|
||||
if (pattr == 0 || posixly_correct == 0)
|
||||
printf ("declare -%s ", i ? flags : "-");
|
||||
else if (i)
|
||||
printf ("%s -%s ", this_command_name, flags);
|
||||
else
|
||||
printf ("%s ", this_command_name);
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (var))
|
||||
print_array_assignment (var, 1);
|
||||
else if (assoc_p (var))
|
||||
print_assoc_assignment (var, 1);
|
||||
else
|
||||
#endif
|
||||
/* force `readonly' and `export' to not print out function definitions
|
||||
when in POSIX mode. */
|
||||
if (nodefs || (function_p (var) && pattr != 0 && posixly_correct))
|
||||
printf ("%s\n", var->name);
|
||||
else if (function_p (var))
|
||||
printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
|
||||
else if (invisible_p (var) || var_isset (var) == 0)
|
||||
printf ("%s\n", var->name);
|
||||
else
|
||||
{
|
||||
x = sh_double_quote (value_cell (var));
|
||||
printf ("%s=%s\n", var->name, x);
|
||||
free (x);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
show_name_attributes (name, nodefs)
|
||||
char *name;
|
||||
int nodefs;
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = find_variable_tempenv (name);
|
||||
|
||||
if (var && invisible_p (var) == 0)
|
||||
{
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
set_var_attribute (name, attribute, undo)
|
||||
char *name;
|
||||
int attribute, undo;
|
||||
{
|
||||
SHELL_VAR *var, *tv;
|
||||
char *tvalue;
|
||||
|
||||
if (undo)
|
||||
var = find_variable (name);
|
||||
else
|
||||
{
|
||||
tv = find_tempenv_variable (name);
|
||||
/* XXX -- need to handle case where tv is a temp variable in a
|
||||
function-scope context, since function_env has been merged into
|
||||
the local variables table. */
|
||||
if (tv && tempvar_p (tv))
|
||||
{
|
||||
tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring ("");
|
||||
|
||||
var = bind_variable (tv->name, tvalue, 0);
|
||||
var->attributes |= tv->attributes & ~att_tempvar;
|
||||
VSETATTR (tv, att_propagate);
|
||||
if (var->context != 0)
|
||||
VSETATTR (var, att_propagate);
|
||||
SETVARATTR (tv, attribute, undo); /* XXX */
|
||||
|
||||
stupidly_hack_special_variables (tv->name);
|
||||
|
||||
free (tvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var = find_variable_notempenv (name);
|
||||
if (var == 0)
|
||||
{
|
||||
var = bind_variable (name, (char *)NULL, 0);
|
||||
VSETATTR (var, att_invisible);
|
||||
}
|
||||
else if (var->context != 0)
|
||||
VSETATTR (var, att_propagate);
|
||||
}
|
||||
}
|
||||
|
||||
if (var)
|
||||
SETVARATTR (var, attribute, undo);
|
||||
|
||||
if (var && (exported_p (var) || (attribute & att_exported)))
|
||||
array_needs_making++; /* XXX */
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
This file is source.def, from which is created source.c.
|
||||
It implements the builtins "." and "source" in Bash.
|
||||
|
||||
Copyright (C) 1987-2009 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$PRODUCES source.c
|
||||
|
||||
$BUILTIN source
|
||||
$FUNCTION source_builtin
|
||||
$SHORT_DOC source filename [arguments]
|
||||
Execute commands from a file in the current shell.
|
||||
|
||||
Read and execute commands from FILENAME in the current shell. The
|
||||
entries in $PATH are used to find the directory containing FILENAME.
|
||||
If any ARGUMENTS are supplied, they become the positional parameters
|
||||
when FILENAME is executed.
|
||||
|
||||
Exit Status:
|
||||
Returns the status of the last command executed in FILENAME; fails if
|
||||
FILENAME cannot be read.
|
||||
$END
|
||||
|
||||
$BUILTIN .
|
||||
$DOCNAME dot
|
||||
$FUNCTION source_builtin
|
||||
$SHORT_DOC . filename [arguments]
|
||||
Execute commands from a file in the current shell.
|
||||
|
||||
Read and execute commands from FILENAME in the current shell. The
|
||||
entries in $PATH are used to find the directory containing FILENAME.
|
||||
If any ARGUMENTS are supplied, they become the positional parameters
|
||||
when FILENAME is executed.
|
||||
|
||||
Exit Status:
|
||||
Returns the status of the last command executed in FILENAME; fails if
|
||||
FILENAME cannot be read.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "../bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
#include "filecntl.h"
|
||||
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../flags.h"
|
||||
#include "../findcmd.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "../trap.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
extern int posixly_correct;
|
||||
extern int last_command_exit_value;
|
||||
extern int executing_command_builtin;
|
||||
|
||||
extern char *the_printed_command_except_trap;
|
||||
|
||||
static void maybe_pop_dollar_vars __P((void));
|
||||
|
||||
/* If non-zero, `.' uses $PATH to look up the script to be sourced. */
|
||||
int source_uses_path = 1;
|
||||
|
||||
/* If non-zero, `.' looks in the current directory if the filename argument
|
||||
is not found in the $PATH. */
|
||||
int source_searches_cwd = 1;
|
||||
|
||||
/* If this . script is supplied arguments, we save the dollar vars and
|
||||
replace them with the script arguments for the duration of the script's
|
||||
execution. If the script does not change the dollar vars, we restore
|
||||
what we saved. If the dollar vars are changed in the script, and we are
|
||||
not executing a shell function, we leave the new values alone and free
|
||||
the saved values. */
|
||||
static void
|
||||
maybe_pop_dollar_vars ()
|
||||
{
|
||||
if (variable_context == 0 && (dollar_vars_changed () & ARGS_SETBLTIN))
|
||||
dispose_saved_dollar_vars ();
|
||||
else
|
||||
pop_dollar_vars ();
|
||||
if (debugging_mode)
|
||||
pop_args (); /* restore BASH_ARGC and BASH_ARGV */
|
||||
set_dollar_vars_unchanged ();
|
||||
}
|
||||
|
||||
/* Read and execute commands from the file passed as argument. Guess what.
|
||||
This cannot be done in a subshell, since things like variable assignments
|
||||
take place in there. So, I open the file, place it into a large string,
|
||||
close the file, and then execute the string. */
|
||||
int
|
||||
source_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int result;
|
||||
char *filename, *debug_trap;
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_error (_("filename argument required"));
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted && strchr (list->word->word, '/'))
|
||||
{
|
||||
sh_restricted (list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
filename = (char *)NULL;
|
||||
/* XXX -- should this be absolute_pathname? */
|
||||
if (posixly_correct && strchr (list->word->word, '/'))
|
||||
filename = savestring (list->word->word);
|
||||
else if (absolute_pathname (list->word->word))
|
||||
filename = savestring (list->word->word);
|
||||
else if (source_uses_path)
|
||||
filename = find_path_file (list->word->word);
|
||||
if (filename == 0)
|
||||
{
|
||||
if (source_searches_cwd == 0)
|
||||
{
|
||||
builtin_error (_("%s: file not found"), list->word->word);
|
||||
if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
|
||||
{
|
||||
last_command_exit_value = 1;
|
||||
jump_to_top_level (EXITPROG);
|
||||
}
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
filename = savestring (list->word->word);
|
||||
}
|
||||
|
||||
begin_unwind_frame ("source");
|
||||
add_unwind_protect ((Function *)xfree, filename);
|
||||
|
||||
if (list->next)
|
||||
{
|
||||
push_dollar_vars ();
|
||||
add_unwind_protect ((Function *)maybe_pop_dollar_vars, (char *)NULL);
|
||||
remember_args (list->next, 1);
|
||||
if (debugging_mode)
|
||||
push_args (list->next); /* Update BASH_ARGV and BASH_ARGC */
|
||||
}
|
||||
set_dollar_vars_unchanged ();
|
||||
|
||||
/* Don't inherit the DEBUG trap unless function_trace_mode (overloaded)
|
||||
is set. XXX - should sourced files inherit the RETURN trap? Functions
|
||||
don't. */
|
||||
debug_trap = TRAP_STRING (DEBUG_TRAP);
|
||||
if (debug_trap && function_trace_mode == 0)
|
||||
{
|
||||
debug_trap = savestring (debug_trap);
|
||||
add_unwind_protect (xfree, debug_trap);
|
||||
add_unwind_protect (set_debug_trap, debug_trap);
|
||||
restore_default_signal (DEBUG_TRAP);
|
||||
}
|
||||
itrace("source_builtin: the printed command = %s", the_printed_command_except_trap);
|
||||
result = source_file (filename, (list && list->next));
|
||||
|
||||
run_unwind_frame ("source");
|
||||
|
||||
return (result);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
# This file is a shell script that caches the results of configure
|
||||
# tests for CYGWIN32 so they don't need to be done when cross-compiling.
|
||||
|
||||
# AC_FUNC_GETPGRP should also define GETPGRP_VOID
|
||||
ac_cv_func_getpgrp_void=${ac_cv_func_getpgrp_void='yes'}
|
||||
# AC_FUNC_SETVBUF_REVERSED should not define anything else
|
||||
ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed='no'}
|
||||
# on CYGWIN32, system calls do not restart
|
||||
ac_cv_sys_restartable_syscalls=${ac_cv_sys_restartable_syscalls='no'}
|
||||
bash_cv_sys_restartable_syscalls=${bash_cv_sys_restartable_syscalls='no'}
|
||||
|
||||
# these may be necessary, but they are currently commented out
|
||||
#ac_cv_c_bigendian=${ac_cv_c_bigendian='no'}
|
||||
ac_cv_sizeof_char_p=${ac_cv_sizeof_char_p='4'}
|
||||
ac_cv_sizeof_int=${ac_cv_sizeof_int='4'}
|
||||
ac_cv_sizeof_long=${ac_cv_sizeof_long='4'}
|
||||
ac_cv_sizeof_double=${ac_cv_sizeof_double='8'}
|
||||
|
||||
bash_cv_dup2_broken=${bash_cv_dup2_broken='no'}
|
||||
bash_cv_pgrp_pipe=${bash_cv_pgrp_pipe='no'}
|
||||
bash_cv_type_rlimit=${bash_cv_type_rlimit='long'}
|
||||
bash_cv_decl_under_sys_siglist=${bash_cv_decl_under_sys_siglist='no'}
|
||||
bash_cv_under_sys_siglist=${bash_cv_under_sys_siglist='no'}
|
||||
bash_cv_sys_siglist=${bash_cv_sys_siglist='no'}
|
||||
bash_cv_opendir_not_robust=${bash_cv_opendir_not_robust='no'}
|
||||
bash_cv_getenv_redef=${bash_cv_getenv_redef='yes'}
|
||||
bash_cv_printf_declared=${bash_cv_printf_declared='yes'}
|
||||
bash_cv_ulimit_maxfds=${bash_cv_ulimit_maxfds='no'}
|
||||
bash_cv_getcwd_calls_popen=${bash_cv_getcwd_calls_popen='no'}
|
||||
bash_cv_must_reinstall_sighandlers=${bash_cv_must_reinstall_sighandlers='no'}
|
||||
bash_cv_job_control_missing=${bash_cv_job_control_missing='present'}
|
||||
bash_cv_sys_named_pipes=${bash_cv_sys_named_pipes='missing'}
|
||||
bash_cv_func_sigsetjmp=${bash_cv_func_sigsetjmp='missing'}
|
||||
bash_cv_mail_dir=${bash_cv_mail_dir='unknown'}
|
||||
bash_cv_func_strcoll_broken=${bash_cv_func_strcoll_broken='no'}
|
||||
|
||||
bash_cv_type_int32_t=${bash_cv_type_int32_t='int'}
|
||||
bash_cv_type_u_int32_t=${bash_cv_type_u_int32_t='int'}
|
||||
|
||||
ac_cv_type_bits64_t=${ac_cv_type_bits64_t='no'}
|
||||
|
||||
# end of cross-build/cygwin32.cache
|
||||
-1745
File diff suppressed because it is too large
Load Diff
-10139
File diff suppressed because it is too large
Load Diff
@@ -1,238 +0,0 @@
|
||||
#
|
||||
# Simple makefile for the sample loadable builtins
|
||||
#
|
||||
# Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
|
||||
# This program 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
# Include some boilerplate Gnu makefile definitions.
|
||||
prefix = @prefix@
|
||||
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
infodir = @infodir@
|
||||
includedir = @includedir@
|
||||
|
||||
topdir = @top_srcdir@
|
||||
BUILD_DIR = @BUILD_DIR@
|
||||
srcdir = @srcdir@
|
||||
VPATH = .:@srcdir@
|
||||
|
||||
@SET_MAKE@
|
||||
CC = @CC@
|
||||
RM = rm -f
|
||||
|
||||
SHELL = @MAKE_SHELL@
|
||||
|
||||
host_os = @host_os@
|
||||
host_cpu = @host_cpu@
|
||||
host_vendor = @host_vendor@
|
||||
|
||||
CFLAGS = @CFLAGS@
|
||||
LOCAL_CFLAGS = @LOCAL_CFLAGS@
|
||||
DEFS = @DEFS@
|
||||
LOCAL_DEFS = @LOCAL_DEFS@
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
|
||||
BASHINCDIR = ${topdir}/include
|
||||
|
||||
LIBBUILD = ${BUILD_DIR}/lib
|
||||
|
||||
INTL_LIBSRC = ${topdir}/lib/intl
|
||||
INTL_BUILDDIR = ${LIBBUILD}/intl
|
||||
INTL_INC = @INTL_INC@
|
||||
LIBINTL_H = @LIBINTL_H@
|
||||
|
||||
CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS)
|
||||
|
||||
#
|
||||
# These values are generated for configure by ${topdir}/support/shobj-conf.
|
||||
# If your system is not supported by that script, but includes facilities for
|
||||
# dynamic loading of shared objects, please update the script and send the
|
||||
# changes to bash-maintainers@gnu.org.
|
||||
#
|
||||
SHOBJ_CC = @SHOBJ_CC@
|
||||
SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
|
||||
SHOBJ_LD = @SHOBJ_LD@
|
||||
SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@
|
||||
SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
|
||||
SHOBJ_LIBS = @SHOBJ_LIBS@
|
||||
SHOBJ_STATUS = @SHOBJ_STATUS@
|
||||
|
||||
INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \
|
||||
-I$(BASHINCDIR) -I$(BUILD_DIR) -I$(LIBBUILD) \
|
||||
-I$(BUILD_DIR)/builtins $(INTL_INC)
|
||||
|
||||
.c.o:
|
||||
$(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $<
|
||||
|
||||
|
||||
ALLPROG = print truefalse sleep pushd finfo logname basename dirname \
|
||||
tty pathchk tee head mkdir rmdir printenv id whoami \
|
||||
uname sync push ln unlink cut realpath getconf strftime
|
||||
OTHERPROG = necho hello cat
|
||||
|
||||
all: $(SHOBJ_STATUS)
|
||||
|
||||
supported: $(ALLPROG)
|
||||
others: $(OTHERPROG)
|
||||
|
||||
unsupported:
|
||||
@echo "Your system (${host_os}) is not supported by the"
|
||||
@echo "${topdir}/support/shobj-conf script."
|
||||
@echo "If your operating system provides facilities for dynamic"
|
||||
@echo "loading of shared objects using the dlopen(3) interface,"
|
||||
@echo "please update the script and re-run configure.
|
||||
@echo "Please send the changes you made to bash-maintainers@gnu.org"
|
||||
@echo "for inclusion in future bash releases."
|
||||
|
||||
everything: supported others
|
||||
|
||||
print: print.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ print.o $(SHOBJ_LIBS)
|
||||
|
||||
necho: necho.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ necho.o $(SHOBJ_LIBS)
|
||||
|
||||
getconf: getconf.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ getconf.o $(SHOBJ_LIBS)
|
||||
|
||||
hello: hello.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ hello.o $(SHOBJ_LIBS)
|
||||
|
||||
truefalse: truefalse.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ truefalse.o $(SHOBJ_LIBS)
|
||||
|
||||
sleep: sleep.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sleep.o $(SHOBJ_LIBS)
|
||||
|
||||
finfo: finfo.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ finfo.o $(SHOBJ_LIBS)
|
||||
|
||||
cat: cat.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS)
|
||||
|
||||
logname: logname.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS)
|
||||
|
||||
basename: basename.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ basename.o $(SHOBJ_LIBS)
|
||||
|
||||
dirname: dirname.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dirname.o $(SHOBJ_LIBS)
|
||||
|
||||
tty: tty.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tty.o $(SHOBJ_LIBS)
|
||||
|
||||
pathchk: pathchk.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pathchk.o $(SHOBJ_LIBS)
|
||||
|
||||
tee: tee.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tee.o $(SHOBJ_LIBS)
|
||||
|
||||
mkdir: mkdir.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkdir.o $(SHOBJ_LIBS)
|
||||
|
||||
rmdir: rmdir.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rmdir.o $(SHOBJ_LIBS)
|
||||
|
||||
head: head.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ head.o $(SHOBJ_LIBS)
|
||||
|
||||
printenv: printenv.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ printenv.o $(SHOBJ_LIBS)
|
||||
|
||||
id: id.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ id.o $(SHOBJ_LIBS)
|
||||
|
||||
whoami: whoami.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ whoami.o $(SHOBJ_LIBS)
|
||||
|
||||
uname: uname.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ uname.o $(SHOBJ_LIBS)
|
||||
|
||||
sync: sync.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sync.o $(SHOBJ_LIBS)
|
||||
|
||||
push: push.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ push.o $(SHOBJ_LIBS)
|
||||
|
||||
ln: ln.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ ln.o $(SHOBJ_LIBS)
|
||||
|
||||
unlink: unlink.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ unlink.o $(SHOBJ_LIBS)
|
||||
|
||||
cut: cut.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cut.o $(SHOBJ_LIBS)
|
||||
|
||||
realpath: realpath.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ realpath.o $(SHOBJ_LIBS)
|
||||
|
||||
strftime: strftime.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ strftime.o $(SHOBJ_LIBS)
|
||||
|
||||
# pushd is a special case. We use the same source that the builtin version
|
||||
# uses, with special compilation options.
|
||||
#
|
||||
pushd.c: ${topdir}/builtins/pushd.def
|
||||
$(RM) $@
|
||||
${BUILD_DIR}/builtins/mkbuiltins -D ${topdir}/builtins ${topdir}/builtins/pushd.def
|
||||
|
||||
pushd.o: pushd.c
|
||||
$(RM) $@
|
||||
$(SHOBJ_CC) -DHAVE_CONFIG_H -DPUSHD_AND_POPD -DLOADABLE_BUILTIN $(SHOBJ_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(INC) -c -o $@ $<
|
||||
|
||||
pushd: pushd.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pushd.o $(SHOBJ_LIBS)
|
||||
|
||||
clean:
|
||||
$(RM) $(ALLPROG) $(OTHERPROG) *.o
|
||||
-( cd perl && ${MAKE} ${MFLAGS} $@ )
|
||||
|
||||
mostlyclean: clean
|
||||
-( cd perl && ${MAKE} ${MFLAGS} $@ )
|
||||
|
||||
distclean maintainer-clean: clean
|
||||
$(RM) Makefile pushd.c
|
||||
-( cd perl && ${MAKE} ${MFLAGS} $@ )
|
||||
|
||||
print.o: print.c
|
||||
truefalse.o: truefalse.c
|
||||
sleep.o: sleep.c
|
||||
finfo.o: finfo.c
|
||||
logname.o: logname.c
|
||||
basename.o: basename.c
|
||||
dirname.o: dirname.c
|
||||
tty.o: tty.c
|
||||
pathchk.o: pathchk.c
|
||||
tee.o: tee.c
|
||||
head.o: head.c
|
||||
rmdir.o: rmdir.c
|
||||
necho.o: necho.c
|
||||
getconf.o: getconf.c
|
||||
hello.o: hello.c
|
||||
cat.o: cat.c
|
||||
printenv.o: printenv.c
|
||||
id.o: id.c
|
||||
whoami.o: whoami.c
|
||||
uname.o: uname.c
|
||||
sync.o: sync.c
|
||||
push.o: push.c
|
||||
mkdir.o: mkdir.c
|
||||
realpath.o: realpath.c
|
||||
strftime.o: strftime.c
|
||||
@@ -1,549 +0,0 @@
|
||||
#!/bin/bash
|
||||
# ash -- "Adventure shell"
|
||||
# last edit: 86/04/21 D A Gwyn
|
||||
# SCCS ID: @(#)ash.sh 1.4
|
||||
|
||||
OPATH=$PATH
|
||||
|
||||
ask()
|
||||
{
|
||||
echo -n "$@" '[y/n] '
|
||||
read ans
|
||||
|
||||
case "$ans" in
|
||||
y*|Y*)
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
CAT=${PAGER:-more}
|
||||
|
||||
ash_inst()
|
||||
{
|
||||
cat <<- EOF
|
||||
|
||||
Instructions for the Adventure shell
|
||||
|
||||
Welcome to the Adventure shell! In this exploration of the UNIX file
|
||||
system, I will act as your eyes and hands. As you move around, I will
|
||||
describe whatever is visible and will carry out your commands. The
|
||||
general form of a command is
|
||||
Verb Object Extra_stuff.
|
||||
Most commands pay no attention to the "Extra_stuff", and many do not
|
||||
need an "Object". A typical command is
|
||||
get all
|
||||
which picks up all files in the current "room" (directory). You can
|
||||
find out what you are carrying by typing the command
|
||||
inventory
|
||||
The command "help" results in a full description of all commands that I
|
||||
understand. To quit the Adventure shell, type
|
||||
quit
|
||||
|
||||
There are UNIX monsters lurking in the background. These are also
|
||||
known as "commands with arguments".
|
||||
|
||||
Good luck!
|
||||
EOF
|
||||
}
|
||||
|
||||
ash_help()
|
||||
{
|
||||
echo "I understand the following commands (synonyms in parentheses):"
|
||||
echo ""
|
||||
|
||||
echo "change OBJECT to NEW_NAME changes the name of the object"
|
||||
echo "clone OBJECT as NEW_NAME duplicates the object"
|
||||
echo "drop OBJECTS leaves the objects in the room"
|
||||
echo "enter (go) PASSAGE takes the labeled passage"
|
||||
echo "examine OBJECTS describes the objects in detail"
|
||||
echo "feed OBJECT to MONSTER stuffs the object into a UNIX monster"
|
||||
echo "get (take) OBJECTS picks up the specified objects"
|
||||
echo "gripe (bug) report a problem with the Adventure shell"
|
||||
echo "help prints this summary"
|
||||
echo "inventory (i) tells what you are carrying"
|
||||
echo "kill (destroy) OBJECTS destroys the objects"
|
||||
echo "look (l) describes the room, including hidden objects"
|
||||
echo "open (read) OBJECT shows the contents of an object"
|
||||
echo "quit (exit) leaves the Adventure shell"
|
||||
echo "resurrect OBJECTS attempts to restore dead objects"
|
||||
echo "steal OBJECT from MONSTER obtains the object from a UNIX monster"
|
||||
echo "throw OBJECT at daemon feeds the object to the printer daemon"
|
||||
echo "up takes the overhead passage"
|
||||
echo "wake MONSTER awakens a UNIX monster"
|
||||
echo "where (w) tells you where you are"
|
||||
echo "xyzzy moves you to your home"
|
||||
}
|
||||
|
||||
MAINT=chet@ins.cwru.edu
|
||||
|
||||
PATH=/usr/ucb:/bin:/usr/bin:/usr/local/bin:.
|
||||
export PATH
|
||||
|
||||
trap 'echo Ouch!' 2 3
|
||||
#trap '' 18 # disable Berkeley job control
|
||||
|
||||
ash_lk(){ echo " $1 " | fgrep " $2 " >&- 2>&-; }
|
||||
ash_pr(){ echo $* | tr ' ' '\012' | pr -5 -t -w75 -l$[ ( $# + 4 ) / 5 ]; }
|
||||
ash_rm(){ echo " $1 " | sed -e "s/ $2 / /" -e 's/^ //' -e 's/ $//'; }
|
||||
|
||||
# enable history, bang history expansion, and emacs editing
|
||||
set -o history
|
||||
set -o histexpand
|
||||
set -o emacs
|
||||
|
||||
cd
|
||||
LIM=.limbo # $HOME/$LIM contains "destroyed" objects
|
||||
mkdir $LIM >&- 2>&-
|
||||
KNAP=.knapsack # $HOME/$KNAP contains objects being "carried"
|
||||
if [ ! -d $KNAP ]
|
||||
then mkdir $KNAP >&- 2>&-
|
||||
if [ $? = 0 ]
|
||||
then echo 'You found a discarded empty knapsack.'
|
||||
else echo 'You have no knapsack to carry things in.'
|
||||
exit 1
|
||||
fi
|
||||
else echo 'One moment while I peek in your old knapsack...'
|
||||
fi
|
||||
|
||||
kn=`echo \`ls -a $KNAP | sed -e '/^\.$/d' -e '/^\.\.$/d'\``
|
||||
|
||||
if ask 'Welcome to the Adventure shell! Do you need instructions?'
|
||||
then
|
||||
ash_inst
|
||||
echo -n 'Type a newline to continue: '
|
||||
read
|
||||
fi
|
||||
|
||||
wiz=false
|
||||
cha=false
|
||||
prev=$LIM
|
||||
while :
|
||||
do room=`pwd`
|
||||
if [ $room != $prev ]
|
||||
then if [ $room = $HOME ]
|
||||
then echo 'You are in your own home.'
|
||||
else echo "You have entered $room."
|
||||
fi
|
||||
exs=
|
||||
obs=
|
||||
hexs=
|
||||
hobs=
|
||||
f=false
|
||||
for i in `ls -a`
|
||||
do case $i in
|
||||
.|..) ;;
|
||||
.*) if [ -f $i ]
|
||||
then hobs="$hobs $i"
|
||||
elif [ -d $i ]
|
||||
then hexs="$hexs $i"
|
||||
else f=true
|
||||
fi
|
||||
;;
|
||||
*) if [ -f $i ]
|
||||
then obs="$obs $i"
|
||||
elif [ -d $i ]
|
||||
then exs="$exs $i"
|
||||
else f=true
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ "$obs" ]
|
||||
then echo 'This room contains:'
|
||||
ash_pr $obs
|
||||
else echo 'The room looks empty.'
|
||||
fi
|
||||
if [ "$exs" ]
|
||||
then echo 'There are exits labeled:'
|
||||
ash_pr $exs
|
||||
echo 'as well as a passage overhead.'
|
||||
else echo 'There is a passage overhead.'
|
||||
fi
|
||||
if sh -c $f
|
||||
then echo 'There are shadowy figures in the corner.'
|
||||
fi
|
||||
prev=$room
|
||||
fi
|
||||
|
||||
read -e -p '-advsh> ' verb obj x # prompt is '-advsh> '
|
||||
if [ $? != 0 ]
|
||||
then verb=quit # EOF
|
||||
fi
|
||||
|
||||
case $verb in
|
||||
change) if [ "$obj" ]
|
||||
then if ash_lk "$obs $hobs" "$obj"
|
||||
then set -- $x
|
||||
case "$1" in
|
||||
to) if [ "$2" ]
|
||||
then if [ -f $2 ]
|
||||
then echo "You must destroy $2 first."
|
||||
set --
|
||||
fi
|
||||
if [ "$2" ]
|
||||
then if mv $obj $2 >&- 2>&-
|
||||
then echo "The $obj shimmers and turns into $2."
|
||||
obs=`ash_rm "$2 $obs" "$obj"`
|
||||
else echo "There is a cloud of smoke but the $obj is unchanged."
|
||||
fi
|
||||
fi
|
||||
else echo 'To what?'
|
||||
fi
|
||||
;;
|
||||
*) echo "Change $obj to what?"
|
||||
;;
|
||||
esac
|
||||
else if ash_lk "$kn" "$obj"
|
||||
then echo 'You must drop it first.'
|
||||
else echo "I see no $obj here."
|
||||
fi
|
||||
fi
|
||||
else echo 'Change what?'
|
||||
fi
|
||||
;;
|
||||
clone) if [ "$obj" ]
|
||||
then if ash_lk "$obs $hobs" "$obj"
|
||||
then if [ ! -r $obj ]
|
||||
then echo "The $obj does not wish to be cloned."
|
||||
else set -- $x
|
||||
case "$1" in
|
||||
as) if [ "$2" ]
|
||||
then if [ -f $2 ]
|
||||
then echo "You must destroy $2 first."
|
||||
else if cp $obj $2 >&- 2>&-
|
||||
then echo "Poof! When the smoke clears, you see the new $2."
|
||||
obs="$obs $2"
|
||||
else echo 'You hear a dull thud but no clone appears.'
|
||||
fi
|
||||
fi
|
||||
else echo 'As what?'
|
||||
fi
|
||||
;;
|
||||
*) echo "Clone $obj as what?"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
else if ash_lk "$kn" "$obj"
|
||||
then echo 'You must drop it first.'
|
||||
else echo "I see no $obj here."
|
||||
fi
|
||||
fi
|
||||
else echo 'Clone what?'
|
||||
fi
|
||||
;;
|
||||
drop) if [ "$obj" ]
|
||||
then for it in $obj $x
|
||||
do if ash_lk "$kn" "$it"
|
||||
then if [ -w $it ]
|
||||
then echo "You must destroy $it first."
|
||||
else if mv $HOME/$KNAP/$it $it >&- 2>&-
|
||||
then echo "$it: dropped."
|
||||
kn=`ash_rm "$kn" "$it"`
|
||||
obs=`echo $it $obs`
|
||||
else echo "The $it is caught in your knapsack."
|
||||
fi
|
||||
fi
|
||||
else echo "You're not carrying the $it!"
|
||||
fi
|
||||
done
|
||||
else echo 'Drop what?'
|
||||
fi
|
||||
;;
|
||||
enter|go) if [ "$obj" ]
|
||||
then if [ $obj != up ]
|
||||
then if ash_lk "$exs $hexs" "$obj"
|
||||
then if [ -x $obj ]
|
||||
then if cd $obj
|
||||
then echo 'You squeeze through the passage.'
|
||||
else echo "You can't go that direction."
|
||||
fi
|
||||
else echo 'An invisible force blocks your way.'
|
||||
fi
|
||||
else echo 'I see no such passage.'
|
||||
fi
|
||||
else if cd ..
|
||||
then echo 'You struggle upwards.'
|
||||
else echo "You can't reach that high."
|
||||
fi
|
||||
fi
|
||||
else echo 'Which passage?'
|
||||
fi
|
||||
;;
|
||||
examine) if [ "$obj" ]
|
||||
then if [ $obj = all ]
|
||||
then $obj=`echo $obs $exs`
|
||||
x=
|
||||
fi
|
||||
for it in $obj $x
|
||||
do if ash_lk "$obs $hobs $exs $hexs" "$it"
|
||||
then echo "Upon close inspection of the $it, you see:"
|
||||
ls -ld $it 2>&-
|
||||
if [ $? != 0 ]
|
||||
then echo "-- when you look directly at the $it, it vanishes."
|
||||
fi
|
||||
else if ash_lk "$kn" "$it"
|
||||
then echo 'You must drop it first.'
|
||||
else echo "I see no $it here."
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else echo 'Examine what?'
|
||||
fi
|
||||
;;
|
||||
feed) if [ "$obj" ]
|
||||
then if ash_lk "$obs $hobs" "$obj"
|
||||
then set -- $x
|
||||
case "$1" in
|
||||
to) if [ "$2" ]
|
||||
then shift
|
||||
if PATH=$OPATH $* <$obj 2>&-
|
||||
then echo "The $1 monster devours your $obj."
|
||||
if rm -f $obj >&- 2>&-
|
||||
then obs=`ash_rm "$obs" "$obj"`
|
||||
else echo 'But he spits it back up.'
|
||||
fi
|
||||
else echo "The $1 monster holds his nose in disdain."
|
||||
fi
|
||||
else echo 'To what?'
|
||||
fi
|
||||
;;
|
||||
*) echo "Feed $obj to what?"
|
||||
;;
|
||||
esac
|
||||
else if ash_lk "$kn" "$obj"
|
||||
then echo 'You must drop it first.'
|
||||
else echo "I see no $obj here."
|
||||
fi
|
||||
fi
|
||||
else echo 'Feed what?'
|
||||
fi
|
||||
;;
|
||||
get|take) if [ "$obj" ]
|
||||
then if [ $obj = all ]
|
||||
then obj="$obs"
|
||||
x=
|
||||
fi
|
||||
for it in $obj $x
|
||||
do if ash_lk "$obs $hobs" "$it"
|
||||
then if ash_lk "$kn" "$it"
|
||||
then echo 'You already have one.'
|
||||
else if mv $it $HOME/$KNAP/$it >&- 2>&-
|
||||
then echo "$it: taken."
|
||||
kn="$it $kn"
|
||||
obs=`ash_rm "$obs" "$it"`
|
||||
else echo "The $it is too heavy."
|
||||
fi
|
||||
fi
|
||||
else echo "I see no $it here."
|
||||
fi
|
||||
done
|
||||
else echo 'Get what?'
|
||||
fi
|
||||
;;
|
||||
gripe|bug) echo 'Please describe the problem and your situation at the time it failed.\nEnd the bug report with a line containing just a Ctrl-D.'
|
||||
cat | mail $MAINT -s 'ash bug'
|
||||
echo 'Thank you!'
|
||||
;;
|
||||
help) ash_help
|
||||
;;
|
||||
inventory|i) if [ "$kn" ]
|
||||
then echo 'Your knapsack contains:'
|
||||
ash_pr $kn
|
||||
else echo 'You are poverty-stricken.'
|
||||
fi
|
||||
;;
|
||||
kill|destroy) if [ "$obj" ]
|
||||
then if [ $obj = all ]
|
||||
then x=
|
||||
if ask "Do you really want to attempt to $verb them all?"
|
||||
then obj=`echo $obs`
|
||||
else echo 'Chicken!'
|
||||
obj=
|
||||
fi
|
||||
fi
|
||||
for it in $obj $x
|
||||
do if ash_lk "$obs $hobs" "$it"
|
||||
then if mv $it $HOME/$LIM <&- >&- 2>&-
|
||||
then if [ $verb = kill ]
|
||||
then echo "The $it cannot defend himself; he dies."
|
||||
else echo "You have destroyed the $it; it vanishes."
|
||||
fi
|
||||
obs=`ash_rm "$obs" "$it"`
|
||||
else if [ $verb = kill ]
|
||||
then echo "Your feeble blows are no match for the $it."
|
||||
else echo "The $it is indestructible."
|
||||
fi
|
||||
fi
|
||||
else if ash_lk "$kn" "$it"
|
||||
then echo "You must drop the $it first."
|
||||
found=false
|
||||
else echo "I see no $it here."
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else echo 'Kill what?'
|
||||
fi
|
||||
;;
|
||||
look|l) obs=`echo $obs $hobs`
|
||||
hobs=
|
||||
if [ "$obs" ]
|
||||
then echo 'The room contains:'
|
||||
ash_pr $obs
|
||||
else echo 'The room is empty.'
|
||||
fi
|
||||
exs=`echo $exs $hexs`
|
||||
hexs=
|
||||
if [ "$exs" ]
|
||||
then echo 'There are exits plainly labeled:'
|
||||
ash_pr $exs
|
||||
echo 'and a passage directly overhead.'
|
||||
else echo 'The only exit is directly overhead.'
|
||||
fi
|
||||
;;
|
||||
magic) if [ "$obj" = mode ]
|
||||
then if sh -c $cha
|
||||
then echo 'You had your chance and you blew it.'
|
||||
else if ask 'Are you a wizard?'
|
||||
then echo -n 'Prove it! Say the magic word: '
|
||||
read obj
|
||||
if [ "$obj" = armadillo ]
|
||||
then echo 'Yes, master!!'
|
||||
wiz=true
|
||||
else echo "Homie says: I don't think so"
|
||||
cha=true
|
||||
fi
|
||||
else echo "I didn't think so."
|
||||
fi
|
||||
fi
|
||||
else echo 'Nice try.'
|
||||
fi
|
||||
;;
|
||||
open|read) if [ "$obj" ]
|
||||
then if ash_lk "$obs $hobs" "$obj"
|
||||
then if [ -r $obj ]
|
||||
then if [ -s $obj ]
|
||||
then echo "Opening the $obj reveals:"
|
||||
$CAT < $obj
|
||||
if [ $? != 0 ]
|
||||
then echo '-- oops, you lost the contents!'
|
||||
fi
|
||||
else echo "There is nothing inside the $obj."
|
||||
fi
|
||||
else echo "You do not have the proper tools to open the $obj."
|
||||
fi
|
||||
else if ash_lk "$kn" "$obj"
|
||||
then echo 'You must drop it first.'
|
||||
found=false
|
||||
else echo "I see no $obj here."
|
||||
fi
|
||||
fi
|
||||
else echo 'Open what?'
|
||||
fi
|
||||
;;
|
||||
quit|exit) if ask 'Do you really want to quit now?'
|
||||
then if [ "$kn" ]
|
||||
then echo 'The contents of your knapsack will still be there next time.'
|
||||
fi
|
||||
rm -rf $HOME/$LIM
|
||||
echo 'See you later!'
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
resurrect) if [ "$obj" ]
|
||||
then for it in $obj $x
|
||||
do if ash_lk "$obs $hobs" "$it"
|
||||
then echo "The $it is already alive and well."
|
||||
else if mv $HOME/$LIM/$it $it <&- >&- 2>&-
|
||||
then echo "The $it staggers to his feet."
|
||||
obs=`echo $it $obs`
|
||||
else echo "There are sparks but no $it appears."
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else echo 'Resurrect what?'
|
||||
fi
|
||||
;;
|
||||
steal) if [ "$obj" ]
|
||||
then if ash_lk "$obs $hobs" "$obj"
|
||||
then echo 'There is already one here.'
|
||||
else set -- $x
|
||||
case "$1" in
|
||||
from) if [ "$2" ]
|
||||
then shift
|
||||
if PATH=$OPATH $* >$obj 2>&-
|
||||
then echo "The $1 monster drops the $obj."
|
||||
obs=`echo $obj $obs`
|
||||
else echo "The $1 monster runs away as you approach."
|
||||
rm -f $obj >&- 2>&-
|
||||
fi
|
||||
else echo 'From what?'
|
||||
fi
|
||||
;;
|
||||
*) echo "Steal $obj from what?"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
else echo 'Steal what?'
|
||||
fi
|
||||
;;
|
||||
throw) if [ "$obj" ]
|
||||
then if ash_lk "$obs $hobs" "$obj"
|
||||
then set -- $x
|
||||
case "$1" in
|
||||
at) case "$2" in
|
||||
daemon) if sh -c "lpr -r $obj"
|
||||
then echo "The daemon catches the $obj, turns it into paper,\nand leaves it in the basket."
|
||||
obs=`ash_rm "$obs" "$obj"`
|
||||
else echo "The daemon is nowhere to be found."
|
||||
fi
|
||||
;;
|
||||
*) echo 'At what?'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*) echo "Throw $obj at what?"
|
||||
;;
|
||||
esac
|
||||
else if ash_lk "$kn" "$obj"
|
||||
then echo 'It is in your knapsack.'
|
||||
found=false
|
||||
else echo "I see no $obj here."
|
||||
fi
|
||||
fi
|
||||
else echo 'Throw what?'
|
||||
fi
|
||||
;;
|
||||
u|up) if cd ..
|
||||
then echo 'You pull yourself up a level.'
|
||||
else echo "You can't reach that high."
|
||||
fi
|
||||
;;
|
||||
wake) if [ "$obj" ]
|
||||
then echo "You awaken the $obj monster:"
|
||||
PATH=$OPATH $obj $x
|
||||
echo 'The monster slithers back into the darkness.'
|
||||
else echo 'Wake what?'
|
||||
fi
|
||||
;;
|
||||
w|where) echo "You are in $room."
|
||||
;;
|
||||
xyzzy) if cd
|
||||
then echo 'A strange feeling comes over you.'
|
||||
else echo 'Your spell fizzles out.'
|
||||
fi
|
||||
;;
|
||||
*) if [ "$verb" ]
|
||||
then if sh -c $wiz
|
||||
then PATH=$OPATH $verb $obj $x
|
||||
else echo "I don't know how to \"$verb\"."
|
||||
echo 'Type "help" for assistance.'
|
||||
fi
|
||||
else echo 'Say something!'
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
-5338
File diff suppressed because it is too large
Load Diff
-502
@@ -1,502 +0,0 @@
|
||||
/* externs.h -- extern function declarations which do not appear in their
|
||||
own header file. */
|
||||
|
||||
/* Copyright (C) 1993-2010 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Make sure that this is included *after* config.h! */
|
||||
|
||||
#if !defined (_EXTERNS_H_)
|
||||
# define _EXTERNS_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
/* Functions from expr.c. */
|
||||
extern intmax_t evalexp __P((char *, int *));
|
||||
|
||||
/* Functions from print_cmd.c. */
|
||||
#define FUNC_MULTILINE 0x01
|
||||
#define FUNC_EXTERNAL 0x02
|
||||
|
||||
extern char *make_command_string __P((COMMAND *));
|
||||
extern char *named_function_string __P((char *, COMMAND *, int));
|
||||
|
||||
extern void print_command __P((COMMAND *));
|
||||
extern void print_simple_command __P((SIMPLE_COM *));
|
||||
extern void print_word_list __P((WORD_LIST *, char *));
|
||||
|
||||
/* debugger support */
|
||||
extern void print_for_command_head __P((FOR_COM *));
|
||||
#if defined (SELECT_COMMAND)
|
||||
extern void print_select_command_head __P((SELECT_COM *));
|
||||
#endif
|
||||
extern void print_case_command_head __P((CASE_COM *));
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
extern void print_arith_command __P((WORD_LIST *));
|
||||
#endif
|
||||
#if defined (COND_COMMAND)
|
||||
extern void print_cond_command __P((COND_COM *));
|
||||
#endif
|
||||
|
||||
/* set -x support */
|
||||
extern void xtrace_init __P((void));
|
||||
#ifdef NEED_XTRACE_SET_DECL
|
||||
extern void xtrace_set __P((int, FILE *));
|
||||
#endif
|
||||
extern void xtrace_fdchk __P((int));
|
||||
extern void xtrace_reset __P((void));
|
||||
extern char *indirection_level_string __P((void));
|
||||
extern void xtrace_print_assignment __P((char *, char *, int, int));
|
||||
extern void xtrace_print_word_list __P((WORD_LIST *, int));
|
||||
extern void xtrace_print_for_command_head __P((FOR_COM *));
|
||||
#if defined (SELECT_COMMAND)
|
||||
extern void xtrace_print_select_command_head __P((SELECT_COM *));
|
||||
#endif
|
||||
extern void xtrace_print_case_command_head __P((CASE_COM *));
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
extern void xtrace_print_arith_cmd __P((WORD_LIST *));
|
||||
#endif
|
||||
#if defined (COND_COMMAND)
|
||||
extern void xtrace_print_cond_term __P((int, int, WORD_DESC *, char *, char *));
|
||||
#endif
|
||||
|
||||
/* Functions from shell.c. */
|
||||
extern void exit_shell __P((int)) __attribute__((__noreturn__));
|
||||
extern void sh_exit __P((int)) __attribute__((__noreturn__));
|
||||
extern void disable_priv_mode __P((void));
|
||||
extern void unbind_args __P((void));
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
extern int shell_is_restricted __P((char *));
|
||||
extern int maybe_make_restricted __P((char *));
|
||||
#endif
|
||||
|
||||
extern void unset_bash_input __P((int));
|
||||
extern void get_current_user_info __P((void));
|
||||
|
||||
/* Functions from eval.c. */
|
||||
extern int reader_loop __P((void));
|
||||
extern int parse_command __P((void));
|
||||
extern int read_command __P((void));
|
||||
|
||||
/* Functions from braces.c. */
|
||||
#if defined (BRACE_EXPANSION)
|
||||
extern char **brace_expand __P((char *));
|
||||
#endif
|
||||
|
||||
/* Miscellaneous functions from parse.y */
|
||||
extern int yyparse __P((void));
|
||||
extern int return_EOF __P((void));
|
||||
extern char *xparse_dolparen __P((char *, char *, int *, int));
|
||||
extern void reset_parser __P((void));
|
||||
extern WORD_LIST *parse_string_to_word_list __P((char *, int, const char *));
|
||||
|
||||
extern int parser_in_command_position __P((void));
|
||||
|
||||
extern void free_pushed_string_input __P((void));
|
||||
|
||||
extern char *decode_prompt_string __P((char *));
|
||||
|
||||
extern int get_current_prompt_level __P((void));
|
||||
extern void set_current_prompt_level __P((int));
|
||||
|
||||
#if defined (HISTORY)
|
||||
extern char *history_delimiting_chars __P((const char *));
|
||||
#endif
|
||||
|
||||
/* Declarations for functions defined in locale.c */
|
||||
extern void set_default_locale __P((void));
|
||||
extern void set_default_locale_vars __P((void));
|
||||
extern int set_locale_var __P((char *, char *));
|
||||
extern int set_lang __P((char *, char *));
|
||||
extern void set_default_lang __P((void));
|
||||
extern char *get_locale_var __P((char *));
|
||||
extern char *localetrans __P((char *, int, int *));
|
||||
extern char *mk_msgstr __P((char *, int *));
|
||||
extern char *localeexpand __P((char *, int, int, int, int *));
|
||||
|
||||
/* Declarations for functions defined in list.c. */
|
||||
extern void list_walk __P((GENERIC_LIST *, sh_glist_func_t *));
|
||||
extern void wlist_walk __P((WORD_LIST *, sh_icpfunc_t *));
|
||||
extern GENERIC_LIST *list_reverse ();
|
||||
extern int list_length ();
|
||||
extern GENERIC_LIST *list_append ();
|
||||
extern GENERIC_LIST *list_remove ();
|
||||
|
||||
/* Declarations for functions defined in stringlib.c */
|
||||
extern int find_string_in_alist __P((char *, STRING_INT_ALIST *, int));
|
||||
extern char *find_token_in_alist __P((int, STRING_INT_ALIST *, int));
|
||||
extern int find_index_in_alist __P((char *, STRING_INT_ALIST *, int));
|
||||
|
||||
extern char *substring __P((const char *, int, int));
|
||||
extern char *strsub __P((char *, char *, char *, int));
|
||||
extern char *strcreplace __P((char *, int, char *, int));
|
||||
extern void strip_leading __P((char *));
|
||||
extern void strip_trailing __P((char *, int, int));
|
||||
extern void xbcopy __P((char *, char *, int));
|
||||
|
||||
/* Functions from version.c. */
|
||||
extern char *shell_version_string __P((void));
|
||||
extern void show_shell_version __P((int));
|
||||
|
||||
/* Functions from the bash library, lib/sh/libsh.a. These should really
|
||||
go into a separate include file. */
|
||||
|
||||
/* declarations for functions defined in lib/sh/casemod.c */
|
||||
extern char *sh_modcase __P((const char *, char *, int));
|
||||
|
||||
/* Defines for flags argument to sh_modcase. These need to agree with what's
|
||||
in lib/sh/casemode.c */
|
||||
#define CASE_LOWER 0x0001
|
||||
#define CASE_UPPER 0x0002
|
||||
#define CASE_CAPITALIZE 0x0004
|
||||
#define CASE_UNCAP 0x0008
|
||||
#define CASE_TOGGLE 0x0010
|
||||
#define CASE_TOGGLEALL 0x0020
|
||||
#define CASE_UPFIRST 0x0040
|
||||
#define CASE_LOWFIRST 0x0080
|
||||
|
||||
#define CASE_USEWORDS 0x1000
|
||||
|
||||
/* declarations for functions defined in lib/sh/clktck.c */
|
||||
extern long get_clk_tck __P((void));
|
||||
|
||||
/* declarations for functions defined in lib/sh/clock.c */
|
||||
extern void clock_t_to_secs ();
|
||||
extern void print_clock_t ();
|
||||
|
||||
/* Declarations for functions defined in lib/sh/dprintf.c */
|
||||
#if !defined (HAVE_DPRINTF)
|
||||
extern void dprintf __P((int, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
|
||||
#endif
|
||||
|
||||
/* Declarations for functions defined in lib/sh/fmtulong.c */
|
||||
#define FL_PREFIX 0x01 /* add 0x, 0X, or 0 prefix as appropriate */
|
||||
#define FL_ADDBASE 0x02 /* add base# prefix to converted value */
|
||||
#define FL_HEXUPPER 0x04 /* use uppercase when converting to hex */
|
||||
#define FL_UNSIGNED 0x08 /* don't add any sign */
|
||||
|
||||
extern char *fmtulong __P((unsigned long int, int, char *, size_t, int));
|
||||
|
||||
/* Declarations for functions defined in lib/sh/fmtulong.c */
|
||||
#if defined (HAVE_LONG_LONG)
|
||||
extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int));
|
||||
#endif
|
||||
|
||||
/* Declarations for functions defined in lib/sh/fmtumax.c */
|
||||
extern char *fmtumax __P((uintmax_t, int, char *, size_t, int));
|
||||
|
||||
/* Declarations for functions defined in lib/sh/fnxform.c */
|
||||
extern char *fnx_fromfs __P((char *, size_t));
|
||||
extern char *fnx_tofs __P((char *, size_t));
|
||||
|
||||
/* Declarations for functions defined in lib/sh/fpurge.c */
|
||||
|
||||
#if defined NEED_FPURGE_DECL
|
||||
#if !HAVE_DECL_FPURGE
|
||||
|
||||
#if HAVE_FPURGE
|
||||
# define fpurge _bash_fpurge
|
||||
#endif
|
||||
extern int fpurge __P((FILE *stream));
|
||||
|
||||
#endif /* HAVE_DECL_FPURGE */
|
||||
#endif /* NEED_FPURGE_DECL */
|
||||
|
||||
/* Declarations for functions defined in lib/sh/getcwd.c */
|
||||
#if !defined (HAVE_GETCWD)
|
||||
extern char *getcwd __P((char *, size_t));
|
||||
#endif
|
||||
|
||||
/* Declarations for functions defined in lib/sh/input_avail.c */
|
||||
extern int input_avail __P((int));
|
||||
|
||||
/* Declarations for functions defined in lib/sh/itos.c */
|
||||
extern char *inttostr __P((intmax_t, char *, size_t));
|
||||
extern char *itos __P((intmax_t));
|
||||
extern char *uinttostr __P((uintmax_t, char *, size_t));
|
||||
extern char *uitos __P((uintmax_t));
|
||||
|
||||
/* declarations for functions defined in lib/sh/makepath.c */
|
||||
#define MP_DOTILDE 0x01
|
||||
#define MP_DOCWD 0x02
|
||||
#define MP_RMDOT 0x04
|
||||
#define MP_IGNDOT 0x08
|
||||
|
||||
extern char *sh_makepath __P((const char *, const char *, int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/mbscasecmp.c */
|
||||
#if !defined (HAVE_MBSCASECMP)
|
||||
extern char *mbscasecmp __P((const char *, const char *));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/mbschr.c */
|
||||
#if !defined (HAVE_MBSCHR)
|
||||
extern char *mbschr __P((const char *, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/mbscmp.c */
|
||||
#if !defined (HAVE_MBSCMP)
|
||||
extern char *mbscmp __P((const char *, const char *));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/netconn.c */
|
||||
extern int isnetconn __P((int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/netopen.c */
|
||||
extern int netopen __P((char *));
|
||||
|
||||
/* Declarations for functions defined in lib/sh/oslib.c */
|
||||
|
||||
#if !defined (HAVE_DUP2) || defined (DUP2_BROKEN)
|
||||
extern int dup2 __P((int, int));
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_GETDTABLESIZE)
|
||||
extern int getdtablesize __P((void));
|
||||
#endif /* !HAVE_GETDTABLESIZE */
|
||||
|
||||
#if !defined (HAVE_GETHOSTNAME)
|
||||
extern int gethostname __P((char *, int));
|
||||
#endif /* !HAVE_GETHOSTNAME */
|
||||
|
||||
extern int getmaxgroups __P((void));
|
||||
extern long getmaxchild __P((void));
|
||||
|
||||
/* declarations for functions defined in lib/sh/pathcanon.c */
|
||||
#define PATH_CHECKDOTDOT 0x0001
|
||||
#define PATH_CHECKEXISTS 0x0002
|
||||
#define PATH_HARDPATH 0x0004
|
||||
#define PATH_NOALLOC 0x0008
|
||||
|
||||
extern char *sh_canonpath __P((char *, int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/pathphys.c */
|
||||
extern char *sh_physpath __P((char *, int));
|
||||
extern char *sh_realpath __P((const char *, char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/setlinebuf.c */
|
||||
#ifdef NEED_SH_SETLINEBUF_DECL
|
||||
extern int sh_setlinebuf __P((FILE *));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/shaccess.c */
|
||||
extern int sh_eaccess __P((char *, int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/shmatch.c */
|
||||
extern int sh_regmatch __P((const char *, const char *, int));
|
||||
|
||||
/* defines for flags argument to sh_regmatch. */
|
||||
#define SHMAT_SUBEXP 0x001 /* save subexpressions in SH_REMATCH */
|
||||
#define SHMAT_PWARN 0x002 /* print a warning message on invalid regexp */
|
||||
|
||||
/* declarations for functions defined in lib/sh/shmbchar.c */
|
||||
extern size_t mbstrlen __P((const char *));
|
||||
extern char *mbsmbchar __P((const char *));
|
||||
extern int sh_mbsnlen __P((const char *, size_t, int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/shquote.c */
|
||||
extern char *sh_single_quote __P((const char *));
|
||||
extern char *sh_double_quote __P((const char *));
|
||||
extern char *sh_mkdoublequoted __P((const char *, int, int));
|
||||
extern char *sh_un_double_quote __P((char *));
|
||||
extern char *sh_backslash_quote __P((char *, const char *));
|
||||
extern char *sh_backslash_quote_for_double_quotes __P((char *));
|
||||
extern int sh_contains_shell_metas __P((char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/spell.c */
|
||||
extern int spname __P((char *, char *));
|
||||
extern char *dirspell __P((char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/strcasecmp.c */
|
||||
#if !defined (HAVE_STRCASECMP)
|
||||
extern int strncasecmp __P((const char *, const char *, int));
|
||||
extern int strcasecmp __P((const char *, const char *));
|
||||
#endif /* HAVE_STRCASECMP */
|
||||
|
||||
/* declarations for functions defined in lib/sh/strcasestr.c */
|
||||
#if ! HAVE_STRCASESTR
|
||||
extern char *strcasestr __P((const char *, const char *));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strchrnul.c */
|
||||
#if ! HAVE_STRCHRNUL
|
||||
extern char *strchrnul __P((const char *, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strerror.c */
|
||||
#if !defined (HAVE_STRERROR) && !defined (strerror)
|
||||
extern char *strerror __P((int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strftime.c */
|
||||
#if !defined (HAVE_STRFTIME) && defined (NEED_STRFTIME_DECL)
|
||||
extern size_t strftime __P((char *, size_t, const char *, const struct tm *));
|
||||
#endif
|
||||
|
||||
/* declarations for functions and structures defined in lib/sh/stringlist.c */
|
||||
|
||||
/* This is a general-purpose argv-style array struct. */
|
||||
typedef struct _list_of_strings {
|
||||
char **list;
|
||||
int list_size;
|
||||
int list_len;
|
||||
} STRINGLIST;
|
||||
|
||||
typedef int sh_strlist_map_func_t __P((char *));
|
||||
|
||||
extern STRINGLIST *strlist_create __P((int));
|
||||
extern STRINGLIST *strlist_resize __P((STRINGLIST *, int));
|
||||
extern void strlist_flush __P((STRINGLIST *));
|
||||
extern void strlist_dispose __P((STRINGLIST *));
|
||||
extern int strlist_remove __P((STRINGLIST *, char *));
|
||||
extern STRINGLIST *strlist_copy __P((STRINGLIST *));
|
||||
extern STRINGLIST *strlist_merge __P((STRINGLIST *, STRINGLIST *));
|
||||
extern STRINGLIST *strlist_append __P((STRINGLIST *, STRINGLIST *));
|
||||
extern STRINGLIST *strlist_prefix_suffix __P((STRINGLIST *, char *, char *));
|
||||
extern void strlist_print __P((STRINGLIST *, char *));
|
||||
extern void strlist_walk __P((STRINGLIST *, sh_strlist_map_func_t *));
|
||||
extern void strlist_sort __P((STRINGLIST *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/stringvec.c */
|
||||
|
||||
extern char **strvec_create __P((int));
|
||||
extern char **strvec_resize __P((char **, int));
|
||||
extern void strvec_flush __P((char **));
|
||||
extern void strvec_dispose __P((char **));
|
||||
extern int strvec_remove __P((char **, char *));
|
||||
extern int strvec_len __P((char **));
|
||||
extern int strvec_search __P((char **, char *));
|
||||
extern char **strvec_copy __P((char **));
|
||||
extern int strvec_strcmp __P((char **, char **));
|
||||
extern void strvec_sort __P((char **));
|
||||
|
||||
extern char **strvec_from_word_list __P((WORD_LIST *, int, int, int *));
|
||||
extern WORD_LIST *strvec_to_word_list __P((char **, int, int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/strnlen.c */
|
||||
#if !defined (HAVE_STRNLEN)
|
||||
extern size_t strnlen __P((const char *, size_t));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strpbrk.c */
|
||||
#if !defined (HAVE_STRPBRK)
|
||||
extern char *strpbrk __P((const char *, const char *));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strtod.c */
|
||||
#if !defined (HAVE_STRTOD)
|
||||
extern double strtod __P((const char *, char **));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strtol.c */
|
||||
#if !HAVE_DECL_STRTOL
|
||||
extern long strtol __P((const char *, char **, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strtoll.c */
|
||||
#if defined (HAVE_LONG_LONG) && !HAVE_DECL_STRTOLL
|
||||
extern long long strtoll __P((const char *, char **, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strtoul.c */
|
||||
#if !HAVE_DECL_STRTOUL
|
||||
extern unsigned long strtoul __P((const char *, char **, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strtoull.c */
|
||||
#if defined (HAVE_LONG_LONG) && !HAVE_DECL_STRTOULL
|
||||
extern unsigned long long strtoull __P((const char *, char **, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strimax.c */
|
||||
#if !HAVE_DECL_STRTOIMAX
|
||||
extern intmax_t strtoimax __P((const char *, char **, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strumax.c */
|
||||
#if !HAVE_DECL_STRTOUMAX
|
||||
extern uintmax_t strtoumax __P((const char *, char **, int));
|
||||
#endif
|
||||
|
||||
/* declarations for functions defined in lib/sh/strtrans.c */
|
||||
extern char *ansicstr __P((char *, int, int, int *, int *));
|
||||
extern char *ansic_quote __P((char *, int, int *));
|
||||
extern int ansic_shouldquote __P((const char *));
|
||||
extern char *ansiexpand __P((char *, int, int, int *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/timeval.c. No prototypes
|
||||
so we don't have to count on having a definition of struct timeval in
|
||||
scope when this file is included. */
|
||||
extern void timeval_to_secs ();
|
||||
extern void print_timeval ();
|
||||
|
||||
/* declarations for functions defined in lib/sh/tmpfile.c */
|
||||
#define MT_USETMPDIR 0x0001
|
||||
#define MT_READWRITE 0x0002
|
||||
#define MT_USERANDOM 0x0004
|
||||
|
||||
extern char *sh_mktmpname __P((char *, int));
|
||||
extern int sh_mktmpfd __P((char *, int, char **));
|
||||
/* extern FILE *sh_mktmpfp __P((char *, int, char **)); */
|
||||
|
||||
/* declarations for functions defined in lib/sh/uconvert.c */
|
||||
extern int uconvert __P((char *, long *, long *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/ufuncs.c */
|
||||
extern unsigned int falarm __P((unsigned int, unsigned int));
|
||||
extern unsigned int fsleep __P((unsigned int, unsigned int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/unicode.c */
|
||||
extern int u32cconv __P((unsigned long, char *));
|
||||
extern void u32reset __P((void));
|
||||
|
||||
/* declarations for functions defined in lib/sh/winsize.c */
|
||||
extern void get_new_window_size __P((int, int *, int *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/zcatfd.c */
|
||||
extern int zcatfd __P((int, int, char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/zgetline.c */
|
||||
extern ssize_t zgetline __P((int, char **, size_t *, int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/zmapfd.c */
|
||||
extern int zmapfd __P((int, char **, char *));
|
||||
|
||||
/* declarations for functions defined in lib/sh/zread.c */
|
||||
extern ssize_t zread __P((int, char *, size_t));
|
||||
extern ssize_t zreadretry __P((int, char *, size_t));
|
||||
extern ssize_t zreadintr __P((int, char *, size_t));
|
||||
extern ssize_t zreadc __P((int, char *));
|
||||
extern ssize_t zreadcintr __P((int, char *));
|
||||
extern void zreset __P((void));
|
||||
extern void zsyncfd __P((int));
|
||||
|
||||
/* declarations for functions defined in lib/sh/zwrite.c */
|
||||
extern int zwrite __P((int, char *, size_t));
|
||||
|
||||
/* declarations for functions defined in lib/glob/gmisc.c */
|
||||
extern int match_pattern_char __P((char *, char *));
|
||||
extern int umatchlen __P((char *, size_t));
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
extern int match_pattern_wchar __P((wchar_t *, wchar_t *));
|
||||
extern int wmatchlen __P((wchar_t *, size_t));
|
||||
#endif
|
||||
|
||||
#endif /* _EXTERNS_H_ */
|
||||
-1244
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,76 +0,0 @@
|
||||
# This makefile for Readline library documentation is in -*- text -*- mode.
|
||||
# Emacs likes it that way.
|
||||
RM = rm -f
|
||||
|
||||
MAKEINFO = makeinfo
|
||||
TEXI2DVI = texi2dvi
|
||||
TEXI2HTML = texi2html
|
||||
QUIETPS = #set this to -q to shut up dvips
|
||||
DVIPS = dvips -D 300 $(QUIETPS) -o $@ # tricky
|
||||
|
||||
INSTALL_DATA = cp
|
||||
infodir = /usr/local/info
|
||||
|
||||
RLSRC = rlman.texinfo rluser.texinfo rltech.texinfo
|
||||
HISTSRC = hist.texinfo hsuser.texinfo hstech.texinfo
|
||||
|
||||
DVIOBJ = readline.dvi history.dvi
|
||||
INFOOBJ = readline.info history.info
|
||||
PSOBJ = readline.ps history.ps
|
||||
HTMLOBJ = readline.html history.html
|
||||
|
||||
all: info dvi html ps
|
||||
nodvi: info html
|
||||
|
||||
readline.dvi: $(RLSRC)
|
||||
$(TEXI2DVI) rlman.texinfo
|
||||
mv rlman.dvi readline.dvi
|
||||
|
||||
readline.info: $(RLSRC)
|
||||
$(MAKEINFO) --no-split -o $@ rlman.texinfo
|
||||
|
||||
history.dvi: ${HISTSRC}
|
||||
$(TEXI2DVI) hist.texinfo
|
||||
mv hist.dvi history.dvi
|
||||
|
||||
history.info: ${HISTSRC}
|
||||
$(MAKEINFO) --no-split -o $@ hist.texinfo
|
||||
|
||||
readline.ps: readline.dvi
|
||||
$(RM) $@
|
||||
$(DVIPS) readline.dvi
|
||||
|
||||
history.ps: history.dvi
|
||||
$(RM) $@
|
||||
$(DVIPS) history.dvi
|
||||
|
||||
readline.html: ${RLSRC}
|
||||
$(TEXI2HTML) rlman.texinfo
|
||||
sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman.html > readline.html
|
||||
sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman_toc.html > readline_toc.html
|
||||
$(RM) rlman.html rlman_toc.html
|
||||
|
||||
history.html: ${HISTSRC}
|
||||
$(TEXI2HTML) hist.texinfo
|
||||
sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist.html > history.html
|
||||
sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist_toc.html > history_toc.html
|
||||
$(RM) hist.html hist_toc.html
|
||||
|
||||
info: $(INFOOBJ)
|
||||
dvi: $(DVIOBJ)
|
||||
ps: $(PSOBJ)
|
||||
html: $(HTMLOBJ)
|
||||
|
||||
clean:
|
||||
$(RM) *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \
|
||||
*.fns *.kys *.tps *.vrs *.o core
|
||||
|
||||
distclean: clean
|
||||
mostlyclean: clean
|
||||
|
||||
maintainer-clean: clean
|
||||
$(RM) *.dvi *.info *.info-* *.ps *.html
|
||||
|
||||
install: info
|
||||
${INSTALL_DATA} readline.info $(infodir)/readline.info
|
||||
${INSTALL_DATA} history.info $(infodir)/history.info
|
||||
@@ -1,378 +0,0 @@
|
||||
/* mbutil.c -- readline multibyte character utility functions */
|
||||
|
||||
/* Copyright (C) 2001-2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library (Readline), a library
|
||||
for reading lines of text with interactive input and history editing.
|
||||
|
||||
Readline 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Readline 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 Readline. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define READLINE_LIBRARY
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include "posixjmp.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h> /* for _POSIX_VERSION */
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#if defined (HAVE_STDLIB_H)
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# include "ansi_stdlib.h"
|
||||
#endif /* HAVE_STDLIB_H */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* System-specific feature definitions and include files. */
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
#if defined (TIOCSTAT_IN_SYS_IOCTL)
|
||||
# include <sys/ioctl.h>
|
||||
#endif /* TIOCSTAT_IN_SYS_IOCTL */
|
||||
|
||||
/* Some standard library routines. */
|
||||
#include "readline.h"
|
||||
|
||||
#include "rlprivate.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* Declared here so it can be shared between the readline and history
|
||||
libraries. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
int rl_byte_oriented = 0;
|
||||
#else
|
||||
int rl_byte_oriented = 1;
|
||||
#endif
|
||||
|
||||
/* Ditto */
|
||||
int _rl_utf8locale = 0;
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Multibyte Character Utility Functions */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
#if defined(HANDLE_MULTIBYTE)
|
||||
|
||||
static int
|
||||
_rl_find_next_mbchar_internal (string, seed, count, find_non_zero)
|
||||
char *string;
|
||||
int seed, count, find_non_zero;
|
||||
{
|
||||
size_t tmp, len;
|
||||
mbstate_t ps;
|
||||
int point;
|
||||
wchar_t wc;
|
||||
|
||||
tmp = 0;
|
||||
|
||||
memset(&ps, 0, sizeof (mbstate_t));
|
||||
if (seed < 0)
|
||||
seed = 0;
|
||||
if (count <= 0)
|
||||
return seed;
|
||||
|
||||
point = seed + _rl_adjust_point (string, seed, &ps);
|
||||
/* if this is true, means that seed was not pointing to a byte indicating
|
||||
the beginning of a multibyte character. Correct the point and consume
|
||||
one char. */
|
||||
if (seed < point)
|
||||
count--;
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
len = strlen (string + point);
|
||||
if (len == 0)
|
||||
break;
|
||||
tmp = mbrtowc (&wc, string+point, len, &ps);
|
||||
if (MB_INVALIDCH ((size_t)tmp))
|
||||
{
|
||||
/* invalid bytes. assume a byte represents a character */
|
||||
point++;
|
||||
count--;
|
||||
/* reset states. */
|
||||
memset(&ps, 0, sizeof(mbstate_t));
|
||||
}
|
||||
else if (MB_NULLWCH (tmp))
|
||||
break; /* found wide '\0' */
|
||||
else
|
||||
{
|
||||
/* valid bytes */
|
||||
point += tmp;
|
||||
if (find_non_zero)
|
||||
{
|
||||
if (WCWIDTH (wc) == 0)
|
||||
continue;
|
||||
else
|
||||
count--;
|
||||
}
|
||||
else
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
if (find_non_zero)
|
||||
{
|
||||
tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
|
||||
while (MB_NULLWCH (tmp) == 0 && MB_INVALIDCH (tmp) == 0 && WCWIDTH (wc) == 0)
|
||||
{
|
||||
point += tmp;
|
||||
tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
|
||||
}
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
static int
|
||||
_rl_find_prev_mbchar_internal (string, seed, find_non_zero)
|
||||
char *string;
|
||||
int seed, find_non_zero;
|
||||
{
|
||||
mbstate_t ps;
|
||||
int prev, non_zero_prev, point, length;
|
||||
size_t tmp;
|
||||
wchar_t wc;
|
||||
|
||||
memset(&ps, 0, sizeof(mbstate_t));
|
||||
length = strlen(string);
|
||||
|
||||
if (seed < 0)
|
||||
return 0;
|
||||
else if (length < seed)
|
||||
return length;
|
||||
|
||||
prev = non_zero_prev = point = 0;
|
||||
while (point < seed)
|
||||
{
|
||||
tmp = mbrtowc (&wc, string + point, length - point, &ps);
|
||||
if (MB_INVALIDCH ((size_t)tmp))
|
||||
{
|
||||
/* in this case, bytes are invalid or shorted to compose
|
||||
multibyte char, so assume that the first byte represents
|
||||
a single character anyway. */
|
||||
tmp = 1;
|
||||
/* clear the state of the byte sequence, because
|
||||
in this case effect of mbstate is undefined */
|
||||
memset(&ps, 0, sizeof (mbstate_t));
|
||||
|
||||
/* Since we're assuming that this byte represents a single
|
||||
non-zero-width character, don't forget about it. */
|
||||
prev = point;
|
||||
}
|
||||
else if (MB_NULLWCH (tmp))
|
||||
break; /* Found '\0' char. Can this happen? */
|
||||
else
|
||||
{
|
||||
if (find_non_zero)
|
||||
{
|
||||
if (WCWIDTH (wc) != 0)
|
||||
prev = point;
|
||||
}
|
||||
else
|
||||
prev = point;
|
||||
}
|
||||
|
||||
point += tmp;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
/* return the number of bytes parsed from the multibyte sequence starting
|
||||
at src, if a non-L'\0' wide character was recognized. It returns 0,
|
||||
if a L'\0' wide character was recognized. It returns (size_t)(-1),
|
||||
if an invalid multibyte sequence was encountered. It returns (size_t)(-2)
|
||||
if it couldn't parse a complete multibyte character. */
|
||||
int
|
||||
_rl_get_char_len (src, ps)
|
||||
char *src;
|
||||
mbstate_t *ps;
|
||||
{
|
||||
size_t tmp;
|
||||
|
||||
tmp = mbrlen((const char *)src, (size_t)strlen (src), ps);
|
||||
if (tmp == (size_t)(-2))
|
||||
{
|
||||
/* shorted to compose multibyte char */
|
||||
if (ps)
|
||||
memset (ps, 0, sizeof(mbstate_t));
|
||||
return -2;
|
||||
}
|
||||
else if (tmp == (size_t)(-1))
|
||||
{
|
||||
/* invalid to compose multibyte char */
|
||||
/* initialize the conversion state */
|
||||
if (ps)
|
||||
memset (ps, 0, sizeof(mbstate_t));
|
||||
return -1;
|
||||
}
|
||||
else if (tmp == (size_t)0)
|
||||
return 0;
|
||||
else
|
||||
return (int)tmp;
|
||||
}
|
||||
|
||||
/* compare the specified two characters. If the characters matched,
|
||||
return 1. Otherwise return 0. */
|
||||
int
|
||||
_rl_compare_chars (buf1, pos1, ps1, buf2, pos2, ps2)
|
||||
char *buf1;
|
||||
int pos1;
|
||||
mbstate_t *ps1;
|
||||
char *buf2;
|
||||
int pos2;
|
||||
mbstate_t *ps2;
|
||||
{
|
||||
int i, w1, w2;
|
||||
|
||||
if ((w1 = _rl_get_char_len (&buf1[pos1], ps1)) <= 0 ||
|
||||
(w2 = _rl_get_char_len (&buf2[pos2], ps2)) <= 0 ||
|
||||
(w1 != w2) ||
|
||||
(buf1[pos1] != buf2[pos2]))
|
||||
return 0;
|
||||
|
||||
for (i = 1; i < w1; i++)
|
||||
if (buf1[pos1+i] != buf2[pos2+i])
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* adjust pointed byte and find mbstate of the point of string.
|
||||
adjusted point will be point <= adjusted_point, and returns
|
||||
differences of the byte(adjusted_point - point).
|
||||
if point is invalied (point < 0 || more than string length),
|
||||
it returns -1 */
|
||||
int
|
||||
_rl_adjust_point(string, point, ps)
|
||||
char *string;
|
||||
int point;
|
||||
mbstate_t *ps;
|
||||
{
|
||||
size_t tmp = 0;
|
||||
int length;
|
||||
int pos = 0;
|
||||
|
||||
length = strlen(string);
|
||||
if (point < 0)
|
||||
return -1;
|
||||
if (length < point)
|
||||
return -1;
|
||||
|
||||
while (pos < point)
|
||||
{
|
||||
tmp = mbrlen (string + pos, length - pos, ps);
|
||||
if (MB_INVALIDCH ((size_t)tmp))
|
||||
{
|
||||
/* in this case, bytes are invalid or shorted to compose
|
||||
multibyte char, so assume that the first byte represents
|
||||
a single character anyway. */
|
||||
pos++;
|
||||
/* clear the state of the byte sequence, because
|
||||
in this case effect of mbstate is undefined */
|
||||
if (ps)
|
||||
memset (ps, 0, sizeof (mbstate_t));
|
||||
}
|
||||
else if (MB_NULLWCH (tmp))
|
||||
pos++;
|
||||
else
|
||||
pos += tmp;
|
||||
}
|
||||
|
||||
return (pos - point);
|
||||
}
|
||||
|
||||
int
|
||||
_rl_is_mbchar_matched (string, seed, end, mbchar, length)
|
||||
char *string;
|
||||
int seed, end;
|
||||
char *mbchar;
|
||||
int length;
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((end - seed) < length)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
if (string[seed + i] != mbchar[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
wchar_t
|
||||
_rl_char_value (buf, ind)
|
||||
char *buf;
|
||||
int ind;
|
||||
{
|
||||
size_t tmp;
|
||||
wchar_t wc;
|
||||
mbstate_t ps;
|
||||
int l;
|
||||
|
||||
if (MB_LEN_MAX == 1 || rl_byte_oriented)
|
||||
return ((wchar_t) buf[ind]);
|
||||
l = strlen (buf);
|
||||
if (ind >= l - 1)
|
||||
return ((wchar_t) buf[ind]);
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
tmp = mbrtowc (&wc, buf + ind, l - ind, &ps);
|
||||
if (MB_INVALIDCH (tmp) || MB_NULLWCH (tmp))
|
||||
return ((wchar_t) buf[ind]);
|
||||
return wc;
|
||||
}
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
|
||||
/* Find next `count' characters started byte point of the specified seed.
|
||||
If flags is MB_FIND_NONZERO, we look for non-zero-width multibyte
|
||||
characters. */
|
||||
#undef _rl_find_next_mbchar
|
||||
int
|
||||
_rl_find_next_mbchar (string, seed, count, flags)
|
||||
char *string;
|
||||
int seed, count, flags;
|
||||
{
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
return _rl_find_next_mbchar_internal (string, seed, count, flags);
|
||||
#else
|
||||
return (seed + count);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Find previous character started byte point of the specified seed.
|
||||
Returned point will be point <= seed. If flags is MB_FIND_NONZERO,
|
||||
we look for non-zero-width multibyte characters. */
|
||||
#undef _rl_find_prev_mbchar
|
||||
int
|
||||
_rl_find_prev_mbchar (string, seed, flags)
|
||||
char *string;
|
||||
int seed, flags;
|
||||
{
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
return _rl_find_prev_mbchar_internal (string, seed, flags);
|
||||
#else
|
||||
return ((seed == 0) ? seed : seed - 1);
|
||||
#endif
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,301 +0,0 @@
|
||||
/* shquote - functions to quote and dequote strings */
|
||||
|
||||
/* Copyright (C) 1999 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "syntax.h"
|
||||
#include <xmalloc.h>
|
||||
|
||||
/* Default set of characters that should be backslash-quoted in strings */
|
||||
static const char bstab[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 0, 0, 0, 0, 0, /* TAB, NL */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
1, 1, 1, 0, 1, 0, 1, 1, /* SPACE, !, DQUOTE, DOL, AMP, SQUOTE */
|
||||
1, 1, 1, 0, 1, 0, 0, 0, /* LPAR, RPAR, STAR, COMMA */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 1, 0, 1, 1, /* SEMI, LESSTHAN, GREATERTHAN, QUEST */
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 1, 1, 1, 0, /* LBRACK, BS, RBRACK, CARAT */
|
||||
|
||||
1, 0, 0, 0, 0, 0, 0, 0, /* BACKQ */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 1, 1, 0, 0, /* LBRACE, BAR, RBRACE */
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* 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. */
|
||||
char *
|
||||
sh_single_quote (string)
|
||||
const char *string;
|
||||
{
|
||||
register int c;
|
||||
char *result, *r;
|
||||
const char *s;
|
||||
|
||||
result = (char *)xmalloc (3 + (4 * strlen (string)));
|
||||
r = result;
|
||||
*r++ = '\'';
|
||||
|
||||
for (s = string; s && (c = *s); s++)
|
||||
{
|
||||
*r++ = c;
|
||||
|
||||
if (c == '\'')
|
||||
{
|
||||
*r++ = '\\'; /* insert escaped single quote */
|
||||
*r++ = '\'';
|
||||
*r++ = '\''; /* start new quoted string */
|
||||
}
|
||||
}
|
||||
|
||||
*r++ = '\'';
|
||||
*r = '\0';
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Quote STRING using double quotes. Return a new string. */
|
||||
char *
|
||||
sh_double_quote (string)
|
||||
const char *string;
|
||||
{
|
||||
register unsigned char c;
|
||||
char *result, *r;
|
||||
const char *s;
|
||||
|
||||
result = (char *)xmalloc (3 + (2 * strlen (string)));
|
||||
r = result;
|
||||
*r++ = '"';
|
||||
|
||||
for (s = string; s && (c = *s); s++)
|
||||
{
|
||||
/* Backslash-newline disappears within double quotes, so don't add one. */
|
||||
if ((sh_syntaxtab[c] & CBSDQUOTE) && c != '\n')
|
||||
*r++ = '\\';
|
||||
else if (c == CTLESC || c == CTLNUL)
|
||||
*r++ = CTLESC; /* could be '\\'? */
|
||||
|
||||
*r++ = c;
|
||||
}
|
||||
|
||||
*r++ = '"';
|
||||
*r = '\0';
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Turn S into a simple double-quoted string. If FLAGS is non-zero, quote
|
||||
double quote characters in S with backslashes. */
|
||||
char *
|
||||
sh_mkdoublequoted (s, slen, flags)
|
||||
const char *s;
|
||||
int slen, flags;
|
||||
{
|
||||
char *r, *ret;
|
||||
int rlen;
|
||||
|
||||
rlen = (flags == 0) ? slen + 3 : (2 * slen) + 1;
|
||||
ret = r = (char *)xmalloc (rlen);
|
||||
|
||||
*r++ = '"';
|
||||
while (*s)
|
||||
{
|
||||
if (flags && *s == '"')
|
||||
*r++ = '\\';
|
||||
*r++ = *s++;
|
||||
}
|
||||
*r++ = '"';
|
||||
*r = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Remove backslashes that are quoting characters that are special between
|
||||
double quotes. Return a new string. XXX - should this handle CTLESC
|
||||
and CTLNUL? */
|
||||
char *
|
||||
sh_un_double_quote (string)
|
||||
char *string;
|
||||
{
|
||||
register int c, pass_next;
|
||||
char *result, *r, *s;
|
||||
|
||||
r = result = (char *)xmalloc (strlen (string) + 1);
|
||||
|
||||
for (pass_next = 0, s = string; s && (c = *s); s++)
|
||||
{
|
||||
if (pass_next)
|
||||
{
|
||||
*r++ = c;
|
||||
pass_next = 0;
|
||||
continue;
|
||||
}
|
||||
if (c == '\\' && (sh_syntaxtab[(unsigned char) s[1]] & CBSDQUOTE))
|
||||
{
|
||||
pass_next = 1;
|
||||
continue;
|
||||
}
|
||||
*r++ = c;
|
||||
}
|
||||
|
||||
*r = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Quote special characters in STRING using backslashes. Return a new
|
||||
string. NOTE: if the string is to be further expanded, we need a
|
||||
way to protect the CTLESC and CTLNUL characters. As I write this,
|
||||
the current callers will never cause the string to be expanded without
|
||||
going through the shell parser, which will protect the internal
|
||||
quoting characters. */
|
||||
char *
|
||||
sh_backslash_quote (string, table)
|
||||
char *string;
|
||||
char *table;
|
||||
{
|
||||
int c;
|
||||
char *result, *r, *s, *backslash_table;
|
||||
|
||||
result = (char *)xmalloc (2 * strlen (string) + 1);
|
||||
|
||||
backslash_table = table ? table : bstab;
|
||||
for (r = result, s = string; s && (c = *s); s++)
|
||||
{
|
||||
|
||||
if (backslash_table[c] == 1)
|
||||
*r++ = '\\';
|
||||
else if (c == '#' && s == string) /* comment char */
|
||||
*r++ = '\\';
|
||||
else if (c == '~' && (s == string || s[-1] == ':' || s[-1] == '='))
|
||||
/* Tildes are special at the start of a word or after a `:' or `='
|
||||
(technically unquoted, but it doesn't make a difference in practice) */
|
||||
*r++ = '\\';
|
||||
*r++ = c;
|
||||
}
|
||||
|
||||
*r = '\0';
|
||||
return (result);
|
||||
}
|
||||
|
||||
#if defined (PROMPT_STRING_DECODE)
|
||||
/* Quote characters that get special treatment when in double quotes in STRING
|
||||
using backslashes. Return a new string. */
|
||||
char *
|
||||
sh_backslash_quote_for_double_quotes (string)
|
||||
char *string;
|
||||
{
|
||||
unsigned char c;
|
||||
char *result, *r, *s;
|
||||
|
||||
result = (char *)xmalloc (2 * strlen (string) + 1);
|
||||
|
||||
for (r = result, s = string; s && (c = *s); s++)
|
||||
{
|
||||
if (sh_syntaxtab[c] & CBSDQUOTE)
|
||||
*r++ = '\\';
|
||||
/* I should probably add flags for these to sh_syntaxtab[] */
|
||||
else if (c == CTLESC || c == CTLNUL)
|
||||
*r++ = CTLESC; /* could be '\\'? */
|
||||
|
||||
*r++ = c;
|
||||
}
|
||||
|
||||
*r = '\0';
|
||||
return (result);
|
||||
}
|
||||
#endif /* PROMPT_STRING_DECODE */
|
||||
|
||||
int
|
||||
sh_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 '~': /* tilde expansion */
|
||||
if (s == string || s[-1] == '=' || s[-1] == ':')
|
||||
return (1);
|
||||
break;
|
||||
case '#':
|
||||
if (s == string) /* comment char */
|
||||
return (1);
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
BUILD_DIR=/usr/local/build/chet/bash/bash-current
|
||||
THIS_SH=$BUILD_DIR/bash
|
||||
PATH=$PATH:$BUILD_DIR
|
||||
|
||||
export THIS_SH PATH
|
||||
|
||||
rm -f /tmp/xx
|
||||
|
||||
/bin/sh "$@"
|
||||
@@ -1,50 +0,0 @@
|
||||
:; ./shx
|
||||
|
||||
sh:
|
||||
<&$fd ok
|
||||
nlbq Mon Aug 3 02:45:00 EDT 1992
|
||||
bang geoff
|
||||
quote 712824302
|
||||
setbq defmsgid=<1992Aug3.024502.6176@host>
|
||||
bgwait sleep done... wait 6187
|
||||
|
||||
|
||||
bash:
|
||||
<&$fd ok
|
||||
nlbq Mon Aug 3 02:45:09 EDT 1992
|
||||
bang geoff
|
||||
quote 712824311
|
||||
setbq defmsgid=<1992Aug3.024512.6212@host>
|
||||
bgwait sleep done... wait 6223
|
||||
|
||||
|
||||
ash:
|
||||
<&$fd shx1: 4: Syntax error: Bad fd number
|
||||
nlbq Mon Aug 3 02:45:19 EDT 1992
|
||||
bang geoff
|
||||
quote getdate: `"now"' not a valid date
|
||||
|
||||
setbq defmsgid=<1992Aug3.` echo 024521
|
||||
bgwait sleep done... wait 6241
|
||||
|
||||
|
||||
ksh:
|
||||
<&$fd ok
|
||||
nlbq ./shx: 6248 Memory fault - core dumped
|
||||
bang geoff
|
||||
quote getdate: `"now"' not a valid date
|
||||
|
||||
setbq defmsgid=<1992Aug3.024530.6257@host>
|
||||
bgwait no such job: 6265
|
||||
wait 6265
|
||||
sleep done...
|
||||
|
||||
zsh:
|
||||
<&$fd ok
|
||||
nlbq Mon Aug 3 02:45:36 EDT 1992
|
||||
bang shx3: event not found: /s/ [4]
|
||||
quote 712824337
|
||||
setbq defmsgid=<..6290@host>
|
||||
bgwait shx7: unmatched " [9]
|
||||
sleep done...
|
||||
:;
|
||||
@@ -1,10 +0,0 @@
|
||||
#! /bin/sh
|
||||
for cmd in sh bash ash ksh zsh
|
||||
do
|
||||
echo
|
||||
echo $cmd:
|
||||
for demo in shx?
|
||||
do
|
||||
$cmd $demo
|
||||
done
|
||||
done
|
||||
@@ -1,108 +0,0 @@
|
||||
# basic nameref tests
|
||||
bar=one
|
||||
flow=two
|
||||
flip=three
|
||||
|
||||
foo=bar
|
||||
typeset -n foo
|
||||
|
||||
typeset -n fee=flow
|
||||
|
||||
echo ${foo}
|
||||
echo ${fee}
|
||||
|
||||
typeset -n fee=flip
|
||||
echo ${fee}
|
||||
|
||||
typeset -n
|
||||
|
||||
echo turning off nameref attribute on foo
|
||||
typeset +n foo=other
|
||||
echo ${foo}
|
||||
echo after +n foo bar = $bar
|
||||
|
||||
unset foo bar fee
|
||||
|
||||
bar=one
|
||||
|
||||
foo=bar
|
||||
typeset -n foo
|
||||
|
||||
foo=two printf "%s\n" $foo
|
||||
foo=two eval 'printf "%s\n" $foo'
|
||||
|
||||
foo=two echo $foo
|
||||
|
||||
unset foo bar
|
||||
# other basic assignment tests
|
||||
bar=one
|
||||
|
||||
echo "expect <one>"
|
||||
recho ${bar}
|
||||
typeset -n foo=bar
|
||||
foo=two
|
||||
|
||||
echo "expect <two>"
|
||||
recho ${bar}
|
||||
|
||||
# this appears to be a ksh93 bug; it doesn't unset foo here and messes up
|
||||
# later
|
||||
unset foo bar
|
||||
|
||||
# initial tests of working inside shell functions
|
||||
echoval()
|
||||
{
|
||||
typeset -n ref=$1
|
||||
printf "%s\n" $ref
|
||||
}
|
||||
|
||||
foo=bar
|
||||
bar=one
|
||||
echo "expect <$foo>"
|
||||
echoval foo
|
||||
echo "expect <$bar>"
|
||||
echoval bar
|
||||
|
||||
unset foo bar
|
||||
changevar()
|
||||
{
|
||||
typeset -n v=$1
|
||||
|
||||
shift
|
||||
v="$@"
|
||||
echo "changevar: expect <$@>"
|
||||
recho "$v"
|
||||
}
|
||||
|
||||
bar=one
|
||||
|
||||
echo "expect <one>"
|
||||
recho ${bar}
|
||||
changevar bar two
|
||||
echo "expect <two>"
|
||||
recho $bar
|
||||
|
||||
changevar bar three four five
|
||||
echo "expect <three four five>"
|
||||
recho "$bar"
|
||||
|
||||
unset foo bar
|
||||
readonly foo=one
|
||||
typeset -n bar=foo
|
||||
bar=4
|
||||
foo=4
|
||||
|
||||
echo $foo
|
||||
echo $bar
|
||||
|
||||
assignvar()
|
||||
{
|
||||
typeset -n ref=$1
|
||||
shift
|
||||
ref="$@"
|
||||
}
|
||||
|
||||
readonly foo=one
|
||||
|
||||
assignvar foo two three four
|
||||
echo $foo
|
||||
@@ -1,4 +0,0 @@
|
||||
echo "warning: all of these tests will fail if arrays have not" >&2
|
||||
echo "warning: been compiled into the shell" >&2
|
||||
${THIS_SH} ./assoc.tests > /tmp/xx 2>&1
|
||||
diff /tmp/xx assoc.right && rm -f /tmp/xx
|
||||
@@ -1,69 +0,0 @@
|
||||
# this is needed because posix mode restricts tilde expansion to assignment
|
||||
# statements preceding a command, instead of the default of expanding all
|
||||
# assignment statements on the line (e.g., after `export'). Without this,
|
||||
# the next-to-last test fails
|
||||
set +o posix
|
||||
|
||||
HOME=/usr/xyz
|
||||
SHELL=~/bash
|
||||
echo ~ch\et
|
||||
echo ~/"foo"
|
||||
echo "~chet"/"foo"
|
||||
echo \~chet/"foo"
|
||||
echo \~chet/bar
|
||||
echo ~\chet/bar
|
||||
echo ~chet""/bar
|
||||
echo ":~chet/"
|
||||
echo abcd~chet
|
||||
echo "SHELL=~/bash"
|
||||
echo $SHELL
|
||||
echo abcd:~chet
|
||||
path=/usr/ucb:/bin:~/bin:~/tmp/bin:/usr/bin
|
||||
echo $path
|
||||
|
||||
cd /usr
|
||||
cd /tmp
|
||||
echo ~-
|
||||
echo ~+
|
||||
|
||||
XPATH=/bin:/usr/bin:.
|
||||
|
||||
# yes tilde expansion
|
||||
PPATH=$XPATH:~/bin
|
||||
echo "$PPATH"
|
||||
|
||||
# no tilde expansion
|
||||
PPATH="$XPATH:~/bin"
|
||||
echo "$PPATH"
|
||||
|
||||
# yes tilde expansion
|
||||
export PPATH=$XPATH:~/bin
|
||||
echo "$PPATH"
|
||||
declare -x PPATH=$XPATH:~/bin
|
||||
echo "$PPATH"
|
||||
|
||||
# no tilde expansion
|
||||
export PPATH="$XPATH:~/bin"
|
||||
echo "$PPATH"
|
||||
declare -x PPATH="$XPATH:~/bin"
|
||||
echo "$PPATH"
|
||||
|
||||
# more tests of tilde expansion when executing case commands
|
||||
case ~ in
|
||||
$HOME) echo ok 1;;
|
||||
*) echo bad 1 ;;
|
||||
esac
|
||||
|
||||
case ~ in
|
||||
~) echo ok 2 ;;
|
||||
\~) echo bad 2a ;;
|
||||
*) echo bad 2b ;;
|
||||
esac
|
||||
|
||||
case $unset in
|
||||
"") echo ok 3 ;;
|
||||
*) echo bad 3 ;;
|
||||
esac
|
||||
|
||||
USER=root # should exist just about everywhere
|
||||
echo ~$USER
|
||||
-5138
File diff suppressed because it is too large
Load Diff
-404
@@ -1,404 +0,0 @@
|
||||
/* variables.h -- data structures for shell variables. */
|
||||
|
||||
/* Copyright (C) 1987-2012 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_VARIABLES_H_)
|
||||
#define _VARIABLES_H_
|
||||
|
||||
#include "stdc.h"
|
||||
#include "array.h"
|
||||
#include "assoc.h"
|
||||
|
||||
/* Shell variables and functions are stored in hash tables. */
|
||||
#include "hashlib.h"
|
||||
|
||||
#include "conftypes.h"
|
||||
|
||||
/* A variable context. */
|
||||
typedef struct var_context {
|
||||
char *name; /* empty or NULL means global context */
|
||||
int scope; /* 0 means global context */
|
||||
int flags;
|
||||
struct var_context *up; /* previous function calls */
|
||||
struct var_context *down; /* down towards global context */
|
||||
HASH_TABLE *table; /* variables at this scope */
|
||||
} VAR_CONTEXT;
|
||||
|
||||
/* Flags for var_context->flags */
|
||||
#define VC_HASLOCAL 0x01
|
||||
#define VC_HASTMPVAR 0x02
|
||||
#define VC_FUNCENV 0x04 /* also function if name != NULL */
|
||||
#define VC_BLTNENV 0x08 /* builtin_env */
|
||||
#define VC_TEMPENV 0x10 /* temporary_env */
|
||||
|
||||
#define VC_TEMPFLAGS (VC_FUNCENV|VC_BLTNENV|VC_TEMPENV)
|
||||
|
||||
/* Accessing macros */
|
||||
#define vc_isfuncenv(vc) (((vc)->flags & VC_FUNCENV) != 0)
|
||||
#define vc_isbltnenv(vc) (((vc)->flags & VC_BLTNENV) != 0)
|
||||
#define vc_istempenv(vc) (((vc)->flags & (VC_TEMPFLAGS)) == VC_TEMPENV)
|
||||
|
||||
#define vc_istempscope(vc) (((vc)->flags & (VC_TEMPENV|VC_BLTNENV)) != 0)
|
||||
|
||||
#define vc_haslocals(vc) (((vc)->flags & VC_HASLOCAL) != 0)
|
||||
#define vc_hastmpvars(vc) (((vc)->flags & VC_HASTMPVAR) != 0)
|
||||
|
||||
/* What a shell variable looks like. */
|
||||
|
||||
typedef struct variable *sh_var_value_func_t __P((struct variable *));
|
||||
typedef struct variable *sh_var_assign_func_t __P((struct variable *, char *, arrayind_t, char *));
|
||||
|
||||
/* For the future */
|
||||
union _value {
|
||||
char *s; /* string value */
|
||||
intmax_t i; /* int value */
|
||||
COMMAND *f; /* function */
|
||||
ARRAY *a; /* array */
|
||||
HASH_TABLE *h; /* associative array */
|
||||
double d; /* floating point number */
|
||||
#if defined (HAVE_LONG_DOUBLE)
|
||||
long double ld; /* long double */
|
||||
#endif
|
||||
struct variable *v; /* possible indirect variable use */
|
||||
void *opaque; /* opaque data for future use */
|
||||
};
|
||||
|
||||
typedef struct variable {
|
||||
char *name; /* Symbol that the user types. */
|
||||
char *value; /* Value that is returned. */
|
||||
char *exportstr; /* String for the environment. */
|
||||
sh_var_value_func_t *dynamic_value; /* Function called to return a `dynamic'
|
||||
value for a variable, like $SECONDS
|
||||
or $RANDOM. */
|
||||
sh_var_assign_func_t *assign_func; /* Function called when this `special
|
||||
variable' is assigned a value in
|
||||
bind_variable. */
|
||||
int attributes; /* export, readonly, array, invisible... */
|
||||
int context; /* Which context this variable belongs to. */
|
||||
} SHELL_VAR;
|
||||
|
||||
typedef struct _vlist {
|
||||
SHELL_VAR **list;
|
||||
int list_size; /* allocated size */
|
||||
int list_len; /* current number of entries */
|
||||
} VARLIST;
|
||||
|
||||
/* The various attributes that a given variable can have. */
|
||||
/* First, the user-visible attributes */
|
||||
#define att_exported 0x0000001 /* export to environment */
|
||||
#define att_readonly 0x0000002 /* cannot change */
|
||||
#define att_array 0x0000004 /* value is an array */
|
||||
#define att_function 0x0000008 /* value is a function */
|
||||
#define att_integer 0x0000010 /* internal representation is int */
|
||||
#define att_local 0x0000020 /* variable is local to a function */
|
||||
#define att_assoc 0x0000040 /* variable is an associative array */
|
||||
#define att_trace 0x0000080 /* function is traced with DEBUG trap */
|
||||
#define att_uppercase 0x0000100 /* word converted to uppercase on assignment */
|
||||
#define att_lowercase 0x0000200 /* word converted to lowercase on assignment */
|
||||
#define att_capcase 0x0000400 /* word capitalized on assignment */
|
||||
#define att_nameref 0x0000800 /* word is a name reference */
|
||||
|
||||
#define user_attrs (att_exported|att_readonly|att_integer|att_local|att_trace|att_uppercase|att_lowercase|att_capcase|att_nameref)
|
||||
|
||||
#define attmask_user 0x0000fff
|
||||
|
||||
/* Internal attributes used for bookkeeping */
|
||||
#define att_invisible 0x0001000 /* cannot see */
|
||||
#define att_nounset 0x0002000 /* cannot unset */
|
||||
#define att_noassign 0x0004000 /* assignment not allowed */
|
||||
#define att_imported 0x0008000 /* came from environment */
|
||||
#define att_special 0x0010000 /* requires special handling */
|
||||
#define att_nofree 0x0020000 /* do not free value on unset */
|
||||
|
||||
#define attmask_int 0x00ff000
|
||||
|
||||
/* Internal attributes used for variable scoping. */
|
||||
#define att_tempvar 0x0100000 /* variable came from the temp environment */
|
||||
#define att_propagate 0x0200000 /* propagate to previous scope */
|
||||
|
||||
#define attmask_scope 0x0f00000
|
||||
|
||||
#define exported_p(var) ((((var)->attributes) & (att_exported)))
|
||||
#define readonly_p(var) ((((var)->attributes) & (att_readonly)))
|
||||
#define array_p(var) ((((var)->attributes) & (att_array)))
|
||||
#define function_p(var) ((((var)->attributes) & (att_function)))
|
||||
#define integer_p(var) ((((var)->attributes) & (att_integer)))
|
||||
#define local_p(var) ((((var)->attributes) & (att_local)))
|
||||
#define assoc_p(var) ((((var)->attributes) & (att_assoc)))
|
||||
#define trace_p(var) ((((var)->attributes) & (att_trace)))
|
||||
#define uppercase_p(var) ((((var)->attributes) & (att_uppercase)))
|
||||
#define lowercase_p(var) ((((var)->attributes) & (att_lowercase)))
|
||||
#define capcase_p(var) ((((var)->attributes) & (att_capcase)))
|
||||
#define nameref_p(var) ((((var)->attributes) & (att_nameref)))
|
||||
|
||||
#define invisible_p(var) ((((var)->attributes) & (att_invisible)))
|
||||
#define non_unsettable_p(var) ((((var)->attributes) & (att_nounset)))
|
||||
#define noassign_p(var) ((((var)->attributes) & (att_noassign)))
|
||||
#define imported_p(var) ((((var)->attributes) & (att_imported)))
|
||||
#define specialvar_p(var) ((((var)->attributes) & (att_special)))
|
||||
#define nofree_p(var) ((((var)->attributes) & (att_nofree)))
|
||||
|
||||
#define tempvar_p(var) ((((var)->attributes) & (att_tempvar)))
|
||||
|
||||
/* Acessing variable values: rvalues */
|
||||
#define value_cell(var) ((var)->value)
|
||||
#define function_cell(var) (COMMAND *)((var)->value)
|
||||
#define array_cell(var) (ARRAY *)((var)->value)
|
||||
#define assoc_cell(var) (HASH_TABLE *)((var)->value)
|
||||
#define nameref_cell(var) ((var)->value) /* so it can change later */
|
||||
|
||||
#define NAMEREF_MAX 8 /* only 8 levels of nameref indirection */
|
||||
|
||||
#define var_isnull(var) ((var)->value == 0)
|
||||
#define var_isset(var) ((var)->value != 0)
|
||||
|
||||
/* Assigning variable values: lvalues */
|
||||
#define var_setvalue(var, str) ((var)->value = (str))
|
||||
#define var_setfunc(var, func) ((var)->value = (char *)(func))
|
||||
#define var_setarray(var, arr) ((var)->value = (char *)(arr))
|
||||
#define var_setassoc(var, arr) ((var)->value = (char *)(arr))
|
||||
#define var_setref(var, str) ((var)->value = (str))
|
||||
|
||||
/* Make VAR be auto-exported. */
|
||||
#define set_auto_export(var) \
|
||||
do { (var)->attributes |= att_exported; array_needs_making = 1; } while (0)
|
||||
|
||||
#define SETVARATTR(var, attr, undo) \
|
||||
((undo == 0) ? ((var)->attributes |= (attr)) \
|
||||
: ((var)->attributes &= ~(attr)))
|
||||
|
||||
#define VSETATTR(var, attr) ((var)->attributes |= (attr))
|
||||
#define VUNSETATTR(var, attr) ((var)->attributes &= ~(attr))
|
||||
|
||||
#define VGETFLAGS(var) ((var)->attributes)
|
||||
|
||||
#define VSETFLAGS(var, flags) ((var)->attributes = (flags))
|
||||
#define VCLRFLAGS(var) ((var)->attributes = 0)
|
||||
|
||||
/* Macros to perform various operations on `exportstr' member of a SHELL_VAR. */
|
||||
#define CLEAR_EXPORTSTR(var) (var)->exportstr = (char *)NULL
|
||||
#define COPY_EXPORTSTR(var) ((var)->exportstr) ? savestring ((var)->exportstr) : (char *)NULL
|
||||
#define SET_EXPORTSTR(var, value) (var)->exportstr = (value)
|
||||
#define SAVE_EXPORTSTR(var, value) (var)->exportstr = (value) ? savestring (value) : (char *)NULL
|
||||
|
||||
#define FREE_EXPORTSTR(var) \
|
||||
do { if ((var)->exportstr) free ((var)->exportstr); } while (0)
|
||||
|
||||
#define CACHE_IMPORTSTR(var, value) \
|
||||
(var)->exportstr = savestring (value)
|
||||
|
||||
#define INVALIDATE_EXPORTSTR(var) \
|
||||
do { \
|
||||
if ((var)->exportstr) \
|
||||
{ \
|
||||
free ((var)->exportstr); \
|
||||
(var)->exportstr = (char *)NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Stuff for hacking variables. */
|
||||
typedef int sh_var_map_func_t __P((SHELL_VAR *));
|
||||
|
||||
/* Where we keep the variables and functions */
|
||||
extern VAR_CONTEXT *global_variables;
|
||||
extern VAR_CONTEXT *shell_variables;
|
||||
|
||||
extern HASH_TABLE *shell_functions;
|
||||
extern HASH_TABLE *temporary_env;
|
||||
|
||||
extern int variable_context;
|
||||
extern char *dollar_vars[];
|
||||
extern char **export_env;
|
||||
|
||||
extern void initialize_shell_variables __P((char **, int));
|
||||
extern SHELL_VAR *set_if_not __P((char *, char *));
|
||||
|
||||
extern void sh_set_lines_and_columns __P((int, int));
|
||||
extern void set_pwd __P((void));
|
||||
extern void set_ppid __P((void));
|
||||
extern void make_funcname_visible __P((int));
|
||||
|
||||
extern SHELL_VAR *var_lookup __P((const char *, VAR_CONTEXT *));
|
||||
|
||||
extern SHELL_VAR *find_function __P((const char *));
|
||||
extern FUNCTION_DEF *find_function_def __P((const char *));
|
||||
extern SHELL_VAR *find_variable __P((const char *));
|
||||
extern SHELL_VAR *find_variable_noref __P((const char *));
|
||||
extern SHELL_VAR *find_variable_last_nameref __P((const char *));
|
||||
extern SHELL_VAR *find_variable_nameref __P((SHELL_VAR *));
|
||||
extern SHELL_VAR *find_variable_internal __P((const char *, int));
|
||||
extern SHELL_VAR *find_variable_tempenv __P((const char *));
|
||||
extern SHELL_VAR *find_variable_notempenv __P((const char *));
|
||||
extern SHELL_VAR *find_global_variable __P((const char *));
|
||||
extern SHELL_VAR *find_global_variable_noref __P((const char *));
|
||||
extern SHELL_VAR *find_shell_variable __P((const char *));
|
||||
extern SHELL_VAR *find_tempenv_variable __P((const char *));
|
||||
extern SHELL_VAR *copy_variable __P((SHELL_VAR *));
|
||||
extern SHELL_VAR *make_local_variable __P((const char *));
|
||||
extern SHELL_VAR *bind_variable __P((const char *, char *, int));
|
||||
extern SHELL_VAR *bind_function __P((const char *, COMMAND *));
|
||||
|
||||
extern void bind_function_def __P((const char *, FUNCTION_DEF *));
|
||||
|
||||
extern SHELL_VAR **map_over __P((sh_var_map_func_t *, VAR_CONTEXT *));
|
||||
SHELL_VAR **map_over_funcs __P((sh_var_map_func_t *));
|
||||
|
||||
extern SHELL_VAR **all_shell_variables __P((void));
|
||||
extern SHELL_VAR **all_shell_functions __P((void));
|
||||
extern SHELL_VAR **all_visible_variables __P((void));
|
||||
extern SHELL_VAR **all_visible_functions __P((void));
|
||||
extern SHELL_VAR **all_exported_variables __P((void));
|
||||
extern SHELL_VAR **local_exported_variables __P((void));
|
||||
extern SHELL_VAR **all_local_variables __P((void));
|
||||
#if defined (ARRAY_VARS)
|
||||
extern SHELL_VAR **all_array_variables __P((void));
|
||||
#endif
|
||||
extern char **all_variables_matching_prefix __P((const char *));
|
||||
|
||||
extern char **make_var_array __P((HASH_TABLE *));
|
||||
extern char **add_or_supercede_exported_var __P((char *, int));
|
||||
|
||||
extern char *get_variable_value __P((SHELL_VAR *));
|
||||
extern char *get_string_value __P((const char *));
|
||||
extern char *sh_get_env_value __P((const char *));
|
||||
extern char *make_variable_value __P((SHELL_VAR *, char *, int));
|
||||
|
||||
extern SHELL_VAR *bind_variable_value __P((SHELL_VAR *, char *, int));
|
||||
extern SHELL_VAR *bind_int_variable __P((char *, char *));
|
||||
extern SHELL_VAR *bind_var_to_int __P((char *, intmax_t));
|
||||
|
||||
extern int assign_in_env __P((WORD_DESC *, int));
|
||||
|
||||
extern int unbind_variable __P((const char *));
|
||||
extern int unbind_func __P((const char *));
|
||||
extern int unbind_function_def __P((const char *));
|
||||
extern int makunbound __P((const char *, VAR_CONTEXT *));
|
||||
extern int kill_local_variable __P((const char *));
|
||||
extern void delete_all_variables __P((HASH_TABLE *));
|
||||
extern void delete_all_contexts __P((VAR_CONTEXT *));
|
||||
|
||||
extern VAR_CONTEXT *new_var_context __P((char *, int));
|
||||
extern void dispose_var_context __P((VAR_CONTEXT *));
|
||||
extern VAR_CONTEXT *push_var_context __P((char *, int, HASH_TABLE *));
|
||||
extern void pop_var_context __P((void));
|
||||
extern VAR_CONTEXT *push_scope __P((int, HASH_TABLE *));
|
||||
extern void pop_scope __P((int));
|
||||
|
||||
extern void push_context __P((char *, int, HASH_TABLE *));
|
||||
extern void pop_context __P((void));
|
||||
extern void push_dollar_vars __P((void));
|
||||
extern void pop_dollar_vars __P((void));
|
||||
extern void dispose_saved_dollar_vars __P((void));
|
||||
|
||||
extern void push_args __P((WORD_LIST *));
|
||||
extern void pop_args __P((void));
|
||||
|
||||
extern void adjust_shell_level __P((int));
|
||||
extern void non_unsettable __P((char *));
|
||||
extern void dispose_variable __P((SHELL_VAR *));
|
||||
extern void dispose_used_env_vars __P((void));
|
||||
extern void dispose_function_env __P((void));
|
||||
extern void dispose_builtin_env __P((void));
|
||||
extern void merge_temporary_env __P((void));
|
||||
extern void merge_builtin_env __P((void));
|
||||
extern void kill_all_local_variables __P((void));
|
||||
|
||||
extern void set_var_read_only __P((char *));
|
||||
extern void set_func_read_only __P((const char *));
|
||||
extern void set_var_auto_export __P((char *));
|
||||
extern void set_func_auto_export __P((const char *));
|
||||
|
||||
extern void sort_variables __P((SHELL_VAR **));
|
||||
|
||||
extern int chkexport __P((char *));
|
||||
extern void maybe_make_export_env __P((void));
|
||||
extern void update_export_env_inplace __P((char *, int, char *));
|
||||
extern void put_command_name_into_env __P((char *));
|
||||
extern void put_gnu_argv_flags_into_env __P((intmax_t, char *));
|
||||
|
||||
extern void print_var_list __P((SHELL_VAR **));
|
||||
extern void print_func_list __P((SHELL_VAR **));
|
||||
extern void print_assignment __P((SHELL_VAR *));
|
||||
extern void print_var_value __P((SHELL_VAR *, int));
|
||||
extern void print_var_function __P((SHELL_VAR *));
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
extern SHELL_VAR *make_new_array_variable __P((char *));
|
||||
extern SHELL_VAR *make_local_array_variable __P((char *, int));
|
||||
|
||||
extern SHELL_VAR *make_new_assoc_variable __P((char *));
|
||||
extern SHELL_VAR *make_local_assoc_variable __P((char *));
|
||||
|
||||
extern void set_pipestatus_array __P((int *, int));
|
||||
extern ARRAY *save_pipestatus_array __P((void));
|
||||
extern void restore_pipestatus_array __P((ARRAY *));
|
||||
#endif
|
||||
|
||||
extern void set_pipestatus_from_exit __P((int));
|
||||
|
||||
/* The variable in NAME has just had its state changed. Check to see if it
|
||||
is one of the special ones where something special happens. */
|
||||
extern void stupidly_hack_special_variables __P((char *));
|
||||
|
||||
/* Reinitialize some special variables that have external effects upon unset
|
||||
when the shell reinitializes itself. */
|
||||
extern void reinit_special_variables __P((void));
|
||||
|
||||
extern int get_random_number __P((void));
|
||||
|
||||
/* The `special variable' functions that get called when a particular
|
||||
variable is set. */
|
||||
extern void sv_ifs __P((char *));
|
||||
extern void sv_path __P((char *));
|
||||
extern void sv_mail __P((char *));
|
||||
extern void sv_funcnest __P((char *));
|
||||
extern void sv_globignore __P((char *));
|
||||
extern void sv_ignoreeof __P((char *));
|
||||
extern void sv_strict_posix __P((char *));
|
||||
extern void sv_optind __P((char *));
|
||||
extern void sv_opterr __P((char *));
|
||||
extern void sv_locale __P((char *));
|
||||
extern void sv_xtracefd __P((char *));
|
||||
|
||||
#if defined (READLINE)
|
||||
extern void sv_comp_wordbreaks __P((char *));
|
||||
extern void sv_terminal __P((char *));
|
||||
extern void sv_hostfile __P((char *));
|
||||
extern void sv_winsize __P((char *));
|
||||
#endif
|
||||
|
||||
#if defined (__CYGWIN__)
|
||||
extern void sv_home __P((char *));
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
extern void sv_histsize __P((char *));
|
||||
extern void sv_histignore __P((char *));
|
||||
extern void sv_history_control __P((char *));
|
||||
# if defined (BANG_HISTORY)
|
||||
extern void sv_histchars __P((char *));
|
||||
# endif
|
||||
extern void sv_histtimefmt __P((char *));
|
||||
#endif /* HISTORY */
|
||||
|
||||
#if defined (HAVE_TZSET)
|
||||
extern void sv_tz __P((char *));
|
||||
#endif
|
||||
|
||||
#endif /* !_VARIABLES_H_ */
|
||||
Reference in New Issue
Block a user