commit bash-20040729 snapshot

This commit is contained in:
Chet Ramey
2011-12-03 13:33:56 -05:00
parent e6e3b44420
commit 898cc92e1b
45 changed files with 41252 additions and 64 deletions
+88
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -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; ) ; \
+621
View File
@@ -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
+1 -1
View File
@@ -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;
+207
View File
@@ -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
View File
@@ -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);
+633
View File
@@ -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
View File
@@ -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);
}
+268
View File
@@ -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);
}
+3 -4
View File
@@ -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 (( ... ))
+201
View File
@@ -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
View File
@@ -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;
+263
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -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
+10
View File
@@ -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
+6 -1
View File
@@ -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
View File
@@ -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;
}
+6
View File
@@ -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
+438
View File
@@ -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_ */
+6 -6
View File
@@ -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)
+3535
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -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;
}
+508
View File
@@ -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;
}
+19 -2
View File
@@ -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 ();
+479
View File
@@ -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;
}
}
+26 -21
View File
@@ -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 */
+525
View File
@@ -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 */
+24 -4
View File
@@ -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;
+7410
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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
+9
View File
@@ -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
View File
@@ -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
+2
View File
@@ -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
View File
@@ -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
+2
View File
@@ -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
+1
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff