mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-29 00:19:51 +02:00
commit bash-20040729 snapshot
This commit is contained in:
@@ -9675,3 +9675,91 @@ general.c
|
||||
|
||||
externs.h
|
||||
- add declaration for zcatfd
|
||||
|
||||
tests/{history,histexp}.tests
|
||||
- unset HISTFILESIZE to avoid problems if a value of 0 is inherited
|
||||
from the environment
|
||||
|
||||
7/30
|
||||
----
|
||||
bashline.c
|
||||
- small changes to glob_expand_word to perform tilde expansion before
|
||||
attempting globbing
|
||||
|
||||
builtins/Makefile.in
|
||||
- fix the install-help target to not cd into the `helpfiles'
|
||||
subdirectory, so a value of $INSTALL_DATA containing a relative
|
||||
pathname (e.g., .././support/install.sh) remains valid
|
||||
|
||||
7/31
|
||||
----
|
||||
subst.c
|
||||
- new function, mbstrlen(s), returns length of a multibyte character
|
||||
string
|
||||
|
||||
include/shmbutil.h
|
||||
- new macro, MB_STRLEN(s), calls mbstrlen or STRLEN as appropriate
|
||||
|
||||
builtins/trap.def
|
||||
- small change so that a first argument that's a valid signal number
|
||||
(digits only -- no symbolic names) will be treated as a signal and
|
||||
reverted back to the original handling disposition. Fixes debian
|
||||
complaints
|
||||
|
||||
subst.c
|
||||
- call MB_STRLEN instead of STRLEN where appropriate in
|
||||
parameter_brace_expand_length to handle multibyte characters properly
|
||||
- call MB_STRLEN instead of strlen in verify_substring_values so that
|
||||
negative substrings of strings with multibyte chars work properly
|
||||
|
||||
8/1
|
||||
---
|
||||
jobs.c
|
||||
- describe_pid needs to write to stderr, not stdout (POSIX)
|
||||
- start_job, since it's only used by builtins (fg/bg), needs to write
|
||||
its output to stdout, not stderr (POSIX)
|
||||
|
||||
sig.c
|
||||
- add an `orig_flags' member to struct terminating_signal so the
|
||||
original signal handling flags (SA_RESTART, etc.) can be preserved
|
||||
on POSIX systems
|
||||
- make sure to preserve the signal flags state in
|
||||
initialize_terminating_signals and reset them for child processes
|
||||
in reset_terminating_signals
|
||||
|
||||
builtins/fc.def
|
||||
- fixed an off-by-one error that caused `fc -l' to list one too many
|
||||
history entries
|
||||
- in posix mode, `fc' should not list any indication as to whether or
|
||||
not history lines have been modified (POSIX)
|
||||
- when in posix mode, the default editor for `fc' should be `ed' (POSIX)
|
||||
|
||||
doc/bashref.texi
|
||||
- updated the description of `trap' behavior when given a first
|
||||
argument that is a valid signal number
|
||||
- noted that `fc -l' won't indicate whether a history entry has been
|
||||
modified if the shell is in posix mode
|
||||
|
||||
builtins/command.def
|
||||
- fixed bug: `command -v' is supposed to be silent if a command is not
|
||||
found
|
||||
|
||||
builtins/hash.def
|
||||
- `hash' should print its `hash table empty' message to stderr
|
||||
|
||||
lib/readline/misc.c
|
||||
- back out 7/7 change to _rl_maybe_save_line; it breaks emacs-mode ^P
|
||||
|
||||
general.c
|
||||
- changed base_pathname so that it will return reasonable results for
|
||||
non-absolute pathnames -- this is what is intended by all of its
|
||||
callers
|
||||
|
||||
arrayfunc.c
|
||||
- fix array_variable_part to return NULL if it finds an invisible
|
||||
variable in the hash table. Fixes seg fault caused by referring to
|
||||
unset local variable using array notation
|
||||
|
||||
{locale,variables}.c
|
||||
- support LC_TIME as a special locale variable so HISTTIMEFORMAT tracks
|
||||
the current locale
|
||||
|
||||
+9765
File diff suppressed because it is too large
Load Diff
@@ -758,7 +758,7 @@ tests/histexp.tests f
|
||||
tests/histexp.right f
|
||||
tests/history.tests f
|
||||
tests/history.right f
|
||||
tests/history.list f
|
||||
tests/history.list f 444
|
||||
tests/ifs.tests f
|
||||
tests/ifs.right f
|
||||
tests/input-line.sh f
|
||||
|
||||
+1
-1
@@ -611,7 +611,7 @@ array_variable_part (s, subp, lenp)
|
||||
var = find_variable (t);
|
||||
|
||||
free (t);
|
||||
return var;
|
||||
return (var == 0 || invisible_p (var)) ? (SHELL_VAR *)0 : var;
|
||||
}
|
||||
|
||||
/* Return a string containing the elements in the array and subscript
|
||||
|
||||
+763
@@ -0,0 +1,763 @@
|
||||
/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
|
||||
|
||||
/* Copyright (C) 2001-2003 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
#include "shmbutil.h"
|
||||
|
||||
#include "builtins/common.h"
|
||||
|
||||
extern char *this_command_name;
|
||||
extern int last_command_exit_value;
|
||||
|
||||
static void quote_array_assignment_chars __P((WORD_LIST *));
|
||||
static char *array_value_internal __P((char *, int, int, int *));
|
||||
|
||||
/* Standard error message to use when encountering an invalid array subscript */
|
||||
char *bash_badsub_errmsg = N_("bad array subscript");
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Functions to manipulate array variables and perform assignments */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Convert a shell variable to an array variable. The original value is
|
||||
saved as array[0]. */
|
||||
SHELL_VAR *
|
||||
convert_var_to_array (var)
|
||||
SHELL_VAR *var;
|
||||
{
|
||||
char *oldval;
|
||||
ARRAY *array;
|
||||
|
||||
oldval = value_cell (var);
|
||||
array = array_create ();
|
||||
if (oldval)
|
||||
array_insert (array, 0, oldval);
|
||||
|
||||
FREE (value_cell (var));
|
||||
var_setarray (var, array);
|
||||
|
||||
/* these aren't valid anymore */
|
||||
var->dynamic_value = (sh_var_value_func_t *)NULL;
|
||||
var->assign_func = (sh_var_assign_func_t *)NULL;
|
||||
|
||||
INVALIDATE_EXPORTSTR (var);
|
||||
|
||||
VSETATTR (var, att_array);
|
||||
VUNSETATTR (var, att_invisible);
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
/* Perform an array assignment name[ind]=value. If NAME already exists and
|
||||
is not an array, and IND is 0, perform name=value instead. If NAME exists
|
||||
and is not an array, and IND is not 0, convert it into an array with the
|
||||
existing value as name[0].
|
||||
|
||||
If NAME does not exist, just create an array variable, no matter what
|
||||
IND's value may be. */
|
||||
SHELL_VAR *
|
||||
bind_array_variable (name, ind, value)
|
||||
char *name;
|
||||
arrayind_t ind;
|
||||
char *value;
|
||||
{
|
||||
SHELL_VAR *entry;
|
||||
char *newval;
|
||||
|
||||
entry = var_lookup (name, shell_variables);
|
||||
|
||||
if (entry == (SHELL_VAR *) 0)
|
||||
entry = make_new_array_variable (name);
|
||||
else if (readonly_p (entry) || noassign_p (entry))
|
||||
{
|
||||
if (readonly_p (entry))
|
||||
err_readonly (name);
|
||||
return (entry);
|
||||
}
|
||||
else if (array_p (entry) == 0)
|
||||
entry = convert_var_to_array (entry);
|
||||
|
||||
/* ENTRY is an array variable, and ARRAY points to the value. */
|
||||
newval = make_variable_value (entry, value);
|
||||
if (entry->assign_func)
|
||||
(*entry->assign_func) (entry, newval, ind);
|
||||
else
|
||||
array_insert (array_cell (entry), ind, newval);
|
||||
FREE (newval);
|
||||
|
||||
return (entry);
|
||||
}
|
||||
|
||||
/* Parse NAME, a lhs of an assignment statement of the form v[s], and
|
||||
assign VALUE to that array element by calling bind_array_variable(). */
|
||||
SHELL_VAR *
|
||||
assign_array_element (name, value)
|
||||
char *name, *value;
|
||||
{
|
||||
char *sub, *vname;
|
||||
arrayind_t ind;
|
||||
int sublen;
|
||||
SHELL_VAR *entry;
|
||||
|
||||
vname = array_variable_name (name, &sub, &sublen);
|
||||
|
||||
if (vname == 0)
|
||||
return ((SHELL_VAR *)NULL);
|
||||
|
||||
if ((ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']') || (sublen <= 1))
|
||||
{
|
||||
free (vname);
|
||||
err_badarraysub (name);
|
||||
return ((SHELL_VAR *)NULL);
|
||||
}
|
||||
|
||||
ind = array_expand_index (sub, sublen);
|
||||
if (ind < 0)
|
||||
{
|
||||
free (vname);
|
||||
err_badarraysub (name);
|
||||
return ((SHELL_VAR *)NULL);
|
||||
}
|
||||
|
||||
entry = bind_array_variable (vname, ind, value);
|
||||
|
||||
free (vname);
|
||||
return (entry);
|
||||
}
|
||||
|
||||
/* Find the array variable corresponding to NAME. If there is no variable,
|
||||
create a new array variable. If the variable exists but is not an array,
|
||||
convert it to an indexed array. If CHECK_FLAGS is non-zero, an existing
|
||||
variable is checked for the readonly or noassign attribute in preparation
|
||||
for assignment (e.g., by the `read' builtin). */
|
||||
SHELL_VAR *
|
||||
find_or_make_array_variable (name, check_flags)
|
||||
char *name;
|
||||
int check_flags;
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = find_variable (name);
|
||||
|
||||
if (var == 0)
|
||||
var = make_new_array_variable (name);
|
||||
else if (check_flags && (readonly_p (var) || noassign_p (var)))
|
||||
{
|
||||
if (readonly_p (var))
|
||||
err_readonly (name);
|
||||
return ((SHELL_VAR *)NULL);
|
||||
}
|
||||
else if (array_p (var) == 0)
|
||||
var = convert_var_to_array (var);
|
||||
|
||||
return (var);
|
||||
}
|
||||
|
||||
/* Perform a compound assignment statement for array NAME, where VALUE is
|
||||
the text between the parens: NAME=( VALUE ) */
|
||||
SHELL_VAR *
|
||||
assign_array_from_string (name, value)
|
||||
char *name, *value;
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = find_or_make_array_variable (name, 1);
|
||||
if (var == 0)
|
||||
return ((SHELL_VAR *)NULL);
|
||||
|
||||
return (assign_array_var_from_string (var, value));
|
||||
}
|
||||
|
||||
/* Sequentially assign the indices of indexed array variable VAR from the
|
||||
words in LIST. */
|
||||
SHELL_VAR *
|
||||
assign_array_var_from_word_list (var, list)
|
||||
SHELL_VAR *var;
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register arrayind_t i;
|
||||
register WORD_LIST *l;
|
||||
ARRAY *a;
|
||||
|
||||
for (a = array_cell (var), l = list, i = 0; l; l = l->next, i++)
|
||||
if (var->assign_func)
|
||||
(*var->assign_func) (var, l->word->word, i);
|
||||
else
|
||||
array_insert (a, i, l->word->word);
|
||||
return var;
|
||||
}
|
||||
|
||||
/* Perform a compound array assignment: VAR->name=( VALUE ). The
|
||||
VALUE has already had the parentheses stripped. */
|
||||
SHELL_VAR *
|
||||
assign_array_var_from_string (var, value)
|
||||
SHELL_VAR *var;
|
||||
char *value;
|
||||
{
|
||||
ARRAY *a;
|
||||
WORD_LIST *list, *nlist;
|
||||
char *w, *val, *nval;
|
||||
int ni, len;
|
||||
arrayind_t ind, last_ind;
|
||||
|
||||
if (value == 0)
|
||||
return var;
|
||||
|
||||
/* If this is called from declare_builtin, value[0] == '(' and
|
||||
xstrchr(value, ')') != 0. In this case, we need to extract
|
||||
the value from between the parens before going on. */
|
||||
if (*value == '(') /*)*/
|
||||
{
|
||||
ni = 1;
|
||||
val = extract_array_assignment_list (value, &ni);
|
||||
if (val == 0)
|
||||
return var;
|
||||
}
|
||||
else
|
||||
val = value;
|
||||
|
||||
/* Expand the value string into a list of words, performing all the
|
||||
shell expansions including pathname generation and word splitting. */
|
||||
/* First we split the string on whitespace, using the shell parser
|
||||
(ksh93 seems to do this). */
|
||||
list = parse_string_to_word_list (val, 1, "array assign");
|
||||
|
||||
/* If we're using [subscript]=value, we need to quote each [ and ] to
|
||||
prevent unwanted filename expansion. */
|
||||
if (list)
|
||||
quote_array_assignment_chars (list);
|
||||
|
||||
/* Now that we've split it, perform the shell expansions on each
|
||||
word in the list. */
|
||||
nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL;
|
||||
|
||||
dispose_words (list);
|
||||
|
||||
if (val != value)
|
||||
free (val);
|
||||
|
||||
a = array_cell (var);
|
||||
|
||||
/* Now that we are ready to assign values to the array, kill the existing
|
||||
value. */
|
||||
if (a)
|
||||
array_flush (a);
|
||||
|
||||
for (last_ind = 0, list = nlist; list; list = list->next)
|
||||
{
|
||||
w = list->word->word;
|
||||
|
||||
/* We have a word of the form [ind]=value */
|
||||
if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
|
||||
{
|
||||
len = skipsubscript (w, 0);
|
||||
|
||||
if (w[len] != ']' || w[len+1] != '=')
|
||||
{
|
||||
nval = make_variable_value (var, w);
|
||||
if (var->assign_func)
|
||||
(*var->assign_func) (var, nval, last_ind);
|
||||
else
|
||||
array_insert (a, last_ind, nval);
|
||||
FREE (nval);
|
||||
last_ind++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len == 1)
|
||||
{
|
||||
err_badarraysub (w);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ALL_ELEMENT_SUB (w[1]) && len == 2)
|
||||
{
|
||||
report_error (_("%s: cannot assign to non-numeric index"), w);
|
||||
continue;
|
||||
}
|
||||
|
||||
ind = array_expand_index (w + 1, len);
|
||||
if (ind < 0)
|
||||
{
|
||||
err_badarraysub (w);
|
||||
continue;
|
||||
}
|
||||
last_ind = ind;
|
||||
val = w + len + 2;
|
||||
}
|
||||
else /* No [ind]=value, just a stray `=' */
|
||||
{
|
||||
ind = last_ind;
|
||||
val = w;
|
||||
}
|
||||
|
||||
if (integer_p (var))
|
||||
this_command_name = (char *)NULL; /* no command name for errors */
|
||||
nval = make_variable_value (var, val);
|
||||
if (var->assign_func)
|
||||
(*var->assign_func) (var, nval, ind);
|
||||
else
|
||||
array_insert (a, ind, nval);
|
||||
FREE (nval);
|
||||
last_ind++;
|
||||
}
|
||||
|
||||
dispose_words (nlist);
|
||||
return (var);
|
||||
}
|
||||
|
||||
/* For each word in a compound array assignment, if the word looks like
|
||||
[ind]=value, quote the `[' and `]' before the `=' to protect them from
|
||||
unwanted filename expansion. */
|
||||
static void
|
||||
quote_array_assignment_chars (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *s, *t, *nword;
|
||||
int saw_eq;
|
||||
WORD_LIST *l;
|
||||
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
|
||||
continue; /* should not happen, but just in case... */
|
||||
/* Don't bother if it doesn't look like [ind]=value */
|
||||
if (l->word->word[0] != '[' || xstrchr (l->word->word, '=') == 0) /* ] */
|
||||
continue;
|
||||
s = nword = (char *)xmalloc (strlen (l->word->word) * 2 + 1);
|
||||
saw_eq = 0;
|
||||
for (t = l->word->word; *t; )
|
||||
{
|
||||
if (*t == '=')
|
||||
saw_eq = 1;
|
||||
if (saw_eq == 0 && (*t == '[' || *t == ']'))
|
||||
*s++ = '\\';
|
||||
*s++ = *t++;
|
||||
}
|
||||
*s = '\0';
|
||||
free (l->word->word);
|
||||
l->word->word = nword;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function assumes s[i] == '['; returns with s[ret] == ']' if
|
||||
an array subscript is correctly parsed. */
|
||||
int
|
||||
skipsubscript (s, i)
|
||||
const char *s;
|
||||
int i;
|
||||
{
|
||||
int count, c;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
mbstate_t state, state_bak;
|
||||
size_t slength, mblength;
|
||||
size_t mb_cur_max;
|
||||
#endif
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
memset (&state, '\0', sizeof (mbstate_t));
|
||||
slength = strlen (s + i);
|
||||
mb_cur_max = MB_CUR_MAX;
|
||||
#endif
|
||||
|
||||
count = 1;
|
||||
while (count)
|
||||
{
|
||||
/* Advance one (possibly multibyte) character in S starting at I. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (mb_cur_max > 1)
|
||||
{
|
||||
state_bak = state;
|
||||
mblength = mbrlen (s + i, slength, &state);
|
||||
|
||||
if (MB_INVALIDCH (mblength))
|
||||
{
|
||||
state = state_bak;
|
||||
i++;
|
||||
slength--;
|
||||
}
|
||||
else if (MB_NULLWCH (mblength))
|
||||
return i;
|
||||
else
|
||||
{
|
||||
i += mblength;
|
||||
slength -= mblength;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
++i;
|
||||
|
||||
c = s[i];
|
||||
|
||||
if (c == 0)
|
||||
break;
|
||||
else if (c == '[')
|
||||
count++;
|
||||
else if (c == ']')
|
||||
count--;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* This function is called with SUB pointing to just after the beginning
|
||||
`[' of an array subscript and removes the array element to which SUB
|
||||
expands from array VAR. A subscript of `*' or `@' unsets the array. */
|
||||
int
|
||||
unbind_array_element (var, sub)
|
||||
SHELL_VAR *var;
|
||||
char *sub;
|
||||
{
|
||||
int len;
|
||||
arrayind_t ind;
|
||||
ARRAY_ELEMENT *ae;
|
||||
|
||||
len = skipsubscript (sub, 0);
|
||||
if (sub[len] != ']' || len == 0)
|
||||
{
|
||||
builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg));
|
||||
return -1;
|
||||
}
|
||||
sub[len] = '\0';
|
||||
|
||||
if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0)
|
||||
{
|
||||
unbind_variable (var->name);
|
||||
return (0);
|
||||
}
|
||||
ind = array_expand_index (sub, len+1);
|
||||
if (ind < 0)
|
||||
{
|
||||
builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
|
||||
return -1;
|
||||
}
|
||||
ae = array_remove (array_cell (var), ind);
|
||||
if (ae)
|
||||
array_dispose_element (ae);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Format and output an array assignment in compound form VAR=(VALUES),
|
||||
suitable for re-use as input. */
|
||||
void
|
||||
print_array_assignment (var, quoted)
|
||||
SHELL_VAR *var;
|
||||
int quoted;
|
||||
{
|
||||
char *vstr;
|
||||
|
||||
vstr = array_to_assign (array_cell (var), quoted);
|
||||
|
||||
if (vstr == 0)
|
||||
printf ("%s=%s\n", var->name, quoted ? "'()'" : "()");
|
||||
else
|
||||
{
|
||||
printf ("%s=%s\n", var->name, vstr);
|
||||
free (vstr);
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
/* */
|
||||
/* Utility functions to manage arrays and their contents for expansion */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
|
||||
/* Return 1 if NAME is a properly-formed array reference v[sub]. */
|
||||
int
|
||||
valid_array_reference (name)
|
||||
char *name;
|
||||
{
|
||||
char *t;
|
||||
int r, len;
|
||||
|
||||
t = xstrchr (name, '['); /* ] */
|
||||
if (t)
|
||||
{
|
||||
*t = '\0';
|
||||
r = legal_identifier (name);
|
||||
*t = '[';
|
||||
if (r == 0)
|
||||
return 0;
|
||||
/* Check for a properly-terminated non-blank subscript. */
|
||||
len = skipsubscript (t, 0);
|
||||
if (t[len] != ']' || len == 1)
|
||||
return 0;
|
||||
for (r = 1; r < len; r++)
|
||||
if (whitespace (t[r]) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Expand the array index beginning at S and extending LEN characters. */
|
||||
arrayind_t
|
||||
array_expand_index (s, len)
|
||||
char *s;
|
||||
int len;
|
||||
{
|
||||
char *exp, *t;
|
||||
int expok;
|
||||
arrayind_t val;
|
||||
|
||||
exp = (char *)xmalloc (len);
|
||||
strncpy (exp, s, len - 1);
|
||||
exp[len - 1] = '\0';
|
||||
t = expand_string_to_string (exp, 0);
|
||||
this_command_name = (char *)NULL;
|
||||
val = evalexp (t, &expok);
|
||||
free (t);
|
||||
free (exp);
|
||||
if (expok == 0)
|
||||
{
|
||||
last_command_exit_value = EXECUTION_FAILURE;
|
||||
jump_to_top_level (DISCARD);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Return the name of the variable specified by S without any subscript.
|
||||
If SUBP is non-null, return a pointer to the start of the subscript
|
||||
in *SUBP. If LENP is non-null, the length of the subscript is returned
|
||||
in *LENP. This returns newly-allocated memory. */
|
||||
char *
|
||||
array_variable_name (s, subp, lenp)
|
||||
char *s, **subp;
|
||||
int *lenp;
|
||||
{
|
||||
char *t, *ret;
|
||||
int ind, ni;
|
||||
|
||||
t = xstrchr (s, '[');
|
||||
if (t == 0)
|
||||
{
|
||||
if (subp)
|
||||
*subp = t;
|
||||
if (lenp)
|
||||
*lenp = 0;
|
||||
return ((char *)NULL);
|
||||
}
|
||||
ind = t - s;
|
||||
ni = skipsubscript (s, ind);
|
||||
if (ni <= ind + 1 || s[ni] != ']')
|
||||
{
|
||||
err_badarraysub (s);
|
||||
if (subp)
|
||||
*subp = t;
|
||||
if (lenp)
|
||||
*lenp = 0;
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
*t = '\0';
|
||||
ret = savestring (s);
|
||||
*t++ = '['; /* ] */
|
||||
|
||||
if (subp)
|
||||
*subp = t;
|
||||
if (lenp)
|
||||
*lenp = ni - ind;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return the variable specified by S without any subscript. If SUBP is
|
||||
non-null, return a pointer to the start of the subscript in *SUBP.
|
||||
If LENP is non-null, the length of the subscript is returned in *LENP. */
|
||||
SHELL_VAR *
|
||||
array_variable_part (s, subp, lenp)
|
||||
char *s, **subp;
|
||||
int *lenp;
|
||||
{
|
||||
char *t;
|
||||
SHELL_VAR *var;
|
||||
|
||||
t = array_variable_name (s, subp, lenp);
|
||||
if (t == 0)
|
||||
return ((SHELL_VAR *)NULL);
|
||||
var = find_variable (t);
|
||||
|
||||
free (t);
|
||||
return var;
|
||||
}
|
||||
|
||||
/* Return a string containing the elements in the array and subscript
|
||||
described by S. If the subscript is * or @, obeys quoting rules akin
|
||||
to the expansion of $* and $@ including double quoting. If RTYPE
|
||||
is non-null it gets 1 if the array reference is name[@] or name[*]
|
||||
and 0 otherwise. */
|
||||
static char *
|
||||
array_value_internal (s, quoted, allow_all, rtype)
|
||||
char *s;
|
||||
int quoted, allow_all, *rtype;
|
||||
{
|
||||
int len;
|
||||
arrayind_t ind;
|
||||
char *retval, *t, *temp;
|
||||
WORD_LIST *l;
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = array_variable_part (s, &t, &len);
|
||||
|
||||
/* Expand the index, even if the variable doesn't exist, in case side
|
||||
effects are needed, like ${w[i++]} where w is unset. */
|
||||
#if 0
|
||||
if (var == 0)
|
||||
return (char *)NULL;
|
||||
#endif
|
||||
|
||||
if (len == 0)
|
||||
return ((char *)NULL); /* error message already printed */
|
||||
|
||||
/* [ */
|
||||
if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
|
||||
{
|
||||
if (rtype)
|
||||
*rtype = 1;
|
||||
if (allow_all == 0)
|
||||
{
|
||||
err_badarraysub (s);
|
||||
return ((char *)NULL);
|
||||
}
|
||||
else if (var == 0)
|
||||
return ((char *)NULL);
|
||||
else if (array_p (var) == 0)
|
||||
l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
|
||||
else
|
||||
{
|
||||
l = array_to_word_list (array_cell (var));
|
||||
if (l == (WORD_LIST *)NULL)
|
||||
return ((char *) NULL);
|
||||
}
|
||||
|
||||
if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
|
||||
{
|
||||
temp = string_list_dollar_star (l);
|
||||
retval = quote_string (temp);
|
||||
free (temp);
|
||||
}
|
||||
else /* ${name[@]} or unquoted ${name[*]} */
|
||||
retval = string_list_dollar_at (l, quoted);
|
||||
|
||||
dispose_words (l);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rtype)
|
||||
*rtype = 0;
|
||||
ind = array_expand_index (t, len);
|
||||
if (ind < 0)
|
||||
{
|
||||
if (var)
|
||||
err_badarraysub (var->name);
|
||||
else
|
||||
{
|
||||
t[-1] = '\0';
|
||||
err_badarraysub (s);
|
||||
t[-1] = '['; /* ] */
|
||||
}
|
||||
return ((char *)NULL);
|
||||
}
|
||||
if (var == 0)
|
||||
return ((char *)NULL);
|
||||
if (array_p (var) == 0)
|
||||
return (ind == 0 ? value_cell (var) : (char *)NULL);
|
||||
retval = array_reference (array_cell (var), ind);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Return a string containing the elements described by the array and
|
||||
subscript contained in S, obeying quoting for subscripts * and @. */
|
||||
char *
|
||||
array_value (s, quoted, rtype)
|
||||
char *s;
|
||||
int quoted, *rtype;
|
||||
{
|
||||
return (array_value_internal (s, quoted, 1, rtype));
|
||||
}
|
||||
|
||||
/* Return the value of the array indexing expression S as a single string.
|
||||
If ALLOW_ALL is 0, do not allow `@' and `*' subscripts. This is used
|
||||
by other parts of the shell such as the arithmetic expression evaluator
|
||||
in expr.c. */
|
||||
char *
|
||||
get_array_value (s, allow_all, rtype)
|
||||
char *s;
|
||||
int allow_all, *rtype;
|
||||
{
|
||||
return (array_value_internal (s, 0, allow_all, rtype));
|
||||
}
|
||||
|
||||
char *
|
||||
array_keys (s, quoted)
|
||||
char *s;
|
||||
int quoted;
|
||||
{
|
||||
int len;
|
||||
char *retval, *t, *temp;
|
||||
WORD_LIST *l;
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = array_variable_part (s, &t, &len);
|
||||
|
||||
/* [ */
|
||||
if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']')
|
||||
return (char *)NULL;
|
||||
|
||||
if (array_p (var) == 0)
|
||||
l = add_string_to_list ("0", (WORD_LIST *)NULL);
|
||||
else
|
||||
{
|
||||
l = array_keys_to_word_list (array_cell (var));
|
||||
if (l == (WORD_LIST *)NULL)
|
||||
return ((char *) NULL);
|
||||
}
|
||||
|
||||
if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
|
||||
{
|
||||
temp = string_list_dollar_star (l);
|
||||
retval = quote_string (temp);
|
||||
free (temp);
|
||||
}
|
||||
else /* ${!name[@]} or unquoted ${!name[*]} */
|
||||
retval = string_list_dollar_at (l, quoted);
|
||||
|
||||
dispose_words (l);
|
||||
return retval;
|
||||
}
|
||||
#endif /* ARRAY_VARS */
|
||||
+10
-5
@@ -2513,7 +2513,7 @@ glob_complete_word (text, state)
|
||||
static char **matches = (char **)NULL;
|
||||
static int ind;
|
||||
int glen;
|
||||
char *ret;
|
||||
char *ret, *ttext;
|
||||
|
||||
if (state == 0)
|
||||
{
|
||||
@@ -2523,17 +2523,22 @@ glob_complete_word (text, state)
|
||||
FREE (globorig);
|
||||
FREE (globtext);
|
||||
|
||||
ttext = bash_tilde_expand (text, 0);
|
||||
|
||||
if (rl_explicit_arg)
|
||||
{
|
||||
globorig = savestring (text);
|
||||
glen = strlen (text);
|
||||
globorig = savestring (ttext);
|
||||
glen = strlen (ttext);
|
||||
globtext = (char *)xmalloc (glen + 2);
|
||||
strcpy (globtext, text);
|
||||
strcpy (globtext, ttext);
|
||||
globtext[glen] = '*';
|
||||
globtext[glen+1] = '\0';
|
||||
}
|
||||
else
|
||||
globtext = globorig = savestring (text);
|
||||
globtext = globorig = savestring (ttext);
|
||||
|
||||
if (ttext != text)
|
||||
free (ttext);
|
||||
|
||||
matches = shell_glob_filename (globtext);
|
||||
if (GLOB_FAILED (matches))
|
||||
|
||||
+3053
File diff suppressed because it is too large
Load Diff
@@ -178,8 +178,7 @@ helpdoc: $(MKBUILTINS) $(DEFSRC)
|
||||
install-help:
|
||||
@-if test -n "${HELPDIR}" && test -d helpfiles ; then \
|
||||
test -d ${HELPDIR} || ${SHELL} ${MKDIRS} $(DESTDIR)$(HELPDIR) ;\
|
||||
( cd helpfiles ; \
|
||||
for f in *; do \
|
||||
( for f in helpfiles/*; do \
|
||||
echo installing $$f; \
|
||||
${INSTALL_DATA} $$f $(DESTDIR)$(HELPDIR); \
|
||||
done; ) ; \
|
||||
|
||||
@@ -0,0 +1,621 @@
|
||||
# This Makefile for building libbuiltins.a is in -*- text -*- for Emacs.
|
||||
#
|
||||
# Copyright (C) 1996-2003 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.
|
||||
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
#
|
||||
SHELL = @MAKE_SHELL@
|
||||
RANLIB = @RANLIB@
|
||||
CC = @CC@
|
||||
CC_FOR_BUILD = @CC_FOR_BUILD@
|
||||
AR = @AR@
|
||||
ARFLAGS = @ARFLAGS@
|
||||
RM = rm -f
|
||||
CP = cp
|
||||
|
||||
EXEEXT = @EXEEXT@
|
||||
|
||||
prefix = @prefix@
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = .:@srcdir@
|
||||
topdir = @top_srcdir@
|
||||
includedir = @includedir@
|
||||
datadir = @datadir@
|
||||
localedir = $(datadir)/locale
|
||||
|
||||
# Support an alternate destination root directory for package building
|
||||
DESTDIR =
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
BUILD_DIR = @BUILD_DIR@
|
||||
|
||||
LIBBUILD = ${BUILD_DIR}/lib
|
||||
|
||||
PROFILE_FLAGS = @PROFILE_FLAGS@
|
||||
CFLAGS = @CFLAGS@
|
||||
CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
|
||||
LOCAL_CFLAGS = @LOCAL_CFLAGS@ ${DEBUG}
|
||||
DEFS = @DEFS@
|
||||
LOCAL_DEFS = @LOCAL_DEFS@
|
||||
|
||||
LIBS = @LIBS@
|
||||
LDFLAGS = @LDFLAGS@ $(LOCAL_LDFLAGS) $(CFLAGS)
|
||||
LDFLAGS_FOR_BUILD = $(LDFLAGS)
|
||||
LOCAL_LDFLAGS = @LOCAL_LDFLAGS@
|
||||
#LIBS_FOR_BUILD = @LIBS_FOR_BUILD@
|
||||
LIBS_FOR_BUILD = $(LIBS)
|
||||
|
||||
BASHINCDIR = ${topdir}/include
|
||||
|
||||
RL_INCLUDEDIR = @RL_INCLUDEDIR@
|
||||
|
||||
INTL_LIBSRC = ${topdir}/lib/intl
|
||||
INTL_BUILDDIR = ${LIBBUILD}/intl
|
||||
INTL_INC = @INTL_INC@
|
||||
LIBINTL_H = @LIBINTL_H@
|
||||
|
||||
HELPDIR = @HELPDIR@
|
||||
MKDIRS = ${topdir}/support/mkdirs
|
||||
|
||||
INCLUDES = -I. -I.. @RL_INCLUDE@ -I$(topdir) -I$(BASHINCDIR) -I$(topdir)/lib -I$(srcdir) ${INTL_INC}
|
||||
|
||||
BASE_CCFLAGS = ${PROFILE_FLAGS} $(DEFS) $(LOCAL_DEFS) $(SYSTEM_FLAGS) \
|
||||
${INCLUDES} $(LOCAL_CFLAGS)
|
||||
|
||||
CCFLAGS = $(BASE_CCFLAGS) $(CPPFLAGS) $(CFLAGS)
|
||||
|
||||
CCFLAGS_FOR_BUILD = $(BASE_CCFLAGS) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD)
|
||||
|
||||
GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual \
|
||||
-Wcast-align -Wstrict-prototypes -Wconversion \
|
||||
-Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic
|
||||
|
||||
MKBUILTINS = mkbuiltins$(EXEEXT)
|
||||
DIRECTDEFINE = -D $(srcdir)
|
||||
HELPDIRDEFINE = @HELPDIRDEFINE@
|
||||
|
||||
# xxx this is bad style
|
||||
RL_LIBSRC = $(topdir)/lib/readline
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .def .c .o
|
||||
# How to make a .o file from a .def file.
|
||||
.def.o:
|
||||
$(RM) $@
|
||||
./$(MKBUILTINS) $(DIRECTDEFINE) $<
|
||||
$(CC) -c $(CCFLAGS) $*.c || ( $(RM) $*.c ; exit 1 )
|
||||
$(RM) $*.c
|
||||
|
||||
# How to make a .c file from a .def file.
|
||||
.def.c:
|
||||
$(RM) $@
|
||||
./$(MKBUILTINS) $(DIRECTDEFINE) $<
|
||||
|
||||
# default rule for making a .o file from a .c file
|
||||
.c.o:
|
||||
$(RM) $@
|
||||
$(CC) -c $(CCFLAGS) $<
|
||||
|
||||
DEFSRC = $(srcdir)/alias.def $(srcdir)/bind.def $(srcdir)/break.def \
|
||||
$(srcdir)/builtin.def $(srcdir)/caller.def \
|
||||
$(srcdir)/cd.def $(srcdir)/colon.def \
|
||||
$(srcdir)/command.def $(srcdir)/declare.def $(srcdir)/echo.def \
|
||||
$(srcdir)/enable.def $(srcdir)/eval.def $(srcdir)/getopts.def \
|
||||
$(srcdir)/exec.def $(srcdir)/exit.def $(srcdir)/fc.def \
|
||||
$(srcdir)/fg_bg.def $(srcdir)/hash.def $(srcdir)/help.def \
|
||||
$(srcdir)/history.def $(srcdir)/jobs.def $(srcdir)/kill.def \
|
||||
$(srcdir)/let.def $(srcdir)/read.def $(srcdir)/return.def \
|
||||
$(srcdir)/set.def $(srcdir)/setattr.def $(srcdir)/shift.def \
|
||||
$(srcdir)/source.def $(srcdir)/suspend.def $(srcdir)/test.def \
|
||||
$(srcdir)/times.def $(srcdir)/trap.def $(srcdir)/type.def \
|
||||
$(srcdir)/ulimit.def $(srcdir)/umask.def $(srcdir)/wait.def \
|
||||
$(srcdir)/reserved.def $(srcdir)/pushd.def $(srcdir)/shopt.def \
|
||||
$(srcdir)/printf.def $(srcdir)/complete.def
|
||||
|
||||
STATIC_SOURCE = common.c evalstring.c evalfile.c getopt.c bashgetopt.c \
|
||||
getopt.h
|
||||
|
||||
OFILES = builtins.o \
|
||||
alias.o bind.o break.o builtin.o caller.o cd.o colon.o command.o \
|
||||
common.o declare.o echo.o enable.o eval.o evalfile.o \
|
||||
evalstring.o exec.o \
|
||||
exit.o fc.o fg_bg.o hash.o help.o history.o jobs.o kill.o let.o \
|
||||
pushd.o read.o return.o set.o setattr.o shift.o source.o \
|
||||
suspend.o test.o times.o trap.o type.o ulimit.o umask.o \
|
||||
wait.o getopts.o shopt.o printf.o getopt.o bashgetopt.o complete.o
|
||||
|
||||
CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h
|
||||
|
||||
all: $(MKBUILTINS) libbuiltins.a
|
||||
|
||||
libbuiltins.a: $(MKBUILTINS) $(OFILES) builtins.o
|
||||
$(RM) $@
|
||||
$(AR) $(ARFLAGS) $@ $(OFILES)
|
||||
-$(RANLIB) $@
|
||||
|
||||
builtext.h builtins.c: $(MKBUILTINS) $(DEFSRC)
|
||||
@-if test -f builtins.c; then mv -f builtins.c old-builtins.c; fi
|
||||
@-if test -f builtext.h; then mv -f builtext.h old-builtext.h; fi
|
||||
./$(MKBUILTINS) -externfile builtext.h -structfile builtins.c \
|
||||
-noproduction $(DIRECTDEFINE) $(HELPDIRDEFINE) $(DEFSRC)
|
||||
@-if cmp -s old-builtext.h builtext.h 2>/dev/null; then \
|
||||
mv old-builtext.h builtext.h; \
|
||||
else \
|
||||
$(RM) old-builtext.h; \
|
||||
fi
|
||||
@-if cmp -s old-builtins.c builtins.c 2>/dev/null; then \
|
||||
mv old-builtins.c builtins.c; \
|
||||
else \
|
||||
$(RM) old-builtins.c; \
|
||||
fi
|
||||
|
||||
helpdoc: $(MKBUILTINS) $(DEFSRC)
|
||||
./$(MKBUILTINS) ${HELPDIRDEFINE} -noproduction $(DIRECTDEFINE) $(DEFSRC)
|
||||
|
||||
install-help:
|
||||
@-if test -n "${HELPDIR}" && test -d helpfiles ; then \
|
||||
test -d ${HELPDIR} || ${SHELL} ${MKDIRS} $(DESTDIR)$(HELPDIR) ;\
|
||||
( cd helpfiles ; \
|
||||
for f in *; do \
|
||||
echo installing $$f; \
|
||||
${INSTALL_DATA} $$f $(DESTDIR)$(HELPDIR); \
|
||||
done; ) ; \
|
||||
fi
|
||||
|
||||
install: @HELPINSTALL@
|
||||
|
||||
mkbuiltins.o: ../config.h
|
||||
mkbuiltins.o: mkbuiltins.c
|
||||
$(RM) $@
|
||||
$(CC_FOR_BUILD) -c $(CCFLAGS_FOR_BUILD) $<
|
||||
|
||||
mkbuiltins$(EXEEXT): mkbuiltins.o
|
||||
$(CC_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $(MKBUILTINS) mkbuiltins.o $(LIBS_FOR_BUILD)
|
||||
|
||||
# rules for deficient makes, like SunOS
|
||||
mkbuiltins.o: mkbuiltins.c
|
||||
builtins.o: builtins.c
|
||||
common.o: common.c
|
||||
bashgetopt.o: bashgetopt.c
|
||||
getopt.o: getopt.c
|
||||
evalstring.o: evalstring.c
|
||||
evalfile.o: evalfile.c
|
||||
|
||||
ulimit.o: pipesize.h
|
||||
|
||||
pipesize.h: psize.aux
|
||||
$(SHELL) $(srcdir)/psize.sh > $@
|
||||
|
||||
psize.aux: psize.c
|
||||
$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(srcdir)/psize.c
|
||||
|
||||
documentation: builtins.texi
|
||||
|
||||
builtins.texi: $(MKBUILTINS)
|
||||
./$(MKBUILTINS) -documentonly $(DEFSRC)
|
||||
|
||||
clean:
|
||||
$(RM) $(OFILES) $(CREATED_FILES) $(MKBUILTINS) mkbuiltins.o libbuiltins.a
|
||||
-test -d helpfiles && $(RM) -r helpfiles
|
||||
|
||||
mostlyclean:
|
||||
$(RM) $(OFILES) libbuiltins.a
|
||||
|
||||
distclean maintainer-clean: clean
|
||||
$(RM) Makefile
|
||||
|
||||
$(OFILES): $(MKBUILTINS) ../config.h
|
||||
|
||||
../version.h: ../config.h ../Makefile Makefile
|
||||
-( cd ${BUILD_DIR} && ${MAKE} ${MFLAGS} version.h )
|
||||
|
||||
# maintainer special - for now
|
||||
po: builtins.c
|
||||
xgettext -L C -o $(topdir)/po/builtins.pot --keyword='N_' builtins.c 2>/dev/null
|
||||
|
||||
# dependencies
|
||||
|
||||
alias.o: alias.def
|
||||
bind.o: bind.def
|
||||
break.o: break.def
|
||||
builtin.o: builtin.def
|
||||
caller.o: caller.def
|
||||
cd.o: cd.def
|
||||
colon.o: colon.def
|
||||
command.o: command.def
|
||||
declare.o: declare.def
|
||||
echo.o: echo.def
|
||||
enable.o: enable.def
|
||||
eval.o: eval.def
|
||||
exec.o: exec.def
|
||||
exit.o: exit.def
|
||||
fc.o: fc.def
|
||||
fg_bg.o: fg_bg.def
|
||||
hash.o: hash.def
|
||||
help.o: help.def
|
||||
history.o: history.def
|
||||
jobs.o: jobs.def
|
||||
kill.o: kill.def
|
||||
let.o: let.def
|
||||
printf.o: printf.def
|
||||
pushd.o: pushd.def
|
||||
read.o: read.def
|
||||
return.o: return.def
|
||||
set.o: set.def
|
||||
setattr.o: setattr.def
|
||||
shift.o: shift.def
|
||||
shopt.o: shopt.def
|
||||
source.o: source.def
|
||||
suspend.o: suspend.def
|
||||
test.o: test.def
|
||||
times.o: times.def
|
||||
trap.o: trap.def
|
||||
type.o: type.def
|
||||
ulimit.o: ulimit.def
|
||||
umask.o: umask.def
|
||||
wait.o: wait.def
|
||||
getopts.o: getopts.def
|
||||
reserved.o: reserved.def
|
||||
complete.o: complete.def
|
||||
|
||||
# C files
|
||||
bashgetopt.o: ../config.h $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h
|
||||
bashgetopt.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/bashjmp.h
|
||||
bashgetopt.o: $(topdir)/command.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/error.h
|
||||
bashgetopt.o: $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/quit.h $(BASHINCDIR)/maxpath.h
|
||||
bashgetopt.o: $(topdir)/unwind_prot.h $(topdir)/dispose_cmd.h
|
||||
bashgetopt.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/sig.h
|
||||
bashgetopt.o: ../pathnames.h $(topdir)/externs.h $(srcdir)/common.h
|
||||
bashgetopt.o: $(BASHINCDIR)/chartypes.h
|
||||
common.o: $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h
|
||||
common.o: $(topdir)/shell.h $(topdir)/syntax.h ../config.h $(topdir)/bashjmp.h $(BASHINCDIR)/posixjmp.h
|
||||
common.o: $(topdir)/sig.h $(topdir)/command.h
|
||||
common.o: $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/stdc.h $(BASHINCDIR)/memalloc.h
|
||||
common.o: $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/input.h
|
||||
common.o: $(topdir)/siglist.h $(topdir)/bashhist.h $(topdir)/quit.h
|
||||
common.o: $(topdir)/unwind_prot.h $(BASHINCDIR)/maxpath.h $(topdir)/jobs.h
|
||||
common.o: $(topdir)/builtins.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
common.o: $(topdir)/subst.h $(topdir)/execute_cmd.h $(topdir)/error.h
|
||||
common.o: $(topdir)/externs.h ../pathnames.h ./builtext.h
|
||||
common.o: $(BASHINCDIR)/chartypes.h
|
||||
evalfile.o: $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h ${BASHINCDIR}/filecntl.h
|
||||
evalfile.o: $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h
|
||||
evalfile.o: $(topdir)/shell.h $(topdir)/syntax.h ../config.h $(topdir)/bashjmp.h
|
||||
evalfile.o: $(topdir)/command.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/error.h
|
||||
evalfile.o: $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/quit.h $(BASHINCDIR)/maxpath.h
|
||||
evalfile.o: $(topdir)/unwind_prot.h $(topdir)/dispose_cmd.h
|
||||
evalfile.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/sig.h
|
||||
evalfile.o: ../pathnames.h $(topdir)/externs.h
|
||||
evalfile.o: $(topdir)/jobs.h $(topdir)/builtins.h $(topdir)/flags.h
|
||||
evalfile.o: $(topdir)/input.h $(topdir)/execute_cmd.h
|
||||
evalfile.o: $(topdir)/bashhist.h $(srcdir)/common.h
|
||||
evalstring.o: ../config.h $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h
|
||||
evalstring.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/bashjmp.h $(BASHINCDIR)/posixjmp.h
|
||||
evalstring.o: $(topdir)/sig.h $(topdir)/command.h $(topdir)/siglist.h
|
||||
evalstring.o: $(BASHINCDIR)/memalloc.h $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/input.h
|
||||
evalstring.o: $(topdir)/quit.h $(topdir)/unwind_prot.h
|
||||
evalstring.o: $(BASHINCDIR)/maxpath.h $(topdir)/jobs.h $(topdir)/builtins.h
|
||||
evalstring.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
|
||||
evalstring.o: $(topdir)/externs.h $(topdir)/jobs.h $(topdir)/builtins.h
|
||||
evalstring.o: $(topdir)/flags.h $(topdir)/input.h $(topdir)/execute_cmd.h
|
||||
evalstring.o: $(topdir)/bashhist.h $(srcdir)/common.h
|
||||
evalstring.o: $(topdir)/trap.h $(topdir)/redir.h
|
||||
getopt.o: ../config.h $(BASHINCDIR)/memalloc.h
|
||||
getopt.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/bashjmp.h $(topdir)/command.h
|
||||
getopt.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/error.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
getopt.o: $(topdir)/quit.h $(BASHINCDIR)/maxpath.h $(topdir)/unwind_prot.h
|
||||
getopt.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
|
||||
getopt.o: $(topdir)/sig.h ../pathnames.h $(topdir)/externs.h
|
||||
getopt.o: $(srcdir)/getopt.h
|
||||
mkbuiltins.o: ../config.h $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h
|
||||
mkbuiltins.o: ${BASHINCDIR}/filecntl.h
|
||||
mkbuiltins.o: $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h
|
||||
|
||||
# def files
|
||||
alias.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
alias.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/maxpath.h
|
||||
alias.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
alias.o: $(topdir)/subst.h $(topdir)/externs.h $(srcdir)/common.h
|
||||
alias.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
bind.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
|
||||
bind.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
bind.o: $(topdir)/subst.h $(topdir)/externs.h $(srcdir)/bashgetopt.h
|
||||
bind.o: $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/maxpath.h $(topdir)/bashline.h
|
||||
bind.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
break.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
break.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
break.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
break.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
break.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
builtin.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
builtin.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/externs.h
|
||||
builtin.o: $(topdir)/quit.h $(srcdir)/common.h $(BASHINCDIR)/maxpath.h
|
||||
builtin.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
|
||||
builtin.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
builtin.o: $(srcdir)/bashgetopt.h
|
||||
caller.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
|
||||
caller.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/quit.h $(topdir)/dispose_cmd.h
|
||||
caller.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/externs.h
|
||||
caller.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
caller.o: $(srcdir)/common.h $(BASHINCDIR)/maxpath.h ./builtext.h
|
||||
caller.o: ${BASHINCDIR}/chartypes.h $(topdir)/bashtypes.h
|
||||
cd.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
|
||||
cd.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/quit.h $(topdir)/dispose_cmd.h
|
||||
cd.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/externs.h
|
||||
cd.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
cd.o: $(srcdir)/common.h $(BASHINCDIR)/maxpath.h
|
||||
command.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
command.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/externs.h
|
||||
command.o: $(topdir)/quit.h $(srcdir)/bashgetopt.h $(BASHINCDIR)/maxpath.h
|
||||
command.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
|
||||
command.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
declare.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
declare.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
declare.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
declare.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
declare.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
declare.o: $(topdir)/arrayfunc.h $(srcdir)/bashgetopt.h
|
||||
declare.o: ./builtext.h
|
||||
echo.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
|
||||
echo.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/externs.h
|
||||
echo.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
echo.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
echo.o: $(BASHINCDIR)/maxpath.h
|
||||
enable.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
enable.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
enable.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
enable.o: $(topdir)/subst.h $(topdir)/externs.h
|
||||
enable.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
enable.o: $(BASHINCDIR)/maxpath.h
|
||||
enable.o: $(topdir)/pcomplete.h
|
||||
eval.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
eval.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
eval.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
eval.o: $(topdir)/subst.h $(topdir)/externs.h
|
||||
eval.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
eval.o: $(BASHINCDIR)/maxpath.h
|
||||
exec.o: $(topdir)/bashtypes.h
|
||||
exec.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
exec.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
exec.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
exec.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/flags.h
|
||||
exec.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
exec.o: $(srcdir)/common.h $(topdir)/execute_cmd.h $(BASHINCDIR)/maxpath.h
|
||||
exec.o: $(topdir)/findcmd.h
|
||||
exit.o: $(topdir)/bashtypes.h
|
||||
exit.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
exit.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
exit.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
exit.o: $(topdir)/subst.h $(topdir)/externs.h
|
||||
exit.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
exit.o: $(BASHINCDIR)/maxpath.h ./builtext.h
|
||||
fc.o: $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h
|
||||
fc.o: $(topdir)/builtins.h $(topdir)/command.h $(srcdir)/bashgetopt.h
|
||||
fc.o: $(topdir)/bashhist.h
|
||||
fc.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
|
||||
fc.o: $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/maxpath.h
|
||||
fc.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
fc.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/shell.h $(topdir)/syntax.h
|
||||
fc.o: $(topdir)/flags.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
fc.o: $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h $(BASHINCDIR)/chartypes.h
|
||||
fg_bg.o: $(topdir)/bashtypes.h $(srcdir)/bashgetopt.h
|
||||
fg_bg.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
fg_bg.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
fg_bg.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
fg_bg.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
fg_bg.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
getopts.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
getopts.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
getopts.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
getopts.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
getopts.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
hash.o: $(topdir)/builtins.h $(topdir)/command.h $(topdir)/quit.h
|
||||
hash.o: $(topdir)/findcmd.h $(topdir)/hashlib.h
|
||||
hash.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
hash.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
hash.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
hash.o: $(srcdir)/common.h $(BASHINCDIR)/maxpath.h
|
||||
help.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
help.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
help.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
help.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
help.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
help.o: ${srcdir}/common.h
|
||||
history.o: $(topdir)/bashtypes.h
|
||||
history.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
history.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
history.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
history.o: $(topdir)/subst.h $(topdir)/externs.h
|
||||
history.o: ${BASHINCDIR}/filecntl.h $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h
|
||||
history.o: $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/bashhist.h $(BASHINCDIR)/maxpath.h
|
||||
inlib.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
inlib.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
inlib.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
inlib.o: $(BASHINCDIR)/maxpath.h $(topdir)/subst.h $(topdir)/externs.h
|
||||
inlib.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
jobs.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
|
||||
jobs.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/quit.h $(srcdir)/bashgetopt.h
|
||||
jobs.o: $(BASHINCDIR)/maxpath.h $(topdir)/externs.h
|
||||
jobs.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
|
||||
jobs.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
kill.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
|
||||
kill.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/externs.h
|
||||
kill.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
kill.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/trap.h $(topdir)/unwind_prot.h
|
||||
kill.o: $(topdir)/variables.h $(topdir)/conftypes.h $(BASHINCDIR)/maxpath.h
|
||||
let.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
let.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
let.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
let.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
let.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
printf.o: ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/bashjmp.h
|
||||
printf.o: $(topdir)/command.h $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
printf.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
printf.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/sig.h
|
||||
printf.o: ../pathnames.h $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h
|
||||
printf.o: $(topdir)/variables.h $(topdir)/conftypes.h $(BASHINCDIR)/stdc.h $(srcdir)/bashgetopt.h
|
||||
printf.o: $(topdir)/bashtypes.h ${srcdir}/common.h $(BASHINCDIR)/chartypes.h
|
||||
pushd.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
pushd.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
pushd.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
pushd.o: $(topdir)/subst.h $(topdir)/externs.h
|
||||
pushd.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
pushd.o: $(BASHINCDIR)/maxpath.h $(srcdir)/common.h ./builtext.h
|
||||
read.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
read.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
read.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
read.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
read.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
read.o: $(BASHINCDIR)/shtty.h
|
||||
read.o: $(topdir)/arrayfunc.h
|
||||
return.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
return.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
return.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
return.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
return.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
set.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
set.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/externs.h
|
||||
set.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
set.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
set.o: $(BASHINCDIR)/maxpath.h $(topdir)/error.h
|
||||
set.o: $(topdir)/arrayfunc.h
|
||||
setattr.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
setattr.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/maxpath.h
|
||||
setattr.o: $(topdir)/quit.h $(srcdir)/common.h $(srcdir)/bashgetopt.h
|
||||
setattr.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
|
||||
setattr.o: $(topdir)/externs.h
|
||||
setattr.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
setattr.o: $(topdir)/arrayfunc.h
|
||||
shift.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
shift.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
shift.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
shift.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
shift.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
source.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
source.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/findcmd.h
|
||||
source.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
source.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
source.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
source.o: $(srcdir)/bashgetopt.h $(topdir)/flags.h $(topdir)/trap.h
|
||||
suspend.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
suspend.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
suspend.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
suspend.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
suspend.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
test.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
test.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
test.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
test.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
test.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
test.o: $(topdir)/test.h
|
||||
times.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
times.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
times.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
times.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
times.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
times.o: $(BASHINCDIR)/posixtime.h
|
||||
trap.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
trap.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/externs.h
|
||||
trap.o: $(topdir)/quit.h $(srcdir)/common.h $(BASHINCDIR)/maxpath.h
|
||||
trap.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
|
||||
trap.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
trap.o: $(topdir)/findcmd.h
|
||||
type.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
type.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
type.o: $(topdir)/quit.h $(srcdir)/common.h $(BASHINCDIR)/maxpath.h
|
||||
type.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
|
||||
type.o: $(topdir)/externs.h $(topdir)/hashcmd.h
|
||||
type.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
ulimit.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
ulimit.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
ulimit.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
ulimit.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
ulimit.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
umask.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
umask.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
umask.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
umask.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
umask.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
umask.o: $(BASHINCDIR)/chartypes.h
|
||||
wait.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
wait.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
wait.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
wait.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
wait.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
wait.o: $(BASHINCDIR)/chartypes.h
|
||||
shopt.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
|
||||
shopt.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
|
||||
shopt.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
|
||||
shopt.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
|
||||
shopt.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
shopt.o: $(srcdir)/common.h $(srcdir)/bashgetopt.h
|
||||
|
||||
complete.o: ../config.h
|
||||
complete.o: ${topdir}/shell.h $(topdir)/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h ${topdir}/sig.h
|
||||
complete.o: ${topdir}/unwind_prot.h ${topdir}/variables.h
|
||||
complete.o: ${topdir}/bashtypes.h ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
complete.o: ${topdir}/builtins.h
|
||||
complete.o: ${topdir}/pcomplete.h
|
||||
complete.o: ${srcdir}/common.h ${srcdir}/bashgetopt.h
|
||||
|
||||
#bind.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h
|
||||
|
||||
# libintl dependencies
|
||||
bind.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
break.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
caller.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
cd.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
common.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
complete.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
declare.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
enable.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
evalfile.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
exec.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
exit.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
fc.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
fg_bg.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
getopt.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
hash.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
help.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
history.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
inlib.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
jobs.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
kill.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
let.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
mkbuiltins.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
printf.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
pushd.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
read.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
return.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
set.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
setattr.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
shift.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
shopt.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
source.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
suspend.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
type.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
ulimit.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
umask.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
|
||||
@@ -101,7 +101,7 @@ command_builtin (list)
|
||||
{
|
||||
found = describe_command (list->word->word, verbose);
|
||||
|
||||
if (found == 0)
|
||||
if (found == 0 && verbose != CDESC_REUSABLE)
|
||||
sh_notfound (list->word->word);
|
||||
|
||||
any_found += found;
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
This file is command.def, from which is created command.c.
|
||||
It implements the builtin "command" in Bash.
|
||||
|
||||
Copyright (C) 1987-2002 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES command.c
|
||||
|
||||
$BUILTIN command
|
||||
$FUNCTION command_builtin
|
||||
$SHORT_DOC command [-pVv] command [arg ...]
|
||||
Runs COMMAND with ARGS ignoring shell functions. If you have a shell
|
||||
function called `ls', and you wish to call the command `ls', you can
|
||||
say "command ls". If the -p option is given, a default value is used
|
||||
for PATH that is guaranteed to find all of the standard utilities. If
|
||||
the -V or -v option is given, a string is printed describing COMMAND.
|
||||
The -V option produces a more verbose description.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../bashansi.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../execute_cmd.h"
|
||||
#include "../flags.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if defined (_CS_PATH) && defined (HAVE_CONFSTR) && !HAVE_DECL_CONFSTR
|
||||
extern size_t confstr __P((int, char *, size_t));
|
||||
#endif
|
||||
|
||||
extern int subshell_environment, posixly_correct;
|
||||
|
||||
static void restore_path __P((char *));
|
||||
static char *get_standard_path __P((void));
|
||||
|
||||
/* Run the commands mentioned in LIST without paying attention to shell
|
||||
functions. */
|
||||
int
|
||||
command_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int result, verbose, use_standard_path, opt;
|
||||
char *old_path, *standard_path;
|
||||
COMMAND *command;
|
||||
|
||||
verbose = use_standard_path = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "pvV")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'p':
|
||||
use_standard_path = 1;
|
||||
break;
|
||||
case 'V':
|
||||
verbose = CDESC_SHORTDESC; /* look in common.h for constants */
|
||||
break;
|
||||
case 'v':
|
||||
verbose = CDESC_REUSABLE; /* ditto */
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
int found, any_found;
|
||||
|
||||
for (any_found = 0; list; list = list->next)
|
||||
{
|
||||
found = describe_command (list->word->word, verbose);
|
||||
|
||||
if (found == 0 && (posixly_correct == 0 || verbose != CDESC_REUSABLE))
|
||||
sh_notfound (list->word->word);
|
||||
|
||||
any_found += found;
|
||||
}
|
||||
return (any_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (use_standard_path && restricted)
|
||||
{
|
||||
sh_restricted ("-p");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
begin_unwind_frame ("command_builtin");
|
||||
|
||||
/* We don't want this to be reparsed (consider command echo 'foo &'), so
|
||||
just make a simple_command structure and call execute_command with it. */
|
||||
if (use_standard_path)
|
||||
{
|
||||
old_path = get_string_value ("PATH");
|
||||
/* If old_path is NULL, $PATH is unset. If so, we want to make sure
|
||||
it's unset after this command completes. */
|
||||
if (old_path)
|
||||
old_path = savestring (old_path);
|
||||
add_unwind_protect ((Function *)restore_path, old_path);
|
||||
|
||||
standard_path = get_standard_path ();
|
||||
bind_variable ("PATH", standard_path ? standard_path : "");
|
||||
FREE (standard_path);
|
||||
}
|
||||
|
||||
#define COMMAND_BUILTIN_FLAGS (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION | CMD_COMMAND_BUILTIN)
|
||||
|
||||
command = make_bare_simple_command ();
|
||||
command->value.Simple->words = (WORD_LIST *)copy_word_list (list);
|
||||
command->value.Simple->redirects = (REDIRECT *)NULL;
|
||||
command->flags |= COMMAND_BUILTIN_FLAGS;
|
||||
command->value.Simple->flags |= COMMAND_BUILTIN_FLAGS;
|
||||
#if 0
|
||||
/* This breaks for things like ( cd /tmp ; command z ababa ; echo next )
|
||||
or $(command echo a ; command echo b;) or even
|
||||
{ command echo a; command echo b; } & */
|
||||
/* If we're in a subshell, see if we can get away without forking
|
||||
again, since we've already forked to run this builtin. */
|
||||
if (subshell_environment)
|
||||
{
|
||||
command->flags |= CMD_NO_FORK;
|
||||
command->value.Simple->flags |= CMD_NO_FORK;
|
||||
}
|
||||
#endif
|
||||
add_unwind_protect ((char *)dispose_command, command);
|
||||
result = execute_command (command);
|
||||
|
||||
run_unwind_frame ("command_builtin");
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Restore the value of the $PATH variable after replacing it when
|
||||
executing `command -p'. */
|
||||
static void
|
||||
restore_path (var)
|
||||
char *var;
|
||||
{
|
||||
if (var)
|
||||
{
|
||||
bind_variable ("PATH", var);
|
||||
free (var);
|
||||
}
|
||||
else
|
||||
unbind_variable ("PATH");
|
||||
}
|
||||
|
||||
/* Return a value for PATH that is guaranteed to find all of the standard
|
||||
utilities. This uses Posix.2 configuration variables, if present. It
|
||||
uses a value defined in config.h as a last resort. */
|
||||
static char *
|
||||
get_standard_path ()
|
||||
{
|
||||
#if defined (_CS_PATH) && defined (HAVE_CONFSTR)
|
||||
char *p;
|
||||
size_t len;
|
||||
|
||||
len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0);
|
||||
if (len > 0)
|
||||
{
|
||||
p = (char *)xmalloc (len + 2);
|
||||
*p = '\0';
|
||||
confstr (_CS_PATH, p, len);
|
||||
return (p);
|
||||
}
|
||||
else
|
||||
return (savestring (STANDARD_UTILS_PATH));
|
||||
#else /* !_CS_PATH || !HAVE_CONFSTR */
|
||||
# if defined (CS_PATH)
|
||||
return (savestring (CS_PATH));
|
||||
# else
|
||||
return (savestring (STANDARD_UTILS_PATH));
|
||||
# endif /* !CS_PATH */
|
||||
#endif /* !_CS_PATH || !HAVE_CONFSTR */
|
||||
}
|
||||
+12
-4
@@ -84,6 +84,7 @@ extern int errno;
|
||||
extern int echo_input_at_read;
|
||||
extern int current_command_line_count;
|
||||
extern int literal_history;
|
||||
extern int posixly_correct;
|
||||
|
||||
extern int unlink __P((const char *));
|
||||
|
||||
@@ -155,6 +156,7 @@ static void fc_addhist __P((char *));
|
||||
|
||||
/* String to execute on a file that we want to edit. */
|
||||
#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
|
||||
#define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}"
|
||||
|
||||
int
|
||||
fc_builtin (list)
|
||||
@@ -166,7 +168,7 @@ fc_builtin (list)
|
||||
int histbeg, histend, last_hist, retval, opt;
|
||||
FILE *stream;
|
||||
REPL *rlist, *rl;
|
||||
char *ename, *command, *newcom;
|
||||
char *ename, *command, *newcom, *fcedit;
|
||||
HIST_ENTRY **hlist;
|
||||
char *fn;
|
||||
|
||||
@@ -302,7 +304,7 @@ fc_builtin (list)
|
||||
if (listing)
|
||||
{
|
||||
histend = last_hist;
|
||||
histbeg = histend - 16;
|
||||
histbeg = histend - 16 + 1; /* +1 because loop below uses >= */
|
||||
if (histbeg < 0)
|
||||
histbeg = 0;
|
||||
}
|
||||
@@ -347,7 +349,12 @@ fc_builtin (list)
|
||||
if (numbering)
|
||||
fprintf (stream, "%d", i + history_base);
|
||||
if (listing)
|
||||
fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
|
||||
{
|
||||
if (posixly_correct)
|
||||
fputs ("\t", stream);
|
||||
else
|
||||
fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
|
||||
}
|
||||
fprintf (stream, "%s\n", histline (i));
|
||||
}
|
||||
|
||||
@@ -364,7 +371,8 @@ fc_builtin (list)
|
||||
}
|
||||
else
|
||||
{
|
||||
command = (char *)xmalloc (3 + strlen (FC_EDIT_COMMAND) + strlen (fn));
|
||||
fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND;
|
||||
command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn));
|
||||
sprintf (command, "%s %s", FC_EDIT_COMMAND, fn);
|
||||
}
|
||||
retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
|
||||
|
||||
@@ -0,0 +1,633 @@
|
||||
This file is fc.def, from which is created fc.c.
|
||||
It implements the builtin "fc" in Bash.
|
||||
|
||||
Copyright (C) 1987-2003 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES fc.c
|
||||
|
||||
$BUILTIN fc
|
||||
$FUNCTION fc_builtin
|
||||
$DEPENDS_ON HISTORY
|
||||
$SHORT_DOC fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [cmd]
|
||||
fc is used to list or edit and re-execute commands from the history list.
|
||||
FIRST and LAST can be numbers specifying the range, or FIRST can be a
|
||||
string, which means the most recent command beginning with that
|
||||
string.
|
||||
|
||||
-e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
|
||||
then vi.
|
||||
|
||||
-l means list lines instead of editing.
|
||||
-n means no line numbers listed.
|
||||
-r means reverse the order of the lines (making it newest listed first).
|
||||
|
||||
With the `fc -s [pat=rep ...] [command]' format, the command is
|
||||
re-executed after the substitution OLD=NEW is performed.
|
||||
|
||||
A useful alias to use with this is r='fc -s', so that typing `r cc'
|
||||
runs the last command beginning with `cc' and typing `r' re-executes
|
||||
the last command.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HISTORY)
|
||||
#ifndef _MINIX
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
#include "../bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <chartypes.h>
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../builtins.h"
|
||||
#include "../flags.h"
|
||||
#include "../bashhist.h"
|
||||
#include "maxpath.h"
|
||||
#include <readline/history.h>
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
extern int echo_input_at_read;
|
||||
extern int current_command_line_count;
|
||||
extern int literal_history;
|
||||
|
||||
extern int unlink __P((const char *));
|
||||
|
||||
extern FILE *sh_mktmpfp __P((char *, int, char **));
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* The K*rn shell style fc command (Fix Command) */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* fc builtin command (fix command) for Bash for those who
|
||||
like K*rn-style history better than csh-style.
|
||||
|
||||
fc [-e ename] [-nlr] [first] [last]
|
||||
|
||||
FIRST and LAST can be numbers specifying the range, or FIRST can be
|
||||
a string, which means the most recent command beginning with that
|
||||
string.
|
||||
|
||||
-e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
|
||||
then the editor which corresponds to the current readline editing
|
||||
mode, then vi.
|
||||
|
||||
-l means list lines instead of editing.
|
||||
-n means no line numbers listed.
|
||||
-r means reverse the order of the lines (making it newest listed first).
|
||||
|
||||
fc -e - [pat=rep ...] [command]
|
||||
fc -s [pat=rep ...] [command]
|
||||
|
||||
Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
|
||||
*/
|
||||
|
||||
/* Data structure describing a list of global replacements to perform. */
|
||||
typedef struct repl {
|
||||
struct repl *next;
|
||||
char *pat;
|
||||
char *rep;
|
||||
} REPL;
|
||||
|
||||
/* Accessors for HIST_ENTRY lists that are called HLIST. */
|
||||
#define histline(i) (hlist[(i)]->line)
|
||||
#define histdata(i) (hlist[(i)]->data)
|
||||
|
||||
#define FREE_RLIST() \
|
||||
do { \
|
||||
for (rl = rlist; rl; ) { \
|
||||
REPL *r; \
|
||||
r = rl->next; \
|
||||
if (rl->pat) \
|
||||
free (rl->pat); \
|
||||
if (rl->rep) \
|
||||
free (rl->rep); \
|
||||
free (rl); \
|
||||
rl = r; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static char *fc_dosubs __P((char *, REPL *));
|
||||
static char *fc_gethist __P((char *, HIST_ENTRY **));
|
||||
static int fc_gethnum __P((char *, HIST_ENTRY **));
|
||||
static int fc_number __P((WORD_LIST *));
|
||||
static void fc_replhist __P((char *));
|
||||
#ifdef INCLUDE_UNUSED
|
||||
static char *fc_readline __P((FILE *));
|
||||
static void fc_addhist __P((char *));
|
||||
#endif
|
||||
|
||||
/* String to execute on a file that we want to edit. */
|
||||
#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
|
||||
|
||||
int
|
||||
fc_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register int i;
|
||||
register char *sep;
|
||||
int numbering, reverse, listing, execute;
|
||||
int histbeg, histend, last_hist, retval, opt;
|
||||
FILE *stream;
|
||||
REPL *rlist, *rl;
|
||||
char *ename, *command, *newcom;
|
||||
HIST_ENTRY **hlist;
|
||||
char *fn;
|
||||
|
||||
numbering = 1;
|
||||
reverse = listing = execute = 0;
|
||||
ename = (char *)NULL;
|
||||
|
||||
/* Parse out the options and set which of the two forms we're in. */
|
||||
reset_internal_getopt ();
|
||||
lcurrent = list; /* XXX */
|
||||
while (fc_number (loptend = lcurrent) == 0 &&
|
||||
(opt = internal_getopt (list, ":e:lnrs")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'n':
|
||||
numbering = 0;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
listing = 1;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
reverse = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
execute = 1;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
ename = list_optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (ename && (*ename == '-') && (ename[1] == '\0'))
|
||||
execute = 1;
|
||||
|
||||
/* The "execute" form of the command (re-run, with possible string
|
||||
substitutions). */
|
||||
if (execute)
|
||||
{
|
||||
rlist = (REPL *)NULL;
|
||||
while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
|
||||
{
|
||||
*sep++ = '\0';
|
||||
rl = (REPL *)xmalloc (sizeof (REPL));
|
||||
rl->next = (REPL *)NULL;
|
||||
rl->pat = savestring (list->word->word);
|
||||
rl->rep = savestring (sep);
|
||||
|
||||
if (rlist == NULL)
|
||||
rlist = rl;
|
||||
else
|
||||
{
|
||||
rl->next = rlist;
|
||||
rlist = rl;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* If we have a list of substitutions to do, then reverse it
|
||||
to get the replacements in the proper order. */
|
||||
|
||||
rlist = REVERSE_LIST (rlist, REPL *);
|
||||
|
||||
hlist = history_list ();
|
||||
|
||||
/* If we still have something in list, it is a command spec.
|
||||
Otherwise, we use the most recent command in time. */
|
||||
command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
|
||||
|
||||
if (command == NULL)
|
||||
{
|
||||
builtin_error (_("no command found"));
|
||||
if (rlist)
|
||||
FREE_RLIST ();
|
||||
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (rlist)
|
||||
{
|
||||
newcom = fc_dosubs (command, rlist);
|
||||
free (command);
|
||||
FREE_RLIST ();
|
||||
command = newcom;
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s\n", command);
|
||||
fc_replhist (command); /* replace `fc -s' with command */
|
||||
return (parse_and_execute (command, "fc", SEVAL_NOHIST));
|
||||
}
|
||||
|
||||
/* This is the second form of the command (the list-or-edit-and-rerun
|
||||
form). */
|
||||
hlist = history_list ();
|
||||
if (hlist == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
for (i = 0; hlist[i]; i++);
|
||||
|
||||
/* With the Bash implementation of history, the current command line
|
||||
("fc blah..." and so on) is already part of the history list by
|
||||
the time we get to this point. This just skips over that command
|
||||
and makes the last command that this deals with be the last command
|
||||
the user entered before the fc. We need to check whether the
|
||||
line was actually added (HISTIGNORE may have caused it to not be),
|
||||
so we check hist_last_line_added. */
|
||||
|
||||
last_hist = i - 1 - hist_last_line_added;
|
||||
|
||||
if (list)
|
||||
{
|
||||
histbeg = fc_gethnum (list->word->word, hlist);
|
||||
list = list->next;
|
||||
|
||||
if (list)
|
||||
histend = fc_gethnum (list->word->word, hlist);
|
||||
else
|
||||
histend = listing ? last_hist : histbeg;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The default for listing is the last 16 history items. */
|
||||
if (listing)
|
||||
{
|
||||
histend = last_hist;
|
||||
histbeg = histend - 16;
|
||||
if (histbeg < 0)
|
||||
histbeg = 0;
|
||||
}
|
||||
else
|
||||
/* For editing, it is the last history command. */
|
||||
histbeg = histend = last_hist;
|
||||
}
|
||||
|
||||
/* We print error messages for line specifications out of range. */
|
||||
if ((histbeg < 0) || (histend < 0))
|
||||
{
|
||||
sh_erange ((char *)NULL, _("history specification"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (histend < histbeg)
|
||||
{
|
||||
i = histend;
|
||||
histend = histbeg;
|
||||
histbeg = i;
|
||||
|
||||
reverse = 1;
|
||||
}
|
||||
|
||||
if (listing)
|
||||
stream = stdout;
|
||||
else
|
||||
{
|
||||
numbering = 0;
|
||||
stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
|
||||
if (stream == 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
|
||||
FREE (fn);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
|
||||
{
|
||||
QUIT;
|
||||
if (numbering)
|
||||
fprintf (stream, "%d", i + history_base);
|
||||
if (listing)
|
||||
fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
|
||||
fprintf (stream, "%s\n", histline (i));
|
||||
}
|
||||
|
||||
if (listing)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
fclose (stream);
|
||||
|
||||
/* Now edit the file of commands. */
|
||||
if (ename)
|
||||
{
|
||||
command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
|
||||
sprintf (command, "%s %s", ename, fn);
|
||||
}
|
||||
else
|
||||
{
|
||||
command = (char *)xmalloc (3 + strlen (FC_EDIT_COMMAND) + strlen (fn));
|
||||
sprintf (command, "%s %s", FC_EDIT_COMMAND, fn);
|
||||
}
|
||||
retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
|
||||
if (retval != EXECUTION_SUCCESS)
|
||||
{
|
||||
unlink (fn);
|
||||
free (fn);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Make sure parse_and_execute doesn't turn this off, even though a
|
||||
call to parse_and_execute farther up the function call stack (e.g.,
|
||||
if this is called by vi_edit_and_execute_command) may have already
|
||||
called bash_history_disable. */
|
||||
remember_on_history = 1;
|
||||
|
||||
/* Turn on the `v' flag while fc_execute_file runs so the commands
|
||||
will be echoed as they are read by the parser. */
|
||||
begin_unwind_frame ("fc builtin");
|
||||
add_unwind_protect ((Function *)xfree, fn);
|
||||
add_unwind_protect (unlink, fn);
|
||||
unwind_protect_int (echo_input_at_read);
|
||||
echo_input_at_read = 1;
|
||||
|
||||
retval = fc_execute_file (fn);
|
||||
|
||||
run_unwind_frame ("fc builtin");
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/* Return 1 if LIST->word->word is a legal number for fc's use. */
|
||||
static int
|
||||
fc_number (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *s;
|
||||
|
||||
if (list == 0)
|
||||
return 0;
|
||||
s = list->word->word;
|
||||
if (*s == '-')
|
||||
s++;
|
||||
return (legal_number (s, (intmax_t *)NULL));
|
||||
}
|
||||
|
||||
/* Return an absolute index into HLIST which corresponds to COMMAND. If
|
||||
COMMAND is a number, then it was specified in relative terms. If it
|
||||
is a string, then it is the start of a command line present in HLIST. */
|
||||
static int
|
||||
fc_gethnum (command, hlist)
|
||||
char *command;
|
||||
HIST_ENTRY **hlist;
|
||||
{
|
||||
int sign = 1, n, clen;
|
||||
register int i, j;
|
||||
register char *s;
|
||||
|
||||
/* Count history elements. */
|
||||
for (i = 0; hlist[i]; i++);
|
||||
|
||||
/* With the Bash implementation of history, the current command line
|
||||
("fc blah..." and so on) is already part of the history list by
|
||||
the time we get to this point. This just skips over that command
|
||||
and makes the last command that this deals with be the last command
|
||||
the user entered before the fc. We need to check whether the
|
||||
line was actually added (HISTIGNORE may have caused it to not be),
|
||||
so we check hist_last_line_added. */
|
||||
i -= 1 + hist_last_line_added;
|
||||
|
||||
/* No specification defaults to most recent command. */
|
||||
if (command == NULL)
|
||||
return (i);
|
||||
|
||||
/* Otherwise, there is a specification. It can be a number relative to
|
||||
the current position, or an absolute history number. */
|
||||
s = command;
|
||||
|
||||
/* Handle possible leading minus sign. */
|
||||
if (s && (*s == '-'))
|
||||
{
|
||||
sign = -1;
|
||||
s++;
|
||||
}
|
||||
|
||||
if (s && DIGIT(*s))
|
||||
{
|
||||
n = atoi (s);
|
||||
n *= sign;
|
||||
|
||||
/* If the value is negative or zero, then it is an offset from
|
||||
the current history item. */
|
||||
if (n < 0)
|
||||
{
|
||||
n += i + 1;
|
||||
return (n < 0 ? 0 : n);
|
||||
}
|
||||
else if (n == 0)
|
||||
return (i);
|
||||
else
|
||||
{
|
||||
n -= history_base;
|
||||
return (i < n ? i : n);
|
||||
}
|
||||
}
|
||||
|
||||
clen = strlen (command);
|
||||
for (j = i; j >= 0; j--)
|
||||
{
|
||||
if (STREQN (command, histline (j), clen))
|
||||
return (j);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Locate the most recent history line which begins with
|
||||
COMMAND in HLIST, and return a malloc()'ed copy of it. */
|
||||
static char *
|
||||
fc_gethist (command, hlist)
|
||||
char *command;
|
||||
HIST_ENTRY **hlist;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!hlist)
|
||||
return ((char *)NULL);
|
||||
|
||||
i = fc_gethnum (command, hlist);
|
||||
|
||||
if (i >= 0)
|
||||
return (savestring (histline (i)));
|
||||
else
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Read the edited history lines from STREAM and return them
|
||||
one at a time. This can read unlimited length lines. The
|
||||
caller should free the storage. */
|
||||
static char *
|
||||
fc_readline (stream)
|
||||
FILE *stream;
|
||||
{
|
||||
register int c;
|
||||
int line_len = 0, lindex = 0;
|
||||
char *line = (char *)NULL;
|
||||
|
||||
while ((c = getc (stream)) != EOF)
|
||||
{
|
||||
if ((lindex + 2) >= line_len)
|
||||
line = (char *)xrealloc (line, (line_len += 128));
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
line[lindex++] = '\n';
|
||||
line[lindex++] = '\0';
|
||||
return (line);
|
||||
}
|
||||
else
|
||||
line[lindex++] = c;
|
||||
}
|
||||
|
||||
if (!lindex)
|
||||
{
|
||||
if (line)
|
||||
free (line);
|
||||
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
if (lindex + 2 >= line_len)
|
||||
line = (char *)xrealloc (line, lindex + 3);
|
||||
|
||||
line[lindex++] = '\n'; /* Finish with newline if none in file */
|
||||
line[lindex++] = '\0';
|
||||
return (line);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Perform the SUBS on COMMAND.
|
||||
SUBS is a list of substitutions, and COMMAND is a simple string.
|
||||
Return a pointer to a malloc'ed string which contains the substituted
|
||||
command. */
|
||||
static char *
|
||||
fc_dosubs (command, subs)
|
||||
char *command;
|
||||
REPL *subs;
|
||||
{
|
||||
register char *new, *t;
|
||||
register REPL *r;
|
||||
|
||||
for (new = savestring (command), r = subs; r; r = r->next)
|
||||
{
|
||||
t = strsub (new, r->pat, r->rep, 1);
|
||||
free (new);
|
||||
new = t;
|
||||
}
|
||||
return (new);
|
||||
}
|
||||
|
||||
/* Use `command' to replace the last entry in the history list, which,
|
||||
by this time, is `fc blah...'. The intent is that the new command
|
||||
become the history entry, and that `fc' should never appear in the
|
||||
history list. This way you can do `r' to your heart's content. */
|
||||
static void
|
||||
fc_replhist (command)
|
||||
char *command;
|
||||
{
|
||||
register int i;
|
||||
HIST_ENTRY **hlist, *histent, *discard;
|
||||
int n;
|
||||
|
||||
if (command == 0 || *command == '\0')
|
||||
return;
|
||||
|
||||
hlist = history_list ();
|
||||
|
||||
if (hlist == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; hlist[i]; i++);
|
||||
i--;
|
||||
|
||||
/* History_get () takes a parameter that should be
|
||||
offset by history_base. */
|
||||
|
||||
histent = history_get (history_base + i); /* Don't free this */
|
||||
if (histent == NULL)
|
||||
return;
|
||||
|
||||
n = strlen (command);
|
||||
|
||||
if (command[n - 1] == '\n')
|
||||
command[n - 1] = '\0';
|
||||
|
||||
if (command && *command)
|
||||
{
|
||||
discard = remove_history (i);
|
||||
if (discard)
|
||||
{
|
||||
FREE (discard->line);
|
||||
free ((char *) discard);
|
||||
}
|
||||
maybe_add_history (command); /* Obeys HISTCONTROL setting. */
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Add LINE to the history, after removing a single trailing newline. */
|
||||
static void
|
||||
fc_addhist (line)
|
||||
char *line;
|
||||
{
|
||||
register int n;
|
||||
|
||||
n = strlen (line);
|
||||
|
||||
if (line[n - 1] == '\n')
|
||||
line[n - 1] = '\0';
|
||||
|
||||
if (line && *line)
|
||||
maybe_add_history (line);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HISTORY */
|
||||
+1
-1
@@ -125,7 +125,7 @@ hash_builtin (list)
|
||||
if (list == 0 && expunge_hash_table == 0)
|
||||
{
|
||||
if (print_hashed_commands (list_portably) == 0)
|
||||
printf (_("%s: hash table empty\n"), this_command_name);
|
||||
fprintf (stderr, _("%s: hash table empty\n"), this_command_name);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
This file is hash.def, from which is created hash.c.
|
||||
It implements the builtin "hash" in Bash.
|
||||
|
||||
Copyright (C) 1987-2003 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES hash.c
|
||||
|
||||
$BUILTIN hash
|
||||
$FUNCTION hash_builtin
|
||||
$SHORT_DOC hash [-lr] [-p pathname] [-dt] [name ...]
|
||||
For each NAME, the full pathname of the command is determined and
|
||||
remembered. If the -p option is supplied, PATHNAME is used as the
|
||||
full pathname of NAME, and no path search is performed. The -r
|
||||
option causes the shell to forget all remembered locations. The -d
|
||||
option causes the shell to forget the remembered location of each NAME.
|
||||
If the -t option is supplied the full pathname to which each NAME
|
||||
corresponds is printed. If multiple NAME arguments are supplied with
|
||||
-t, the NAME is printed before the hashed full pathname. The -l option
|
||||
causes output to be displayed in a format that may be reused as input.
|
||||
If no arguments are given, information about remembered commands is displayed.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../builtins.h"
|
||||
#include "../flags.h"
|
||||
#include "../findcmd.h"
|
||||
#include "../hashcmd.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int dot_found_in_search;
|
||||
extern char *this_command_name;
|
||||
|
||||
static int add_hashed_command __P((char *, int));
|
||||
static int print_hash_info __P((BUCKET_CONTENTS *));
|
||||
static int print_portable_hash_info __P((BUCKET_CONTENTS *));
|
||||
static int print_hashed_commands __P((int));
|
||||
static int list_hashed_filename_targets __P((WORD_LIST *, int));
|
||||
|
||||
/* Print statistics on the current state of hashed commands. If LIST is
|
||||
not empty, then rehash (or hash in the first place) the specified
|
||||
commands. */
|
||||
int
|
||||
hash_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int expunge_hash_table, list_targets, list_portably, delete, opt;
|
||||
char *w, *pathname;
|
||||
|
||||
if (hashing_enabled == 0)
|
||||
{
|
||||
builtin_error (_("hashing disabled"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
expunge_hash_table = list_targets = list_portably = delete = 0;
|
||||
pathname = (char *)NULL;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "dlp:rt")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'd':
|
||||
delete = 1;
|
||||
break;
|
||||
case 'l':
|
||||
list_portably = 1;
|
||||
break;
|
||||
case 'p':
|
||||
pathname = list_optarg;
|
||||
break;
|
||||
case 'r':
|
||||
expunge_hash_table = 1;
|
||||
break;
|
||||
case 't':
|
||||
list_targets = 1;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
/* hash -t requires at least one argument. */
|
||||
if (list == 0 && list_targets)
|
||||
{
|
||||
sh_needarg ("-t");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* We want hash -r to be silent, but hash -- to print hashing info, so
|
||||
we test expunge_hash_table. */
|
||||
if (list == 0 && expunge_hash_table == 0)
|
||||
{
|
||||
if (print_hashed_commands (list_portably) == 0)
|
||||
printf (_("%s: hash table empty\n"), this_command_name);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
if (expunge_hash_table)
|
||||
phash_flush ();
|
||||
|
||||
/* If someone runs `hash -r -t xyz' he will be disappointed. */
|
||||
if (list_targets)
|
||||
return (list_hashed_filename_targets (list, list_portably));
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted && pathname && strchr (pathname, '/'))
|
||||
{
|
||||
sh_restricted (pathname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (opt = EXECUTION_SUCCESS; list; list = list->next)
|
||||
{
|
||||
/* Add, remove or rehash the specified commands. */
|
||||
w = list->word->word;
|
||||
if (pathname)
|
||||
{
|
||||
if (is_directory (pathname))
|
||||
{
|
||||
#ifdef EISDIR
|
||||
builtin_error ("%s: %s", pathname, strerror (EISDIR));
|
||||
#else
|
||||
builtin_error ("%s: is a directory", pathname);
|
||||
#endif
|
||||
opt = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
phash_insert (w, pathname, 0, 0);
|
||||
}
|
||||
else if (absolute_program (w))
|
||||
continue;
|
||||
else if (delete && phash_remove (w))
|
||||
{
|
||||
sh_notfound (w);
|
||||
opt = EXECUTION_FAILURE;
|
||||
}
|
||||
else if (add_hashed_command (w, 0))
|
||||
opt = EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
return (opt);
|
||||
}
|
||||
|
||||
static int
|
||||
add_hashed_command (w, quiet)
|
||||
char *w;
|
||||
int quiet;
|
||||
{
|
||||
int rv;
|
||||
char *full_path;
|
||||
|
||||
rv = 0;
|
||||
if (find_function (w) == 0 && find_shell_builtin (w) == 0)
|
||||
{
|
||||
full_path = find_user_command (w);
|
||||
if (full_path && executable_file (full_path))
|
||||
phash_insert (w, full_path, dot_found_in_search, 0);
|
||||
else
|
||||
{
|
||||
if (quiet == 0)
|
||||
sh_notfound (w);
|
||||
rv++;
|
||||
}
|
||||
FREE (full_path);
|
||||
}
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/* Print information about current hashed info. */
|
||||
static int
|
||||
print_hash_info (item)
|
||||
BUCKET_CONTENTS *item;
|
||||
{
|
||||
printf ("%4d\t%s\n", item->times_found, pathdata(item)->path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
print_portable_hash_info (item)
|
||||
BUCKET_CONTENTS *item;
|
||||
{
|
||||
printf ("builtin hash -p %s %s\n", pathdata(item)->path, item->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
print_hashed_commands (fmt)
|
||||
int fmt;
|
||||
{
|
||||
if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
|
||||
return (0);
|
||||
|
||||
if (fmt == 0)
|
||||
printf ("hits\tcommand\n");
|
||||
hash_walk (hashed_filenames, fmt ? print_portable_hash_info : print_hash_info);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
list_hashed_filename_targets (list, fmt)
|
||||
WORD_LIST *list;
|
||||
int fmt;
|
||||
{
|
||||
int all_found, multiple;
|
||||
char *target;
|
||||
WORD_LIST *l;
|
||||
|
||||
all_found = 1;
|
||||
multiple = list->next != 0;
|
||||
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
target = phash_search (l->word->word);
|
||||
if (target == 0)
|
||||
{
|
||||
all_found = 0;
|
||||
sh_notfound (l->word->word);
|
||||
continue;
|
||||
}
|
||||
if (fmt)
|
||||
printf ("builtin hash -p %s %s\n", target, l->word->word);
|
||||
else
|
||||
{
|
||||
if (multiple)
|
||||
printf ("%s\t", l->word->word);
|
||||
printf ("%s\n", target);
|
||||
}
|
||||
}
|
||||
|
||||
return (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
@@ -109,11 +109,10 @@ $END
|
||||
|
||||
$BUILTIN %
|
||||
$DOCNAME fg_percent
|
||||
$SHORT_DOC %[DIGITS | WORD] [&]
|
||||
$SHORT_DOC %JOBSPEC [&]
|
||||
This is similar to the `fg' command. Resume a stopped or background
|
||||
job. If you specifiy DIGITS, then that job is used. If you specify
|
||||
WORD, then the job whose name begins with WORD is used. Following the
|
||||
job specification with a `&' places the job in the background.
|
||||
job specified by %JOBSPEC. Following the job specification with a `&'
|
||||
places the job in the background.
|
||||
$END
|
||||
|
||||
$BUILTIN (( ... ))
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
This file is reserved.def, in which the shell reserved words are defined.
|
||||
It has no direct C file production, but defines builtins for the Bash
|
||||
builtin help command.
|
||||
|
||||
Copyright (C) 1987-2002 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$BUILTIN for
|
||||
$SHORT_DOC for NAME [in WORDS ... ;] do COMMANDS; done
|
||||
The `for' loop executes a sequence of commands for each member in a
|
||||
list of items. If `in WORDS ...;' is not present, then `in "$@"' is
|
||||
assumed. For each element in WORDS, NAME is set to that element, and
|
||||
the COMMANDS are executed.
|
||||
$END
|
||||
|
||||
$BUILTIN for ((
|
||||
$DOCNAME arith_for
|
||||
$SHORT_DOC for (( exp1; exp2; exp3 )); do COMMANDS; done
|
||||
Equivalent to
|
||||
(( EXP1 ))
|
||||
while (( EXP2 )); do
|
||||
COMMANDS
|
||||
(( EXP3 ))
|
||||
done
|
||||
EXP1, EXP2, and EXP3 are arithmetic expressions. If any expression is
|
||||
omitted, it behaves as if it evaluates to 1.
|
||||
$END
|
||||
|
||||
$BUILTIN select
|
||||
$SHORT_DOC select NAME [in WORDS ... ;] do COMMANDS; done
|
||||
The WORDS are expanded, generating a list of words. The
|
||||
set of expanded words is printed on the standard error, each
|
||||
preceded by a number. If `in WORDS' is not present, `in "$@"'
|
||||
is assumed. The PS3 prompt is then displayed and a line read
|
||||
from the standard input. If the line consists of the number
|
||||
corresponding to one of the displayed words, then NAME is set
|
||||
to that word. If the line is empty, WORDS and the prompt are
|
||||
redisplayed. If EOF is read, the command completes. Any other
|
||||
value read causes NAME to be set to null. The line read is saved
|
||||
in the variable REPLY. COMMANDS are executed after each selection
|
||||
until a break command is executed.
|
||||
$END
|
||||
|
||||
$BUILTIN time
|
||||
$SHORT_DOC time [-p] PIPELINE
|
||||
Execute PIPELINE and print a summary of the real time, user CPU time,
|
||||
and system CPU time spent executing PIPELINE when it terminates.
|
||||
The return status is the return status of PIPELINE. The `-p' option
|
||||
prints the timing summary in a slightly different format. This uses
|
||||
the value of the TIMEFORMAT variable as the output format.
|
||||
$END
|
||||
|
||||
$BUILTIN case
|
||||
$SHORT_DOC case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
|
||||
Selectively execute COMMANDS based upon WORD matching PATTERN. The
|
||||
`|' is used to separate multiple patterns.
|
||||
$END
|
||||
|
||||
$BUILTIN if
|
||||
$SHORT_DOC if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
|
||||
The if COMMANDS are executed. If the exit status is zero, then the then
|
||||
COMMANDS are executed. Otherwise, each of the elif COMMANDS are executed
|
||||
in turn, and if the exit status is zero, the corresponding then COMMANDS
|
||||
are executed and the if command completes. Otherwise, the else COMMANDS
|
||||
are executed, if present. The exit status is the exit status of the last
|
||||
command executed, or zero if no condition tested true.
|
||||
$END
|
||||
|
||||
$BUILTIN while
|
||||
$SHORT_DOC while COMMANDS; do COMMANDS; done
|
||||
Expand and execute COMMANDS as long as the final command in the
|
||||
`while' COMMANDS has an exit status of zero.
|
||||
$END
|
||||
|
||||
$BUILTIN until
|
||||
$SHORT_DOC until COMMANDS; do COMMANDS; done
|
||||
Expand and execute COMMANDS as long as the final command in the
|
||||
`until' COMMANDS has an exit status which is not zero.
|
||||
$END
|
||||
|
||||
$BUILTIN function
|
||||
$SHORT_DOC function NAME { COMMANDS ; } or NAME () { COMMANDS ; }
|
||||
Create a simple command invoked by NAME which runs COMMANDS.
|
||||
Arguments on the command line along with NAME are passed to the
|
||||
function as $0 .. $n.
|
||||
$END
|
||||
|
||||
$BUILTIN { ... }
|
||||
$DOCNAME grouping_braces
|
||||
$SHORT_DOC { COMMANDS ; }
|
||||
Run a set of commands in a group. This is one way to redirect an
|
||||
entire set of commands.
|
||||
$END
|
||||
|
||||
$BUILTIN %
|
||||
$DOCNAME fg_percent
|
||||
$SHORT_DOC %[DIGITS | WORD] [&]
|
||||
This is similar to the `fg' command. Resume a stopped or background
|
||||
job. If you specifiy DIGITS, then that job is used. If you specify
|
||||
WORD, then the job whose name begins with WORD is used. Following the
|
||||
job specification with a `&' places the job in the background.
|
||||
$END
|
||||
|
||||
$BUILTIN (( ... ))
|
||||
$DOCNAME arith
|
||||
$SHORT_DOC (( expression ))
|
||||
The EXPRESSION is evaluated according to the rules for arithmetic
|
||||
evaluation. Equivalent to "let EXPRESSION".
|
||||
$END
|
||||
|
||||
$BUILTIN [[ ... ]]
|
||||
$DOCNAME conditional
|
||||
$SHORT_DOC [[ expression ]]
|
||||
Returns a status of 0 or 1 depending on the evaluation of the conditional
|
||||
expression EXPRESSION. Expressions are composed of the same primaries used
|
||||
by the `test' builtin, and may be combined using the following operators
|
||||
|
||||
( EXPRESSION ) Returns the value of EXPRESSION
|
||||
! EXPRESSION True if EXPRESSION is false; else false
|
||||
EXPR1 && EXPR2 True if both EXPR1 and EXPR2 are true; else false
|
||||
EXPR1 || EXPR2 True if either EXPR1 or EXPR2 is true; else false
|
||||
|
||||
When the `==' and `!=' operators are used, the string to the right of the
|
||||
operator is used as a pattern and pattern matching is performed. The
|
||||
&& and || operators do not evaluate EXPR2 if EXPR1 is sufficient to
|
||||
determine the expression's value.
|
||||
$END
|
||||
|
||||
$BUILTIN variables
|
||||
$DOCNAME variable_help
|
||||
$SHORT_DOC variables - Some variable names and meanings
|
||||
BASH_VERSION Version information for this Bash.
|
||||
CDPATH A colon-separated list of directories to search
|
||||
for directries given as arguments to `cd'.
|
||||
GLOBIGNORE A colon-separated list of patterns describing filenames to
|
||||
be ignored by pathname expansion.
|
||||
#if defined (HISTORY)
|
||||
HISTFILE The name of the file where your command history is stored.
|
||||
HISTFILESIZE The maximum number of lines this file can contain.
|
||||
HISTSIZE The maximum number of history lines that a running
|
||||
shell can access.
|
||||
#endif /* HISTORY */
|
||||
HOME The complete pathname to your login directory.
|
||||
HOSTNAME The name of the current host.
|
||||
HOSTTYPE The type of CPU this version of Bash is running under.
|
||||
IGNOREEOF Controls the action of the shell on receipt of an EOF
|
||||
character as the sole input. If set, then the value
|
||||
of it is the number of EOF characters that can be seen
|
||||
in a row on an empty line before the shell will exit
|
||||
(default 10). When unset, EOF signifies the end of input.
|
||||
MACHTYPE A string describing the current system Bash is running on.
|
||||
MAILCHECK How often, in seconds, Bash checks for new mail.
|
||||
MAILPATH A colon-separated list of filenames which Bash checks
|
||||
for new mail.
|
||||
OSTYPE The version of Unix this version of Bash is running on.
|
||||
PATH A colon-separated list of directories to search when
|
||||
looking for commands.
|
||||
PROMPT_COMMAND A command to be executed before the printing of each
|
||||
primary prompt.
|
||||
PS1 The primary prompt string.
|
||||
PS2 The secondary prompt string.
|
||||
PWD The full pathname of the current directory.
|
||||
SHELLOPTS A colon-separated list of enabled shell options.
|
||||
TERM The name of the current terminal type.
|
||||
TIMEFORMAT The output format for timing statistics displayed by the
|
||||
`time' reserved word.
|
||||
auto_resume Non-null means a command word appearing on a line by
|
||||
itself is first looked for in the list of currently
|
||||
stopped jobs. If found there, that job is foregrounded.
|
||||
A value of `exact' means that the command word must
|
||||
exactly match a command in the list of stopped jobs. A
|
||||
value of `substring' means that the command word must
|
||||
match a substring of the job. Any other value means that
|
||||
the command must be a prefix of a stopped job.
|
||||
#if defined (HISTORY)
|
||||
# if defined (BANG_HISTORY)
|
||||
histchars Characters controlling history expansion and quick
|
||||
substitution. The first character is the history
|
||||
substitution character, usually `!'. The second is
|
||||
the `quick substitution' character, usually `^'. The
|
||||
third is the `history comment' character, usually `#'.
|
||||
# endif /* BANG_HISTORY */
|
||||
HISTIGNORE A colon-separated list of patterns used to decide which
|
||||
commands should be saved on the history list.
|
||||
#endif /* HISTORY */
|
||||
$END
|
||||
+8
-3
@@ -87,7 +87,7 @@ int
|
||||
trap_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int list_signal_names, display, result, opt;
|
||||
int list_signal_names, display, result, opt, first_signal;
|
||||
|
||||
list_signal_names = display = 0;
|
||||
result = EXECUTION_SUCCESS;
|
||||
@@ -118,14 +118,19 @@ trap_builtin (list)
|
||||
else
|
||||
{
|
||||
char *first_arg;
|
||||
int operation, sig;
|
||||
int operation, sig, first_signal;
|
||||
|
||||
operation = SET;
|
||||
first_arg = list->word->word;
|
||||
first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt);
|
||||
|
||||
/* Backwards compatibility */
|
||||
if (first_signal)
|
||||
operation = REVERT;
|
||||
/* When in posix mode, the historical behavior of looking for a
|
||||
missing first argument is disabled. To revert to the original
|
||||
signal handling disposition, use `-' as the first argument. */
|
||||
if (posixly_correct == 0 && first_arg && *first_arg &&
|
||||
else if (posixly_correct == 0 && first_arg && *first_arg &&
|
||||
(*first_arg != '-' || first_arg[1]) &&
|
||||
signal_object_p (first_arg, opt) && list->next == 0)
|
||||
operation = REVERT;
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
This file is trap.def, from which is created trap.c.
|
||||
It implements the builtin "trap" in Bash.
|
||||
|
||||
Copyright (C) 1987-2004 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES trap.c
|
||||
|
||||
$BUILTIN trap
|
||||
$FUNCTION trap_builtin
|
||||
$SHORT_DOC trap [-lp] [[arg] signal_spec ...]
|
||||
The command ARG is to be read and executed when the shell receives
|
||||
signal(s) SIGNAL_SPEC. If ARG is absent (and a single SIGNAL_SPEC
|
||||
is supplied) or `-', each specified signal is reset to its original
|
||||
value. If ARG is the null string each SIGNAL_SPEC is ignored by the
|
||||
shell and by the commands it invokes. If a SIGNAL_SPEC is EXIT (0)
|
||||
the command ARG is executed on exit from the shell. If a SIGNAL_SPEC
|
||||
is DEBUG, ARG is executed after every simple command. If the`-p' option
|
||||
is supplied then the trap commands associated with each SIGNAL_SPEC are
|
||||
displayed. If no arguments are supplied or if only `-p' is given, trap
|
||||
prints the list of commands associated with each signal. Each SIGNAL_SPEC
|
||||
is either a signal name in <signal.h> or a signal number. Signal names
|
||||
are case insensitive and the SIG prefix is optional. `trap -l' prints
|
||||
a list of signal names and their corresponding numbers. Note that a
|
||||
signal can be sent to the shell with "kill -signal $$".
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../bashtypes.h"
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include "../bashansi.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../trap.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
static void showtrap __P((int));
|
||||
static int display_traps __P((WORD_LIST *));
|
||||
|
||||
/* The trap command:
|
||||
|
||||
trap <arg> <signal ...>
|
||||
trap <signal ...>
|
||||
trap -l
|
||||
trap -p [sigspec ...]
|
||||
trap [--]
|
||||
|
||||
Set things up so that ARG is executed when SIGNAL(s) N is recieved.
|
||||
If ARG is the empty string, then ignore the SIGNAL(s). If there is
|
||||
no ARG, then set the trap for SIGNAL(s) to its original value. Just
|
||||
plain "trap" means to print out the list of commands associated with
|
||||
each signal number. Single arg of "-l" means list the signal names. */
|
||||
|
||||
/* Possible operations to perform on the list of signals.*/
|
||||
#define SET 0 /* Set this signal to first_arg. */
|
||||
#define REVERT 1 /* Revert to this signals original value. */
|
||||
#define IGNORE 2 /* Ignore this signal. */
|
||||
|
||||
extern int posixly_correct;
|
||||
|
||||
int
|
||||
trap_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int list_signal_names, display, result, opt, first_signal;
|
||||
|
||||
list_signal_names = display = 0;
|
||||
result = EXECUTION_SUCCESS;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "lp")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'l':
|
||||
list_signal_names++;
|
||||
break;
|
||||
case 'p':
|
||||
display++;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
opt = DSIG_NOCASE|DSIG_SIGPREFIX; /* flags for decode_signal */
|
||||
|
||||
if (list_signal_names)
|
||||
return (display_signal_list ((WORD_LIST *)NULL, 1));
|
||||
else if (display || list == 0)
|
||||
return (display_traps (list));
|
||||
else
|
||||
{
|
||||
char *first_arg;
|
||||
int operation, sig, first_signal;
|
||||
|
||||
operation = SET;
|
||||
first_arg = list->word->word;
|
||||
first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt);
|
||||
|
||||
/* When in posix mode, the historical behavior of looking for a
|
||||
missing first argument is disabled. To revert to the original
|
||||
signal handling disposition, use `-' as the first argument. */
|
||||
if (posixly_correct == 0 && first_arg && *first_arg &&
|
||||
(*first_arg != '-' || first_arg[1]) &&
|
||||
signal_object_p (first_arg, opt) && list->next == 0)
|
||||
operation = REVERT;
|
||||
else
|
||||
{
|
||||
list = list->next;
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else if (*first_arg == '\0')
|
||||
operation = IGNORE;
|
||||
else if (first_arg[0] == '-' && !first_arg[1])
|
||||
operation = REVERT;
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
sig = decode_signal (list->word->word, opt);
|
||||
|
||||
if (sig == NO_SIG)
|
||||
{
|
||||
sh_invalidsig (list->word->word);
|
||||
result = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case SET:
|
||||
set_signal (sig, first_arg);
|
||||
break;
|
||||
|
||||
case REVERT:
|
||||
restore_default_signal (sig);
|
||||
|
||||
/* Signals that the shell treats specially need special
|
||||
handling. */
|
||||
switch (sig)
|
||||
{
|
||||
case SIGINT:
|
||||
if (interactive)
|
||||
set_signal_handler (SIGINT, sigint_sighandler);
|
||||
else
|
||||
set_signal_handler (SIGINT, termination_unwind_protect);
|
||||
break;
|
||||
|
||||
case SIGQUIT:
|
||||
/* Always ignore SIGQUIT. */
|
||||
set_signal_handler (SIGQUIT, SIG_IGN);
|
||||
break;
|
||||
case SIGTERM:
|
||||
#if defined (JOB_CONTROL)
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
case SIGTSTP:
|
||||
#endif /* JOB_CONTROL */
|
||||
if (interactive)
|
||||
set_signal_handler (sig, SIG_IGN);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case IGNORE:
|
||||
ignore_signal (sig);
|
||||
break;
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
showtrap (i)
|
||||
int i;
|
||||
{
|
||||
char *t, *p, *sn;
|
||||
|
||||
p = trap_list[i];
|
||||
|
||||
if (p == (char *)DEFAULT_SIG)
|
||||
return;
|
||||
|
||||
t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p);
|
||||
sn = signal_name (i);
|
||||
/* Make sure that signals whose names are unknown (for whatever reason)
|
||||
are printed as signal numbers. */
|
||||
if (STREQN (sn, "SIGJUNK", 7) || STREQN (sn, "unknown", 7))
|
||||
printf ("trap -- %s %d\n", t ? t : "''", i);
|
||||
else if (posixly_correct)
|
||||
{
|
||||
if (STREQN (sn, "SIG", 3))
|
||||
printf ("trap -- %s %s\n", t ? t : "''", sn+3);
|
||||
else
|
||||
printf ("trap -- %s %s\n", t ? t : "''", sn);
|
||||
}
|
||||
else
|
||||
printf ("trap -- %s %s\n", t ? t : "''", sn);
|
||||
|
||||
FREE (t);
|
||||
}
|
||||
|
||||
static int
|
||||
display_traps (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int result, i;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
for (i = 0; i < BASH_NSIG; i++)
|
||||
showtrap (i);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
for (result = EXECUTION_SUCCESS; list; list = list->next)
|
||||
{
|
||||
i = decode_signal (list->word->word, DSIG_NOCASE|DSIG_SIGPREFIX);
|
||||
if (i == NO_SIG)
|
||||
{
|
||||
sh_invalidsig (list->word->word);
|
||||
result = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
showtrap (i);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
+10
-1
@@ -5953,7 +5953,8 @@ The @code{trap} builtin displays signal names without the leading
|
||||
@item
|
||||
The @code{trap} builtin doesn't check the first argument for a possible
|
||||
signal specification and revert the signal handling to the original
|
||||
disposition if it is. If users want to reset the handler for a given
|
||||
disposition if it is, unless that argument consists solely of digits and
|
||||
is a valid signal number. If users want to reset the handler for a given
|
||||
signal to the original disposition, they should use @samp{-} as the
|
||||
first argument.
|
||||
|
||||
@@ -5988,6 +5989,14 @@ When the @code{cd} builtin is invoked in @var{logical} mode, and the pathname
|
||||
constructed from @code{$PWD} and the directory name supplied as an argument
|
||||
does not refer to an existing directory, @code{cd} will fail instead of
|
||||
falling back to @var{physical} mode.
|
||||
|
||||
@item
|
||||
When listing the history, the @code{fc} builtin does not include an
|
||||
indication of whether or not a history entry has been modified.
|
||||
|
||||
@item
|
||||
The default editor used by @code{fc} is @code{ed}.
|
||||
|
||||
@end enumerate
|
||||
|
||||
There is other @sc{posix} 1003.2 behavior that Bash does not implement.
|
||||
|
||||
+7273
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -4,7 +4,7 @@ Copyright (C) 1988-2004 Free Software Foundation, Inc.
|
||||
|
||||
@set EDITION 3.0
|
||||
@set VERSION 3.0
|
||||
@set UPDATED 27 July 2004
|
||||
@set UPDATED-MONTH July 2004
|
||||
@set UPDATED 1 August 2004
|
||||
@set UPDATED-MONTH August 2004
|
||||
|
||||
@set LASTCHANGE Tue Jul 27 09:12:07 EDT 2004
|
||||
@set LASTCHANGE Sun Aug 1 14:48:46 EDT 2004
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
@ignore
|
||||
Copyright (C) 1988-2004 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set EDITION 3.0
|
||||
@set VERSION 3.0
|
||||
@set UPDATED 27 July 2004
|
||||
@set UPDATED-MONTH July 2004
|
||||
|
||||
@set LASTCHANGE Tue Jul 27 09:12:07 EDT 2004
|
||||
@@ -566,15 +566,20 @@ absolute_program (string)
|
||||
}
|
||||
|
||||
/* Return the `basename' of the pathname in STRING (the stuff after the
|
||||
last '/'). If STRING is not a full pathname, simply return it. */
|
||||
last '/'). If STRING is `/', just return it. */
|
||||
char *
|
||||
base_pathname (string)
|
||||
char *string;
|
||||
{
|
||||
char *p;
|
||||
|
||||
#if 0
|
||||
if (absolute_pathname (string) == 0)
|
||||
return (string);
|
||||
#endif
|
||||
|
||||
if (string[0] == '/' && string[1] == 0)
|
||||
return (string);
|
||||
|
||||
p = (char *)strrchr (string, '/');
|
||||
return (p ? ++p : string);
|
||||
|
||||
+964
@@ -0,0 +1,964 @@
|
||||
/* general.c -- Stuff that is used by all files. */
|
||||
|
||||
/* Copyright (C) 1987-2004 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#ifndef _MINIX
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
#include "posixstat.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "filecntl.h"
|
||||
#include "bashansi.h"
|
||||
#include <stdio.h>
|
||||
#include "chartypes.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "test.h"
|
||||
|
||||
#include <tilde/tilde.h>
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
extern int expand_aliases;
|
||||
extern int interrupt_immediately;
|
||||
extern int interactive_comments;
|
||||
extern int check_hashed_filenames;
|
||||
extern int source_uses_path;
|
||||
extern int source_searches_cwd;
|
||||
|
||||
static char *bash_special_tilde_expansions __P((char *));
|
||||
static int unquoted_tilde_word __P((const char *));
|
||||
static void initialize_group_array __P((void));
|
||||
|
||||
/* A standard error message to use when getcwd() returns NULL. */
|
||||
char *bash_getcwd_errstr = N_("getcwd: cannot access parent directories");
|
||||
|
||||
/* Do whatever is necessary to initialize `Posix mode'. */
|
||||
void
|
||||
posix_initialize (on)
|
||||
int on;
|
||||
{
|
||||
/* Things that should be turned on when posix mode is enabled. */
|
||||
if (on != 0)
|
||||
{
|
||||
interactive_comments = source_uses_path = expand_aliases = 1;
|
||||
}
|
||||
|
||||
/* Things that should be turned on when posix mode is disabled. */
|
||||
if (on == 0)
|
||||
{
|
||||
source_searches_cwd = 1;
|
||||
expand_aliases = interactive_shell;
|
||||
}
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Functions to convert to and from and display non-standard types */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
#if defined (RLIMTYPE)
|
||||
RLIMTYPE
|
||||
string_to_rlimtype (s)
|
||||
char *s;
|
||||
{
|
||||
RLIMTYPE ret;
|
||||
int neg;
|
||||
|
||||
ret = 0;
|
||||
neg = 0;
|
||||
while (s && *s && whitespace (*s))
|
||||
s++;
|
||||
if (*s == '-' || *s == '+')
|
||||
{
|
||||
neg = *s == '-';
|
||||
s++;
|
||||
}
|
||||
for ( ; s && *s && DIGIT (*s); s++)
|
||||
ret = (ret * 10) + TODIGIT (*s);
|
||||
return (neg ? -ret : ret);
|
||||
}
|
||||
|
||||
void
|
||||
print_rlimtype (n, addnl)
|
||||
RLIMTYPE n;
|
||||
int addnl;
|
||||
{
|
||||
char s[INT_STRLEN_BOUND (RLIMTYPE) + 1], *p;
|
||||
|
||||
p = s + sizeof(s);
|
||||
*--p = '\0';
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
do
|
||||
*--p = '0' - n % 10;
|
||||
while ((n /= 10) != 0);
|
||||
|
||||
*--p = '-';
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
*--p = '0' + n % 10;
|
||||
while ((n /= 10) != 0);
|
||||
}
|
||||
|
||||
printf ("%s%s", p, addnl ? "\n" : "");
|
||||
}
|
||||
#endif /* RLIMTYPE */
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Input Validation Functions */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Return non-zero if all of the characters in STRING are digits. */
|
||||
int
|
||||
all_digits (string)
|
||||
char *string;
|
||||
{
|
||||
register char *s;
|
||||
|
||||
for (s = string; *s; s++)
|
||||
if (DIGIT (*s) == 0)
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Return non-zero if the characters pointed to by STRING constitute a
|
||||
valid number. Stuff the converted number into RESULT if RESULT is
|
||||
not null. */
|
||||
int
|
||||
legal_number (string, result)
|
||||
char *string;
|
||||
intmax_t *result;
|
||||
{
|
||||
intmax_t value;
|
||||
char *ep;
|
||||
|
||||
if (result)
|
||||
*result = 0;
|
||||
|
||||
errno = 0;
|
||||
value = strtoimax (string, &ep, 10);
|
||||
if (errno)
|
||||
return 0; /* errno is set on overflow or underflow */
|
||||
|
||||
/* Skip any trailing whitespace, since strtoimax does not. */
|
||||
while (whitespace (*ep))
|
||||
ep++;
|
||||
|
||||
/* If *string is not '\0' but *ep is '\0' on return, the entire string
|
||||
is valid. */
|
||||
if (string && *string && *ep == '\0')
|
||||
{
|
||||
if (result)
|
||||
*result = value;
|
||||
/* The SunOS4 implementation of strtol() will happily ignore
|
||||
overflow conditions, so this cannot do overflow correctly
|
||||
on those systems. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Return 1 if this token is a legal shell `identifier'; that is, it consists
|
||||
solely of letters, digits, and underscores, and does not begin with a
|
||||
digit. */
|
||||
int
|
||||
legal_identifier (name)
|
||||
char *name;
|
||||
{
|
||||
register char *s;
|
||||
unsigned char c;
|
||||
|
||||
if (!name || !(c = *name) || (legal_variable_starter (c) == 0))
|
||||
return (0);
|
||||
|
||||
for (s = name + 1; (c = *s) != 0; s++)
|
||||
{
|
||||
if (legal_variable_char (c) == 0)
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Make sure that WORD is a valid shell identifier, i.e.
|
||||
does not contain a dollar sign, nor is quoted in any way. Nor
|
||||
does it consist of all digits. If CHECK_WORD is non-zero,
|
||||
the word is checked to ensure that it consists of only letters,
|
||||
digits, and underscores. */
|
||||
int
|
||||
check_identifier (word, check_word)
|
||||
WORD_DESC *word;
|
||||
int check_word;
|
||||
{
|
||||
if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word))
|
||||
{
|
||||
internal_error (_("`%s': not a valid identifier"), word->word);
|
||||
return (0);
|
||||
}
|
||||
else if (check_word && legal_identifier (word->word) == 0)
|
||||
{
|
||||
internal_error (_("`%s': not a valid identifier"), word->word);
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Return 1 if STRING comprises a valid alias name. The shell accepts
|
||||
essentially all characters except those which must be quoted to the
|
||||
parser (which disqualifies them from alias expansion anyway) and `/'. */
|
||||
int
|
||||
legal_alias_name (string, flags)
|
||||
char *string;
|
||||
int flags;
|
||||
{
|
||||
register char *s;
|
||||
|
||||
for (s = string; *s; s++)
|
||||
if (shellbreak (*s) || shellxquote (*s) || shellexp (*s) || (*s == '/'))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Returns non-zero if STRING is an assignment statement. The returned value
|
||||
is the index of the `=' sign. */
|
||||
int
|
||||
assignment (string, flags)
|
||||
const char *string;
|
||||
int flags;
|
||||
{
|
||||
register unsigned char c;
|
||||
register int newi, indx;
|
||||
|
||||
c = string[indx = 0];
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if ((legal_variable_starter (c) == 0) && (flags && c != '[')) /* ] */
|
||||
#else
|
||||
if (legal_variable_starter (c) == 0)
|
||||
#endif
|
||||
return (0);
|
||||
|
||||
while (c = string[indx])
|
||||
{
|
||||
/* The following is safe. Note that '=' at the start of a word
|
||||
is not an assignment statement. */
|
||||
if (c == '=')
|
||||
return (indx);
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (c == '[')
|
||||
{
|
||||
newi = skipsubscript (string, indx);
|
||||
if (string[newi++] != ']')
|
||||
return (0);
|
||||
return ((string[newi] == '=') ? newi : 0);
|
||||
}
|
||||
#endif /* ARRAY_VARS */
|
||||
|
||||
/* Variable names in assignment statements may contain only letters,
|
||||
digits, and `_'. */
|
||||
if (legal_variable_char (c) == 0)
|
||||
return (0);
|
||||
|
||||
indx++;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Functions to manage files and file descriptors */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* A function to unset no-delay mode on a file descriptor. Used in shell.c
|
||||
to unset it on the fd passed as stdin. Should be called on stdin if
|
||||
readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */
|
||||
|
||||
#if !defined (O_NDELAY)
|
||||
# if defined (FNDELAY)
|
||||
# define O_NDELAY FNDELAY
|
||||
# endif
|
||||
#endif /* O_NDELAY */
|
||||
|
||||
/* Make sure no-delay mode is not set on file descriptor FD. */
|
||||
int
|
||||
sh_unset_nodelay_mode (fd)
|
||||
int fd;
|
||||
{
|
||||
int flags, bflags;
|
||||
|
||||
if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
|
||||
return -1;
|
||||
|
||||
bflags = 0;
|
||||
|
||||
/* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present
|
||||
and O_NDELAY is defined. */
|
||||
#ifdef O_NONBLOCK
|
||||
bflags |= O_NONBLOCK;
|
||||
#endif
|
||||
|
||||
#ifdef O_NDELAY
|
||||
bflags |= O_NDELAY;
|
||||
#endif
|
||||
|
||||
if (flags & bflags)
|
||||
{
|
||||
flags &= ~bflags;
|
||||
return (fcntl (fd, F_SETFL, flags));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return 1 if file descriptor FD is valid; 0 otherwise. */
|
||||
int
|
||||
sh_validfd (fd)
|
||||
int fd;
|
||||
{
|
||||
return (fcntl (fd, F_GETFD, 0) >= 0);
|
||||
}
|
||||
|
||||
/* There is a bug in the NeXT 2.1 rlogind that causes opens
|
||||
of /dev/tty to fail. */
|
||||
|
||||
#if defined (__BEOS__)
|
||||
/* On BeOS, opening in non-blocking mode exposes a bug in BeOS, so turn it
|
||||
into a no-op. This should probably go away in the future. */
|
||||
# undef O_NONBLOCK
|
||||
# define O_NONBLOCK 0
|
||||
#endif /* __BEOS__ */
|
||||
|
||||
void
|
||||
check_dev_tty ()
|
||||
{
|
||||
int tty_fd;
|
||||
char *tty;
|
||||
|
||||
tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK);
|
||||
|
||||
if (tty_fd < 0)
|
||||
{
|
||||
tty = (char *)ttyname (fileno (stdin));
|
||||
if (tty == 0)
|
||||
return;
|
||||
tty_fd = open (tty, O_RDWR|O_NONBLOCK);
|
||||
}
|
||||
close (tty_fd);
|
||||
}
|
||||
|
||||
/* Return 1 if PATH1 and PATH2 are the same file. This is kind of
|
||||
expensive. If non-NULL STP1 and STP2 point to stat structures
|
||||
corresponding to PATH1 and PATH2, respectively. */
|
||||
int
|
||||
same_file (path1, path2, stp1, stp2)
|
||||
char *path1, *path2;
|
||||
struct stat *stp1, *stp2;
|
||||
{
|
||||
struct stat st1, st2;
|
||||
|
||||
if (stp1 == NULL)
|
||||
{
|
||||
if (stat (path1, &st1) != 0)
|
||||
return (0);
|
||||
stp1 = &st1;
|
||||
}
|
||||
|
||||
if (stp2 == NULL)
|
||||
{
|
||||
if (stat (path2, &st2) != 0)
|
||||
return (0);
|
||||
stp2 = &st2;
|
||||
}
|
||||
|
||||
return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino));
|
||||
}
|
||||
|
||||
/* Move FD to a number close to the maximum number of file descriptors
|
||||
allowed in the shell process, to avoid the user stepping on it with
|
||||
redirection and causing us extra work. If CHECK_NEW is non-zero,
|
||||
we check whether or not the file descriptors are in use before
|
||||
duplicating FD onto them. MAXFD says where to start checking the
|
||||
file descriptors. If it's less than 20, we get the maximum value
|
||||
available from getdtablesize(2). */
|
||||
int
|
||||
move_to_high_fd (fd, check_new, maxfd)
|
||||
int fd, check_new, maxfd;
|
||||
{
|
||||
int script_fd, nfds, ignore;
|
||||
|
||||
if (maxfd < 20)
|
||||
{
|
||||
nfds = getdtablesize ();
|
||||
if (nfds <= 0)
|
||||
nfds = 20;
|
||||
if (nfds > HIGH_FD_MAX)
|
||||
nfds = HIGH_FD_MAX; /* reasonable maximum */
|
||||
}
|
||||
else
|
||||
nfds = maxfd;
|
||||
|
||||
for (nfds--; check_new && nfds > 3; nfds--)
|
||||
if (fcntl (nfds, F_GETFD, &ignore) == -1)
|
||||
break;
|
||||
|
||||
if (nfds > 3 && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
|
||||
{
|
||||
if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */
|
||||
close (fd);
|
||||
return (script_fd);
|
||||
}
|
||||
|
||||
/* OK, we didn't find one less than our artificial maximum; return the
|
||||
original file descriptor. */
|
||||
return (fd);
|
||||
}
|
||||
|
||||
/* Return non-zero if the characters from SAMPLE are not all valid
|
||||
characters to be found in the first line of a shell script. We
|
||||
check up to the first newline, or SAMPLE_LEN, whichever comes first.
|
||||
All of the characters must be printable or whitespace. */
|
||||
|
||||
int
|
||||
check_binary_file (sample, sample_len)
|
||||
char *sample;
|
||||
int sample_len;
|
||||
{
|
||||
register int i;
|
||||
unsigned char c;
|
||||
|
||||
for (i = 0; i < sample_len; i++)
|
||||
{
|
||||
c = sample[i];
|
||||
if (c == '\n')
|
||||
return (0);
|
||||
|
||||
if (ISSPACE (c) == 0 && ISPRINT (c) == 0)
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Functions to inspect pathnames */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
int
|
||||
file_isdir (fn)
|
||||
char *fn;
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
return ((stat (fn, &sb) == 0) && S_ISDIR (sb.st_mode));
|
||||
}
|
||||
|
||||
int
|
||||
file_iswdir (fn)
|
||||
char *fn;
|
||||
{
|
||||
return (file_isdir (fn) && test_eaccess (fn, W_OK) == 0);
|
||||
}
|
||||
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Functions to manipulate pathnames */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Turn STRING (a pathname) into an absolute pathname, assuming that
|
||||
DOT_PATH contains the symbolic location of `.'. This always
|
||||
returns a new string, even if STRING was an absolute pathname to
|
||||
begin with. */
|
||||
char *
|
||||
make_absolute (string, dot_path)
|
||||
char *string, *dot_path;
|
||||
{
|
||||
char *result;
|
||||
|
||||
if (dot_path == 0 || ABSPATH(string))
|
||||
#ifdef __CYGWIN__
|
||||
{
|
||||
char pathbuf[PATH_MAX + 1];
|
||||
|
||||
cygwin_conv_to_full_posix_path (string, pathbuf);
|
||||
result = savestring (pathbuf);
|
||||
}
|
||||
#else
|
||||
result = savestring (string);
|
||||
#endif
|
||||
else
|
||||
result = sh_makepath (dot_path, string, 0);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Return 1 if STRING contains an absolute pathname, else 0. Used by `cd'
|
||||
to decide whether or not to look up a directory name in $CDPATH. */
|
||||
int
|
||||
absolute_pathname (string)
|
||||
const char *string;
|
||||
{
|
||||
if (string == 0 || *string == '\0')
|
||||
return (0);
|
||||
|
||||
if (ABSPATH(string))
|
||||
return (1);
|
||||
|
||||
if (string[0] == '.' && PATHSEP(string[1])) /* . and ./ */
|
||||
return (1);
|
||||
|
||||
if (string[0] == '.' && string[1] == '.' && PATHSEP(string[2])) /* .. and ../ */
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Return 1 if STRING is an absolute program name; it is absolute if it
|
||||
contains any slashes. This is used to decide whether or not to look
|
||||
up through $PATH. */
|
||||
int
|
||||
absolute_program (string)
|
||||
const char *string;
|
||||
{
|
||||
return ((char *)xstrchr (string, '/') != (char *)NULL);
|
||||
}
|
||||
|
||||
/* Return the `basename' of the pathname in STRING (the stuff after the
|
||||
last '/'). If STRING is `/', just return it. */
|
||||
char *
|
||||
base_pathname (string)
|
||||
char *string;
|
||||
{
|
||||
char *p;
|
||||
|
||||
#if 0
|
||||
if (absolute_pathname (string) == 0)
|
||||
return (string);
|
||||
#endif
|
||||
if (string[0] == '/' && string[1] == 0)
|
||||
return (string);
|
||||
|
||||
p = (char *)strrchr (string, '/');
|
||||
return (p ? ++p : string);
|
||||
}
|
||||
|
||||
/* Return the full pathname of FILE. Easy. Filenames that begin
|
||||
with a '/' are returned as themselves. Other filenames have
|
||||
the current working directory prepended. A new string is
|
||||
returned in either case. */
|
||||
char *
|
||||
full_pathname (file)
|
||||
char *file;
|
||||
{
|
||||
char *ret;
|
||||
|
||||
file = (*file == '~') ? bash_tilde_expand (file, 0) : savestring (file);
|
||||
|
||||
if (ABSPATH(file))
|
||||
return (file);
|
||||
|
||||
ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT));
|
||||
free (file);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* A slightly related function. Get the prettiest name of this
|
||||
directory possible. */
|
||||
static char tdir[PATH_MAX];
|
||||
|
||||
/* Return a pretty pathname. If the first part of the pathname is
|
||||
the same as $HOME, then replace that with `~'. */
|
||||
char *
|
||||
polite_directory_format (name)
|
||||
char *name;
|
||||
{
|
||||
char *home;
|
||||
int l;
|
||||
|
||||
home = get_string_value ("HOME");
|
||||
l = home ? strlen (home) : 0;
|
||||
if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
|
||||
{
|
||||
strncpy (tdir + 1, name + l, sizeof(tdir) - 2);
|
||||
tdir[0] = '~';
|
||||
tdir[sizeof(tdir) - 1] = '\0';
|
||||
return (tdir);
|
||||
}
|
||||
else
|
||||
return (name);
|
||||
}
|
||||
|
||||
/* Given a string containing units of information separated by colons,
|
||||
return the next one pointed to by (P_INDEX), or NULL if there are no more.
|
||||
Advance (P_INDEX) to the character after the colon. */
|
||||
char *
|
||||
extract_colon_unit (string, p_index)
|
||||
char *string;
|
||||
int *p_index;
|
||||
{
|
||||
int i, start, len;
|
||||
char *value;
|
||||
|
||||
if (string == 0)
|
||||
return (string);
|
||||
|
||||
len = strlen (string);
|
||||
if (*p_index >= len)
|
||||
return ((char *)NULL);
|
||||
|
||||
i = *p_index;
|
||||
|
||||
/* Each call to this routine leaves the index pointing at a colon if
|
||||
there is more to the path. If I is > 0, then increment past the
|
||||
`:'. If I is 0, then the path has a leading colon. Trailing colons
|
||||
are handled OK by the `else' part of the if statement; an empty
|
||||
string is returned in that case. */
|
||||
if (i && string[i] == ':')
|
||||
i++;
|
||||
|
||||
for (start = i; string[i] && string[i] != ':'; i++)
|
||||
;
|
||||
|
||||
*p_index = i;
|
||||
|
||||
if (i == start)
|
||||
{
|
||||
if (string[i])
|
||||
(*p_index)++;
|
||||
/* Return "" in the case of a trailing `:'. */
|
||||
value = (char *)xmalloc (1);
|
||||
value[0] = '\0';
|
||||
}
|
||||
else
|
||||
value = substring (string, start, i);
|
||||
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Tilde Initialization and Expansion */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
#if defined (PUSHD_AND_POPD)
|
||||
extern char *get_dirstack_from_string __P((char *));
|
||||
#endif
|
||||
|
||||
static char **bash_tilde_prefixes;
|
||||
static char **bash_tilde_suffixes;
|
||||
|
||||
/* If tilde_expand hasn't been able to expand the text, perhaps it
|
||||
is a special shell expansion. This function is installed as the
|
||||
tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+.
|
||||
If PUSHD_AND_POPD is defined, ~[+-]N expands to directories from the
|
||||
directory stack. */
|
||||
static char *
|
||||
bash_special_tilde_expansions (text)
|
||||
char *text;
|
||||
{
|
||||
char *result;
|
||||
|
||||
result = (char *)NULL;
|
||||
|
||||
if (text[0] == '+' && text[1] == '\0')
|
||||
result = get_string_value ("PWD");
|
||||
else if (text[0] == '-' && text[1] == '\0')
|
||||
result = get_string_value ("OLDPWD");
|
||||
#if defined (PUSHD_AND_POPD)
|
||||
else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1])))
|
||||
result = get_dirstack_from_string (text);
|
||||
#endif
|
||||
|
||||
return (result ? savestring (result) : (char *)NULL);
|
||||
}
|
||||
|
||||
/* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as
|
||||
well as handling special tilde prefixes; `:~" and `=~' are indications
|
||||
that we should do tilde expansion. */
|
||||
void
|
||||
tilde_initialize ()
|
||||
{
|
||||
static int times_called = 0;
|
||||
|
||||
/* Tell the tilde expander that we want a crack first. */
|
||||
tilde_expansion_preexpansion_hook = bash_special_tilde_expansions;
|
||||
|
||||
/* Tell the tilde expander about special strings which start a tilde
|
||||
expansion, and the special strings that end one. Only do this once.
|
||||
tilde_initialize () is called from within bashline_reinitialize (). */
|
||||
if (times_called++ == 0)
|
||||
{
|
||||
bash_tilde_prefixes = strvec_create (3);
|
||||
bash_tilde_prefixes[0] = "=~";
|
||||
bash_tilde_prefixes[1] = ":~";
|
||||
bash_tilde_prefixes[2] = (char *)NULL;
|
||||
|
||||
tilde_additional_prefixes = bash_tilde_prefixes;
|
||||
|
||||
bash_tilde_suffixes = strvec_create (3);
|
||||
bash_tilde_suffixes[0] = ":";
|
||||
bash_tilde_suffixes[1] = "=~"; /* XXX - ?? */
|
||||
bash_tilde_suffixes[2] = (char *)NULL;
|
||||
|
||||
tilde_additional_suffixes = bash_tilde_suffixes;
|
||||
}
|
||||
}
|
||||
|
||||
/* POSIX.2, 3.6.1: A tilde-prefix consists of an unquoted tilde character
|
||||
at the beginning of the word, followed by all of the characters preceding
|
||||
the first unquoted slash in the word, or all the characters in the word
|
||||
if there is no slash...If none of the characters in the tilde-prefix are
|
||||
quoted, the characters in the tilde-prefix following the tilde shell be
|
||||
treated as a possible login name. */
|
||||
|
||||
#define TILDE_END(c) ((c) == '\0' || (c) == '/' || (c) == ':')
|
||||
|
||||
static int
|
||||
unquoted_tilde_word (s)
|
||||
const char *s;
|
||||
{
|
||||
const char *r;
|
||||
|
||||
for (r = s; TILDE_END(*r) == 0; r++)
|
||||
{
|
||||
switch (*r)
|
||||
{
|
||||
case '\\':
|
||||
case '\'':
|
||||
case '"':
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Tilde-expand S by running it through the tilde expansion library.
|
||||
ASSIGN_P is 1 if this is a variable assignment, so the alternate
|
||||
tilde prefixes should be enabled (`=~' and `:~', see above). */
|
||||
char *
|
||||
bash_tilde_expand (s, assign_p)
|
||||
const char *s;
|
||||
int assign_p;
|
||||
{
|
||||
int old_immed, r;
|
||||
char *ret;
|
||||
|
||||
old_immed = interrupt_immediately;
|
||||
interrupt_immediately = 1;
|
||||
tilde_additional_prefixes = assign_p ? bash_tilde_prefixes : (char **)0;
|
||||
r = (*s == '~') ? unquoted_tilde_word (s) : 1;
|
||||
ret = r ? tilde_expand (s) : savestring (s);
|
||||
interrupt_immediately = old_immed;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Functions to manipulate and search the group list */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
static int ngroups, maxgroups;
|
||||
|
||||
/* The set of groups that this user is a member of. */
|
||||
static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
|
||||
|
||||
#if !defined (NOGROUP)
|
||||
# define NOGROUP (gid_t) -1
|
||||
#endif
|
||||
|
||||
static void
|
||||
initialize_group_array ()
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (maxgroups == 0)
|
||||
maxgroups = getmaxgroups ();
|
||||
|
||||
ngroups = 0;
|
||||
group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
|
||||
|
||||
#if defined (HAVE_GETGROUPS)
|
||||
ngroups = getgroups (maxgroups, group_array);
|
||||
#endif
|
||||
|
||||
/* If getgroups returns nothing, or the OS does not support getgroups(),
|
||||
make sure the groups array includes at least the current gid. */
|
||||
if (ngroups == 0)
|
||||
{
|
||||
group_array[0] = current_user.gid;
|
||||
ngroups = 1;
|
||||
}
|
||||
|
||||
/* If the primary group is not in the groups array, add it as group_array[0]
|
||||
and shuffle everything else up 1, if there's room. */
|
||||
for (i = 0; i < ngroups; i++)
|
||||
if (current_user.gid == (gid_t)group_array[i])
|
||||
break;
|
||||
if (i == ngroups && ngroups < maxgroups)
|
||||
{
|
||||
for (i = ngroups; i > 0; i--)
|
||||
group_array[i] = group_array[i - 1];
|
||||
group_array[0] = current_user.gid;
|
||||
ngroups++;
|
||||
}
|
||||
|
||||
/* If the primary group is not group_array[0], swap group_array[0] and
|
||||
whatever the current group is. The vast majority of systems should
|
||||
not need this; a notable exception is Linux. */
|
||||
if (group_array[0] != current_user.gid)
|
||||
{
|
||||
for (i = 0; i < ngroups; i++)
|
||||
if (group_array[i] == current_user.gid)
|
||||
break;
|
||||
if (i < ngroups)
|
||||
{
|
||||
group_array[i] = group_array[0];
|
||||
group_array[0] = current_user.gid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return non-zero if GID is one that we have in our groups list. */
|
||||
int
|
||||
#if defined (__STDC__) || defined ( _MINIX)
|
||||
group_member (gid_t gid)
|
||||
#else
|
||||
group_member (gid)
|
||||
gid_t gid;
|
||||
#endif /* !__STDC__ && !_MINIX */
|
||||
{
|
||||
#if defined (HAVE_GETGROUPS)
|
||||
register int i;
|
||||
#endif
|
||||
|
||||
/* Short-circuit if possible, maybe saving a call to getgroups(). */
|
||||
if (gid == current_user.gid || gid == current_user.egid)
|
||||
return (1);
|
||||
|
||||
#if defined (HAVE_GETGROUPS)
|
||||
if (ngroups == 0)
|
||||
initialize_group_array ();
|
||||
|
||||
/* In case of error, the user loses. */
|
||||
if (ngroups <= 0)
|
||||
return (0);
|
||||
|
||||
/* Search through the list looking for GID. */
|
||||
for (i = 0; i < ngroups; i++)
|
||||
if (gid == (gid_t)group_array[i])
|
||||
return (1);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
char **
|
||||
get_group_list (ngp)
|
||||
int *ngp;
|
||||
{
|
||||
static char **group_vector = (char **)NULL;
|
||||
register int i;
|
||||
|
||||
if (group_vector)
|
||||
{
|
||||
if (ngp)
|
||||
*ngp = ngroups;
|
||||
return group_vector;
|
||||
}
|
||||
|
||||
if (ngroups == 0)
|
||||
initialize_group_array ();
|
||||
|
||||
if (ngroups <= 0)
|
||||
{
|
||||
if (ngp)
|
||||
*ngp = 0;
|
||||
return (char **)NULL;
|
||||
}
|
||||
|
||||
group_vector = strvec_create (ngroups);
|
||||
for (i = 0; i < ngroups; i++)
|
||||
group_vector[i] = itos (group_array[i]);
|
||||
|
||||
if (ngp)
|
||||
*ngp = ngroups;
|
||||
return group_vector;
|
||||
}
|
||||
|
||||
int *
|
||||
get_group_array (ngp)
|
||||
int *ngp;
|
||||
{
|
||||
int i;
|
||||
static int *group_iarray = (int *)NULL;
|
||||
|
||||
if (group_iarray)
|
||||
{
|
||||
if (ngp)
|
||||
*ngp = ngroups;
|
||||
return (group_iarray);
|
||||
}
|
||||
|
||||
if (ngroups == 0)
|
||||
initialize_group_array ();
|
||||
|
||||
if (ngroups <= 0)
|
||||
{
|
||||
if (ngp)
|
||||
*ngp = 0;
|
||||
return (int *)NULL;
|
||||
}
|
||||
|
||||
group_iarray = (int *)xmalloc (ngroups * sizeof (int));
|
||||
for (i = 0; i < ngroups; i++)
|
||||
group_iarray[i] = (int)group_array[i];
|
||||
|
||||
if (ngp)
|
||||
*ngp = ngroups;
|
||||
return group_iarray;
|
||||
}
|
||||
@@ -31,6 +31,8 @@
|
||||
extern size_t xmbsrtowcs __P((wchar_t *, const char **, size_t, mbstate_t *));
|
||||
extern size_t xdupmbstowcs __P((wchar_t **, char ***, const char *));
|
||||
|
||||
extern size_t mbstrlen __P((const char *));
|
||||
|
||||
extern char *xstrchr __P((const char *, int));
|
||||
|
||||
#ifndef MB_INVALIDCH
|
||||
@@ -38,6 +40,8 @@ extern char *xstrchr __P((const char *, int));
|
||||
#define MB_NULLWCH(x) ((x) == 0)
|
||||
#endif
|
||||
|
||||
#define MB_STRLEN(s) ((MB_CUR_MAX > 1) ? mbstrlen (s) : STRLEN (s))
|
||||
|
||||
#else /* !HANDLE_MULTIBYTE */
|
||||
|
||||
#undef MB_LEN_MAX
|
||||
@@ -54,6 +58,8 @@ extern char *xstrchr __P((const char *, int));
|
||||
#define MB_NULLWCH(x) (0)
|
||||
#endif
|
||||
|
||||
#define MB_STRLEN(s) (STRLEN(s))
|
||||
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Declare and initialize a multibyte state. Call must be terminated
|
||||
|
||||
@@ -0,0 +1,438 @@
|
||||
/* shmbutil.h -- utility functions for multibyte characters. */
|
||||
|
||||
/* Copyright (C) 2002-2004 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#if !defined (_SH_MBUTIL_H_)
|
||||
#define _SH_MBUTIL_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
/* Include config.h for HANDLE_MULTIBYTE */
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
|
||||
extern size_t xmbsrtowcs __P((wchar_t *, const char **, size_t, mbstate_t *));
|
||||
extern size_t xdupmbstowcs __P((wchar_t **, char ***, const char *));
|
||||
|
||||
extern size_t mbstrlen __P((const char *));
|
||||
|
||||
extern char *xstrchr __P((const char *, int));
|
||||
|
||||
#ifndef MB_INVALIDCH
|
||||
#define MB_INVALIDCH(x) ((x) == (size_t)-1 || (x) == (size_t)-2)
|
||||
#define MB_NULLWCH(x) ((x) == 0)
|
||||
#endif
|
||||
|
||||
#define MB_STRLEN(s) ((MB_CUR_MAX > 1) ? mb_strlen (s) : STRLEN (s))
|
||||
|
||||
#else /* !HANDLE_MULTIBYTE */
|
||||
|
||||
#undef MB_LEN_MAX
|
||||
#undef MB_CUR_MAX
|
||||
|
||||
#define MB_LEN_MAX 1
|
||||
#define MB_CUR_MAX 1
|
||||
|
||||
#undef xstrchr
|
||||
#define xstrchr(s, c) strchr(s, c)
|
||||
|
||||
#ifndef MB_INVALIDCH
|
||||
#define MB_INVALIDCH(x) (0)
|
||||
#define MB_NULLWCH(x) (0)
|
||||
#endif
|
||||
|
||||
#define MB_STRLEN(s) (STRLEN(s))
|
||||
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Declare and initialize a multibyte state. Call must be terminated
|
||||
with `;'. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define DECLARE_MBSTATE \
|
||||
mbstate_t state; \
|
||||
memset (&state, '\0', sizeof (mbstate_t))
|
||||
#else
|
||||
# define DECLARE_MBSTATE
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Initialize or reinitialize a multibyte state named `state'. Call must be
|
||||
terminated with `;'. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define INITIALIZE_MBSTATE memset (&state, '\0', sizeof (mbstate_t))
|
||||
#else
|
||||
# define INITIALIZE_MBSTATE
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Advance one (possibly multi-byte) character in string _STR of length
|
||||
_STRSIZE, starting at index _I. STATE must have already been declared. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define ADVANCE_CHAR(_str, _strsize, _i) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_str) + (_i), (_strsize) - (_i), &state); \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
(_i)++; \
|
||||
} \
|
||||
else if (mblength == 0) \
|
||||
(_i)++; \
|
||||
else \
|
||||
(_i) += mblength; \
|
||||
} \
|
||||
else \
|
||||
(_i)++; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define ADVANCE_CHAR(_str, _strsize, _i) (_i)++
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Advance one (possibly multibyte) character in the string _STR of length
|
||||
_STRSIZE.
|
||||
SPECIAL: assume that _STR will be incremented by 1 after this call. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define ADVANCE_CHAR_P(_str, _strsize) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_str), (_strsize), &state); \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
(_str) += (mblength < 1) ? 0 : (mblength - 1); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define ADVANCE_CHAR_P(_str, _strsize)
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Back up one (possibly multi-byte) character in string _STR of length
|
||||
_STRSIZE, starting at index _I. STATE must have already been declared. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define BACKUP_CHAR(_str, _strsize, _i) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _x, _p; /* _x == temp index into string, _p == prev index */ \
|
||||
\
|
||||
_x = _p = 0; \
|
||||
while (_x < (_i)) \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_str) + (_x), (_strsize) - (_x), &state); \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
_x++; \
|
||||
} \
|
||||
else if (mblength == 0) \
|
||||
_x++; \
|
||||
else \
|
||||
{ \
|
||||
_p = _x; /* _p == start of prev mbchar */ \
|
||||
_x += mblength; \
|
||||
} \
|
||||
} \
|
||||
(_i) = _p; \
|
||||
} \
|
||||
else \
|
||||
(_i)--; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define BACKUP_CHAR(_str, _strsize, _i) (_i)--
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Back up one (possibly multibyte) character in the string _BASE of length
|
||||
_STRSIZE starting at _STR (_BASE <= _STR <= (_BASE + _STRSIZE) ).
|
||||
SPECIAL: DO NOT assume that _STR will be decremented by 1 after this call. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define BACKUP_CHAR_P(_base, _strsize, _str) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
char *_x, _p; /* _x == temp pointer into string, _p == prev pointer */ \
|
||||
\
|
||||
_x = _p = _base; \
|
||||
while (_x < (_str)) \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen (_x, (_strsize) - _x, &state); \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
_x++; \
|
||||
} \
|
||||
else if (mblength == 0) \
|
||||
_x++; \
|
||||
else \
|
||||
{ \
|
||||
_p = _x; /* _p == start of prev mbchar */ \
|
||||
_x += mblength; \
|
||||
} \
|
||||
} \
|
||||
(_str) = _p; \
|
||||
} \
|
||||
else \
|
||||
(_str)--; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define BACKUP_CHAR_P(_base, _strsize, _str) (_str)--
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Copy a single character from the string _SRC to the string _DST.
|
||||
_SRCEND is a pointer to the end of _SRC. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define COPY_CHAR_P(_dst, _src, _srcend) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _k; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src), (_srcend) - (_src), &state); \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
mblength = (mblength < 1) ? 1 : mblength; \
|
||||
\
|
||||
for (_k = 0; _k < mblength; _k++) \
|
||||
*(_dst)++ = *(_src)++; \
|
||||
} \
|
||||
else \
|
||||
*(_dst)++ = *(_src)++; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define COPY_CHAR_P(_dst, _src, _srcend) *(_dst)++ = *(_src)++
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Copy a single character from the string _SRC at index _SI to the string
|
||||
_DST at index _DI. _SRCEND is a pointer to the end of _SRC. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define COPY_CHAR_I(_dst, _di, _src, _srcend, _si) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _k; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src)+(_si)), &state); \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
mblength = (mblength < 1) ? 1 : mblength; \
|
||||
\
|
||||
for (_k = 0; _k < mblength; _k++) \
|
||||
_dst[_di++] = _src[_si++]; \
|
||||
} \
|
||||
else \
|
||||
_dst[_di++] = _src[_si++]; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define COPY_CHAR_I(_dst, _di, _src, _srcend, _si) _dst[_di++] = _src[_si++]
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/****************************************************************
|
||||
* *
|
||||
* The following are only guaranteed to work in subst.c *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define SCOPY_CHAR_I(_dst, _escchar, _sc, _src, _si, _slen) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _i; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_slen) - (_si), &state); \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
mblength = (mblength < 1) ? 1 : mblength; \
|
||||
\
|
||||
temp = xmalloc (mblength + 2); \
|
||||
temp[0] = _escchar; \
|
||||
for (_i = 0; _i < mblength; _i++) \
|
||||
temp[_i + 1] = _src[_si++]; \
|
||||
temp[mblength + 1] = '\0'; \
|
||||
\
|
||||
goto add_string; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
_dst[0] = _escchar; \
|
||||
_dst[1] = _sc; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define SCOPY_CHAR_I(_dst, _escchar, _sc, _src, _si, _slen) \
|
||||
_dst[0] = _escchar; \
|
||||
_dst[1] = _sc
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define SCOPY_CHAR_M(_dst, _src, _srcend, _si) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src) + (_si)), &state); \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
mblength = (mblength < 1) ? 1 : mblength; \
|
||||
\
|
||||
FASTCOPY(((_src) + (_si)), (_dst), mblength); \
|
||||
\
|
||||
(_dst) += mblength; \
|
||||
(_si) += mblength; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
*(_dst)++ = _src[(_si)]; \
|
||||
(_si)++; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define SCOPY_CHAR_M(_dst, _src, _srcend, _si) \
|
||||
*(_dst)++ = _src[(_si)]; \
|
||||
(_si)++
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
#if HANDLE_MULTIBYTE
|
||||
# define SADD_MBCHAR(_dst, _src, _si, _srcsize) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
{ \
|
||||
int i; \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \
|
||||
if (mblength == (size_t)-1 || mblength == (size_t)-2) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
if (mblength < 1) \
|
||||
mblength = 1; \
|
||||
\
|
||||
_dst = (char *)xmalloc (mblength + 1); \
|
||||
for (i = 0; i < mblength; i++) \
|
||||
(_dst)[i] = (_src)[(_si)++]; \
|
||||
(_dst)[mblength] = '\0'; \
|
||||
\
|
||||
goto add_string; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#else
|
||||
# define SADD_MBCHAR(_dst, _src, _si, _srcsize)
|
||||
#endif
|
||||
|
||||
/* Watch out when using this -- it's just straight textual subsitution */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define SADD_MBQCHAR_BODY(_dst, _src, _si, _srcsize) \
|
||||
\
|
||||
int i; \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \
|
||||
if (mblength == (size_t)-1 || mblength == (size_t)-2) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
if (mblength < 1) \
|
||||
mblength = 1; \
|
||||
\
|
||||
(_dst) = (char *)xmalloc (mblength + 2); \
|
||||
(_dst)[0] = CTLESC; \
|
||||
for (i = 0; i < mblength; i++) \
|
||||
(_dst)[i+1] = (_src)[(_si)++]; \
|
||||
(_dst)[mblength+1] = '\0'; \
|
||||
\
|
||||
goto add_string
|
||||
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
#endif /* _SH_MBUTIL_H_ */
|
||||
@@ -997,7 +997,7 @@ describe_pid (pid)
|
||||
job = find_job (pid, 0);
|
||||
|
||||
if (job != NO_JOB)
|
||||
printf ("[%d] %ld\n", job + 1, (long)pid);
|
||||
fprintf (stderr, "[%d] %ld\n", job + 1, (long)pid);
|
||||
else
|
||||
programming_error (_("describe_pid: %ld: no such pid"), (long)pid);
|
||||
|
||||
@@ -2311,12 +2311,12 @@ start_job (job, foreground)
|
||||
p = jobs[job]->pipe;
|
||||
|
||||
if (foreground == 0)
|
||||
fprintf (stderr, "[%d]%c ", job + 1,
|
||||
printf ("[%d]%c ", job + 1,
|
||||
(job == current_job) ? '+': ((job == previous_job) ? '-' : ' '));
|
||||
|
||||
do
|
||||
{
|
||||
fprintf (stderr, "%s%s",
|
||||
printf ("%s%s",
|
||||
p->command ? p->command : "",
|
||||
p->next != jobs[job]->pipe? " | " : "");
|
||||
p = p->next;
|
||||
@@ -2324,12 +2324,12 @@ start_job (job, foreground)
|
||||
while (p != jobs[job]->pipe);
|
||||
|
||||
if (foreground == 0)
|
||||
fprintf (stderr, " &");
|
||||
printf (" &");
|
||||
|
||||
if (strcmp (wd, jobs[job]->wd) != 0)
|
||||
fprintf (stderr, " (wd: %s)", polite_directory_format (jobs[job]->wd));
|
||||
printf (" (wd: %s)", polite_directory_format (jobs[job]->wd));
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
printf ("\n");
|
||||
|
||||
/* Run the job. */
|
||||
if (already_running == 0)
|
||||
|
||||
@@ -276,12 +276,14 @@ rl_maybe_save_line ()
|
||||
_rl_saved_line_for_history->line = savestring (rl_line_buffer);
|
||||
_rl_saved_line_for_history->data = (char *)rl_undo_list;
|
||||
}
|
||||
#if 0
|
||||
else if (STREQ (rl_line_buffer, _rl_saved_line_for_history->line) == 0)
|
||||
{
|
||||
free (_rl_saved_line_for_history->line);
|
||||
_rl_saved_line_for_history->line = savestring (rl_line_buffer);
|
||||
_rl_saved_line_for_history->data = (char *)rl_undo_list; /* XXX possible memleak */
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,508 @@
|
||||
/* misc.c -- miscellaneous bindable readline functions. */
|
||||
|
||||
/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library, a library for
|
||||
reading lines of text with interactive input and history editing.
|
||||
|
||||
The GNU Readline Library 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.
|
||||
|
||||
The GNU Readline Library 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.
|
||||
|
||||
The GNU General Public License is often shipped with GNU software, and
|
||||
is generally kept in a file called COPYING or LICENSE. If you do not
|
||||
have a copy of the license, write to the Free Software Foundation,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
#define READLINE_LIBRARY
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#if defined (HAVE_STDLIB_H)
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# include "ansi_stdlib.h"
|
||||
#endif /* HAVE_STDLIB_H */
|
||||
|
||||
#if defined (HAVE_LOCALE_H)
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* System-specific feature definitions and include files. */
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
/* Some standard library routines. */
|
||||
#include "readline.h"
|
||||
#include "history.h"
|
||||
|
||||
#include "rlprivate.h"
|
||||
#include "rlshell.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
static int rl_digit_loop PARAMS((void));
|
||||
static void _rl_history_set_point PARAMS((void));
|
||||
|
||||
/* Forward declarations used in this file */
|
||||
void _rl_free_history_entry PARAMS((HIST_ENTRY *));
|
||||
|
||||
/* If non-zero, rl_get_previous_history and rl_get_next_history attempt
|
||||
to preserve the value of rl_point from line to line. */
|
||||
int _rl_history_preserve_point = 0;
|
||||
|
||||
/* Saved target point for when _rl_history_preserve_point is set. Special
|
||||
value of -1 means that point is at the end of the line. */
|
||||
int _rl_history_saved_point = -1;
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Numeric Arguments */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Handle C-u style numeric args, as well as M--, and M-digits. */
|
||||
static int
|
||||
rl_digit_loop ()
|
||||
{
|
||||
int key, c, sawminus, sawdigits;
|
||||
|
||||
rl_save_prompt ();
|
||||
|
||||
RL_SETSTATE(RL_STATE_NUMERICARG);
|
||||
sawminus = sawdigits = 0;
|
||||
while (1)
|
||||
{
|
||||
if (rl_numeric_arg > 1000000)
|
||||
{
|
||||
sawdigits = rl_explicit_arg = rl_numeric_arg = 0;
|
||||
rl_ding ();
|
||||
rl_restore_prompt ();
|
||||
rl_clear_message ();
|
||||
RL_UNSETSTATE(RL_STATE_NUMERICARG);
|
||||
return 1;
|
||||
}
|
||||
rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
|
||||
RL_SETSTATE(RL_STATE_MOREINPUT);
|
||||
key = c = rl_read_key ();
|
||||
RL_UNSETSTATE(RL_STATE_MOREINPUT);
|
||||
|
||||
if (c < 0)
|
||||
{
|
||||
_rl_abort_internal ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If we see a key bound to `universal-argument' after seeing digits,
|
||||
it ends the argument but is otherwise ignored. */
|
||||
if (_rl_keymap[c].type == ISFUNC &&
|
||||
_rl_keymap[c].function == rl_universal_argument)
|
||||
{
|
||||
if (sawdigits == 0)
|
||||
{
|
||||
rl_numeric_arg *= 4;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
RL_SETSTATE(RL_STATE_MOREINPUT);
|
||||
key = rl_read_key ();
|
||||
RL_UNSETSTATE(RL_STATE_MOREINPUT);
|
||||
rl_restore_prompt ();
|
||||
rl_clear_message ();
|
||||
RL_UNSETSTATE(RL_STATE_NUMERICARG);
|
||||
return (_rl_dispatch (key, _rl_keymap));
|
||||
}
|
||||
}
|
||||
|
||||
c = UNMETA (c);
|
||||
|
||||
if (_rl_digit_p (c))
|
||||
{
|
||||
rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + c - '0' : c - '0';
|
||||
sawdigits = rl_explicit_arg = 1;
|
||||
}
|
||||
else if (c == '-' && rl_explicit_arg == 0)
|
||||
{
|
||||
rl_numeric_arg = sawminus = 1;
|
||||
rl_arg_sign = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Make M-- command equivalent to M--1 command. */
|
||||
if (sawminus && rl_numeric_arg == 1 && rl_explicit_arg == 0)
|
||||
rl_explicit_arg = 1;
|
||||
rl_restore_prompt ();
|
||||
rl_clear_message ();
|
||||
RL_UNSETSTATE(RL_STATE_NUMERICARG);
|
||||
return (_rl_dispatch (key, _rl_keymap));
|
||||
}
|
||||
}
|
||||
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/* Add the current digit to the argument in progress. */
|
||||
int
|
||||
rl_digit_argument (ignore, key)
|
||||
int ignore, key;
|
||||
{
|
||||
rl_execute_next (key);
|
||||
return (rl_digit_loop ());
|
||||
}
|
||||
|
||||
/* What to do when you abort reading an argument. */
|
||||
int
|
||||
rl_discard_argument ()
|
||||
{
|
||||
rl_ding ();
|
||||
rl_clear_message ();
|
||||
_rl_init_argument ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create a default argument. */
|
||||
int
|
||||
_rl_init_argument ()
|
||||
{
|
||||
rl_numeric_arg = rl_arg_sign = 1;
|
||||
rl_explicit_arg = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* C-u, universal argument. Multiply the current argument by 4.
|
||||
Read a key. If the key has nothing to do with arguments, then
|
||||
dispatch on it. If the key is the abort character then abort. */
|
||||
int
|
||||
rl_universal_argument (count, key)
|
||||
int count, key;
|
||||
{
|
||||
rl_numeric_arg *= 4;
|
||||
return (rl_digit_loop ());
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* History Utilities */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* We already have a history library, and that is what we use to control
|
||||
the history features of readline. This is our local interface to
|
||||
the history mechanism. */
|
||||
|
||||
/* While we are editing the history, this is the saved
|
||||
version of the original line. */
|
||||
HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
|
||||
|
||||
/* Set the history pointer back to the last entry in the history. */
|
||||
void
|
||||
_rl_start_using_history ()
|
||||
{
|
||||
using_history ();
|
||||
if (_rl_saved_line_for_history)
|
||||
_rl_free_history_entry (_rl_saved_line_for_history);
|
||||
|
||||
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
|
||||
}
|
||||
|
||||
/* Free the contents (and containing structure) of a HIST_ENTRY. */
|
||||
void
|
||||
_rl_free_history_entry (entry)
|
||||
HIST_ENTRY *entry;
|
||||
{
|
||||
if (entry == 0)
|
||||
return;
|
||||
if (entry->line)
|
||||
free (entry->line);
|
||||
free (entry);
|
||||
}
|
||||
|
||||
/* Perhaps put back the current line if it has changed. */
|
||||
int
|
||||
rl_maybe_replace_line ()
|
||||
{
|
||||
HIST_ENTRY *temp;
|
||||
|
||||
temp = current_history ();
|
||||
/* If the current line has changed, save the changes. */
|
||||
if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list))
|
||||
{
|
||||
temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list);
|
||||
free (temp->line);
|
||||
free (temp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Restore the _rl_saved_line_for_history if there is one. */
|
||||
int
|
||||
rl_maybe_unsave_line ()
|
||||
{
|
||||
if (_rl_saved_line_for_history)
|
||||
{
|
||||
/* Can't call with `1' because rl_undo_list might point to an undo
|
||||
list from a history entry, as in rl_replace_from_history() below. */
|
||||
rl_replace_line (_rl_saved_line_for_history->line, 0);
|
||||
rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data;
|
||||
_rl_free_history_entry (_rl_saved_line_for_history);
|
||||
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
|
||||
rl_point = rl_end; /* rl_replace_line sets rl_end */
|
||||
}
|
||||
else
|
||||
rl_ding ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save the current line in _rl_saved_line_for_history. */
|
||||
int
|
||||
rl_maybe_save_line ()
|
||||
{
|
||||
if (_rl_saved_line_for_history == 0)
|
||||
{
|
||||
_rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
|
||||
_rl_saved_line_for_history->line = savestring (rl_line_buffer);
|
||||
_rl_saved_line_for_history->data = (char *)rl_undo_list;
|
||||
}
|
||||
else if (STREQ (rl_line_buffer, _rl_saved_line_for_history->line) == 0)
|
||||
{
|
||||
free (_rl_saved_line_for_history->line);
|
||||
_rl_saved_line_for_history->line = savestring (rl_line_buffer);
|
||||
_rl_saved_line_for_history->data = (char *)rl_undo_list; /* XXX possible memleak */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_rl_free_saved_history_line ()
|
||||
{
|
||||
if (_rl_saved_line_for_history)
|
||||
{
|
||||
_rl_free_history_entry (_rl_saved_line_for_history);
|
||||
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_rl_history_set_point ()
|
||||
{
|
||||
rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1)
|
||||
? _rl_history_saved_point
|
||||
: rl_end;
|
||||
if (rl_point > rl_end)
|
||||
rl_point = rl_end;
|
||||
|
||||
#if defined (VI_MODE)
|
||||
if (rl_editing_mode == vi_mode && _rl_keymap != vi_insertion_keymap)
|
||||
rl_point = 0;
|
||||
#endif /* VI_MODE */
|
||||
|
||||
if (rl_editing_mode == emacs_mode)
|
||||
rl_mark = (rl_point == rl_end ? 0 : rl_end);
|
||||
}
|
||||
|
||||
void
|
||||
rl_replace_from_history (entry, flags)
|
||||
HIST_ENTRY *entry;
|
||||
int flags; /* currently unused */
|
||||
{
|
||||
/* Can't call with `1' because rl_undo_list might point to an undo list
|
||||
from a history entry, just like we're setting up here. */
|
||||
rl_replace_line (entry->line, 0);
|
||||
rl_undo_list = (UNDO_LIST *)entry->data;
|
||||
rl_point = rl_end;
|
||||
rl_mark = 0;
|
||||
|
||||
#if defined (VI_MODE)
|
||||
if (rl_editing_mode == vi_mode)
|
||||
{
|
||||
rl_point = 0;
|
||||
rl_mark = rl_end;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* History Commands */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Meta-< goes to the start of the history. */
|
||||
int
|
||||
rl_beginning_of_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
return (rl_get_previous_history (1 + where_history (), key));
|
||||
}
|
||||
|
||||
/* Meta-> goes to the end of the history. (The current line). */
|
||||
int
|
||||
rl_end_of_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
rl_maybe_replace_line ();
|
||||
using_history ();
|
||||
rl_maybe_unsave_line ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move down to the next history line. */
|
||||
int
|
||||
rl_get_next_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
HIST_ENTRY *temp;
|
||||
|
||||
if (count < 0)
|
||||
return (rl_get_previous_history (-count, key));
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
rl_maybe_replace_line ();
|
||||
|
||||
/* either not saved by rl_newline or at end of line, so set appropriately. */
|
||||
if (_rl_history_saved_point == -1 && (rl_point || rl_end))
|
||||
_rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
|
||||
|
||||
temp = (HIST_ENTRY *)NULL;
|
||||
while (count)
|
||||
{
|
||||
temp = next_history ();
|
||||
if (!temp)
|
||||
break;
|
||||
--count;
|
||||
}
|
||||
|
||||
if (temp == 0)
|
||||
rl_maybe_unsave_line ();
|
||||
else
|
||||
{
|
||||
rl_replace_from_history (temp, 0);
|
||||
_rl_history_set_point ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the previous item out of our interactive history, making it the current
|
||||
line. If there is no previous history, just ding. */
|
||||
int
|
||||
rl_get_previous_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
HIST_ENTRY *old_temp, *temp;
|
||||
|
||||
if (count < 0)
|
||||
return (rl_get_next_history (-count, key));
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
/* either not saved by rl_newline or at end of line, so set appropriately. */
|
||||
if (_rl_history_saved_point == -1 && (rl_point || rl_end))
|
||||
_rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
|
||||
|
||||
/* If we don't have a line saved, then save this one. */
|
||||
rl_maybe_save_line ();
|
||||
|
||||
/* If the current line has changed, save the changes. */
|
||||
rl_maybe_replace_line ();
|
||||
|
||||
temp = old_temp = (HIST_ENTRY *)NULL;
|
||||
while (count)
|
||||
{
|
||||
temp = previous_history ();
|
||||
if (temp == 0)
|
||||
break;
|
||||
|
||||
old_temp = temp;
|
||||
--count;
|
||||
}
|
||||
|
||||
/* If there was a large argument, and we moved back to the start of the
|
||||
history, that is not an error. So use the last value found. */
|
||||
if (!temp && old_temp)
|
||||
temp = old_temp;
|
||||
|
||||
if (temp == 0)
|
||||
rl_ding ();
|
||||
else
|
||||
{
|
||||
rl_replace_from_history (temp, 0);
|
||||
_rl_history_set_point ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Editing Modes */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
/* How to toggle back and forth between editing modes. */
|
||||
int
|
||||
rl_vi_editing_mode (count, key)
|
||||
int count, key;
|
||||
{
|
||||
#if defined (VI_MODE)
|
||||
_rl_set_insert_mode (RL_IM_INSERT, 1); /* vi mode ignores insert mode */
|
||||
rl_editing_mode = vi_mode;
|
||||
rl_vi_insertion_mode (1, key);
|
||||
#endif /* VI_MODE */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rl_emacs_editing_mode (count, key)
|
||||
int count, key;
|
||||
{
|
||||
rl_editing_mode = emacs_mode;
|
||||
_rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */
|
||||
_rl_keymap = emacs_standard_keymap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Function for the rest of the library to use to set insert/overwrite mode. */
|
||||
void
|
||||
_rl_set_insert_mode (im, force)
|
||||
int im, force;
|
||||
{
|
||||
#ifdef CURSOR_MODE
|
||||
_rl_set_cursor (im, force);
|
||||
#endif
|
||||
|
||||
rl_insert_mode = im;
|
||||
}
|
||||
|
||||
/* Toggle overwrite mode. A positive explicit argument selects overwrite
|
||||
mode. A negative or zero explicit argument selects insert mode. */
|
||||
int
|
||||
rl_overwrite_mode (count, key)
|
||||
int count, key;
|
||||
{
|
||||
if (rl_explicit_arg == 0)
|
||||
_rl_set_insert_mode (rl_insert_mode ^ 1, 0);
|
||||
else if (count > 0)
|
||||
_rl_set_insert_mode (RL_IM_OVERWRITE, 0);
|
||||
else
|
||||
_rl_set_insert_mode (RL_IM_INSERT, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -71,8 +71,8 @@ set_default_locale ()
|
||||
textdomain (PACKAGE);
|
||||
}
|
||||
|
||||
/* Set default values for LC_CTYPE, LC_COLLATE, LC_MESSAGES and LC_NUMERIC
|
||||
if they are not specified in the environment, but LC_ALL is. This
|
||||
/* Set default values for LC_CTYPE, LC_COLLATE, LC_MESSAGES, LC_NUMERIC and
|
||||
LC_TIME if they are not specified in the environment, but LC_ALL is. This
|
||||
should be called from main() after parsing the environment. */
|
||||
void
|
||||
set_default_locale_vars ()
|
||||
@@ -109,6 +109,12 @@ set_default_locale_vars ()
|
||||
setlocale (LC_NUMERIC, lc_all);
|
||||
# endif /* LC_NUMERIC */
|
||||
|
||||
# if defined (LC_TIME)
|
||||
val = get_string_value ("LC_TIME");
|
||||
if (val == 0 && lc_all && *lc_all)
|
||||
setlocale (LC_TIME, lc_all);
|
||||
# endif /* LC_TIME */
|
||||
|
||||
#endif /* HAVE_SETLOCALE */
|
||||
|
||||
val = get_string_value ("TEXTDOMAIN");
|
||||
@@ -213,7 +219,15 @@ set_locale_var (var, value)
|
||||
return (setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC")) != 0);
|
||||
# endif /* LC_NUMERIC */
|
||||
}
|
||||
else if (var[3] == 'T' && var[4] == 'I') /* LC_TIME */
|
||||
{
|
||||
# if defined (LC_TIME)
|
||||
if (lc_all == 0 || *lc_all == '\0')
|
||||
return (setlocale (LC_TIME, get_locale_var ("LC_TIME")) != 0);
|
||||
# endif /* LC_TIME */
|
||||
}
|
||||
#endif /* HAVE_SETLOCALE */
|
||||
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -285,6 +299,9 @@ reset_locale_vars ()
|
||||
# if defined (LC_NUMERIC)
|
||||
setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC"));
|
||||
# endif
|
||||
# if defined (LC_TIME)
|
||||
setlocale (LC_TIME, get_locale_var ("LC_TIME"));
|
||||
# endif
|
||||
|
||||
locale_setblanks ();
|
||||
|
||||
|
||||
@@ -0,0 +1,479 @@
|
||||
/* locale.c - Miscellaneous internationalization functions. */
|
||||
|
||||
/* Copyright (C) 1996-2004 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashintl.h"
|
||||
#include "bashansi.h"
|
||||
#include <stdio.h>
|
||||
#include "chartypes.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "input.h" /* For bash_input */
|
||||
|
||||
extern int dump_translatable_strings, dump_po_strings;
|
||||
|
||||
/* The current locale when the program begins */
|
||||
static char *default_locale;
|
||||
|
||||
/* The current domain for textdomain(3). */
|
||||
static char *default_domain;
|
||||
static char *default_dir;
|
||||
|
||||
/* tracks the value of LC_ALL; used to override values for other locale
|
||||
categories */
|
||||
static char *lc_all;
|
||||
|
||||
/* tracks the value of LC_ALL; used to provide defaults for locale
|
||||
categories */
|
||||
static char *lang;
|
||||
|
||||
/* Called to reset all of the locale variables to their appropriate values
|
||||
if (and only if) LC_ALL has not been assigned a value. */
|
||||
static int reset_locale_vars __P((void));
|
||||
|
||||
static void locale_setblanks __P((void));
|
||||
|
||||
/* Set the value of default_locale and make the current locale the
|
||||
system default locale. This should be called very early in main(). */
|
||||
void
|
||||
set_default_locale ()
|
||||
{
|
||||
#if defined (HAVE_SETLOCALE)
|
||||
default_locale = setlocale (LC_ALL, "");
|
||||
if (default_locale)
|
||||
default_locale = savestring (default_locale);
|
||||
#endif /* HAVE_SETLOCALE */
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
}
|
||||
|
||||
/* Set default values for LC_CTYPE, LC_COLLATE, LC_MESSAGES and LC_NUMERIC
|
||||
if they are not specified in the environment, but LC_ALL is. This
|
||||
should be called from main() after parsing the environment. */
|
||||
void
|
||||
set_default_locale_vars ()
|
||||
{
|
||||
char *val;
|
||||
int r;
|
||||
|
||||
#if defined (HAVE_SETLOCALE)
|
||||
|
||||
# if defined (LC_CTYPE)
|
||||
val = get_string_value ("LC_CTYPE");
|
||||
if (val == 0 && lc_all && *lc_all)
|
||||
{
|
||||
setlocale (LC_CTYPE, lc_all);
|
||||
locale_setblanks ();
|
||||
}
|
||||
# endif
|
||||
|
||||
# if defined (LC_COLLATE)
|
||||
val = get_string_value ("LC_COLLATE");
|
||||
if (val == 0 && lc_all && *lc_all)
|
||||
setlocale (LC_COLLATE, lc_all);
|
||||
# endif /* LC_COLLATE */
|
||||
|
||||
# if defined (LC_MESSAGES)
|
||||
val = get_string_value ("LC_MESSAGES");
|
||||
if (val == 0 && lc_all && *lc_all)
|
||||
setlocale (LC_MESSAGES, lc_all);
|
||||
# endif /* LC_MESSAGES */
|
||||
|
||||
# if defined (LC_NUMERIC)
|
||||
val = get_string_value ("LC_NUMERIC");
|
||||
if (val == 0 && lc_all && *lc_all)
|
||||
setlocale (LC_NUMERIC, lc_all);
|
||||
# endif /* LC_NUMERIC */
|
||||
|
||||
#endif /* HAVE_SETLOCALE */
|
||||
|
||||
val = get_string_value ("TEXTDOMAIN");
|
||||
if (val && *val)
|
||||
{
|
||||
FREE (default_domain);
|
||||
default_domain = savestring (val);
|
||||
#if 0
|
||||
/* Don't want to override the shell's textdomain as the default */
|
||||
textdomain (default_domain);
|
||||
#endif
|
||||
}
|
||||
|
||||
val = get_string_value ("TEXTDOMAINDIR");
|
||||
if (val && *val)
|
||||
{
|
||||
FREE (default_dir);
|
||||
default_dir = savestring (val);
|
||||
if (default_domain && *default_domain)
|
||||
bindtextdomain (default_domain, default_dir);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set one of the locale categories (specified by VAR) to VALUE. Returns 1
|
||||
if successful, 0 otherwise. */
|
||||
int
|
||||
set_locale_var (var, value)
|
||||
char *var, *value;
|
||||
{
|
||||
int r;
|
||||
|
||||
if (var[0] == 'T' && var[10] == 0) /* TEXTDOMAIN */
|
||||
{
|
||||
FREE (default_domain);
|
||||
default_domain = value ? savestring (value) : (char *)NULL;
|
||||
#if 0
|
||||
/* Don't want to override the shell's textdomain as the default */
|
||||
textdomain (default_domain);
|
||||
#endif
|
||||
return (1);
|
||||
}
|
||||
else if (var[0] == 'T') /* TEXTDOMAINDIR */
|
||||
{
|
||||
FREE (default_dir);
|
||||
default_dir = value ? savestring (value) : (char *)NULL;
|
||||
if (default_domain && *default_domain)
|
||||
bindtextdomain (default_domain, default_dir);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* var[0] == 'L' && var[1] == 'C' && var[2] == '_' */
|
||||
|
||||
else if (var[3] == 'A') /* LC_ALL */
|
||||
{
|
||||
FREE (lc_all);
|
||||
if (value)
|
||||
lc_all = savestring (value);
|
||||
else
|
||||
{
|
||||
lc_all = (char *)xmalloc (1);
|
||||
lc_all[0] = '\0';
|
||||
}
|
||||
#if defined (HAVE_SETLOCALE)
|
||||
r = *lc_all ? (setlocale (LC_ALL, lc_all) != 0) : reset_locale_vars ();
|
||||
locale_setblanks ();
|
||||
return r;
|
||||
#else
|
||||
return (1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined (HAVE_SETLOCALE)
|
||||
else if (var[3] == 'C' && var[4] == 'T') /* LC_CTYPE */
|
||||
{
|
||||
# if defined (LC_CTYPE)
|
||||
if (lc_all == 0 || *lc_all == '\0')
|
||||
{
|
||||
r = (setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE")) != 0);
|
||||
locale_setblanks ();
|
||||
return r;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
else if (var[3] == 'C' && var[4] == 'O') /* LC_COLLATE */
|
||||
{
|
||||
# if defined (LC_COLLATE)
|
||||
if (lc_all == 0 || *lc_all == '\0')
|
||||
return (setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE")) != 0);
|
||||
# endif /* LC_COLLATE */
|
||||
}
|
||||
else if (var[3] == 'M' && var[4] == 'E') /* LC_MESSAGES */
|
||||
{
|
||||
# if defined (LC_MESSAGES)
|
||||
if (lc_all == 0 || *lc_all == '\0')
|
||||
return (setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES")) != 0);
|
||||
# endif /* LC_MESSAGES */
|
||||
}
|
||||
else if (var[3] == 'N' && var[4] == 'U') /* LC_NUMERIC */
|
||||
{
|
||||
# if defined (LC_NUMERIC)
|
||||
if (lc_all == 0 || *lc_all == '\0')
|
||||
return (setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC")) != 0);
|
||||
# endif /* LC_NUMERIC */
|
||||
}
|
||||
#endif /* HAVE_SETLOCALE */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Called when LANG is assigned a value. Tracks value in `lang'. Calls
|
||||
reset_locale_vars() to reset any default values if LC_ALL is unset or
|
||||
null. */
|
||||
int
|
||||
set_lang (var, value)
|
||||
char *var, *value;
|
||||
{
|
||||
FREE (lang);
|
||||
if (value)
|
||||
lang = savestring (value);
|
||||
else
|
||||
{
|
||||
lang = (char *)xmalloc (1);
|
||||
lang[0] = '\0';
|
||||
}
|
||||
|
||||
return ((lc_all == 0 || *lc_all == 0) ? reset_locale_vars () : 0);
|
||||
}
|
||||
|
||||
/* Get the value of one of the locale variables (LC_MESSAGES, LC_CTYPE).
|
||||
The precedence is as POSIX.2 specifies: LC_ALL has precedence over
|
||||
the specific locale variables, and LANG, if set, is used as the default. */
|
||||
char *
|
||||
get_locale_var (var)
|
||||
char *var;
|
||||
{
|
||||
char *locale;
|
||||
|
||||
locale = lc_all;
|
||||
|
||||
if (locale == 0 || *locale == 0)
|
||||
locale = get_string_value (var);
|
||||
if (locale == 0 || *locale == 0)
|
||||
locale = lang;
|
||||
if (locale == 0 || *locale == 0)
|
||||
locale = default_locale; /* system-dependent; not really portable */
|
||||
|
||||
return (locale);
|
||||
}
|
||||
|
||||
/* Called to reset all of the locale variables to their appropriate values
|
||||
if (and only if) LC_ALL has not been assigned a value. DO NOT CALL THIS
|
||||
IF LC_ALL HAS BEEN ASSIGNED A VALUE. */
|
||||
static int
|
||||
reset_locale_vars ()
|
||||
{
|
||||
#if defined (HAVE_SETLOCALE)
|
||||
char *locale;
|
||||
|
||||
locale = lang;
|
||||
if (locale == 0 || *locale == '\0')
|
||||
locale = default_locale;
|
||||
if (setlocale (LC_ALL, locale) == 0)
|
||||
return 0;
|
||||
|
||||
# if defined (LC_CTYPE)
|
||||
setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE"));
|
||||
# endif
|
||||
# if defined (LC_COLLATE)
|
||||
setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE"));
|
||||
# endif
|
||||
# if defined (LC_MESSAGES)
|
||||
setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES"));
|
||||
# endif
|
||||
# if defined (LC_NUMERIC)
|
||||
setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC"));
|
||||
# endif
|
||||
|
||||
locale_setblanks ();
|
||||
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Translate the contents of STRING, a $"..." quoted string, according
|
||||
to the current locale. In the `C' or `POSIX' locale, or if gettext()
|
||||
is not available, the passed string is returned unchanged. The
|
||||
length of the translated string is returned in LENP, if non-null. */
|
||||
char *
|
||||
localetrans (string, len, lenp)
|
||||
char *string;
|
||||
int len, *lenp;
|
||||
{
|
||||
char *locale, *t;
|
||||
char *translated;
|
||||
int tlen;
|
||||
|
||||
/* Don't try to translate null strings. */
|
||||
if (string == 0 || *string == 0)
|
||||
{
|
||||
if (lenp)
|
||||
*lenp = 0;
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
locale = get_locale_var ("LC_MESSAGES");
|
||||
|
||||
/* If we don't have setlocale() or the current locale is `C' or `POSIX',
|
||||
just return the string. If we don't have gettext(), there's no use
|
||||
doing anything else. */
|
||||
if (locale == 0 || locale[0] == '\0' ||
|
||||
(locale[0] == 'C' && locale[1] == '\0') || STREQ (locale, "POSIX"))
|
||||
{
|
||||
t = (char *)xmalloc (len + 1);
|
||||
strcpy (t, string);
|
||||
if (lenp)
|
||||
*lenp = len;
|
||||
return (t);
|
||||
}
|
||||
|
||||
/* Now try to translate it. */
|
||||
if (default_domain && *default_domain)
|
||||
translated = dgettext (default_domain, string);
|
||||
else
|
||||
translated = string;
|
||||
|
||||
if (translated == string) /* gettext returns its argument if untranslatable */
|
||||
{
|
||||
t = (char *)xmalloc (len + 1);
|
||||
strcpy (t, string);
|
||||
if (lenp)
|
||||
*lenp = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
tlen = strlen (translated);
|
||||
t = (char *)xmalloc (tlen + 1);
|
||||
strcpy (t, translated);
|
||||
if (lenp)
|
||||
*lenp = tlen;
|
||||
}
|
||||
return (t);
|
||||
}
|
||||
|
||||
/* Change a bash string into a string suitable for inclusion in a `po' file.
|
||||
This backslash-escapes `"' and `\' and changes newlines into \\\n"\n". */
|
||||
char *
|
||||
mk_msgstr (string, foundnlp)
|
||||
char *string;
|
||||
int *foundnlp;
|
||||
{
|
||||
register int c, len;
|
||||
char *result, *r, *s;
|
||||
|
||||
for (len = 0, s = string; s && *s; s++)
|
||||
{
|
||||
len++;
|
||||
if (*s == '"' || *s == '\\')
|
||||
len++;
|
||||
else if (*s == '\n')
|
||||
len += 5;
|
||||
}
|
||||
|
||||
r = result = (char *)xmalloc (len + 3);
|
||||
*r++ = '"';
|
||||
|
||||
for (s = string; s && (c = *s); s++)
|
||||
{
|
||||
if (c == '\n') /* <NL> -> \n"<NL>" */
|
||||
{
|
||||
*r++ = '\\';
|
||||
*r++ = 'n';
|
||||
*r++ = '"';
|
||||
*r++ = '\n';
|
||||
*r++ = '"';
|
||||
if (foundnlp)
|
||||
*foundnlp = 1;
|
||||
continue;
|
||||
}
|
||||
if (c == '"' || c == '\\')
|
||||
*r++ = '\\';
|
||||
*r++ = c;
|
||||
}
|
||||
|
||||
*r++ = '"';
|
||||
*r++ = '\0';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* $"..." -- Translate the portion of STRING between START and END
|
||||
according to current locale using gettext (if available) and return
|
||||
the result. The caller will take care of leaving the quotes intact.
|
||||
The string will be left without the leading `$' by the caller.
|
||||
If translation is performed, the translated string will be double-quoted
|
||||
by the caller. The length of the translated string is returned in LENP,
|
||||
if non-null. */
|
||||
char *
|
||||
localeexpand (string, start, end, lineno, lenp)
|
||||
char *string;
|
||||
int start, end, lineno, *lenp;
|
||||
{
|
||||
int len, tlen, foundnl;
|
||||
char *temp, *t, *t2;
|
||||
|
||||
temp = (char *)xmalloc (end - start + 1);
|
||||
for (tlen = 0, len = start; len < end; )
|
||||
temp[tlen++] = string[len++];
|
||||
temp[tlen] = '\0';
|
||||
|
||||
/* If we're just dumping translatable strings, don't do anything with the
|
||||
string itself, but if we're dumping in `po' file format, convert it into
|
||||
a form more palatable to gettext(3) and friends by quoting `"' and `\'
|
||||
with backslashes and converting <NL> into `\n"<NL>"'. If we find a
|
||||
newline in TEMP, we first output a `msgid ""' line and then the
|
||||
translated string; otherwise we output the `msgid' and translated
|
||||
string all on one line. */
|
||||
if (dump_translatable_strings)
|
||||
{
|
||||
if (dump_po_strings)
|
||||
{
|
||||
foundnl = 0;
|
||||
t = mk_msgstr (temp, &foundnl);
|
||||
t2 = foundnl ? "\"\"\n" : "";
|
||||
|
||||
printf ("#: %s:%d\nmsgid %s%s\nmsgstr \"\"\n",
|
||||
yy_input_name (), lineno, t2, t);
|
||||
free (t);
|
||||
}
|
||||
else
|
||||
printf ("\"%s\"\n", temp);
|
||||
|
||||
if (lenp)
|
||||
*lenp = tlen;
|
||||
return (temp);
|
||||
}
|
||||
else if (*temp)
|
||||
{
|
||||
t = localetrans (temp, tlen, &len);
|
||||
free (temp);
|
||||
if (lenp)
|
||||
*lenp = len;
|
||||
return (t);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lenp)
|
||||
*lenp = 0;
|
||||
return (temp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set every character in the <blank> character class to be a shell break
|
||||
character for the lexical analyzer when the locale changes. */
|
||||
static void
|
||||
locale_setblanks ()
|
||||
{
|
||||
int x;
|
||||
|
||||
for (x = 0; x < sh_syntabsiz; x++)
|
||||
{
|
||||
if (isblank (x))
|
||||
sh_syntaxtab[x] |= CSHBRK;
|
||||
else if (member (x, shell_break_chars))
|
||||
sh_syntaxtab[x] |= CSHBRK;
|
||||
else
|
||||
sh_syntaxtab[x] &= ~CSHBRK;
|
||||
}
|
||||
}
|
||||
@@ -93,6 +93,7 @@ initialize_signals (reinit)
|
||||
struct termsig {
|
||||
int signum;
|
||||
SigHandler *orig_handler;
|
||||
int orig_flags;
|
||||
};
|
||||
|
||||
#define NULL_HANDLER (SigHandler *)SIG_DFL
|
||||
@@ -102,89 +103,89 @@ struct termsig {
|
||||
and so forth. */
|
||||
static struct termsig terminating_signals[] = {
|
||||
#ifdef SIGHUP
|
||||
{ SIGHUP, NULL_HANDLER },
|
||||
{ SIGHUP, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGINT
|
||||
{ SIGINT, NULL_HANDLER },
|
||||
{ SIGINT, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGILL
|
||||
{ SIGILL, NULL_HANDLER },
|
||||
{ SIGILL, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGTRAP
|
||||
{ SIGTRAP, NULL_HANDLER },
|
||||
{ SIGTRAP, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGIOT
|
||||
{ SIGIOT, NULL_HANDLER },
|
||||
{ SIGIOT, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGDANGER
|
||||
{ SIGDANGER, NULL_HANDLER },
|
||||
{ SIGDANGER, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGEMT
|
||||
{ SIGEMT, NULL_HANDLER },
|
||||
{ SIGEMT, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGFPE
|
||||
{ SIGFPE, NULL_HANDLER },
|
||||
{ SIGFPE, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGBUS
|
||||
{ SIGBUS, NULL_HANDLER },
|
||||
{ SIGBUS, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGSEGV
|
||||
{ SIGSEGV, NULL_HANDLER },
|
||||
{ SIGSEGV, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGSYS
|
||||
{ SIGSYS, NULL_HANDLER },
|
||||
{ SIGSYS, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGPIPE
|
||||
{ SIGPIPE, NULL_HANDLER },
|
||||
{ SIGPIPE, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGALRM
|
||||
{ SIGALRM, NULL_HANDLER },
|
||||
{ SIGALRM, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGTERM
|
||||
{ SIGTERM, NULL_HANDLER },
|
||||
{ SIGTERM, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGXCPU
|
||||
{ SIGXCPU, NULL_HANDLER },
|
||||
{ SIGXCPU, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGXFSZ
|
||||
{ SIGXFSZ, NULL_HANDLER },
|
||||
{ SIGXFSZ, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGVTALRM
|
||||
{ SIGVTALRM, NULL_HANDLER },
|
||||
{ SIGVTALRM, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#ifdef SIGPROF
|
||||
{ SIGPROF, NULL_HANDLER },
|
||||
{ SIGPROF, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGLOST
|
||||
{ SIGLOST, NULL_HANDLER },
|
||||
{ SIGLOST, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGUSR1
|
||||
{ SIGUSR1, NULL_HANDLER },
|
||||
{ SIGUSR1, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGUSR2
|
||||
{ SIGUSR2, NULL_HANDLER },
|
||||
{ SIGUSR2, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -192,6 +193,7 @@ static struct termsig terminating_signals[] = {
|
||||
|
||||
#define XSIG(x) (terminating_signals[x].signum)
|
||||
#define XHANDLER(x) (terminating_signals[x].orig_handler)
|
||||
#define XSAFLAGS(x) (terminating_signals[x].orig_flags)
|
||||
|
||||
static int termsigs_initialized = 0;
|
||||
|
||||
@@ -228,6 +230,7 @@ initialize_terminating_signals ()
|
||||
|
||||
sigaction (XSIG (i), &act, &oact);
|
||||
XHANDLER(i) = oact.sa_handler;
|
||||
XSAFLAGS(i) = oact.sa_flags;
|
||||
/* Don't do anything with signals that are ignored at shell entry
|
||||
if the shell is not interactive. */
|
||||
if (!interactive_shell && XHANDLER (i) == SIG_IGN)
|
||||
@@ -250,6 +253,7 @@ initialize_terminating_signals ()
|
||||
continue;
|
||||
|
||||
XHANDLER(i) = signal (XSIG (i), termination_unwind_protect);
|
||||
XSAFLAGS(i) = 0;
|
||||
/* Don't do anything with signals that are ignored at shell entry
|
||||
if the shell is not interactive. */
|
||||
if (!interactive_shell && XHANDLER (i) == SIG_IGN)
|
||||
@@ -316,6 +320,7 @@ reset_terminating_signals ()
|
||||
continue;
|
||||
|
||||
act.sa_handler = XHANDLER (i);
|
||||
act.sa_flags = XSAFLAGS (i);
|
||||
sigaction (XSIG (i), &act, (struct sigaction *) NULL);
|
||||
}
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
@@ -0,0 +1,525 @@
|
||||
/* sig.c - interface for shell signal handlers and signal initialization. */
|
||||
|
||||
/* Copyright (C) 1994 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#if defined (JOB_CONTROL)
|
||||
#include "jobs.h"
|
||||
#endif /* JOB_CONTROL */
|
||||
#include "siglist.h"
|
||||
#include "sig.h"
|
||||
#include "trap.h"
|
||||
|
||||
#include "builtins/common.h"
|
||||
|
||||
#if defined (READLINE)
|
||||
# include "bashline.h"
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "bashhist.h"
|
||||
#endif
|
||||
|
||||
extern int last_command_exit_value;
|
||||
extern int last_command_exit_signal;
|
||||
extern int return_catch_flag;
|
||||
extern int loop_level, continuing, breaking;
|
||||
extern int parse_and_execute_level, shell_initialized;
|
||||
|
||||
/* Non-zero after SIGINT. */
|
||||
int interrupt_state;
|
||||
|
||||
/* The environment at the top-level R-E loop. We use this in
|
||||
the case of error return. */
|
||||
procenv_t top_level;
|
||||
|
||||
#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
|
||||
/* The signal masks that this shell runs with. */
|
||||
sigset_t top_level_mask;
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
/* When non-zero, we throw_to_top_level (). */
|
||||
int interrupt_immediately = 0;
|
||||
|
||||
static void initialize_shell_signals __P((void));
|
||||
|
||||
void
|
||||
initialize_signals (reinit)
|
||||
int reinit;
|
||||
{
|
||||
initialize_shell_signals ();
|
||||
initialize_job_signals ();
|
||||
#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL)
|
||||
if (reinit == 0)
|
||||
initialize_siglist ();
|
||||
#endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */
|
||||
}
|
||||
|
||||
/* A structure describing a signal that terminates the shell if not
|
||||
caught. The orig_handler member is present so children can reset
|
||||
these signals back to their original handlers. */
|
||||
struct termsig {
|
||||
int signum;
|
||||
SigHandler *orig_handler;
|
||||
int orig_flags;
|
||||
};
|
||||
|
||||
#define NULL_HANDLER (SigHandler *)SIG_DFL
|
||||
|
||||
/* The list of signals that would terminate the shell if not caught.
|
||||
We catch them, but just so that we can write the history file,
|
||||
and so forth. */
|
||||
static struct termsig terminating_signals[] = {
|
||||
#ifdef SIGHUP
|
||||
{ SIGHUP, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGINT
|
||||
{ SIGINT, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGILL
|
||||
{ SIGILL, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGTRAP
|
||||
{ SIGTRAP, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGIOT
|
||||
{ SIGIOT, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGDANGER
|
||||
{ SIGDANGER, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGEMT
|
||||
{ SIGEMT, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGFPE
|
||||
{ SIGFPE, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGBUS
|
||||
{ SIGBUS, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGSEGV
|
||||
{ SIGSEGV, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGSYS
|
||||
{ SIGSYS, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGPIPE
|
||||
{ SIGPIPE, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGALRM
|
||||
{ SIGALRM, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGTERM
|
||||
{ SIGTERM, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGXCPU
|
||||
{ SIGXCPU, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGXFSZ
|
||||
{ SIGXFSZ, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGVTALRM
|
||||
{ SIGVTALRM, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#ifdef SIGPROF
|
||||
{ SIGPROF, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGLOST
|
||||
{ SIGLOST, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGUSR1
|
||||
{ SIGUSR1, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGUSR2
|
||||
{ SIGUSR2, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
};
|
||||
|
||||
#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig))
|
||||
|
||||
#define XSIG(x) (terminating_signals[x].signum)
|
||||
#define XHANDLER(x) (terminating_signals[x].orig_handler)
|
||||
#define XSAFLAGS(x) (terminating_signals[x].orig_flags)
|
||||
|
||||
static int termsigs_initialized = 0;
|
||||
|
||||
/* Initialize signals that will terminate the shell to do some
|
||||
unwind protection. For non-interactive shells, we only call
|
||||
this when a trap is defined for EXIT (0). */
|
||||
void
|
||||
initialize_terminating_signals ()
|
||||
{
|
||||
register int i;
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
struct sigaction act, oact;
|
||||
#endif
|
||||
|
||||
if (termsigs_initialized)
|
||||
return;
|
||||
|
||||
/* The following code is to avoid an expensive call to
|
||||
set_signal_handler () for each terminating_signals. Fortunately,
|
||||
this is possible in Posix. Unfortunately, we have to call signal ()
|
||||
on non-Posix systems for each signal in terminating_signals. */
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
act.sa_handler = termination_unwind_protect;
|
||||
act.sa_flags = 0;
|
||||
sigemptyset (&act.sa_mask);
|
||||
sigemptyset (&oact.sa_mask);
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
sigaddset (&act.sa_mask, XSIG (i));
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
{
|
||||
/* If we've already trapped it, don't do anything. */
|
||||
if (signal_is_trapped (XSIG (i)))
|
||||
continue;
|
||||
|
||||
sigaction (XSIG (i), &act, &oact);
|
||||
XHANDLER(i) = oact.sa_handler;
|
||||
/* Don't do anything with signals that are ignored at shell entry
|
||||
if the shell is not interactive. */
|
||||
if (!interactive_shell && XHANDLER (i) == SIG_IGN)
|
||||
{
|
||||
sigaction (XSIG (i), &oact, &act);
|
||||
set_signal_ignored (XSIG (i));
|
||||
}
|
||||
#if defined (SIGPROF) && !defined (_MINIX)
|
||||
if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
|
||||
sigaction (XSIG (i), &oact, (struct sigaction *)NULL);
|
||||
#endif /* SIGPROF && !_MINIX */
|
||||
}
|
||||
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
{
|
||||
/* If we've already trapped it, don't do anything. */
|
||||
if (signal_is_trapped (XSIG (i)))
|
||||
continue;
|
||||
|
||||
XHANDLER(i) = signal (XSIG (i), termination_unwind_protect);
|
||||
/* Don't do anything with signals that are ignored at shell entry
|
||||
if the shell is not interactive. */
|
||||
if (!interactive_shell && XHANDLER (i) == SIG_IGN)
|
||||
{
|
||||
signal (XSIG (i), SIG_IGN);
|
||||
set_signal_ignored (XSIG (i));
|
||||
}
|
||||
#ifdef SIGPROF
|
||||
if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
|
||||
signal (XSIG (i), XHANDLER (i));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
termsigs_initialized = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
initialize_shell_signals ()
|
||||
{
|
||||
if (interactive)
|
||||
initialize_terminating_signals ();
|
||||
|
||||
#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
|
||||
/* All shells use the signal mask they inherit, and pass it along
|
||||
to child processes. Children will never block SIGCHLD, though. */
|
||||
sigemptyset (&top_level_mask);
|
||||
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask);
|
||||
# if defined (SIGCHLD)
|
||||
sigdelset (&top_level_mask, SIGCHLD);
|
||||
# endif
|
||||
#endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */
|
||||
|
||||
/* And, some signals that are specifically ignored by the shell. */
|
||||
set_signal_handler (SIGQUIT, SIG_IGN);
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
set_signal_handler (SIGINT, sigint_sighandler);
|
||||
set_signal_handler (SIGTERM, SIG_IGN);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
reset_terminating_signals ()
|
||||
{
|
||||
register int i;
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
struct sigaction act;
|
||||
#endif
|
||||
|
||||
if (termsigs_initialized == 0)
|
||||
return;
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
act.sa_flags = 0;
|
||||
sigemptyset (&act.sa_mask);
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
{
|
||||
/* Skip a signal if it's trapped or handled specially, because the
|
||||
trap code will restore the correct value. */
|
||||
if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
|
||||
continue;
|
||||
|
||||
act.sa_handler = XHANDLER (i);
|
||||
sigaction (XSIG (i), &act, (struct sigaction *) NULL);
|
||||
}
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
{
|
||||
if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
|
||||
continue;
|
||||
|
||||
signal (XSIG (i), XHANDLER (i));
|
||||
}
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
}
|
||||
#undef XSIG
|
||||
#undef XHANDLER
|
||||
|
||||
/* What to do when we've been interrupted, and it is safe to handle it. */
|
||||
void
|
||||
throw_to_top_level ()
|
||||
{
|
||||
int print_newline = 0;
|
||||
|
||||
if (interrupt_state)
|
||||
{
|
||||
print_newline = 1;
|
||||
DELINTERRUPT;
|
||||
}
|
||||
|
||||
if (interrupt_state)
|
||||
return;
|
||||
|
||||
last_command_exit_signal = (last_command_exit_value > 128) ?
|
||||
(last_command_exit_value - 128) : 0;
|
||||
last_command_exit_value |= 128;
|
||||
|
||||
/* Run any traps set on SIGINT. */
|
||||
run_interrupt_trap ();
|
||||
|
||||
/* Cleanup string parser environment. */
|
||||
while (parse_and_execute_level)
|
||||
parse_and_execute_cleanup ();
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
give_terminal_to (shell_pgrp, 0);
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
|
||||
/* This should not be necessary on systems using sigsetjmp/siglongjmp. */
|
||||
sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
|
||||
#endif
|
||||
|
||||
reset_parser ();
|
||||
|
||||
#if defined (READLINE)
|
||||
if (interactive)
|
||||
bashline_reinitialize ();
|
||||
#endif /* READLINE */
|
||||
|
||||
#if defined (PROCESS_SUBSTITUTION)
|
||||
unlink_fifo_list ();
|
||||
#endif /* PROCESS_SUBSTITUTION */
|
||||
|
||||
run_unwind_protects ();
|
||||
loop_level = continuing = breaking = 0;
|
||||
return_catch_flag = 0;
|
||||
|
||||
if (interactive && print_newline)
|
||||
{
|
||||
fflush (stdout);
|
||||
fprintf (stderr, "\n");
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
/* An interrupted `wait' command in a script does not exit the script. */
|
||||
if (interactive || (interactive_shell && !shell_initialized) ||
|
||||
(print_newline && signal_is_trapped (SIGINT)))
|
||||
jump_to_top_level (DISCARD);
|
||||
else
|
||||
jump_to_top_level (EXITPROG);
|
||||
}
|
||||
|
||||
/* This is just here to isolate the longjmp calls. */
|
||||
void
|
||||
jump_to_top_level (value)
|
||||
int value;
|
||||
{
|
||||
longjmp (top_level, value);
|
||||
}
|
||||
|
||||
sighandler
|
||||
termination_unwind_protect (sig)
|
||||
int sig;
|
||||
{
|
||||
if (sig == SIGINT && signal_is_trapped (SIGINT))
|
||||
run_interrupt_trap ();
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (interactive_shell && sig != SIGABRT)
|
||||
maybe_save_shell_history ();
|
||||
#endif /* HISTORY */
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
if (interactive && sig == SIGHUP)
|
||||
hangup_all_jobs ();
|
||||
end_job_control ();
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#if defined (PROCESS_SUBSTITUTION)
|
||||
unlink_fifo_list ();
|
||||
#endif /* PROCESS_SUBSTITUTION */
|
||||
|
||||
run_exit_trap ();
|
||||
set_signal_handler (sig, SIG_DFL);
|
||||
kill (getpid (), sig);
|
||||
|
||||
SIGRETURN (0);
|
||||
}
|
||||
|
||||
/* What we really do when SIGINT occurs. */
|
||||
sighandler
|
||||
sigint_sighandler (sig)
|
||||
int sig;
|
||||
{
|
||||
#if defined (MUST_REINSTALL_SIGHANDLERS)
|
||||
signal (sig, sigint_sighandler);
|
||||
#endif
|
||||
|
||||
/* interrupt_state needs to be set for the stack of interrupts to work
|
||||
right. Should it be set unconditionally? */
|
||||
if (interrupt_state == 0)
|
||||
ADDINTERRUPT;
|
||||
|
||||
if (interrupt_immediately)
|
||||
{
|
||||
interrupt_immediately = 0;
|
||||
throw_to_top_level ();
|
||||
}
|
||||
|
||||
SIGRETURN (0);
|
||||
}
|
||||
|
||||
/* Signal functions used by the rest of the code. */
|
||||
#if !defined (HAVE_POSIX_SIGNALS)
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
|
||||
sigprocmask (operation, newset, oldset)
|
||||
int operation, *newset, *oldset;
|
||||
{
|
||||
int old, new;
|
||||
|
||||
if (newset)
|
||||
new = *newset;
|
||||
else
|
||||
new = 0;
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case SIG_BLOCK:
|
||||
old = sigblock (new);
|
||||
break;
|
||||
|
||||
case SIG_SETMASK:
|
||||
sigsetmask (new);
|
||||
break;
|
||||
|
||||
default:
|
||||
internal_error (_("sigprocmask: %d: invalid operation"), operation);
|
||||
}
|
||||
|
||||
if (oldset)
|
||||
*oldset = old;
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#else
|
||||
|
||||
#if !defined (SA_INTERRUPT)
|
||||
# define SA_INTERRUPT 0
|
||||
#endif
|
||||
|
||||
#if !defined (SA_RESTART)
|
||||
# define SA_RESTART 0
|
||||
#endif
|
||||
|
||||
SigHandler *
|
||||
set_signal_handler (sig, handler)
|
||||
int sig;
|
||||
SigHandler *handler;
|
||||
{
|
||||
struct sigaction act, oact;
|
||||
|
||||
act.sa_handler = handler;
|
||||
act.sa_flags = 0;
|
||||
#if 0
|
||||
if (sig == SIGALRM)
|
||||
act.sa_flags |= SA_INTERRUPT; /* XXX */
|
||||
else
|
||||
act.sa_flags |= SA_RESTART; /* XXX */
|
||||
#endif
|
||||
sigemptyset (&act.sa_mask);
|
||||
sigemptyset (&oact.sa_mask);
|
||||
sigaction (sig, &act, &oact);
|
||||
return (oact.sa_handler);
|
||||
}
|
||||
#endif /* HAVE_POSIX_SIGNALS */
|
||||
@@ -4691,6 +4691,26 @@ valid_length_expression (name)
|
||||
legal_identifier (name + 1)); /* ${#PS1} */
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
size_t
|
||||
mbstrlen (s)
|
||||
const char *s;
|
||||
{
|
||||
size_t clen, nc;
|
||||
mbstate_t mbs;
|
||||
|
||||
nc = 0;
|
||||
memset (&mbs, 0, sizeof (mbs));
|
||||
while ((clen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0 && (MB_INVALIDCH(clen) == 0))
|
||||
{
|
||||
s += clen;
|
||||
nc++;
|
||||
}
|
||||
return nc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Handle the parameter brace expansion that requires us to return the
|
||||
length of a parameter. */
|
||||
static intmax_t
|
||||
@@ -4746,14 +4766,14 @@ parameter_brace_expand_length (name)
|
||||
if (legal_number (name + 1, &arg_index)) /* ${#1} */
|
||||
{
|
||||
t = get_dollar_var_value (arg_index);
|
||||
number = STRLEN (t);
|
||||
number = MB_STRLEN (t);
|
||||
FREE (t);
|
||||
}
|
||||
#if defined (ARRAY_VARS)
|
||||
else if ((var = find_variable (name + 1)) && array_p (var))
|
||||
{
|
||||
t = array_reference (array_cell (var), 0);
|
||||
number = STRLEN (t);
|
||||
number = MB_STRLEN (t);
|
||||
}
|
||||
#endif
|
||||
else /* ${#PS1} */
|
||||
@@ -4766,7 +4786,7 @@ parameter_brace_expand_length (name)
|
||||
if (list)
|
||||
dispose_words (list);
|
||||
|
||||
number = STRLEN (t);
|
||||
number = MB_STRLEN (t);
|
||||
FREE (t);
|
||||
}
|
||||
}
|
||||
@@ -4871,7 +4891,7 @@ verify_substring_values (value, substr, vtype, e1p, e2p)
|
||||
{
|
||||
case VT_VARIABLE:
|
||||
case VT_ARRAYMEMBER:
|
||||
len = strlen (value);
|
||||
len = MB_STRLEN (value);
|
||||
break;
|
||||
case VT_POSPARMS:
|
||||
len = number_of_args () + 1;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
BUILD_DIR=/usr/local/build/chet/bash/bash-current
|
||||
BUILD_DIR=/usr/local/build/bash/bash-current
|
||||
THIS_SH=$BUILD_DIR/bash
|
||||
PATH=$PATH:$BUILD_DIR
|
||||
|
||||
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
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
-1
@@ -1,5 +1,5 @@
|
||||
echo $BASH_VERSION
|
||||
./histexp.tests: line 22: history: !!:z: history expansion failed
|
||||
./histexp.tests: line 24: history: !!:z: history expansion failed
|
||||
1 for i in one two three; do echo $i; done
|
||||
2 /bin/sh -c 'echo this is $0'
|
||||
3 ls
|
||||
|
||||
@@ -5,6 +5,8 @@ trap 'rm /tmp/newhistory' 0
|
||||
file=bax
|
||||
histchars='!^#' # make sure history comment char is set correctly
|
||||
|
||||
unset HISTFILESIZE
|
||||
|
||||
history -c
|
||||
|
||||
HISTFILE=history.list
|
||||
|
||||
+2
-2
@@ -97,7 +97,7 @@ line 2 for history
|
||||
6 HISTFILE=/tmp/newhistory
|
||||
7 echo displaying \$HISTFILE after history -a
|
||||
8 cat $HISTFILE
|
||||
./history.tests: line 73: fc: history specification out of range
|
||||
./history.tests: line 75: fc: history specification out of range
|
||||
14 set -H
|
||||
15 echo line 2 for history
|
||||
16 unset HISTSIZE
|
||||
@@ -107,5 +107,5 @@ echo xx xb xc
|
||||
xx xb xc
|
||||
echo 44 48 4c
|
||||
44 48 4c
|
||||
./history.tests: line 88: fc: no command found
|
||||
./history.tests: line 90: fc: no command found
|
||||
1
|
||||
|
||||
@@ -8,6 +8,8 @@ history -r -w /dev/null
|
||||
# bad option
|
||||
fc -v
|
||||
|
||||
unset HISTFILESIZE
|
||||
|
||||
# all of these should result in an empty history list
|
||||
history -c
|
||||
history -r /dev/null
|
||||
|
||||
@@ -3646,6 +3646,7 @@ static struct name_and_function special_vars[] = {
|
||||
{ "LC_CTYPE", sv_locale },
|
||||
{ "LC_MESSAGES", sv_locale },
|
||||
{ "LC_NUMERIC", sv_locale },
|
||||
{ "LC_TIME", sv_locale },
|
||||
|
||||
{ "MAIL", sv_mail },
|
||||
{ "MAILCHECK", sv_mail },
|
||||
|
||||
+4090
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user