mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-29 00:19:51 +02:00
commit bash-20120525 snapshot
This commit is contained in:
@@ -13823,3 +13823,76 @@ arrayfunc.c
|
||||
|
||||
arrayfunc.h
|
||||
- make_array_variable_value: new extern declaration
|
||||
|
||||
5/24
|
||||
----
|
||||
|
||||
braces.c
|
||||
- mkseq: handle possible overflow and break the sequence generating
|
||||
loop if it occurs. Fixes OpenSUSE bug 763591:
|
||||
https://bugzilla.novell.com/show_bug.cgi?id=763591
|
||||
|
||||
5/25
|
||||
----
|
||||
Makefile.in
|
||||
- LDFLAGS_FOR_BUILD: add to compilation recipes for build tools
|
||||
buildversion, mksignames, mksyntax
|
||||
- LDFLAGS_FOR_BUILD: add to compilation recipes for test tools
|
||||
recho, zecho, printenv, xcase
|
||||
|
||||
builtins/Makefile.in
|
||||
- LDFLAGS_FOR_BUILD: add to compilation recipes for build tools
|
||||
gen-helpfiles, psize.aux
|
||||
|
||||
variables.c
|
||||
- bind_int_variable: if LHS is a simple variable name without an array
|
||||
reference, but resolves to an array variable, call
|
||||
bind_array_variable with index 0 to make x=1 equivalent to x[0]=1.
|
||||
Fixes bug reported by Dan Douglas <ormaaj@gmail.com>
|
||||
|
||||
5/27
|
||||
----
|
||||
subst.c
|
||||
- expand_word_internal: make sure has_dollar_at doesn't get reset before
|
||||
recursive calls to param_expand or expand_word_internal, since it has
|
||||
to save state of what came before. Use temp variable and make sure
|
||||
has_dollar_at is incremented if recursive call processes "$@".
|
||||
Fixes bug reported by gregrwm <backuppc-users@whitleymott.net> and
|
||||
supplemented by Dan Douglas <ormaaj@gmail.com>
|
||||
|
||||
doc/{bash.1,bashref.texi}
|
||||
- changes to the description of substring expansion inspired by
|
||||
suggestions from Bill Gradwohl <bill@ycc.com>
|
||||
|
||||
doc/bashref.texi
|
||||
- added substring expansion examples inspired by suggestions from
|
||||
Bill Gradwohl <bill@ycc.com>
|
||||
|
||||
variables.c
|
||||
- find_shell_variable: search for a variable in the list of shell
|
||||
contexts, ignore the temporary environment
|
||||
- find_variable_tempenv: search for a variable in the list of shell
|
||||
contexts, force search of the temporary environment
|
||||
- find_variable_notempenv: search for a variable in the list of shell
|
||||
contexts, don't force search of the temporary environment
|
||||
|
||||
variables.h
|
||||
- find_shell_variable: extern declaration
|
||||
- find_variable_tempenv: extern declaration
|
||||
- find_variable_notempenv: extern declaration
|
||||
|
||||
arrayfunc.c
|
||||
- bind_array_variable: call find_shell_variable instead of calling
|
||||
var_lookup directly
|
||||
|
||||
findcmd.c
|
||||
- search_for_command: call find_variable_tempenv instead of
|
||||
find_variable_internal directly
|
||||
- _find_user_command_internal: call find_variable_tempenv instead of
|
||||
find_variable_internal directly
|
||||
|
||||
builtins/setattr.def
|
||||
- set_var_attribute: call find_variable_notempenv instead of
|
||||
find_variable_internal directly
|
||||
- show_name_attributes: call find_variable_tempenv instead of
|
||||
find_variable_internal directly
|
||||
|
||||
@@ -13799,3 +13799,94 @@ subst.c
|
||||
and returning a quoted null string if there's nothing else in
|
||||
ISTRING. If there is, the quoted null should just go away. Part of
|
||||
fix for bug reported by Ruediger Kuhlmann <RKuhlmann@orga-systems.com>
|
||||
- expand_word_internal: when processing ISTRING to build return value,
|
||||
only set W_HASQUOTEDNULL in the returned word flags if the word is
|
||||
a quoted null string AND had_quoted_null is set. Rest of fix
|
||||
|
||||
5/9
|
||||
---
|
||||
variables.c
|
||||
- bind_variable_internal: if we get an array variable here (implicit
|
||||
assignment to index 0), call make_array_variable_value, which
|
||||
dummies up a fake SHELL_VAR * from array[0]. This matters when
|
||||
we're appending and have to use the current value
|
||||
- bind_variable_internal: after computing the new value, treat assoc
|
||||
variables with higher precedence than simple array variables; it
|
||||
might be that a variable has both attributes set
|
||||
|
||||
arrayfunc.c
|
||||
- bind_array_var_internal: break code out that handles creating the
|
||||
new value to be assigned to an array variable index into a new
|
||||
function, make_array_variable_value. This handles creating a
|
||||
dummy SHELL_VAR * for implicit array[0] assignment. Fixes bug
|
||||
reported by Dan Douglas <ormaaj@gmail.com>
|
||||
|
||||
arrayfunc.h
|
||||
- make_array_variable_value: new extern declaration
|
||||
|
||||
5/24
|
||||
----
|
||||
|
||||
braces.c
|
||||
- mkseq: handle possible overflow and break the sequence generating
|
||||
loop if it occurs. Fixes OpenSUSE bug 763591:
|
||||
https://bugzilla.novell.com/show_bug.cgi?id=763591
|
||||
|
||||
5/25
|
||||
----
|
||||
Makefile.in
|
||||
- LDFLAGS_FOR_BUILD: add to compilation recipes for build tools
|
||||
buildversion, mksignames, mksyntax
|
||||
- LDFLAGS_FOR_BUILD: add to compilation recipes for test tools
|
||||
recho, zecho, printenv, xcase
|
||||
|
||||
builtins/Makefile.in
|
||||
- LDFLAGS_FOR_BUILD: add to compilation recipes for build tools
|
||||
gen-helpfiles, psize.aux
|
||||
|
||||
variables.c
|
||||
- bind_int_variable: if LHS is a simple variable name without an array
|
||||
reference, but resolves to an array variable, call
|
||||
bind_array_variable with index 0 to make x=1 equivalent to x[0]=1.
|
||||
Fixes bug reported by Dan Douglas <ormaaj@gmail.com>
|
||||
|
||||
5/27
|
||||
----
|
||||
subst.c
|
||||
- expand_word_internal: make sure has_dollar_at doesn't get reset before
|
||||
recursive calls to param_expand or expand_word_internal, since it has
|
||||
to save state of what came before. Use temp variable and make sure
|
||||
has_dollar_at is incremented if recursive call processes "$@".
|
||||
Fixes bug reported by gregrwm <backuppc-users@whitleymott.net> and
|
||||
supplemented by Dan Douglas <ormaaj@gmail.com>
|
||||
|
||||
doc/{bash.1,bashref.texi}
|
||||
- changes to the description of substring expansion inspired by
|
||||
suggestions from Bill Gradwohl <bill@ycc.com>
|
||||
|
||||
doc/bashref.texi
|
||||
- added substring expansion examples inspired by suggestions from
|
||||
Bill Gradwohl <bill@ycc.com>
|
||||
|
||||
variables.c
|
||||
- find_shell_variable: search for a variable in the list of shell
|
||||
contexts, ignore the temporary environment
|
||||
- find_variable_tempenv: search for a variable in the list of shell
|
||||
contexts, force search of the temporary environment
|
||||
- find_variable_notempenv: search for a variable in the list of shell
|
||||
contexts, don't force search of the temporary environment
|
||||
|
||||
variables.h
|
||||
- find_shell_variable: extern declaration
|
||||
- find_variable_tempenv: extern declaration
|
||||
- find_variable_notempenv: extern declaration
|
||||
|
||||
arrayfunc.c
|
||||
- bind_array_variable: call find_shell_variable instead of calling
|
||||
var_lookup directly
|
||||
|
||||
findcmd.c
|
||||
- search_for_command: call find_variable_tempenv instead of
|
||||
find_variable_internal directly
|
||||
- _find_user_command_internal: call find_variable_tempenv instead of
|
||||
find_variable_internal directly
|
||||
|
||||
@@ -855,6 +855,7 @@ tests/dollar-at1.sub f
|
||||
tests/dollar-at2.sub f
|
||||
tests/dollar-at3.sub f
|
||||
tests/dollar-at4.sub f
|
||||
tests/dollar-at5.sub f
|
||||
tests/dollar-star1.sub f
|
||||
tests/dollar-star2.sub f
|
||||
tests/dollar-star3.sub f
|
||||
|
||||
@@ -766,6 +766,7 @@ tests/alias.tests f
|
||||
tests/alias1.sub f
|
||||
tests/alias.right f
|
||||
tests/appendop.tests f
|
||||
tests/appendop1.sub f
|
||||
tests/appendop.right f
|
||||
tests/arith-for.tests f
|
||||
tests/arith-for.right f
|
||||
@@ -942,6 +943,7 @@ tests/intl2.sub f
|
||||
tests/intl.right f
|
||||
tests/iquote.tests f
|
||||
tests/iquote.right f
|
||||
tests/iquote1.sub f
|
||||
tests/invert.tests f
|
||||
tests/invert.right f
|
||||
tests/jobs.tests f
|
||||
|
||||
+8
-8
@@ -1,4 +1,4 @@
|
||||
# Makefile for bash-4.2, version 4.6
|
||||
# Makefile for bash-4.2, version 4.7
|
||||
#
|
||||
# Copyright (C) 1996-2011 Free Software Foundation, Inc.
|
||||
|
||||
@@ -575,7 +575,7 @@ version.h: $(SOURCES) config.h Makefile patchlevel.h
|
||||
&& mv newversion.h version.h
|
||||
|
||||
bashversion$(EXEEXT): patchlevel.h conftypes.h version.h buildversion.o $(SUPPORT_SRC)bashversion.c
|
||||
$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)bashversion.c buildversion.o ${LIBS_FOR_BUILD}
|
||||
$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)bashversion.c buildversion.o ${LIBS_FOR_BUILD}
|
||||
|
||||
buildversion.o: version.h conftypes.h patchlevel.h $(srcdir)/version.c
|
||||
$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -c -o $@ $(srcdir)/version.c
|
||||
@@ -655,11 +655,11 @@ mksignames.o: $(SUPPORT_SRC)mksignames.c
|
||||
|
||||
mksignames$(EXEEXT): mksignames.o buildsignames.o
|
||||
$(RM) $@
|
||||
$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ mksignames.o buildsignames.o ${LIBS_FOR_BUILD}
|
||||
$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ mksignames.o buildsignames.o ${LIBS_FOR_BUILD}
|
||||
|
||||
mksyntax$(EXEEXT): ${srcdir}/mksyntax.c config.h syntax.h ${BASHINCDIR}/chartypes.h
|
||||
$(RM) $@
|
||||
${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} -o $@ ${srcdir}/mksyntax.c ${LIBS_FOR_BUILD}
|
||||
${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} ${LDFLAGS_FOR_BUILD} -o $@ ${srcdir}/mksyntax.c ${LIBS_FOR_BUILD}
|
||||
|
||||
# make a list of signals for the local system -- this is done when we're
|
||||
# *not* cross-compiling
|
||||
@@ -834,16 +834,16 @@ maybe-clean:
|
||||
fi
|
||||
|
||||
recho$(EXEEXT): $(SUPPORT_SRC)recho.c
|
||||
@$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)recho.c ${LIBS_FOR_BUILD}
|
||||
@$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)recho.c ${LIBS_FOR_BUILD}
|
||||
|
||||
zecho$(EXEEXT): $(SUPPORT_SRC)zecho.c
|
||||
@$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)zecho.c ${LIBS_FOR_BUILD}
|
||||
@$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)zecho.c ${LIBS_FOR_BUILD}
|
||||
|
||||
printenv$(EXEEXT): $(SUPPORT_SRC)printenv.c
|
||||
@$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)printenv.c ${LIBS_FOR_BUILD}
|
||||
@$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)printenv.c ${LIBS_FOR_BUILD}
|
||||
|
||||
xcase$(EXEEXT): $(SUPPORT_SRC)xcase.c
|
||||
@$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)xcase.c ${LIBS_FOR_BUILD}
|
||||
@$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(SUPPORT_SRC)xcase.c ${LIBS_FOR_BUILD}
|
||||
|
||||
test tests check: force $(Program) $(TESTS_SUPPORT)
|
||||
@-test -d tests || mkdir tests
|
||||
|
||||
+1
-1
@@ -198,7 +198,7 @@ bind_array_variable (name, ind, value, flags)
|
||||
{
|
||||
SHELL_VAR *entry;
|
||||
|
||||
entry = var_lookup (name, shell_variables);
|
||||
entry = find_shell_variable (name);
|
||||
|
||||
if (entry == (SHELL_VAR *) 0)
|
||||
entry = make_new_array_variable (name);
|
||||
|
||||
+1115
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
@%:@! /bin/sh
|
||||
@%:@ From configure.in for Bash 4.2, version 4.047.
|
||||
@%:@ From configure.in for Bash 4.2, version 4.048.
|
||||
@%:@ Guess values for system-dependent variables and create Makefiles.
|
||||
@%:@ Generated by GNU Autoconf 2.68 for bash 4.2-maint.
|
||||
@%:@
|
||||
@@ -4897,7 +4897,8 @@ if test "$opt_static_link" = yes; then
|
||||
fi
|
||||
|
||||
# set the appropriate make variables for building the "build tools"
|
||||
|
||||
# modify defaults based on whether or not we are cross compiling, since the
|
||||
# options for the target host may not be appropriate for the build host
|
||||
if test "X$cross_compiling" = "Xno"; then
|
||||
CC_FOR_BUILD=${CC_FOR_BUILD-'$(CC)'}
|
||||
CPPFLAGS_FOR_BUILD=${CPPFLAGS_FOR_BUILD-"$CPPFLAGS"} # XXX - should it be '$(CPPFLAGS)'
|
||||
|
||||
+1420
-1420
File diff suppressed because it is too large
Load Diff
@@ -319,7 +319,7 @@ mkseq (start, end, incr, type, width)
|
||||
intmax_t start, end;
|
||||
int incr, type, width;
|
||||
{
|
||||
intmax_t n;
|
||||
intmax_t n, prevn;
|
||||
int i;
|
||||
char **result, *t;
|
||||
|
||||
@@ -336,7 +336,7 @@ mkseq (start, end, incr, type, width)
|
||||
|
||||
/* Make sure we go through the loop at least once, so {3..3} prints `3' */
|
||||
i = 0;
|
||||
n = start;
|
||||
prevn = n = start;
|
||||
do
|
||||
{
|
||||
#if defined (SHELL)
|
||||
@@ -359,6 +359,11 @@ mkseq (start, end, incr, type, width)
|
||||
result[i++] = t;
|
||||
}
|
||||
n += incr;
|
||||
|
||||
/* Handle overflow */
|
||||
if ((incr > 0 && n < prevn) || (incr < 0 && n > prevn))
|
||||
break;
|
||||
|
||||
if ((incr < 0 && n < end) || (incr > 0 && n > end))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ gen-helpfiles.o: gen-helpfiles.c
|
||||
$(CC_FOR_BUILD) -c $(CCFLAGS_FOR_BUILD) $<
|
||||
|
||||
gen-helpfiles: tmpbuiltins.o gen-helpfiles.o
|
||||
$(CC_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ gen-helpfiles.o tmpbuiltins.o $(LIBS_FOR_BUILD)
|
||||
$(CC_FOR_BUILD) ${CCFLAGS_FOR_BUILD} $(LDFLAGS_FOR_BUILD) -o $@ gen-helpfiles.o tmpbuiltins.o $(LIBS_FOR_BUILD)
|
||||
|
||||
builtext.h builtins.c: $(MKBUILTINS) $(DEFSRC)
|
||||
@-if test -f builtins.c; then mv -f builtins.c old-builtins.c; fi
|
||||
@@ -237,8 +237,10 @@ ulimit.o: pipesize.h
|
||||
pipesize.h: psize.aux
|
||||
$(SHELL) $(srcdir)/psize.sh > $@
|
||||
|
||||
# Technically this is wrong; the pipe size should be for the target system,
|
||||
# not the build host.
|
||||
psize.aux: psize.c
|
||||
$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(srcdir)/psize.c
|
||||
$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(srcdir)/psize.c
|
||||
|
||||
documentation: builtins.texi
|
||||
|
||||
|
||||
@@ -451,7 +451,7 @@ show_name_attributes (name, nodefs)
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = find_variable_internal (name, 1);
|
||||
var = find_variable_tempenv (name);
|
||||
|
||||
if (var && invisible_p (var) == 0)
|
||||
{
|
||||
@@ -495,7 +495,7 @@ set_var_attribute (name, attribute, undo)
|
||||
}
|
||||
else
|
||||
{
|
||||
var = find_variable_internal (name, 0);
|
||||
var = find_variable_notempenv (name);
|
||||
if (var == 0)
|
||||
{
|
||||
var = bind_variable (name, (char *)NULL, 0);
|
||||
|
||||
@@ -0,0 +1,514 @@
|
||||
This file is setattr.def, from which is created setattr.c.
|
||||
It implements the builtins "export" and "readonly", in Bash.
|
||||
|
||||
Copyright (C) 1987-2010 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$PRODUCES setattr.c
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int posixly_correct;
|
||||
extern int array_needs_making;
|
||||
extern char *this_command_name;
|
||||
extern sh_builtin_func_t *this_shell_builtin;
|
||||
|
||||
#ifdef ARRAY_VARS
|
||||
extern int declare_builtin __P((WORD_LIST *));
|
||||
#endif
|
||||
|
||||
#define READONLY_OR_EXPORT \
|
||||
(this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin)
|
||||
|
||||
$BUILTIN export
|
||||
$FUNCTION export_builtin
|
||||
$SHORT_DOC export [-fn] [name[=value] ...] or export -p
|
||||
Set export attribute for shell variables.
|
||||
|
||||
Marks each NAME for automatic export to the environment of subsequently
|
||||
executed commands. If VALUE is supplied, assign VALUE before exporting.
|
||||
|
||||
Options:
|
||||
-f refer to shell functions
|
||||
-n remove the export property from each NAME
|
||||
-p display a list of all exported variables and functions
|
||||
|
||||
An argument of `--' disables further option processing.
|
||||
|
||||
Exit Status:
|
||||
Returns success unless an invalid option is given or NAME is invalid.
|
||||
$END
|
||||
|
||||
/* For each variable name in LIST, make that variable appear in the
|
||||
environment passed to simple commands. If there is no LIST, then
|
||||
print all such variables. An argument of `-n' says to remove the
|
||||
exported attribute from variables named in LIST. An argument of
|
||||
-f indicates that the names present in LIST refer to functions. */
|
||||
int
|
||||
export_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
return (set_or_show_attributes (list, att_exported, 0));
|
||||
}
|
||||
|
||||
$BUILTIN readonly
|
||||
$FUNCTION readonly_builtin
|
||||
$SHORT_DOC readonly [-aAf] [name[=value] ...] or readonly -p
|
||||
Mark shell variables as unchangeable.
|
||||
|
||||
Mark each NAME as read-only; the values of these NAMEs may not be
|
||||
changed by subsequent assignment. If VALUE is supplied, assign VALUE
|
||||
before marking as read-only.
|
||||
|
||||
Options:
|
||||
-a refer to indexed array variables
|
||||
-A refer to associative array variables
|
||||
-f refer to shell functions
|
||||
-p display a list of all readonly variables and functions
|
||||
|
||||
An argument of `--' disables further option processing.
|
||||
|
||||
Exit Status:
|
||||
Returns success unless an invalid option is given or NAME is invalid.
|
||||
$END
|
||||
|
||||
/* For each variable name in LIST, make that variable readonly. Given an
|
||||
empty LIST, print out all existing readonly variables. */
|
||||
int
|
||||
readonly_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
return (set_or_show_attributes (list, att_readonly, 0));
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
# define ATTROPTS "aAfnp"
|
||||
#else
|
||||
# define ATTROPTS "fnp"
|
||||
#endif
|
||||
|
||||
/* For each variable name in LIST, make that variable have the specified
|
||||
ATTRIBUTE. An arg of `-n' says to remove the attribute from the the
|
||||
remaining names in LIST (doesn't work for readonly). */
|
||||
int
|
||||
set_or_show_attributes (list, attribute, nodefs)
|
||||
register WORD_LIST *list;
|
||||
int attribute, nodefs;
|
||||
{
|
||||
register SHELL_VAR *var;
|
||||
int assign, undo, any_failed, assign_error, opt;
|
||||
int functions_only, arrays_only, assoc_only;
|
||||
int aflags;
|
||||
char *name;
|
||||
#if defined (ARRAY_VARS)
|
||||
WORD_LIST *nlist, *tlist;
|
||||
WORD_DESC *w;
|
||||
#endif
|
||||
|
||||
functions_only = arrays_only = assoc_only = 0;
|
||||
undo = any_failed = assign_error = 0;
|
||||
/* Read arguments from the front of the list. */
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, ATTROPTS)) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'n':
|
||||
undo = 1;
|
||||
break;
|
||||
case 'f':
|
||||
functions_only = 1;
|
||||
break;
|
||||
#if defined (ARRAY_VARS)
|
||||
case 'a':
|
||||
arrays_only = 1;
|
||||
break;
|
||||
case 'A':
|
||||
assoc_only = 1;
|
||||
break;
|
||||
#endif
|
||||
case 'p':
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list)
|
||||
{
|
||||
if (attribute & att_exported)
|
||||
array_needs_making = 1;
|
||||
|
||||
/* Cannot undo readonly status, silently disallowed. */
|
||||
if (undo && (attribute & att_readonly))
|
||||
attribute &= ~att_readonly;
|
||||
|
||||
while (list)
|
||||
{
|
||||
name = list->word->word;
|
||||
|
||||
if (functions_only) /* xxx -f name */
|
||||
{
|
||||
var = find_function (name);
|
||||
if (var == 0)
|
||||
{
|
||||
builtin_error (_("%s: not a function"), name);
|
||||
any_failed++;
|
||||
}
|
||||
else
|
||||
SETVARATTR (var, attribute, undo);
|
||||
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* xxx [-np] name[=value] */
|
||||
assign = assignment (name, 0);
|
||||
|
||||
aflags = 0;
|
||||
if (assign)
|
||||
{
|
||||
name[assign] = '\0';
|
||||
if (name[assign - 1] == '+')
|
||||
{
|
||||
aflags |= ASS_APPEND;
|
||||
name[assign - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (legal_identifier (name) == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
if (assign)
|
||||
assign_error++;
|
||||
else
|
||||
any_failed++;
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assign) /* xxx [-np] name=value */
|
||||
{
|
||||
name[assign] = '=';
|
||||
if (aflags & ASS_APPEND)
|
||||
name[assign - 1] = '+';
|
||||
#if defined (ARRAY_VARS)
|
||||
/* Let's try something here. Turn readonly -a xxx=yyy into
|
||||
declare -ra xxx=yyy and see what that gets us. */
|
||||
if (arrays_only || assoc_only)
|
||||
{
|
||||
tlist = list->next;
|
||||
list->next = (WORD_LIST *)NULL;
|
||||
w = arrays_only ? make_word ("-ra") : make_word ("-rA");
|
||||
nlist = make_word_list (w, list);
|
||||
opt = declare_builtin (nlist);
|
||||
if (opt != EXECUTION_SUCCESS)
|
||||
assign_error++;
|
||||
list->next = tlist;
|
||||
dispose_word (w);
|
||||
free (nlist);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* This word has already been expanded once with command
|
||||
and parameter expansion. Call do_assignment_no_expand (),
|
||||
which does not do command or parameter substitution. If
|
||||
the assignment is not performed correctly, flag an error. */
|
||||
if (do_assignment_no_expand (name) == 0)
|
||||
assign_error++;
|
||||
name[assign] = '\0';
|
||||
if (aflags & ASS_APPEND)
|
||||
name[assign - 1] = '\0';
|
||||
}
|
||||
|
||||
set_var_attribute (name, attribute, undo);
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SHELL_VAR **variable_list;
|
||||
register int i;
|
||||
|
||||
if ((attribute & att_function) || functions_only)
|
||||
{
|
||||
variable_list = all_shell_functions ();
|
||||
if (attribute != att_function)
|
||||
attribute &= ~att_function; /* so declare -xf works, for example */
|
||||
}
|
||||
else
|
||||
variable_list = all_shell_variables ();
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (attribute & att_array)
|
||||
{
|
||||
arrays_only++;
|
||||
if (attribute != att_array)
|
||||
attribute &= ~att_array;
|
||||
}
|
||||
else if (attribute & att_assoc)
|
||||
{
|
||||
assoc_only++;
|
||||
if (attribute != att_assoc)
|
||||
attribute &= ~att_assoc;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (variable_list)
|
||||
{
|
||||
for (i = 0; var = variable_list[i]; i++)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (arrays_only && array_p (var) == 0)
|
||||
continue;
|
||||
else if (assoc_only && assoc_p (var) == 0)
|
||||
continue;
|
||||
#endif
|
||||
if ((var->attributes & attribute))
|
||||
{
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
if (any_failed = sh_chkwrite (any_failed))
|
||||
break;
|
||||
}
|
||||
}
|
||||
free (variable_list);
|
||||
}
|
||||
}
|
||||
|
||||
return (assign_error ? EX_BADASSIGN
|
||||
: ((any_failed == 0) ? EXECUTION_SUCCESS
|
||||
: EXECUTION_FAILURE));
|
||||
}
|
||||
|
||||
/* Show all variable variables (v == 1) or functions (v == 0) with
|
||||
attributes. */
|
||||
int
|
||||
show_all_var_attributes (v, nodefs)
|
||||
int v, nodefs;
|
||||
{
|
||||
SHELL_VAR **variable_list, *var;
|
||||
int any_failed;
|
||||
register int i;
|
||||
|
||||
variable_list = v ? all_shell_variables () : all_shell_functions ();
|
||||
if (variable_list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
for (i = any_failed = 0; var = variable_list[i]; i++)
|
||||
{
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
if (any_failed = sh_chkwrite (any_failed))
|
||||
break;
|
||||
}
|
||||
free (variable_list);
|
||||
return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Show the attributes for shell variable VAR. If NODEFS is non-zero,
|
||||
don't show function definitions along with the name. If PATTR is
|
||||
non-zero, it indicates we're being called from `export' or `readonly'.
|
||||
In POSIX mode, this prints the name of the calling builtin (`export'
|
||||
or `readonly') instead of `declare', and doesn't print function defs
|
||||
when called by `export' or `readonly'. */
|
||||
int
|
||||
show_var_attributes (var, pattr, nodefs)
|
||||
SHELL_VAR *var;
|
||||
int pattr, nodefs;
|
||||
{
|
||||
char flags[16], *x;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
|
||||
/* pattr == 0 means we are called from `declare'. */
|
||||
if (pattr == 0 || posixly_correct == 0)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (var))
|
||||
flags[i++] = 'a';
|
||||
|
||||
if (assoc_p (var))
|
||||
flags[i++] = 'A';
|
||||
#endif
|
||||
|
||||
if (function_p (var))
|
||||
flags[i++] = 'f';
|
||||
|
||||
if (integer_p (var))
|
||||
flags[i++] = 'i';
|
||||
|
||||
if (readonly_p (var))
|
||||
flags[i++] = 'r';
|
||||
|
||||
if (trace_p (var))
|
||||
flags[i++] = 't';
|
||||
|
||||
if (exported_p (var))
|
||||
flags[i++] = 'x';
|
||||
|
||||
if (capcase_p (var))
|
||||
flags[i++] = 'c';
|
||||
|
||||
if (lowercase_p (var))
|
||||
flags[i++] = 'l';
|
||||
|
||||
if (uppercase_p (var))
|
||||
flags[i++] = 'u';
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (var))
|
||||
flags[i++] = 'a';
|
||||
|
||||
if (assoc_p (var))
|
||||
flags[i++] = 'A';
|
||||
#endif
|
||||
|
||||
if (function_p (var))
|
||||
flags[i++] = 'f';
|
||||
}
|
||||
|
||||
flags[i] = '\0';
|
||||
|
||||
/* If we're printing functions with definitions, print the function def
|
||||
first, then the attributes, instead of printing output that can't be
|
||||
reused as input to recreate the current state. */
|
||||
if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0))
|
||||
{
|
||||
printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
|
||||
nodefs++;
|
||||
if (pattr == 0 && i == 1 && flags[0] == 'f')
|
||||
return 0; /* don't print `declare -f name' */
|
||||
}
|
||||
|
||||
if (pattr == 0 || posixly_correct == 0)
|
||||
printf ("declare -%s ", i ? flags : "-");
|
||||
else if (i)
|
||||
printf ("%s -%s ", this_command_name, flags);
|
||||
else
|
||||
printf ("%s ", this_command_name);
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (var))
|
||||
print_array_assignment (var, 1);
|
||||
else if (assoc_p (var))
|
||||
print_assoc_assignment (var, 1);
|
||||
else
|
||||
#endif
|
||||
/* force `readonly' and `export' to not print out function definitions
|
||||
when in POSIX mode. */
|
||||
if (nodefs || (function_p (var) && pattr != 0 && posixly_correct))
|
||||
printf ("%s\n", var->name);
|
||||
else if (function_p (var))
|
||||
printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
|
||||
else if (invisible_p (var) || var_isset (var) == 0)
|
||||
printf ("%s\n", var->name);
|
||||
else
|
||||
{
|
||||
x = sh_double_quote (value_cell (var));
|
||||
printf ("%s=%s\n", var->name, x);
|
||||
free (x);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
show_name_attributes (name, nodefs)
|
||||
char *name;
|
||||
int nodefs;
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = find_variable_internal (name, 1);
|
||||
|
||||
if (var && invisible_p (var) == 0)
|
||||
{
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
set_var_attribute (name, attribute, undo)
|
||||
char *name;
|
||||
int attribute, undo;
|
||||
{
|
||||
SHELL_VAR *var, *tv;
|
||||
char *tvalue;
|
||||
|
||||
if (undo)
|
||||
var = find_variable (name);
|
||||
else
|
||||
{
|
||||
tv = find_tempenv_variable (name);
|
||||
/* XXX -- need to handle case where tv is a temp variable in a
|
||||
function-scope context, since function_env has been merged into
|
||||
the local variables table. */
|
||||
if (tv && tempvar_p (tv))
|
||||
{
|
||||
tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring ("");
|
||||
|
||||
var = bind_variable (tv->name, tvalue, 0);
|
||||
var->attributes |= tv->attributes & ~att_tempvar;
|
||||
VSETATTR (tv, att_propagate);
|
||||
if (var->context != 0)
|
||||
VSETATTR (var, att_propagate);
|
||||
SETVARATTR (tv, attribute, undo); /* XXX */
|
||||
|
||||
stupidly_hack_special_variables (tv->name);
|
||||
|
||||
free (tvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var = find_variable_internal (name, 0);
|
||||
if (var == 0)
|
||||
{
|
||||
var = bind_variable (name, (char *)NULL, 0);
|
||||
VSETATTR (var, att_invisible);
|
||||
}
|
||||
else if (var->context != 0)
|
||||
VSETATTR (var, att_propagate);
|
||||
}
|
||||
}
|
||||
|
||||
if (var)
|
||||
SETVARATTR (var, attribute, undo);
|
||||
|
||||
if (var && (exported_p (var) || (attribute & att_exported)))
|
||||
array_needs_making++; /* XXX */
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#! /bin/sh
|
||||
# From configure.in for Bash 4.2, version 4.047.
|
||||
# From configure.in for Bash 4.2, version 4.048.
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.68 for bash 4.2-maint.
|
||||
#
|
||||
@@ -4897,7 +4897,8 @@ if test "$opt_static_link" = yes; then
|
||||
fi
|
||||
|
||||
# set the appropriate make variables for building the "build tools"
|
||||
|
||||
# modify defaults based on whether or not we are cross compiling, since the
|
||||
# options for the target host may not be appropriate for the build host
|
||||
if test "X$cross_compiling" = "Xno"; then
|
||||
CC_FOR_BUILD=${CC_FOR_BUILD-'$(CC)'}
|
||||
CPPFLAGS_FOR_BUILD=${CPPFLAGS_FOR_BUILD-"$CPPFLAGS"} # XXX - should it be '$(CPPFLAGS)'
|
||||
|
||||
+3
-2
@@ -21,7 +21,7 @@ dnl Process this file with autoconf to produce a configure script.
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AC_REVISION([for Bash 4.2, version 4.047])dnl
|
||||
AC_REVISION([for Bash 4.2, version 4.048])dnl
|
||||
|
||||
define(bashvers, 4.2)
|
||||
define(relstatus, maint)
|
||||
@@ -482,7 +482,8 @@ if test "$opt_static_link" = yes; then
|
||||
fi
|
||||
|
||||
# set the appropriate make variables for building the "build tools"
|
||||
|
||||
# modify defaults based on whether or not we are cross compiling, since the
|
||||
# options for the target host may not be appropriate for the build host
|
||||
if test "X$cross_compiling" = "Xno"; then
|
||||
CC_FOR_BUILD=${CC_FOR_BUILD-'$(CC)'}
|
||||
CPPFLAGS_FOR_BUILD=${CPPFLAGS_FOR_BUILD-"$CPPFLAGS"} # XXX - should it be '$(CPPFLAGS)'
|
||||
|
||||
+35
-15
@@ -5,12 +5,12 @@
|
||||
.\" Case Western Reserve University
|
||||
.\" chet@po.cwru.edu
|
||||
.\"
|
||||
.\" Last Change: Sat Apr 7 20:01:48 EDT 2012
|
||||
.\" Last Change: Sun May 27 20:28:33 EDT 2012
|
||||
.\"
|
||||
.\" bash_builtins, strip all but Built-Ins section
|
||||
.if \n(zZ=1 .ig zZ
|
||||
.if \n(zY=1 .ig zY
|
||||
.TH BASH 1 "2012 April 7" "GNU Bash 4.2"
|
||||
.TH BASH 1 "2012 May 27" "GNU Bash 4.2"
|
||||
.\"
|
||||
.\" There's some problem with having a `@'
|
||||
.\" in a tagged paragraph with the BSD man macros.
|
||||
@@ -2697,10 +2697,12 @@ or when
|
||||
.I parameter
|
||||
is followed by a character which is not to be
|
||||
interpreted as part of its name.
|
||||
The \fIparameter\fP is a shell parameter as described above
|
||||
\fBPARAMETERS\fP) or an array reference (\fBArrays\fP).
|
||||
.PD
|
||||
.PP
|
||||
If the first character of \fIparameter\fP is an exclamation point (\fB!\fP),
|
||||
a level of variable indirection is introduced.
|
||||
it introduces a level of variable indirection.
|
||||
\fBBash\fP uses the value of the variable formed from the rest of
|
||||
\fIparameter\fP as the name of the variable; this variable is then
|
||||
expanded and that value is used in the rest of the substitution, rather
|
||||
@@ -2714,7 +2716,8 @@ introduce indirection.
|
||||
In each of the cases below, \fIword\fP is subject to tilde expansion,
|
||||
parameter expansion, command substitution, and arithmetic expansion.
|
||||
.PP
|
||||
When not performing substring expansion, using the forms documented below,
|
||||
When not performing substring expansion, using the forms documented below
|
||||
(e.g., \fB:-\fP),
|
||||
\fBbash\fP tests for a parameter that is unset or null. Omitting the colon
|
||||
results in a test only for a parameter that is unset.
|
||||
.PP
|
||||
@@ -2767,33 +2770,50 @@ ${\fIparameter\fP\fB:\fP\fIoffset\fP}
|
||||
${\fIparameter\fP\fB:\fP\fIoffset\fP\fB:\fP\fIlength\fP}
|
||||
.PD
|
||||
\fBSubstring Expansion\fP.
|
||||
Expands to up to \fIlength\fP characters of \fIparameter\fP
|
||||
Expands to up to \fIlength\fP characters of the value of \fIparameter\fP
|
||||
starting at the character specified by \fIoffset\fP.
|
||||
If \fIlength\fP is omitted, expands to the substring of
|
||||
\fIparameter\fP starting at the character specified by \fIoffset\fP.
|
||||
If \fIparameter\fP is \fB@\fP, an indexed array subscripted by
|
||||
\fB@\fP or \fB*\fP, or an associative array name, the results differ as
|
||||
described below.
|
||||
If \fIlength\fP is omitted, expands to the substring of the value of
|
||||
\fIparameter\fP starting at the character specified by \fIoffset\fP
|
||||
and extending to the end of the value.
|
||||
\fIlength\fP and \fIoffset\fP are arithmetic expressions (see
|
||||
.SM
|
||||
.B
|
||||
ARITHMETIC EVALUATION
|
||||
below).
|
||||
.sp 1
|
||||
If \fIoffset\fP evaluates to a number less than zero, the value
|
||||
is used as an offset from the end of the value of \fIparameter\fP.
|
||||
If \fIlength\fP evaluates to a number less than zero, and \fIparameter\fP
|
||||
is not \fB@\fP and not an indexed or associative array, it is interpreted
|
||||
as an offset from the end of the value of \fIparameter\fP rather than
|
||||
a number of characters, and the expansion is the characters between the
|
||||
two offsets.
|
||||
is used as an offset in characters
|
||||
from the end of the value of \fIparameter\fP.
|
||||
If \fIlength\fP evaluates to a number less than zero,
|
||||
it is interpreted as an offset in characters
|
||||
from the end of the value of \fIparameter\fP rather than
|
||||
a number of characters, and the expansion is the characters between
|
||||
\fIoffset\fP and that result.
|
||||
Note that a negative offset must be separated from the colon by at least
|
||||
one space to avoid being confused with the \fB:-\fP expansion.
|
||||
.sp 1
|
||||
If \fIparameter\fP is \fB@\fP, the result is \fIlength\fP positional
|
||||
parameters beginning at \fIoffset\fP.
|
||||
A negative \fIoffset\fP is taken relative to one greater than the greatest
|
||||
positional parameter, so an offset of -1 evaluates to the last positional
|
||||
parameter.
|
||||
It is an expansion error if \fIlength\fP evaluates to a number less than
|
||||
zero.
|
||||
.sp 1
|
||||
If \fIparameter\fP is an indexed array name subscripted by @ or *,
|
||||
the result is the \fIlength\fP
|
||||
members of the array beginning with ${\fIparameter\fP[\fIoffset\fP]}.
|
||||
A negative \fIoffset\fP is taken relative to one greater than the maximum
|
||||
index of the specified array.
|
||||
It is an expansion error if \fIlength\fP evaluates to a number less than
|
||||
zero.
|
||||
.sp 1
|
||||
Substring expansion applied to an associative array produces undefined
|
||||
results.
|
||||
Note that a negative offset must be separated from the colon by at least
|
||||
one space to avoid being confused with the :- expansion.
|
||||
.sp 1
|
||||
Substring indexing is zero-based unless the positional parameters
|
||||
are used, in which case the indexing starts at 1 by default.
|
||||
If \fIoffset\fP is 0, and the positional parameters are used, \fB$0\fP is
|
||||
|
||||
+10138
File diff suppressed because it is too large
Load Diff
+133
-18
@@ -1781,15 +1781,16 @@ embedded arithmetic expansion, command substitution, or parameter
|
||||
expansion.
|
||||
|
||||
The basic form of parameter expansion is $@{@var{parameter}@}.
|
||||
The value of @var{parameter} is substituted. The braces are required
|
||||
when @var{parameter}
|
||||
The value of @var{parameter} is substituted.
|
||||
The @var{parameter} is a shell parameter as described above
|
||||
(@pxref{Shell Parameters}) or an array reference (@pxref{Arrays}).
|
||||
The braces are required when @var{parameter}
|
||||
is a positional parameter with more than one digit,
|
||||
or when @var{parameter}
|
||||
is followed by a character that is not to be
|
||||
or when @var{parameter} is followed by a character that is not to be
|
||||
interpreted as part of its name.
|
||||
|
||||
If the first character of @var{parameter} is an exclamation point (!),
|
||||
a level of variable indirection is introduced.
|
||||
it introduces a level of variable indirection.
|
||||
Bash uses the value of the variable formed from the rest of
|
||||
@var{parameter} as the name of the variable; this variable is then
|
||||
expanded and that value is used in the rest of the substitution, rather
|
||||
@@ -1805,7 +1806,7 @@ In each of the cases below, @var{word} is subject to tilde expansion,
|
||||
parameter expansion, command substitution, and arithmetic expansion.
|
||||
|
||||
When not performing substring expansion, using the form described
|
||||
below, Bash tests for a parameter that is unset or null.
|
||||
below (e.g., @samp{:-}), Bash tests for a parameter that is unset or null.
|
||||
Omitting the colon results in a test only for a parameter that is unset.
|
||||
Put another way, if the colon is included,
|
||||
the operator tests for both @var{parameter}'s existence and that its value
|
||||
@@ -1841,33 +1842,147 @@ is null or unset, nothing is substituted, otherwise the expansion of
|
||||
|
||||
@item $@{@var{parameter}:@var{offset}@}
|
||||
@itemx $@{@var{parameter}:@var{offset}:@var{length}@}
|
||||
Expands to up to @var{length} characters of @var{parameter}
|
||||
This is referred to as Substring Expansion.
|
||||
It expands to up to @var{length} characters of the value of @var{parameter}
|
||||
starting at the character specified by @var{offset}.
|
||||
If @var{length} is omitted, expands to the substring of
|
||||
@var{parameter} starting at the character specified by @var{offset}.
|
||||
If @var{parameter} is @samp{@@}, an indexed array subscripted by
|
||||
@samp{@@} or @samp{*}, or an associative array name, the results differ as
|
||||
described below.
|
||||
If @var{length} is omitted, it expands to the substring of the value of
|
||||
@var{parameter} starting at the character specified by @var{offset}
|
||||
and extending to the end of the value.
|
||||
@var{length} and @var{offset} are arithmetic expressions
|
||||
(@pxref{Shell Arithmetic}).
|
||||
This is referred to as Substring Expansion.
|
||||
|
||||
If @var{offset} evaluates to a number less than zero, the value
|
||||
is used as an offset from the end of the value of @var{parameter}.
|
||||
If @var{length} evaluates to a number less than zero, and @var{parameter}
|
||||
is not @samp{@@} and not an indexed or associative array, it is interpreted
|
||||
as an offset from the end of the value of @var{parameter} rather than
|
||||
a number of characters, and the expansion is the characters between the
|
||||
two offsets.
|
||||
is used as an offset in characters
|
||||
from the end of the value of @var{parameter}.
|
||||
If @var{length} evaluates to a number less than zero,
|
||||
it is interpreted as an offset in characters
|
||||
from the end of the value of @var{parameter} rather than
|
||||
a number of characters, and the expansion is the characters between
|
||||
@var{offset} and that result.
|
||||
Note that a negative offset must be separated from the colon by at least
|
||||
one space to avoid being confused with the @samp{:-} expansion.
|
||||
|
||||
Here are some examples illustrating substring expansion on parameters and
|
||||
subscripted arrays:
|
||||
|
||||
@verbatim
|
||||
$ string=01234567890abcdefgh
|
||||
$ echo ${string:7}
|
||||
7890abcdefgh
|
||||
$ echo ${string:7:0}
|
||||
|
||||
$ echo ${string:7:2}
|
||||
78
|
||||
$ echo ${string:7:-2}
|
||||
7890abcdef
|
||||
$ echo ${string: -7}
|
||||
bcdefgh
|
||||
$ echo ${string: -7:0}
|
||||
|
||||
$ echo ${string: -7:2}
|
||||
bc
|
||||
$ echo ${string: -7:-2}
|
||||
bcdef
|
||||
$ set -- 01234567890abcdefgh
|
||||
$ echo ${1:7}
|
||||
7890abcdefgh
|
||||
$ echo ${1:7:0}
|
||||
|
||||
$ echo ${1:7:2}
|
||||
78
|
||||
$ echo ${1:7:-2}
|
||||
7890abcdef
|
||||
$ echo ${1: -7}
|
||||
bcdefgh
|
||||
$ echo ${1: -7:0}
|
||||
|
||||
$ echo ${1: -7:2}
|
||||
bc
|
||||
$ echo ${1: -7:-2}
|
||||
bcdef
|
||||
$ array[0]=01234567890abcdefgh
|
||||
$ echo ${array[0]:7}
|
||||
7890abcdefgh
|
||||
$ echo ${array[0]:7:0}
|
||||
|
||||
$ echo ${array[0]:7:2}
|
||||
78
|
||||
$ echo ${array[0]:7:-2}
|
||||
7890abcdef
|
||||
$ echo ${array[0]: -7}
|
||||
bcdefgh
|
||||
$ echo ${array[0]: -7:0}
|
||||
|
||||
$ echo ${array[0]: -7:2}
|
||||
bc
|
||||
$ echo ${array[0]: -7:-2}
|
||||
bcdef
|
||||
@end verbatim
|
||||
|
||||
If @var{parameter} is @samp{@@}, the result is @var{length} positional
|
||||
parameters beginning at @var{offset}.
|
||||
A negative @var{offset} is taken relative to one greater than the greatest
|
||||
positional parameter, so an offset of -1 evaluates to the last positional
|
||||
parameter.
|
||||
It is an expansion error if @var{length} evaluates to a number less than zero.
|
||||
|
||||
The following examples illustrate substring expansion using positional
|
||||
parameters:
|
||||
|
||||
@verbatim
|
||||
$ set -- 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
|
||||
$ echo ${@:7}
|
||||
7 8 9 0 a b c d e f g h
|
||||
$ echo ${@:7:0}
|
||||
|
||||
$ echo ${@:7:2}
|
||||
7 8
|
||||
$ echo ${@:7:-2}
|
||||
bash: -2: substring expression < 0
|
||||
$ echo ${@: -7:2}
|
||||
b c
|
||||
$ echo ${@:0}
|
||||
./bash 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
|
||||
$ echo ${@:0:2}
|
||||
./bash 1
|
||||
$ echo ${@: -7:0}
|
||||
|
||||
@end verbatim
|
||||
|
||||
If @var{parameter} is an indexed array name subscripted
|
||||
by @samp{@@} or @samp{*}, the result is the @var{length}
|
||||
members of the array beginning with @code{$@{@var{parameter}[@var{offset}]@}}.
|
||||
A negative @var{offset} is taken relative to one greater than the maximum
|
||||
index of the specified array.
|
||||
It is an expansion error if @var{length} evaluates to a number less than zero.
|
||||
|
||||
These examples show how you can use substring expansion with indexed
|
||||
arrays:
|
||||
|
||||
@verbatim
|
||||
$ array=(0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h)
|
||||
$ echo ${array[@]:7}
|
||||
7 8 9 0 a b c d e f g h
|
||||
$ echo ${array[@]:7:2}
|
||||
7 8
|
||||
$ echo ${array[@]: -7:2}
|
||||
b c
|
||||
$ echo ${array[@]: -7:-2}
|
||||
bash: -2: substring expression < 0
|
||||
$ echo ${array[@]:0}
|
||||
0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
|
||||
$ echo ${array[@]:0:2}
|
||||
0 1
|
||||
$ echo ${array[@]: -7:0}
|
||||
|
||||
@end verbatim
|
||||
|
||||
Substring expansion applied to an associative array produces undefined
|
||||
results.
|
||||
|
||||
Note that a negative offset must be separated from the colon by at least
|
||||
one space to avoid being confused with the @samp{:-} expansion.
|
||||
Substring indexing is zero-based unless the positional parameters
|
||||
are used, in which case the indexing starts at 1 by default.
|
||||
If @var{offset} is 0, and the positional parameters are used, @code{$@@} is
|
||||
|
||||
+8494
File diff suppressed because it is too large
Load Diff
+3
-5
@@ -2,14 +2,12 @@
|
||||
Copyright (C) 1988-2012 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set LASTCHANGE Sat Apr 7 20:02:15 EDT 2012
|
||||
|
||||
@set LASTCHANGE Sun May 27 20:28:13 EDT 2012
|
||||
|
||||
@set EDITION 4.2
|
||||
@set VERSION 4.2
|
||||
@set UPDATED 7 April 2012
|
||||
@set UPDATED-MONTH April 2012
|
||||
|
||||
@set UPDATED 27 May 2012
|
||||
@set UPDATED-MONTH May 2012
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
@ignore
|
||||
Copyright (C) 1988-2012 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set LASTCHANGE Sat Apr 7 20:02:15 EDT 2012
|
||||
|
||||
|
||||
@set EDITION 4.2
|
||||
@set VERSION 4.2
|
||||
@set UPDATED 7 April 2012
|
||||
@set UPDATED-MONTH April 2012
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ _find_user_command_internal (name, flags)
|
||||
|
||||
/* Search for the value of PATH in both the temporary environments and
|
||||
in the regular list of variables. */
|
||||
if (var = find_variable_internal ("PATH", 1)) /* XXX could be array? */
|
||||
if (var = find_variable_tempenv ("PATH")) /* XXX could be array? */
|
||||
path_list = value_cell (var);
|
||||
else
|
||||
path_list = (char *)NULL;
|
||||
@@ -312,7 +312,7 @@ search_for_command (pathname, flags)
|
||||
|
||||
/* If PATH is in the temporary environment for this command, don't use the
|
||||
hash table to search for the full pathname. */
|
||||
path = find_variable_internal ("PATH", 1);
|
||||
path = find_variable_tempenv ("PATH");
|
||||
temp_path = path && tempvar_p (path);
|
||||
if (temp_path == 0 && path)
|
||||
path = (SHELL_VAR *)NULL;
|
||||
|
||||
+622
@@ -0,0 +1,622 @@
|
||||
/* findcmd.c -- Functions to search for commands by name. */
|
||||
|
||||
/* Copyright (C) 1997-2012 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "chartypes.h"
|
||||
#include "bashtypes.h"
|
||||
#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
#include "filecntl.h"
|
||||
#include "posixstat.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#include "memalloc.h"
|
||||
#include "shell.h"
|
||||
#include "flags.h"
|
||||
#include "hashlib.h"
|
||||
#include "pathexp.h"
|
||||
#include "hashcmd.h"
|
||||
#include "findcmd.h" /* matching prototypes and declarations */
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern int posixly_correct;
|
||||
|
||||
/* Static functions defined and used in this file. */
|
||||
static char *_find_user_command_internal __P((const char *, int));
|
||||
static char *find_user_command_internal __P((const char *, int));
|
||||
static char *find_user_command_in_path __P((const char *, char *, int));
|
||||
static char *find_in_path_element __P((const char *, char *, int, int, struct stat *));
|
||||
static char *find_absolute_program __P((const char *, int));
|
||||
|
||||
static char *get_next_path_element __P((char *, int *));
|
||||
|
||||
/* The file name which we would try to execute, except that it isn't
|
||||
possible to execute it. This is the first file that matches the
|
||||
name that we are looking for while we are searching $PATH for a
|
||||
suitable one to execute. If we cannot find a suitable executable
|
||||
file, then we use this one. */
|
||||
static char *file_to_lose_on;
|
||||
|
||||
/* Non-zero if we should stat every command found in the hash table to
|
||||
make sure it still exists. */
|
||||
int check_hashed_filenames;
|
||||
|
||||
/* DOT_FOUND_IN_SEARCH becomes non-zero when find_user_command ()
|
||||
encounters a `.' as the directory pathname while scanning the
|
||||
list of possible pathnames; i.e., if `.' comes before the directory
|
||||
containing the file of interest. */
|
||||
int dot_found_in_search = 0;
|
||||
|
||||
/* Return some flags based on information about this file.
|
||||
The EXISTS bit is non-zero if the file is found.
|
||||
The EXECABLE bit is non-zero the file is executble.
|
||||
Zero is returned if the file is not found. */
|
||||
int
|
||||
file_status (name)
|
||||
const char *name;
|
||||
{
|
||||
struct stat finfo;
|
||||
int r;
|
||||
|
||||
/* Determine whether this file exists or not. */
|
||||
if (stat (name, &finfo) < 0)
|
||||
return (0);
|
||||
|
||||
/* If the file is a directory, then it is not "executable" in the
|
||||
sense of the shell. */
|
||||
if (S_ISDIR (finfo.st_mode))
|
||||
return (FS_EXISTS|FS_DIRECTORY);
|
||||
|
||||
r = FS_EXISTS;
|
||||
|
||||
#if defined (HAVE_EACCESS)
|
||||
/* Use eaccess(2) if we have it to take things like ACLs and other
|
||||
file access mechanisms into account. eaccess uses the effective
|
||||
user and group IDs, not the real ones. We could use sh_eaccess,
|
||||
but we don't want any special treatment for /dev/fd. */
|
||||
if (eaccess (name, X_OK) == 0)
|
||||
r |= FS_EXECABLE;
|
||||
if (eaccess (name, R_OK) == 0)
|
||||
r |= FS_READABLE;
|
||||
|
||||
return r;
|
||||
#elif defined (AFS)
|
||||
/* We have to use access(2) to determine access because AFS does not
|
||||
support Unix file system semantics. This may produce wrong
|
||||
answers for non-AFS files when ruid != euid. I hate AFS. */
|
||||
if (access (name, X_OK) == 0)
|
||||
r |= FS_EXECABLE;
|
||||
if (access (name, R_OK) == 0)
|
||||
r |= FS_READABLE;
|
||||
|
||||
return r;
|
||||
#else /* !HAVE_EACCESS && !AFS */
|
||||
|
||||
/* Find out if the file is actually executable. By definition, the
|
||||
only other criteria is that the file has an execute bit set that
|
||||
we can use. The same with whether or not a file is readable. */
|
||||
|
||||
/* Root only requires execute permission for any of owner, group or
|
||||
others to be able to exec a file, and can read any file. */
|
||||
if (current_user.euid == (uid_t)0)
|
||||
{
|
||||
r |= FS_READABLE;
|
||||
if (finfo.st_mode & S_IXUGO)
|
||||
r |= FS_EXECABLE;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* If we are the owner of the file, the owner bits apply. */
|
||||
if (current_user.euid == finfo.st_uid)
|
||||
{
|
||||
if (finfo.st_mode & S_IXUSR)
|
||||
r |= FS_EXECABLE;
|
||||
if (finfo.st_mode & S_IRUSR)
|
||||
r |= FS_READABLE;
|
||||
}
|
||||
|
||||
/* If we are in the owning group, the group permissions apply. */
|
||||
else if (group_member (finfo.st_gid))
|
||||
{
|
||||
if (finfo.st_mode & S_IXGRP)
|
||||
r |= FS_EXECABLE;
|
||||
if (finfo.st_mode & S_IRGRP)
|
||||
r |= FS_READABLE;
|
||||
}
|
||||
|
||||
/* Else we check whether `others' have permission to execute the file */
|
||||
else
|
||||
{
|
||||
if (finfo.st_mode & S_IXOTH)
|
||||
r |= FS_EXECABLE;
|
||||
if (finfo.st_mode & S_IROTH)
|
||||
r |= FS_READABLE;
|
||||
}
|
||||
|
||||
return r;
|
||||
#endif /* !AFS */
|
||||
}
|
||||
|
||||
/* Return non-zero if FILE exists and is executable.
|
||||
Note that this function is the definition of what an
|
||||
executable file is; do not change this unless YOU know
|
||||
what an executable file is. */
|
||||
int
|
||||
executable_file (file)
|
||||
const char *file;
|
||||
{
|
||||
int s;
|
||||
|
||||
s = file_status (file);
|
||||
#if defined EISDIR
|
||||
if (s & FS_DIRECTORY)
|
||||
errno = EISDIR; /* let's see if we can improve error messages */
|
||||
#endif
|
||||
return ((s & FS_EXECABLE) && ((s & FS_DIRECTORY) == 0));
|
||||
}
|
||||
|
||||
int
|
||||
is_directory (file)
|
||||
const char *file;
|
||||
{
|
||||
return (file_status (file) & FS_DIRECTORY);
|
||||
}
|
||||
|
||||
int
|
||||
executable_or_directory (file)
|
||||
const char *file;
|
||||
{
|
||||
int s;
|
||||
|
||||
s = file_status (file);
|
||||
return ((s & FS_EXECABLE) || (s & FS_DIRECTORY));
|
||||
}
|
||||
|
||||
/* Locate the executable file referenced by NAME, searching along
|
||||
the contents of the shell PATH variable. Return a new string
|
||||
which is the full pathname to the file, or NULL if the file
|
||||
couldn't be found. If a file is found that isn't executable,
|
||||
and that is the only match, then return that. */
|
||||
char *
|
||||
find_user_command (name)
|
||||
const char *name;
|
||||
{
|
||||
return (find_user_command_internal (name, FS_EXEC_PREFERRED|FS_NODIRS));
|
||||
}
|
||||
|
||||
/* Locate the file referenced by NAME, searching along the contents
|
||||
of the shell PATH variable. Return a new string which is the full
|
||||
pathname to the file, or NULL if the file couldn't be found. This
|
||||
returns the first readable file found; designed to be used to look
|
||||
for shell scripts or files to source. */
|
||||
char *
|
||||
find_path_file (name)
|
||||
const char *name;
|
||||
{
|
||||
return (find_user_command_internal (name, FS_READABLE));
|
||||
}
|
||||
|
||||
static char *
|
||||
_find_user_command_internal (name, flags)
|
||||
const char *name;
|
||||
int flags;
|
||||
{
|
||||
char *path_list, *cmd;
|
||||
SHELL_VAR *var;
|
||||
|
||||
/* Search for the value of PATH in both the temporary environments and
|
||||
in the regular list of variables. */
|
||||
if (var = find_variable_internal ("PATH", 1)) /* XXX could be array? */
|
||||
path_list = value_cell (var);
|
||||
else
|
||||
path_list = (char *)NULL;
|
||||
|
||||
if (path_list == 0 || *path_list == '\0')
|
||||
return (savestring (name));
|
||||
|
||||
cmd = find_user_command_in_path (name, path_list, flags);
|
||||
|
||||
return (cmd);
|
||||
}
|
||||
|
||||
static char *
|
||||
find_user_command_internal (name, flags)
|
||||
const char *name;
|
||||
int flags;
|
||||
{
|
||||
#ifdef __WIN32__
|
||||
char *res, *dotexe;
|
||||
|
||||
dotexe = (char *)xmalloc (strlen (name) + 5);
|
||||
strcpy (dotexe, name);
|
||||
strcat (dotexe, ".exe");
|
||||
res = _find_user_command_internal (dotexe, flags);
|
||||
free (dotexe);
|
||||
if (res == 0)
|
||||
res = _find_user_command_internal (name, flags);
|
||||
return res;
|
||||
#else
|
||||
return (_find_user_command_internal (name, flags));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return the next element from PATH_LIST, a colon separated list of
|
||||
paths. PATH_INDEX_POINTER is the address of an index into PATH_LIST;
|
||||
the index is modified by this function.
|
||||
Return the next element of PATH_LIST or NULL if there are no more. */
|
||||
static char *
|
||||
get_next_path_element (path_list, path_index_pointer)
|
||||
char *path_list;
|
||||
int *path_index_pointer;
|
||||
{
|
||||
char *path;
|
||||
|
||||
path = extract_colon_unit (path_list, path_index_pointer);
|
||||
|
||||
if (path == 0)
|
||||
return (path);
|
||||
|
||||
if (*path == '\0')
|
||||
{
|
||||
free (path);
|
||||
path = savestring (".");
|
||||
}
|
||||
|
||||
return (path);
|
||||
}
|
||||
|
||||
/* Look for PATHNAME in $PATH. Returns either the hashed command
|
||||
corresponding to PATHNAME or the first instance of PATHNAME found
|
||||
in $PATH. If (FLAGS&1) is non-zero, insert the instance of PATHNAME
|
||||
found in $PATH into the command hash table. Returns a newly-allocated
|
||||
string. */
|
||||
char *
|
||||
search_for_command (pathname, flags)
|
||||
const char *pathname;
|
||||
int flags;
|
||||
{
|
||||
char *hashed_file, *command;
|
||||
int temp_path, st;
|
||||
SHELL_VAR *path;
|
||||
|
||||
hashed_file = command = (char *)NULL;
|
||||
|
||||
/* If PATH is in the temporary environment for this command, don't use the
|
||||
hash table to search for the full pathname. */
|
||||
path = find_variable_internal ("PATH", 1);
|
||||
temp_path = path && tempvar_p (path);
|
||||
if (temp_path == 0 && path)
|
||||
path = (SHELL_VAR *)NULL;
|
||||
|
||||
/* Don't waste time trying to find hashed data for a pathname
|
||||
that is already completely specified or if we're using a command-
|
||||
specific value for PATH. */
|
||||
if (path == 0 && absolute_program (pathname) == 0)
|
||||
hashed_file = phash_search (pathname);
|
||||
|
||||
/* If a command found in the hash table no longer exists, we need to
|
||||
look for it in $PATH. Thank you Posix.2. This forces us to stat
|
||||
every command found in the hash table. */
|
||||
|
||||
if (hashed_file && (posixly_correct || check_hashed_filenames))
|
||||
{
|
||||
st = file_status (hashed_file);
|
||||
if ((st & (FS_EXISTS|FS_EXECABLE)) != (FS_EXISTS|FS_EXECABLE))
|
||||
{
|
||||
phash_remove (pathname);
|
||||
free (hashed_file);
|
||||
hashed_file = (char *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (hashed_file)
|
||||
command = hashed_file;
|
||||
else if (absolute_program (pathname))
|
||||
/* A command containing a slash is not looked up in PATH or saved in
|
||||
the hash table. */
|
||||
command = savestring (pathname);
|
||||
else
|
||||
{
|
||||
/* If $PATH is in the temporary environment, we've already retrieved
|
||||
it, so don't bother trying again. */
|
||||
if (temp_path)
|
||||
{
|
||||
command = find_user_command_in_path (pathname, value_cell (path),
|
||||
FS_EXEC_PREFERRED|FS_NODIRS);
|
||||
}
|
||||
else
|
||||
command = find_user_command (pathname);
|
||||
if (command && hashing_enabled && temp_path == 0 && (flags & 1))
|
||||
phash_insert ((char *)pathname, command, dot_found_in_search, 1); /* XXX fix const later */
|
||||
}
|
||||
return (command);
|
||||
}
|
||||
|
||||
char *
|
||||
user_command_matches (name, flags, state)
|
||||
const char *name;
|
||||
int flags, state;
|
||||
{
|
||||
register int i;
|
||||
int path_index, name_len;
|
||||
char *path_list, *path_element, *match;
|
||||
struct stat dotinfo;
|
||||
static char **match_list = NULL;
|
||||
static int match_list_size = 0;
|
||||
static int match_index = 0;
|
||||
|
||||
if (state == 0)
|
||||
{
|
||||
/* Create the list of matches. */
|
||||
if (match_list == 0)
|
||||
{
|
||||
match_list_size = 5;
|
||||
match_list = strvec_create (match_list_size);
|
||||
}
|
||||
|
||||
/* Clear out the old match list. */
|
||||
for (i = 0; i < match_list_size; i++)
|
||||
match_list[i] = 0;
|
||||
|
||||
/* We haven't found any files yet. */
|
||||
match_index = 0;
|
||||
|
||||
if (absolute_program (name))
|
||||
{
|
||||
match_list[0] = find_absolute_program (name, flags);
|
||||
match_list[1] = (char *)NULL;
|
||||
path_list = (char *)NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
name_len = strlen (name);
|
||||
file_to_lose_on = (char *)NULL;
|
||||
dot_found_in_search = 0;
|
||||
if (stat (".", &dotinfo) < 0)
|
||||
dotinfo.st_dev = dotinfo.st_ino = 0; /* so same_file won't match */
|
||||
path_list = get_string_value ("PATH");
|
||||
path_index = 0;
|
||||
}
|
||||
|
||||
while (path_list && path_list[path_index])
|
||||
{
|
||||
path_element = get_next_path_element (path_list, &path_index);
|
||||
|
||||
if (path_element == 0)
|
||||
break;
|
||||
|
||||
match = find_in_path_element (name, path_element, flags, name_len, &dotinfo);
|
||||
|
||||
free (path_element);
|
||||
|
||||
if (match == 0)
|
||||
continue;
|
||||
|
||||
if (match_index + 1 == match_list_size)
|
||||
{
|
||||
match_list_size += 10;
|
||||
match_list = strvec_resize (match_list, (match_list_size + 1));
|
||||
}
|
||||
|
||||
match_list[match_index++] = match;
|
||||
match_list[match_index] = (char *)NULL;
|
||||
FREE (file_to_lose_on);
|
||||
file_to_lose_on = (char *)NULL;
|
||||
}
|
||||
|
||||
/* We haven't returned any strings yet. */
|
||||
match_index = 0;
|
||||
}
|
||||
|
||||
match = match_list[match_index];
|
||||
|
||||
if (match)
|
||||
match_index++;
|
||||
|
||||
return (match);
|
||||
}
|
||||
|
||||
static char *
|
||||
find_absolute_program (name, flags)
|
||||
const char *name;
|
||||
int flags;
|
||||
{
|
||||
int st;
|
||||
|
||||
st = file_status (name);
|
||||
|
||||
/* If the file doesn't exist, quit now. */
|
||||
if ((st & FS_EXISTS) == 0)
|
||||
return ((char *)NULL);
|
||||
|
||||
/* If we only care about whether the file exists or not, return
|
||||
this filename. Otherwise, maybe we care about whether this
|
||||
file is executable. If it is, and that is what we want, return it. */
|
||||
if ((flags & FS_EXISTS) || ((flags & FS_EXEC_ONLY) && (st & FS_EXECABLE)))
|
||||
return (savestring (name));
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static char *
|
||||
find_in_path_element (name, path, flags, name_len, dotinfop)
|
||||
const char *name;
|
||||
char *path;
|
||||
int flags, name_len;
|
||||
struct stat *dotinfop;
|
||||
{
|
||||
int status;
|
||||
char *full_path, *xpath;
|
||||
|
||||
xpath = (*path == '~') ? bash_tilde_expand (path, 0) : path;
|
||||
|
||||
/* Remember the location of "." in the path, in all its forms
|
||||
(as long as they begin with a `.', e.g. `./.') */
|
||||
if (dot_found_in_search == 0 && *xpath == '.')
|
||||
dot_found_in_search = same_file (".", xpath, dotinfop, (struct stat *)NULL);
|
||||
|
||||
full_path = sh_makepath (xpath, name, 0);
|
||||
|
||||
status = file_status (full_path);
|
||||
|
||||
if (xpath != path)
|
||||
free (xpath);
|
||||
|
||||
if ((status & FS_EXISTS) == 0)
|
||||
{
|
||||
free (full_path);
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
/* The file exists. If the caller simply wants the first file, here it is. */
|
||||
if (flags & FS_EXISTS)
|
||||
return (full_path);
|
||||
|
||||
/* If we have a readable file, and the caller wants a readable file, this
|
||||
is it. */
|
||||
if ((flags & FS_READABLE) && (status & FS_READABLE))
|
||||
return (full_path);
|
||||
|
||||
/* If the file is executable, then it satisfies the cases of
|
||||
EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */
|
||||
if ((status & FS_EXECABLE) && (flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) &&
|
||||
(((flags & FS_NODIRS) == 0) || ((status & FS_DIRECTORY) == 0)))
|
||||
{
|
||||
FREE (file_to_lose_on);
|
||||
file_to_lose_on = (char *)NULL;
|
||||
return (full_path);
|
||||
}
|
||||
|
||||
/* The file is not executable, but it does exist. If we prefer
|
||||
an executable, then remember this one if it is the first one
|
||||
we have found. */
|
||||
if ((flags & FS_EXEC_PREFERRED) && file_to_lose_on == 0)
|
||||
file_to_lose_on = savestring (full_path);
|
||||
|
||||
/* If we want only executable files, or we don't want directories and
|
||||
this file is a directory, or we want a readable file and this file
|
||||
isn't readable, fail. */
|
||||
if ((flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) ||
|
||||
((flags & FS_NODIRS) && (status & FS_DIRECTORY)) ||
|
||||
((flags & FS_READABLE) && (status & FS_READABLE) == 0))
|
||||
{
|
||||
free (full_path);
|
||||
return ((char *)NULL);
|
||||
}
|
||||
else
|
||||
return (full_path);
|
||||
}
|
||||
|
||||
/* This does the dirty work for find_user_command_internal () and
|
||||
user_command_matches ().
|
||||
NAME is the name of the file to search for.
|
||||
PATH_LIST is a colon separated list of directories to search.
|
||||
FLAGS contains bit fields which control the files which are eligible.
|
||||
Some values are:
|
||||
FS_EXEC_ONLY: The file must be an executable to be found.
|
||||
FS_EXEC_PREFERRED: If we can't find an executable, then the
|
||||
the first file matching NAME will do.
|
||||
FS_EXISTS: The first file found will do.
|
||||
FS_NODIRS: Don't find any directories.
|
||||
*/
|
||||
static char *
|
||||
find_user_command_in_path (name, path_list, flags)
|
||||
const char *name;
|
||||
char *path_list;
|
||||
int flags;
|
||||
{
|
||||
char *full_path, *path;
|
||||
int path_index, name_len;
|
||||
struct stat dotinfo;
|
||||
|
||||
/* We haven't started looking, so we certainly haven't seen
|
||||
a `.' as the directory path yet. */
|
||||
dot_found_in_search = 0;
|
||||
|
||||
if (absolute_program (name))
|
||||
{
|
||||
full_path = find_absolute_program (name, flags);
|
||||
return (full_path);
|
||||
}
|
||||
|
||||
if (path_list == 0 || *path_list == '\0')
|
||||
return (savestring (name)); /* XXX */
|
||||
|
||||
file_to_lose_on = (char *)NULL;
|
||||
name_len = strlen (name);
|
||||
if (stat (".", &dotinfo) < 0)
|
||||
dotinfo.st_dev = dotinfo.st_ino = 0;
|
||||
path_index = 0;
|
||||
|
||||
while (path_list[path_index])
|
||||
{
|
||||
/* Allow the user to interrupt out of a lengthy path search. */
|
||||
QUIT;
|
||||
|
||||
path = get_next_path_element (path_list, &path_index);
|
||||
if (path == 0)
|
||||
break;
|
||||
|
||||
/* Side effects: sets dot_found_in_search, possibly sets
|
||||
file_to_lose_on. */
|
||||
full_path = find_in_path_element (name, path, flags, name_len, &dotinfo);
|
||||
free (path);
|
||||
|
||||
/* This should really be in find_in_path_element, but there isn't the
|
||||
right combination of flags. */
|
||||
if (full_path && is_directory (full_path))
|
||||
{
|
||||
free (full_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (full_path)
|
||||
{
|
||||
FREE (file_to_lose_on);
|
||||
return (full_path);
|
||||
}
|
||||
}
|
||||
|
||||
/* We didn't find exactly what the user was looking for. Return
|
||||
the contents of FILE_TO_LOSE_ON which is NULL when the search
|
||||
required an executable, or non-NULL if a file was found and the
|
||||
search would accept a non-executable as a last resort. If the
|
||||
caller specified FS_NODIRS, and file_to_lose_on is a directory,
|
||||
return NULL. */
|
||||
if (file_to_lose_on && (flags & FS_NODIRS) && is_directory (file_to_lose_on))
|
||||
{
|
||||
free (file_to_lose_on);
|
||||
file_to_lose_on = (char *)NULL;
|
||||
}
|
||||
|
||||
return (file_to_lose_on);
|
||||
}
|
||||
@@ -6151,7 +6151,13 @@ verify_substring_values (v, value, substr, vtype, e1p, e2p)
|
||||
free (temp1);
|
||||
if (expok == 0)
|
||||
return (0);
|
||||
#if 1
|
||||
if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
|
||||
#else
|
||||
/* bash-4.3: allow positional parameter length < 0 to count backwards
|
||||
from end of positional parameters */
|
||||
if (vtype == VT_ARRAYVAR && *e2p < 0)
|
||||
#endif
|
||||
{
|
||||
internal_error (_("%s: substring expression < 0"), t);
|
||||
return (0);
|
||||
@@ -7100,6 +7106,8 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
|
||||
if (contains_dollar_at)
|
||||
*contains_dollar_at = 1;
|
||||
|
||||
tflag |= W_DOLLARAT;
|
||||
}
|
||||
|
||||
/* Process ${!PREFIX*} expansion. */
|
||||
@@ -7124,6 +7132,8 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
*quoted_dollar_atp = 1;
|
||||
if (contains_dollar_at)
|
||||
*contains_dollar_at = 1;
|
||||
|
||||
tflag |= W_DOLLARAT;
|
||||
}
|
||||
free (x);
|
||||
dispose_words (xlist);
|
||||
@@ -7134,6 +7144,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
|
||||
ret = alloc_word_desc ();
|
||||
ret->word = temp;
|
||||
ret->flags = tflag; /* XXX */
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -7156,6 +7167,8 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
*quoted_dollar_atp = 1;
|
||||
if (contains_dollar_at)
|
||||
*contains_dollar_at = 1;
|
||||
|
||||
tflag |= W_DOLLARAT;
|
||||
}
|
||||
|
||||
free (temp1);
|
||||
@@ -7163,6 +7176,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
|
||||
ret = alloc_word_desc ();
|
||||
ret->word = temp;
|
||||
ret->flags = tflag; /* XXX */
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -7639,12 +7653,9 @@ param_expand (string, sindex, quoted, expanded_something,
|
||||
We also want to make sure that splitting is done no matter what --
|
||||
according to POSIX.2, this expands to a list of the positional
|
||||
parameters no matter what IFS is set to. */
|
||||
#if 0
|
||||
temp = string_list_dollar_at (list, quoted);
|
||||
#else
|
||||
temp = string_list_dollar_at (list, (pflags & PF_ASSIGNRHS) ? (quoted|Q_DOUBLE_QUOTES) : quoted);
|
||||
#endif
|
||||
|
||||
tflag |= W_DOLLARAT;
|
||||
dispose_words (list);
|
||||
break;
|
||||
|
||||
@@ -7928,7 +7939,7 @@ expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_somethin
|
||||
|
||||
/* State flags */
|
||||
int had_quoted_null;
|
||||
int has_dollar_at;
|
||||
int has_dollar_at, temp_has_dollar_at;
|
||||
int tflag;
|
||||
int pflags; /* flags passed to param_expand */
|
||||
|
||||
@@ -8133,15 +8144,16 @@ add_string:
|
||||
if (expanded_something)
|
||||
*expanded_something = 1;
|
||||
|
||||
has_dollar_at = 0;
|
||||
temp_has_dollar_at = 0;
|
||||
pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
|
||||
if (word->flags & W_NOSPLIT2)
|
||||
pflags |= PF_NOSPLIT2;
|
||||
if (word->flags & W_ASSIGNRHS)
|
||||
pflags |= PF_ASSIGNRHS;
|
||||
tword = param_expand (string, &sindex, quoted, expanded_something,
|
||||
&has_dollar_at, "ed_dollar_at,
|
||||
&temp_has_dollar_at, "ed_dollar_at,
|
||||
&had_quoted_null, pflags);
|
||||
has_dollar_at += temp_has_dollar_at;
|
||||
|
||||
if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
|
||||
{
|
||||
@@ -8283,9 +8295,10 @@ add_twochars:
|
||||
|
||||
temp = (char *)NULL;
|
||||
|
||||
has_dollar_at = 0;
|
||||
temp_has_dollar_at = 0; /* XXX */
|
||||
/* Need to get W_HASQUOTEDNULL flag through this function. */
|
||||
list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL);
|
||||
list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL);
|
||||
has_dollar_at += temp_has_dollar_at;
|
||||
|
||||
if (list == &expand_word_error || list == &expand_word_fatal)
|
||||
{
|
||||
|
||||
@@ -6151,7 +6151,11 @@ verify_substring_values (v, value, substr, vtype, e1p, e2p)
|
||||
free (temp1);
|
||||
if (expok == 0)
|
||||
return (0);
|
||||
#if 0
|
||||
if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
|
||||
#else
|
||||
if (vtype == VT_ARRAYVAR && *e2p < 0)
|
||||
#endif
|
||||
{
|
||||
internal_error (_("%s: substring expression < 0"), t);
|
||||
return (0);
|
||||
@@ -7100,6 +7104,8 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
|
||||
if (contains_dollar_at)
|
||||
*contains_dollar_at = 1;
|
||||
|
||||
tflag |= W_DOLLARAT;
|
||||
}
|
||||
|
||||
/* Process ${!PREFIX*} expansion. */
|
||||
@@ -7124,6 +7130,8 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
*quoted_dollar_atp = 1;
|
||||
if (contains_dollar_at)
|
||||
*contains_dollar_at = 1;
|
||||
|
||||
tflag |= W_DOLLARAT;
|
||||
}
|
||||
free (x);
|
||||
dispose_words (xlist);
|
||||
@@ -7134,6 +7142,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
|
||||
ret = alloc_word_desc ();
|
||||
ret->word = temp;
|
||||
ret->flags = tflag; /* XXX */
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -7156,6 +7165,8 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
*quoted_dollar_atp = 1;
|
||||
if (contains_dollar_at)
|
||||
*contains_dollar_at = 1;
|
||||
|
||||
tflag |= W_DOLLARAT;
|
||||
}
|
||||
|
||||
free (temp1);
|
||||
@@ -7163,6 +7174,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
|
||||
|
||||
ret = alloc_word_desc ();
|
||||
ret->word = temp;
|
||||
ret->flags = tflag; /* XXX */
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -7639,12 +7651,9 @@ param_expand (string, sindex, quoted, expanded_something,
|
||||
We also want to make sure that splitting is done no matter what --
|
||||
according to POSIX.2, this expands to a list of the positional
|
||||
parameters no matter what IFS is set to. */
|
||||
#if 0
|
||||
temp = string_list_dollar_at (list, quoted);
|
||||
#else
|
||||
temp = string_list_dollar_at (list, (pflags & PF_ASSIGNRHS) ? (quoted|Q_DOUBLE_QUOTES) : quoted);
|
||||
#endif
|
||||
|
||||
tflag |= W_DOLLARAT;
|
||||
dispose_words (list);
|
||||
break;
|
||||
|
||||
@@ -7928,7 +7937,7 @@ expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_somethin
|
||||
|
||||
/* State flags */
|
||||
int had_quoted_null;
|
||||
int has_dollar_at;
|
||||
int has_dollar_at, temp_has_dollar_at;
|
||||
int tflag;
|
||||
int pflags; /* flags passed to param_expand */
|
||||
|
||||
@@ -8133,15 +8142,16 @@ add_string:
|
||||
if (expanded_something)
|
||||
*expanded_something = 1;
|
||||
|
||||
has_dollar_at = 0;
|
||||
temp_has_dollar_at = 0;
|
||||
pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
|
||||
if (word->flags & W_NOSPLIT2)
|
||||
pflags |= PF_NOSPLIT2;
|
||||
if (word->flags & W_ASSIGNRHS)
|
||||
pflags |= PF_ASSIGNRHS;
|
||||
tword = param_expand (string, &sindex, quoted, expanded_something,
|
||||
&has_dollar_at, "ed_dollar_at,
|
||||
&temp_has_dollar_at, "ed_dollar_at,
|
||||
&had_quoted_null, pflags);
|
||||
has_dollar_at += temp_has_dollar_at;
|
||||
|
||||
if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
|
||||
{
|
||||
@@ -8157,7 +8167,7 @@ add_string:
|
||||
had_quoted_null = 1;
|
||||
|
||||
temp = tword ? tword->word : (char *)NULL;
|
||||
dispose_word_desc (tword); /* nulls tword->word so ok */
|
||||
dispose_word_desc (tword);
|
||||
|
||||
/* Kill quoted nulls; we will add them back at the end of
|
||||
expand_word_internal if nothing else in the string */
|
||||
@@ -8283,9 +8293,10 @@ add_twochars:
|
||||
|
||||
temp = (char *)NULL;
|
||||
|
||||
has_dollar_at = 0;
|
||||
temp_has_dollar_at = 0; /* XXX */
|
||||
/* Need to get W_HASQUOTEDNULL flag through this function. */
|
||||
list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL);
|
||||
list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL);
|
||||
has_dollar_at += temp_has_dollar_at;
|
||||
|
||||
if (list == &expand_word_error || list == &expand_word_fatal)
|
||||
{
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
BUILD_DIR=/usr/local/build/chet/bash/bash-current
|
||||
BUILD_DIR=/usr/local/build/bash/bash-current
|
||||
THIS_SH=$BUILD_DIR/bash
|
||||
PATH=$PATH:$BUILD_DIR
|
||||
|
||||
|
||||
@@ -221,6 +221,7 @@ ok
|
||||
-9223372036854775808
|
||||
-9223372036854775808
|
||||
-9223372036854775808
|
||||
9223372036854775805 9223372036854775806 9223372036854775807
|
||||
8 12
|
||||
./arith.tests: line 283: ((: x=9 y=41 : syntax error in expression (error token is "y=41 ")
|
||||
./arith.tests: line 287: a b: syntax error in expression (error token is "b")
|
||||
|
||||
@@ -50,3 +50,7 @@ echo $lvalue
|
||||
|
||||
echo $(( -${intmax_min1} ))
|
||||
echo $(( -${intmax_min2} ))
|
||||
|
||||
foo1=$(( $intmax_max - 2 ))
|
||||
|
||||
eval echo \{${foo1}..${intmax_max}\}
|
||||
|
||||
@@ -238,4 +238,8 @@ ${THIS_SH} ./dollar-star5.sub
|
||||
# tests for inappropriate word splitting through bash-4.2
|
||||
${THIS_SH} ./dollar-at4.sub
|
||||
|
||||
# tests for problems with "$@" preceded and followed by other quoted expansions
|
||||
# through bash-4.2
|
||||
${THIS_SH} ./dollar-at5.sub
|
||||
|
||||
exit 0
|
||||
|
||||
Executable
+241
@@ -0,0 +1,241 @@
|
||||
# first, let's start with the basics
|
||||
|
||||
recho "$@"
|
||||
recho "$*"
|
||||
|
||||
recho $@
|
||||
recho $*
|
||||
|
||||
set a b
|
||||
|
||||
recho "$*"
|
||||
|
||||
# If IFS is null, the parameters are joined without separators
|
||||
IFS=''
|
||||
recho "$*"
|
||||
|
||||
# If IFS is unset, the parameters are separated by spaces
|
||||
unset IFS
|
||||
recho "${*}"
|
||||
|
||||
recho "$@"
|
||||
recho $@
|
||||
|
||||
IFS='/'
|
||||
set bob 'tom dick harry' joe
|
||||
set $*
|
||||
recho $#
|
||||
recho $1
|
||||
recho $2
|
||||
recho $3
|
||||
|
||||
set bob 'tom dick harry' joe
|
||||
set ${*}
|
||||
recho $#
|
||||
recho $1
|
||||
recho $2
|
||||
recho $3
|
||||
|
||||
set bob 'tom dick harry' joe
|
||||
set $@
|
||||
recho $#
|
||||
recho $1
|
||||
recho $2
|
||||
recho $3
|
||||
|
||||
set bob 'tom dick harry' joe
|
||||
set ${@}
|
||||
recho $#
|
||||
recho $1
|
||||
recho $2
|
||||
recho $3
|
||||
|
||||
# according to POSIX.2, unquoted $* should expand to multiple words if
|
||||
# $IFS is null, just like unquoted $@
|
||||
IFS=''
|
||||
set bob 'tom dick harry' joe
|
||||
set $*
|
||||
recho $#
|
||||
recho $1
|
||||
recho $2
|
||||
recho $3
|
||||
|
||||
set bob 'tom dick harry' joe
|
||||
set $@
|
||||
recho $#
|
||||
recho $1
|
||||
recho $2
|
||||
recho $3
|
||||
|
||||
# if IFS is unset, the individual positional parameters are split on
|
||||
# " \t\n" if $* or $@ are unquoted
|
||||
unset IFS
|
||||
set bob 'tom dick harry' joe
|
||||
set $*
|
||||
recho $#
|
||||
recho $1
|
||||
recho $2
|
||||
recho $3
|
||||
|
||||
set bob 'tom dick harry' joe
|
||||
set $@
|
||||
recho $#
|
||||
recho $1
|
||||
recho $2
|
||||
recho $3
|
||||
|
||||
# but not for "$@" or "$*"
|
||||
set bob 'tom dick harry' joe
|
||||
set "$*"
|
||||
recho $#
|
||||
recho $1
|
||||
recho $2
|
||||
recho $3
|
||||
|
||||
set bob 'tom dick harry' joe
|
||||
set "$@"
|
||||
recho $#
|
||||
recho $1
|
||||
recho $2
|
||||
recho $3
|
||||
|
||||
# POSIX.2 says these should both expand the positional parameters
|
||||
# to multiple words
|
||||
set a b c d e
|
||||
IFS=""
|
||||
recho $@
|
||||
recho "$@"
|
||||
|
||||
# this example is straight from the POSIX.2 rationale
|
||||
set foo bar bam
|
||||
|
||||
recho "$@"
|
||||
recho "$*"
|
||||
|
||||
unset IFS
|
||||
|
||||
recho "$@"
|
||||
recho $@
|
||||
recho "$*"
|
||||
|
||||
IFS=:
|
||||
|
||||
# special variables
|
||||
set -- 1 2 3 4 5 6 7 8 9 10
|
||||
|
||||
bar=${*}
|
||||
foo=$*
|
||||
echo foo = "$foo"
|
||||
echo bar = "$bar"
|
||||
|
||||
foo1=$@
|
||||
bar1=${@}
|
||||
|
||||
echo foo1 = "$foo1"
|
||||
echo bar1 = "$bar1"
|
||||
|
||||
foo2="$*"
|
||||
bar2="${*}"
|
||||
|
||||
echo foo2 = "$foo2"
|
||||
echo bar2 = "$bar2"
|
||||
|
||||
eval foo3='$*' bar3='${*}'
|
||||
echo foo3 = "$foo3"
|
||||
echo bar3 = "$bar3"
|
||||
|
||||
case $* in
|
||||
*\:*) echo ok 1;;
|
||||
*) echo bad 1;;
|
||||
esac
|
||||
|
||||
case $@ in
|
||||
*\:*) echo bad 2;;
|
||||
*) echo ok 2;;
|
||||
esac
|
||||
|
||||
case "$*" in
|
||||
*\:*) echo ok 3;;
|
||||
*) echo bad 3;;
|
||||
esac
|
||||
|
||||
case "$@" in
|
||||
*\:*) echo bad 4;;
|
||||
*) echo ok 4;;
|
||||
esac
|
||||
|
||||
IFS=$' \t\n'
|
||||
|
||||
bar=${*}
|
||||
foo=$*
|
||||
echo foo = "$foo"
|
||||
echo bar = "$bar"
|
||||
|
||||
foo1=$@
|
||||
bar1=${@}
|
||||
|
||||
echo foo1 = "$foo1"
|
||||
echo bar1 = "$bar1"
|
||||
|
||||
foo2="$*"
|
||||
bar2="${*}"
|
||||
|
||||
echo foo2 = "$foo2"
|
||||
echo bar2 = "$bar2"
|
||||
|
||||
eval foo3='$*' bar3='${*}'
|
||||
echo foo3 = "$foo3"
|
||||
echo bar3 = "$bar3"
|
||||
|
||||
case $* in
|
||||
*\ *) echo ok 1;;
|
||||
*) echo bad 1;;
|
||||
esac
|
||||
|
||||
case $@ in
|
||||
*\ *) echo ok 2;;
|
||||
*) echo bad 2;;
|
||||
esac
|
||||
|
||||
case "$*" in
|
||||
*\ *) echo ok 3;;
|
||||
*) echo bad 3;;
|
||||
esac
|
||||
|
||||
case "$@" in
|
||||
*\ *) echo ok 4;;
|
||||
*) echo bad 4;;
|
||||
esac
|
||||
|
||||
# tests for special expansion of "$*" and "${array[*]}" when used with other
|
||||
# expansions -- bugs through bash-2.05b
|
||||
${THIS_SH} ./dollar-star1.sub
|
||||
|
||||
# tests for expansion of "$@" on rhs of things like ${param:+word}. Bugs
|
||||
# though bash-2.05b
|
||||
${THIS_SH} ./dollar-at1.sub
|
||||
|
||||
# tests for expansion of other variables in double-quoted strings containing
|
||||
# $@. Bugs through bash-2.05b
|
||||
${THIS_SH} ./dollar-at2.sub
|
||||
|
||||
# tests for various expansions of $* in different contexts -- word split,
|
||||
# no splitting, etc. when $IFS is NUL
|
||||
${THIS_SH} ./dollar-star2.sub
|
||||
|
||||
# tests for expansions of "${array[*]}" and "${array[@]}" when $IFS is not the
|
||||
# default and the array contains null elements
|
||||
${THIS_SH} ./dollar-star3.sub
|
||||
|
||||
# test for set -u and expansions of $@ when there are no positional parameters
|
||||
${THIS_SH} ./dollar-at3.sub
|
||||
# test for set -u and expansions of $* when there are no positional parameters
|
||||
${THIS_SH} ./dollar-star4.sub
|
||||
|
||||
# tests for expansions of $* when IFS is null
|
||||
${THIS_SH} ./dollar-star5.sub
|
||||
|
||||
# tests for inappropriate word splitting through bash-4.2
|
||||
${THIS_SH} ./dollar-at4.sub
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,82 @@
|
||||
args() { printf '<%s> ' "$@"; echo; }
|
||||
|
||||
set -- 1 2 3 4 5
|
||||
|
||||
args "${@} ${1}"
|
||||
args "${1} ${@}"
|
||||
args "${1}${@}${1}"
|
||||
args "${1} ${@} ${1}"
|
||||
args ${1}"$@"${1}
|
||||
args "$@"${1}
|
||||
args ${1}"$@"
|
||||
|
||||
args "$@""${1}"
|
||||
args "${1}""$@"
|
||||
|
||||
args "${@}foo"
|
||||
args ${@}${1}
|
||||
args ${@}foo
|
||||
|
||||
IFS=
|
||||
args "$@""${1}"
|
||||
args "${1}""$@"
|
||||
|
||||
args ${@}${1}
|
||||
args ${1}${@}
|
||||
args ${@}foo
|
||||
|
||||
echo second set:
|
||||
IFS=$' \t\n'
|
||||
set -- '1 2' 3 4 5
|
||||
|
||||
args "${@} ${1}"
|
||||
args "${1} ${@}"
|
||||
|
||||
args "${1}${@}${1}"
|
||||
args "${1} ${@} ${1}"
|
||||
args ${1}"$@"${1}
|
||||
args "$@"${1}
|
||||
args ${1}"$@"
|
||||
|
||||
args "$@""${1}"
|
||||
args "${1}""$@"
|
||||
|
||||
args "${@}foo"
|
||||
args ${@}${1}
|
||||
args ${@}foo
|
||||
|
||||
IFS=
|
||||
|
||||
args "$@""${1}"
|
||||
args "${1}""$@"
|
||||
|
||||
args ${@}${1}
|
||||
args ${1}${@}
|
||||
args ${@}foo
|
||||
|
||||
echo third set:
|
||||
IFS=$' \t\n'
|
||||
|
||||
alias declare=typeset
|
||||
|
||||
a(){ echo
|
||||
echo '"${@:2}a3 a2" a$1 #works as long as $1 and 3 are swapped'
|
||||
echo "${@:2}a3 a2" a$1
|
||||
"${@:2}a3 a2" a$1
|
||||
echo $?
|
||||
a=("${@}");}
|
||||
b(){ echo
|
||||
echo '"${@:2}b$1 b2" b3 #fails! why?'
|
||||
echo "${@:2}b$1 b2" b3
|
||||
"${@:2}b$1 b2" b3
|
||||
echo $?
|
||||
b=("${@}");}
|
||||
c(){ echo
|
||||
echo '${@:2}c$1 c2 c3 #works as long as quoting omitted'
|
||||
echo ${@:2}c$1 c2 c3
|
||||
${@:2}c$1 c2 c3
|
||||
echo $?
|
||||
c=("${@}");}
|
||||
a x set y z;declare -p a
|
||||
b x set y z;declare -p b
|
||||
c x set y z;declare -p c
|
||||
@@ -174,3 +174,54 @@ argv[3] = <c>
|
||||
argv[4] = <d>
|
||||
argv[1] = <a b c d>
|
||||
argv[1] = <a b c d>
|
||||
<1> <2> <3> <4> <5 1>
|
||||
<1 1> <2> <3> <4> <5>
|
||||
<11> <2> <3> <4> <51>
|
||||
<1 1> <2> <3> <4> <5 1>
|
||||
<11> <2> <3> <4> <51>
|
||||
<1> <2> <3> <4> <51>
|
||||
<11> <2> <3> <4> <5>
|
||||
<1> <2> <3> <4> <51>
|
||||
<11> <2> <3> <4> <5>
|
||||
<1> <2> <3> <4> <5foo>
|
||||
<1> <2> <3> <4> <51>
|
||||
<1> <2> <3> <4> <5foo>
|
||||
<1> <2> <3> <4> <51>
|
||||
<11> <2> <3> <4> <5>
|
||||
<1> <2> <3> <4> <51>
|
||||
<11> <2> <3> <4> <5>
|
||||
<1> <2> <3> <4> <5foo>
|
||||
second set:
|
||||
<1 2> <3> <4> <5 1 2>
|
||||
<1 2 1 2> <3> <4> <5>
|
||||
<1 21 2> <3> <4> <51 2>
|
||||
<1 2 1 2> <3> <4> <5 1 2>
|
||||
<1> <21 2> <3> <4> <51> <2>
|
||||
<1 2> <3> <4> <51> <2>
|
||||
<1> <21 2> <3> <4> <5>
|
||||
<1 2> <3> <4> <51 2>
|
||||
<1 21 2> <3> <4> <5>
|
||||
<1 2> <3> <4> <5foo>
|
||||
<1> <2> <3> <4> <51> <2>
|
||||
<1> <2> <3> <4> <5foo>
|
||||
<1 2> <3> <4> <51 2>
|
||||
<1 21 2> <3> <4> <5>
|
||||
<1 2> <3> <4> <51 2>
|
||||
<1 21 2> <3> <4> <5>
|
||||
<1 2> <3> <4> <5foo>
|
||||
third set:
|
||||
|
||||
"${@:2}a3 a2" a$1 #works as long as $1 and 3 are swapped
|
||||
set y za3 a2 ax
|
||||
0
|
||||
declare -a a='([0]="y" [1]="za3 a2" [2]="ax")'
|
||||
|
||||
"${@:2}b$1 b2" b3 #fails! why?
|
||||
set y zbx b2 b3
|
||||
0
|
||||
declare -a b='([0]="y" [1]="zbx b2" [2]="b3")'
|
||||
|
||||
${@:2}c$1 c2 c3 #works as long as quoting omitted
|
||||
set y zcx c2 c3
|
||||
0
|
||||
declare -a c='([0]="y" [1]="zcx" [2]="c2" [3]="c3")'
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
LANG=en_US.UTF-8
|
||||
|
||||
shopt -s extglob
|
||||
a="aaaäöü"
|
||||
|
||||
echo "${a}" "${a//?aa}" "${a//\aaa}"
|
||||
exit 0
|
||||
+44
-2
@@ -1803,6 +1803,28 @@ find_variable_internal (name, force_tempenv)
|
||||
return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
|
||||
}
|
||||
|
||||
/* Find a variable, forcing a search of the temporary environment first */
|
||||
SHELL_VAR *
|
||||
find_variable_tempenv (name)
|
||||
const char *name;
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = find_variable_internal (name, 1);
|
||||
return (var);
|
||||
}
|
||||
|
||||
/* Find a variable, not forcing a search of the temporary environment first */
|
||||
SHELL_VAR *
|
||||
find_variable_notempenv (name)
|
||||
const char *name;
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = find_variable_internal (name, 0);
|
||||
return (var);
|
||||
}
|
||||
|
||||
SHELL_VAR *
|
||||
find_global_variable (name)
|
||||
const char *name;
|
||||
@@ -1817,6 +1839,20 @@ find_global_variable (name)
|
||||
return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
|
||||
}
|
||||
|
||||
SHELL_VAR *
|
||||
find_shell_variable (name)
|
||||
const char *name;
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = var_lookup (name, shell_variables);
|
||||
|
||||
if (var == 0)
|
||||
return ((SHELL_VAR *)NULL);
|
||||
|
||||
return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
|
||||
}
|
||||
|
||||
/* Look up the variable entry named NAME. Returns the entry or NULL. */
|
||||
SHELL_VAR *
|
||||
find_variable (name)
|
||||
@@ -2378,9 +2414,9 @@ bind_int_variable (lhs, rhs)
|
||||
char *lhs, *rhs;
|
||||
{
|
||||
register SHELL_VAR *v;
|
||||
int isint, isarr;
|
||||
int isint, isarr, implicitarray;
|
||||
|
||||
isint = isarr = 0;
|
||||
isint = isarr = implicitarray = 0;
|
||||
#if defined (ARRAY_VARS)
|
||||
if (valid_array_reference (lhs))
|
||||
{
|
||||
@@ -2395,11 +2431,17 @@ bind_int_variable (lhs, rhs)
|
||||
{
|
||||
isint = integer_p (v);
|
||||
VUNSETATTR (v, att_integer);
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (v) && isarr == 0)
|
||||
implicitarray = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (isarr)
|
||||
v = assign_array_element (lhs, rhs, 0);
|
||||
else if (implicitarray)
|
||||
v = bind_array_variable (lhs, 0, rhs, 0);
|
||||
else
|
||||
#endif
|
||||
v = bind_variable (lhs, rhs, 0);
|
||||
|
||||
+4865
File diff suppressed because it is too large
Load Diff
+6
-2
@@ -112,8 +112,9 @@ typedef struct _vlist {
|
||||
#define att_uppercase 0x0000100 /* word converted to uppercase on assignment */
|
||||
#define att_lowercase 0x0000200 /* word converted to lowercase on assignment */
|
||||
#define att_capcase 0x0000400 /* word capitalized on assignment */
|
||||
#define att_nameref 0x0000800 /* word is a name reference */
|
||||
|
||||
#define user_attrs (att_exported|att_readonly|att_integer|att_local|att_trace|att_uppercase|att_lowercase|att_capcase)
|
||||
#define user_attrs (att_exported|att_readonly|att_integer|att_local|att_trace|att_uppercase|att_lowercase|att_capcase|att_nameref)
|
||||
|
||||
#define attmask_user 0x0000fff
|
||||
|
||||
@@ -234,8 +235,11 @@ extern SHELL_VAR *find_function __P((const char *));
|
||||
extern FUNCTION_DEF *find_function_def __P((const char *));
|
||||
extern SHELL_VAR *find_variable __P((const char *));
|
||||
extern SHELL_VAR *find_variable_internal __P((const char *, int));
|
||||
extern SHELL_VAR *find_tempenv_variable __P((const char *));
|
||||
extern SHELL_VAR *find_variable_tempenv __P((const char *));
|
||||
extern SHELL_VAR *find_variable_notempenv __P((const char *));
|
||||
extern SHELL_VAR *find_global_variable __P((const char *));
|
||||
extern SHELL_VAR *find_shell_variable __P((const char *));
|
||||
extern SHELL_VAR *find_tempenv_variable __P((const char *));
|
||||
extern SHELL_VAR *copy_variable __P((SHELL_VAR *));
|
||||
extern SHELL_VAR *make_local_variable __P((const char *));
|
||||
extern SHELL_VAR *bind_variable __P((const char *, char *, int));
|
||||
|
||||
+394
@@ -0,0 +1,394 @@
|
||||
/* variables.h -- data structures for shell variables. */
|
||||
|
||||
/* Copyright (C) 1987-2010 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_VARIABLES_H_)
|
||||
#define _VARIABLES_H_
|
||||
|
||||
#include "stdc.h"
|
||||
#include "array.h"
|
||||
#include "assoc.h"
|
||||
|
||||
/* Shell variables and functions are stored in hash tables. */
|
||||
#include "hashlib.h"
|
||||
|
||||
#include "conftypes.h"
|
||||
|
||||
/* A variable context. */
|
||||
typedef struct var_context {
|
||||
char *name; /* empty or NULL means global context */
|
||||
int scope; /* 0 means global context */
|
||||
int flags;
|
||||
struct var_context *up; /* previous function calls */
|
||||
struct var_context *down; /* down towards global context */
|
||||
HASH_TABLE *table; /* variables at this scope */
|
||||
} VAR_CONTEXT;
|
||||
|
||||
/* Flags for var_context->flags */
|
||||
#define VC_HASLOCAL 0x01
|
||||
#define VC_HASTMPVAR 0x02
|
||||
#define VC_FUNCENV 0x04 /* also function if name != NULL */
|
||||
#define VC_BLTNENV 0x08 /* builtin_env */
|
||||
#define VC_TEMPENV 0x10 /* temporary_env */
|
||||
|
||||
#define VC_TEMPFLAGS (VC_FUNCENV|VC_BLTNENV|VC_TEMPENV)
|
||||
|
||||
/* Accessing macros */
|
||||
#define vc_isfuncenv(vc) (((vc)->flags & VC_FUNCENV) != 0)
|
||||
#define vc_isbltnenv(vc) (((vc)->flags & VC_BLTNENV) != 0)
|
||||
#define vc_istempenv(vc) (((vc)->flags & (VC_TEMPFLAGS)) == VC_TEMPENV)
|
||||
|
||||
#define vc_istempscope(vc) (((vc)->flags & (VC_TEMPENV|VC_BLTNENV)) != 0)
|
||||
|
||||
#define vc_haslocals(vc) (((vc)->flags & VC_HASLOCAL) != 0)
|
||||
#define vc_hastmpvars(vc) (((vc)->flags & VC_HASTMPVAR) != 0)
|
||||
|
||||
/* What a shell variable looks like. */
|
||||
|
||||
typedef struct variable *sh_var_value_func_t __P((struct variable *));
|
||||
typedef struct variable *sh_var_assign_func_t __P((struct variable *, char *, arrayind_t, char *));
|
||||
|
||||
/* For the future */
|
||||
union _value {
|
||||
char *s; /* string value */
|
||||
intmax_t i; /* int value */
|
||||
COMMAND *f; /* function */
|
||||
ARRAY *a; /* array */
|
||||
HASH_TABLE *h; /* associative array */
|
||||
double d; /* floating point number */
|
||||
#if defined (HAVE_LONG_DOUBLE)
|
||||
long double ld; /* long double */
|
||||
#endif
|
||||
struct variable *v; /* possible indirect variable use */
|
||||
void *opaque; /* opaque data for future use */
|
||||
};
|
||||
|
||||
typedef struct variable {
|
||||
char *name; /* Symbol that the user types. */
|
||||
char *value; /* Value that is returned. */
|
||||
char *exportstr; /* String for the environment. */
|
||||
sh_var_value_func_t *dynamic_value; /* Function called to return a `dynamic'
|
||||
value for a variable, like $SECONDS
|
||||
or $RANDOM. */
|
||||
sh_var_assign_func_t *assign_func; /* Function called when this `special
|
||||
variable' is assigned a value in
|
||||
bind_variable. */
|
||||
int attributes; /* export, readonly, array, invisible... */
|
||||
int context; /* Which context this variable belongs to. */
|
||||
} SHELL_VAR;
|
||||
|
||||
typedef struct _vlist {
|
||||
SHELL_VAR **list;
|
||||
int list_size; /* allocated size */
|
||||
int list_len; /* current number of entries */
|
||||
} VARLIST;
|
||||
|
||||
/* The various attributes that a given variable can have. */
|
||||
/* First, the user-visible attributes */
|
||||
#define att_exported 0x0000001 /* export to environment */
|
||||
#define att_readonly 0x0000002 /* cannot change */
|
||||
#define att_array 0x0000004 /* value is an array */
|
||||
#define att_function 0x0000008 /* value is a function */
|
||||
#define att_integer 0x0000010 /* internal representation is int */
|
||||
#define att_local 0x0000020 /* variable is local to a function */
|
||||
#define att_assoc 0x0000040 /* variable is an associative array */
|
||||
#define att_trace 0x0000080 /* function is traced with DEBUG trap */
|
||||
#define att_uppercase 0x0000100 /* word converted to uppercase on assignment */
|
||||
#define att_lowercase 0x0000200 /* word converted to lowercase on assignment */
|
||||
#define att_capcase 0x0000400 /* word capitalized on assignment */
|
||||
#define att_nameref 0x0000800 /* word is a name reference */
|
||||
|
||||
#define user_attrs (att_exported|att_readonly|att_integer|att_local|att_trace|att_uppercase|att_lowercase|att_capcase|att_nameref)
|
||||
|
||||
#define attmask_user 0x0000fff
|
||||
|
||||
/* Internal attributes used for bookkeeping */
|
||||
#define att_invisible 0x0001000 /* cannot see */
|
||||
#define att_nounset 0x0002000 /* cannot unset */
|
||||
#define att_noassign 0x0004000 /* assignment not allowed */
|
||||
#define att_imported 0x0008000 /* came from environment */
|
||||
#define att_special 0x0010000 /* requires special handling */
|
||||
#define att_nofree 0x0020000 /* do not free value on unset */
|
||||
|
||||
#define attmask_int 0x00ff000
|
||||
|
||||
/* Internal attributes used for variable scoping. */
|
||||
#define att_tempvar 0x0100000 /* variable came from the temp environment */
|
||||
#define att_propagate 0x0200000 /* propagate to previous scope */
|
||||
|
||||
#define attmask_scope 0x0f00000
|
||||
|
||||
#define exported_p(var) ((((var)->attributes) & (att_exported)))
|
||||
#define readonly_p(var) ((((var)->attributes) & (att_readonly)))
|
||||
#define array_p(var) ((((var)->attributes) & (att_array)))
|
||||
#define function_p(var) ((((var)->attributes) & (att_function)))
|
||||
#define integer_p(var) ((((var)->attributes) & (att_integer)))
|
||||
#define local_p(var) ((((var)->attributes) & (att_local)))
|
||||
#define assoc_p(var) ((((var)->attributes) & (att_assoc)))
|
||||
#define trace_p(var) ((((var)->attributes) & (att_trace)))
|
||||
#define uppercase_p(var) ((((var)->attributes) & (att_uppercase)))
|
||||
#define lowercase_p(var) ((((var)->attributes) & (att_lowercase)))
|
||||
#define capcase_p(var) ((((var)->attributes) & (att_capcase)))
|
||||
|
||||
#define invisible_p(var) ((((var)->attributes) & (att_invisible)))
|
||||
#define non_unsettable_p(var) ((((var)->attributes) & (att_nounset)))
|
||||
#define noassign_p(var) ((((var)->attributes) & (att_noassign)))
|
||||
#define imported_p(var) ((((var)->attributes) & (att_imported)))
|
||||
#define specialvar_p(var) ((((var)->attributes) & (att_special)))
|
||||
#define nofree_p(var) ((((var)->attributes) & (att_nofree)))
|
||||
|
||||
#define tempvar_p(var) ((((var)->attributes) & (att_tempvar)))
|
||||
|
||||
/* Acessing variable values: rvalues */
|
||||
#define value_cell(var) ((var)->value)
|
||||
#define function_cell(var) (COMMAND *)((var)->value)
|
||||
#define array_cell(var) (ARRAY *)((var)->value)
|
||||
#define assoc_cell(var) (HASH_TABLE *)((var)->value)
|
||||
|
||||
#define var_isnull(var) ((var)->value == 0)
|
||||
#define var_isset(var) ((var)->value != 0)
|
||||
|
||||
/* Assigning variable values: lvalues */
|
||||
#define var_setvalue(var, str) ((var)->value = (str))
|
||||
#define var_setfunc(var, func) ((var)->value = (char *)(func))
|
||||
#define var_setarray(var, arr) ((var)->value = (char *)(arr))
|
||||
#define var_setassoc(var, arr) ((var)->value = (char *)(arr))
|
||||
|
||||
/* Make VAR be auto-exported. */
|
||||
#define set_auto_export(var) \
|
||||
do { (var)->attributes |= att_exported; array_needs_making = 1; } while (0)
|
||||
|
||||
#define SETVARATTR(var, attr, undo) \
|
||||
((undo == 0) ? ((var)->attributes |= (attr)) \
|
||||
: ((var)->attributes &= ~(attr)))
|
||||
|
||||
#define VSETATTR(var, attr) ((var)->attributes |= (attr))
|
||||
#define VUNSETATTR(var, attr) ((var)->attributes &= ~(attr))
|
||||
|
||||
#define VGETFLAGS(var) ((var)->attributes)
|
||||
|
||||
#define VSETFLAGS(var, flags) ((var)->attributes = (flags))
|
||||
#define VCLRFLAGS(var) ((var)->attributes = 0)
|
||||
|
||||
/* Macros to perform various operations on `exportstr' member of a SHELL_VAR. */
|
||||
#define CLEAR_EXPORTSTR(var) (var)->exportstr = (char *)NULL
|
||||
#define COPY_EXPORTSTR(var) ((var)->exportstr) ? savestring ((var)->exportstr) : (char *)NULL
|
||||
#define SET_EXPORTSTR(var, value) (var)->exportstr = (value)
|
||||
#define SAVE_EXPORTSTR(var, value) (var)->exportstr = (value) ? savestring (value) : (char *)NULL
|
||||
|
||||
#define FREE_EXPORTSTR(var) \
|
||||
do { if ((var)->exportstr) free ((var)->exportstr); } while (0)
|
||||
|
||||
#define CACHE_IMPORTSTR(var, value) \
|
||||
(var)->exportstr = savestring (value)
|
||||
|
||||
#define INVALIDATE_EXPORTSTR(var) \
|
||||
do { \
|
||||
if ((var)->exportstr) \
|
||||
{ \
|
||||
free ((var)->exportstr); \
|
||||
(var)->exportstr = (char *)NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Stuff for hacking variables. */
|
||||
typedef int sh_var_map_func_t __P((SHELL_VAR *));
|
||||
|
||||
/* Where we keep the variables and functions */
|
||||
extern VAR_CONTEXT *global_variables;
|
||||
extern VAR_CONTEXT *shell_variables;
|
||||
|
||||
extern HASH_TABLE *shell_functions;
|
||||
extern HASH_TABLE *temporary_env;
|
||||
|
||||
extern int variable_context;
|
||||
extern char *dollar_vars[];
|
||||
extern char **export_env;
|
||||
|
||||
extern void initialize_shell_variables __P((char **, int));
|
||||
extern SHELL_VAR *set_if_not __P((char *, char *));
|
||||
|
||||
extern void sh_set_lines_and_columns __P((int, int));
|
||||
extern void set_pwd __P((void));
|
||||
extern void set_ppid __P((void));
|
||||
extern void make_funcname_visible __P((int));
|
||||
|
||||
extern SHELL_VAR *var_lookup __P((const char *, VAR_CONTEXT *));
|
||||
|
||||
extern SHELL_VAR *find_function __P((const char *));
|
||||
extern FUNCTION_DEF *find_function_def __P((const char *));
|
||||
extern SHELL_VAR *find_variable __P((const char *));
|
||||
extern SHELL_VAR *find_variable_internal __P((const char *, int));
|
||||
extern SHELL_VAR *find_variable_tempenv __P((const char *));
|
||||
extern SHELL_VAR *find_global_variable __P((const char *));
|
||||
extern SHELL_VAR *find_shell_variable __P((const char *));
|
||||
extern SHELL_VAR *find_tempenv_variable __P((const char *));
|
||||
extern SHELL_VAR *copy_variable __P((SHELL_VAR *));
|
||||
extern SHELL_VAR *make_local_variable __P((const char *));
|
||||
extern SHELL_VAR *bind_variable __P((const char *, char *, int));
|
||||
extern SHELL_VAR *bind_function __P((const char *, COMMAND *));
|
||||
|
||||
extern void bind_function_def __P((const char *, FUNCTION_DEF *));
|
||||
|
||||
extern SHELL_VAR **map_over __P((sh_var_map_func_t *, VAR_CONTEXT *));
|
||||
SHELL_VAR **map_over_funcs __P((sh_var_map_func_t *));
|
||||
|
||||
extern SHELL_VAR **all_shell_variables __P((void));
|
||||
extern SHELL_VAR **all_shell_functions __P((void));
|
||||
extern SHELL_VAR **all_visible_variables __P((void));
|
||||
extern SHELL_VAR **all_visible_functions __P((void));
|
||||
extern SHELL_VAR **all_exported_variables __P((void));
|
||||
extern SHELL_VAR **local_exported_variables __P((void));
|
||||
extern SHELL_VAR **all_local_variables __P((void));
|
||||
#if defined (ARRAY_VARS)
|
||||
extern SHELL_VAR **all_array_variables __P((void));
|
||||
#endif
|
||||
extern char **all_variables_matching_prefix __P((const char *));
|
||||
|
||||
extern char **make_var_array __P((HASH_TABLE *));
|
||||
extern char **add_or_supercede_exported_var __P((char *, int));
|
||||
|
||||
extern char *get_variable_value __P((SHELL_VAR *));
|
||||
extern char *get_string_value __P((const char *));
|
||||
extern char *sh_get_env_value __P((const char *));
|
||||
extern char *make_variable_value __P((SHELL_VAR *, char *, int));
|
||||
|
||||
extern SHELL_VAR *bind_variable_value __P((SHELL_VAR *, char *, int));
|
||||
extern SHELL_VAR *bind_int_variable __P((char *, char *));
|
||||
extern SHELL_VAR *bind_var_to_int __P((char *, intmax_t));
|
||||
|
||||
extern int assign_in_env __P((WORD_DESC *, int));
|
||||
|
||||
extern int unbind_variable __P((const char *));
|
||||
extern int unbind_func __P((const char *));
|
||||
extern int unbind_function_def __P((const char *));
|
||||
extern int makunbound __P((const char *, VAR_CONTEXT *));
|
||||
extern int kill_local_variable __P((const char *));
|
||||
extern void delete_all_variables __P((HASH_TABLE *));
|
||||
extern void delete_all_contexts __P((VAR_CONTEXT *));
|
||||
|
||||
extern VAR_CONTEXT *new_var_context __P((char *, int));
|
||||
extern void dispose_var_context __P((VAR_CONTEXT *));
|
||||
extern VAR_CONTEXT *push_var_context __P((char *, int, HASH_TABLE *));
|
||||
extern void pop_var_context __P((void));
|
||||
extern VAR_CONTEXT *push_scope __P((int, HASH_TABLE *));
|
||||
extern void pop_scope __P((int));
|
||||
|
||||
extern void push_context __P((char *, int, HASH_TABLE *));
|
||||
extern void pop_context __P((void));
|
||||
extern void push_dollar_vars __P((void));
|
||||
extern void pop_dollar_vars __P((void));
|
||||
extern void dispose_saved_dollar_vars __P((void));
|
||||
|
||||
extern void push_args __P((WORD_LIST *));
|
||||
extern void pop_args __P((void));
|
||||
|
||||
extern void adjust_shell_level __P((int));
|
||||
extern void non_unsettable __P((char *));
|
||||
extern void dispose_variable __P((SHELL_VAR *));
|
||||
extern void dispose_used_env_vars __P((void));
|
||||
extern void dispose_function_env __P((void));
|
||||
extern void dispose_builtin_env __P((void));
|
||||
extern void merge_temporary_env __P((void));
|
||||
extern void merge_builtin_env __P((void));
|
||||
extern void kill_all_local_variables __P((void));
|
||||
|
||||
extern void set_var_read_only __P((char *));
|
||||
extern void set_func_read_only __P((const char *));
|
||||
extern void set_var_auto_export __P((char *));
|
||||
extern void set_func_auto_export __P((const char *));
|
||||
|
||||
extern void sort_variables __P((SHELL_VAR **));
|
||||
|
||||
extern int chkexport __P((char *));
|
||||
extern void maybe_make_export_env __P((void));
|
||||
extern void update_export_env_inplace __P((char *, int, char *));
|
||||
extern void put_command_name_into_env __P((char *));
|
||||
extern void put_gnu_argv_flags_into_env __P((intmax_t, char *));
|
||||
|
||||
extern void print_var_list __P((SHELL_VAR **));
|
||||
extern void print_func_list __P((SHELL_VAR **));
|
||||
extern void print_assignment __P((SHELL_VAR *));
|
||||
extern void print_var_value __P((SHELL_VAR *, int));
|
||||
extern void print_var_function __P((SHELL_VAR *));
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
extern SHELL_VAR *make_new_array_variable __P((char *));
|
||||
extern SHELL_VAR *make_local_array_variable __P((char *, int));
|
||||
|
||||
extern SHELL_VAR *make_new_assoc_variable __P((char *));
|
||||
extern SHELL_VAR *make_local_assoc_variable __P((char *));
|
||||
|
||||
extern void set_pipestatus_array __P((int *, int));
|
||||
extern ARRAY *save_pipestatus_array __P((void));
|
||||
extern void restore_pipestatus_array __P((ARRAY *));
|
||||
#endif
|
||||
|
||||
extern void set_pipestatus_from_exit __P((int));
|
||||
|
||||
/* The variable in NAME has just had its state changed. Check to see if it
|
||||
is one of the special ones where something special happens. */
|
||||
extern void stupidly_hack_special_variables __P((char *));
|
||||
|
||||
/* Reinitialize some special variables that have external effects upon unset
|
||||
when the shell reinitializes itself. */
|
||||
extern void reinit_special_variables __P((void));
|
||||
|
||||
extern int get_random_number __P((void));
|
||||
|
||||
/* The `special variable' functions that get called when a particular
|
||||
variable is set. */
|
||||
extern void sv_ifs __P((char *));
|
||||
extern void sv_path __P((char *));
|
||||
extern void sv_mail __P((char *));
|
||||
extern void sv_funcnest __P((char *));
|
||||
extern void sv_globignore __P((char *));
|
||||
extern void sv_ignoreeof __P((char *));
|
||||
extern void sv_strict_posix __P((char *));
|
||||
extern void sv_optind __P((char *));
|
||||
extern void sv_opterr __P((char *));
|
||||
extern void sv_locale __P((char *));
|
||||
extern void sv_xtracefd __P((char *));
|
||||
|
||||
#if defined (READLINE)
|
||||
extern void sv_comp_wordbreaks __P((char *));
|
||||
extern void sv_terminal __P((char *));
|
||||
extern void sv_hostfile __P((char *));
|
||||
extern void sv_winsize __P((char *));
|
||||
#endif
|
||||
|
||||
#if defined (__CYGWIN__)
|
||||
extern void sv_home __P((char *));
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
extern void sv_histsize __P((char *));
|
||||
extern void sv_histignore __P((char *));
|
||||
extern void sv_history_control __P((char *));
|
||||
# if defined (BANG_HISTORY)
|
||||
extern void sv_histchars __P((char *));
|
||||
# endif
|
||||
extern void sv_histtimefmt __P((char *));
|
||||
#endif /* HISTORY */
|
||||
|
||||
#if defined (HAVE_TZSET)
|
||||
extern void sv_tz __P((char *));
|
||||
#endif
|
||||
|
||||
#endif /* !_VARIABLES_H_ */
|
||||
Reference in New Issue
Block a user