diff options
author | Chet Ramey <chet.ramey@case.edu> | 2014-02-26 09:36:43 -0500 |
---|---|---|
committer | Chet Ramey <chet.ramey@case.edu> | 2014-02-26 09:36:43 -0500 |
commit | ac50fbac377e32b98d2de396f016ea81e8ee9961 (patch) | |
tree | f71882366b98fedf1a88a063103219a4935de926 /builtins | |
parent | 4539d736f1aff232857a854fd2a68df0c98d9f34 (diff) | |
download | android_external_bash-ac50fbac377e32b98d2de396f016ea81e8ee9961.tar.gz android_external_bash-ac50fbac377e32b98d2de396f016ea81e8ee9961.tar.bz2 android_external_bash-ac50fbac377e32b98d2de396f016ea81e8ee9961.zip |
Bash-4.3 distribution sources and documentation
Diffstat (limited to 'builtins')
35 files changed, 1318 insertions, 267 deletions
diff --git a/builtins/Makefile.in b/builtins/Makefile.in index 3d8bad4..a2e7911 100644 --- a/builtins/Makefile.in +++ b/builtins/Makefile.in @@ -1,6 +1,6 @@ # This Makefile for building libbuiltins.a is in -*- text -*- for Emacs. # -# Copyright (C) 1996-2009 Free Software Foundation, Inc. +# Copyright (C) 1996-2009 Free Software Foundation, Inc. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -67,8 +67,8 @@ LIBS = @LIBS@ LDFLAGS = @LDFLAGS@ $(LOCAL_LDFLAGS) $(CFLAGS) LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ $(LOCAL_LDFLAGS) $(CFLAGS_FOR_BUILD) LOCAL_LDFLAGS = @LOCAL_LDFLAGS@ -#LIBS_FOR_BUILD = @LIBS_FOR_BUILD@ -LIBS_FOR_BUILD = $(LIBS) +LIBS_FOR_BUILD = @LIBS_FOR_BUILD@ +#LIBS_FOR_BUILD = $(LIBS) BASHINCDIR = ${topdir}/include @@ -85,6 +85,8 @@ LIBINTL_H = @LIBINTL_H@ HELPDIR = @HELPDIR@ MKDIRS = ${topdir}/support/mkdirs +HELPFILES_TARGET = @HELPFILES_TARGET@ + INCLUDES = -I. -I.. @RL_INCLUDE@ -I$(topdir) -I$(BASHINCDIR) -I$(topdir)/lib -I$(srcdir) ${INTL_INC} BASE_CCFLAGS = ${PROFILE_FLAGS} $(DEFS) $(LOCAL_DEFS) $(SYSTEM_FLAGS) \ @@ -153,15 +155,33 @@ OFILES = builtins.o \ suspend.o test.o times.o trap.o type.o ulimit.o umask.o \ wait.o getopts.o shopt.o printf.o getopt.o bashgetopt.o complete.o -CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h +CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h tmpbuiltins.c \ + tmpbuiltins.h +CREATED_OBJECTS = tmpbuiltins.o gen-helpfiles.o mkbuiltins.o -all: $(MKBUILTINS) libbuiltins.a +all: $(MKBUILTINS) libbuiltins.a $(HELPFILES_TARGET) +targets: libbuiltins.a $(HELPFILES_TARGET) libbuiltins.a: $(MKBUILTINS) $(OFILES) builtins.o $(RM) $@ $(AR) $(ARFLAGS) $@ $(OFILES) -$(RANLIB) $@ +tmpbuiltins.c: $(MKBUILTINS) $(DEFSRC) + ./$(MKBUILTINS) -externfile tmpbuiltins.h -structfile $@ \ + -noproduction -nofunctions \ + $(DIRECTDEFINE) $(HELPSTRINGS) $(DEFSRC) + +tmpbuiltins.h: tmpbuiltins.c + +gen-helpfiles.o: ../config.h +gen-helpfiles.o: gen-helpfiles.c + $(RM) $@ + $(CC_FOR_BUILD) -c $(CCFLAGS_FOR_BUILD) $< + +gen-helpfiles: tmpbuiltins.o gen-helpfiles.o + $(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 @-if test -f builtext.h; then mv -f builtext.h old-builtext.h; fi @@ -178,8 +198,8 @@ builtext.h builtins.c: $(MKBUILTINS) $(DEFSRC) $(RM) old-builtins.c; \ fi -helpdoc: $(MKBUILTINS) $(DEFSRC) - ./$(MKBUILTINS) ${HELPDIRDEFINE} -noproduction $(DIRECTDEFINE) $(DEFSRC) +helpdoc: gen-helpfiles + ./gen-helpfiles ${HELPDIRDEFINE} install-help: @-if test -n "${HELPDIR}" && test -d helpfiles ; then \ @@ -207,15 +227,20 @@ common.o: common.c bashgetopt.o: bashgetopt.c getopt.o: getopt.c evalstring.o: evalstring.c -evalfile.o: evalfile.c +evalfile.o: evalfile.c + +tmpbuiltins.o: tmpbuiltins.c +gen-helpfiles.o: gen-helpfiles.c 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 @@ -223,7 +248,8 @@ builtins.texi: $(MKBUILTINS) ./$(MKBUILTINS) -documentonly $(DEFSRC) clean: - $(RM) $(OFILES) $(CREATED_FILES) $(MKBUILTINS) mkbuiltins.o libbuiltins.a + $(RM) $(OFILES) $(CREATED_FILES) libbuiltins.a + $(RM) $(MKBUILTINS) gen-helpfiles $(CREATED_OBJECTS) -test -d helpfiles && $(RM) -r helpfiles mostlyclean: @@ -547,7 +573,7 @@ shopt.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h shopt.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h shopt.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h shopt.o: $(srcdir)/common.h $(srcdir)/bashgetopt.h ../pathnames.h -shopt.o: $(topdir)/bashhist.h +shopt.o: $(topdir)/bashhist.h $(topdir)/bashline.h source.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h source.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/findcmd.h source.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h diff --git a/builtins/bind.def b/builtins/bind.def index d0c953b..3a7cc4e 100644 --- a/builtins/bind.def +++ b/builtins/bind.def @@ -25,7 +25,7 @@ $PRODUCES bind.c $BUILTIN bind $DEPENDS_ON READLINE $FUNCTION bind_builtin -$SHORT_DOC bind [-lpvsPVS] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x keyseq:shell-command] [keyseq:readline-function or readline-command] +$SHORT_DOC bind [-lpsvPSVX] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x keyseq:shell-command] [keyseq:readline-function or readline-command] Set Readline key bindings and variables. Bind a key sequence to a Readline function or a macro, or set a @@ -54,6 +54,8 @@ Options: -f filename Read key bindings from FILENAME. -x keyseq:shell-command Cause SHELL-COMMAND to be executed when KEYSEQ is entered. + -X List key sequences bound with -x and associated commands + in a form that can be reused as input. Exit Status: bind returns 0 unless an unrecognized option is given or an error occurs. @@ -104,6 +106,7 @@ extern int no_line_editing; #define SSFLAG 0x0400 #define UFLAG 0x0800 #define XFLAG 0x1000 +#define XXFLAG 0x2000 int bind_builtin (list) @@ -138,7 +141,7 @@ bind_builtin (list) rl_outstream = stdout; reset_internal_getopt (); - while ((opt = internal_getopt (list, "lvpVPsSf:q:u:m:r:x:")) != EOF) + while ((opt = internal_getopt (list, "lvpVPsSXf:q:u:m:r:x:")) != EOF) { switch (opt) { @@ -187,6 +190,9 @@ bind_builtin (list) flags |= XFLAG; cmd_seq = list_optarg; break; + case 'X': + flags |= XXFLAG; + break; default: builtin_usage (); BIND_RETURN (EX_USAGE); @@ -201,7 +207,7 @@ bind_builtin (list) if ((flags & MFLAG) && map_name) { kmap = rl_get_keymap_by_name (map_name); - if (!kmap) + if (kmap == 0) { builtin_error (_("`%s': invalid keymap name"), map_name); BIND_RETURN (EXECUTION_FAILURE); @@ -265,6 +271,9 @@ bind_builtin (list) if (flags & XFLAG) return_code = bind_keyseq_to_unix_command (cmd_seq); + if (flags & XXFLAG) + return_code = print_unix_command_map (); + /* Process the rest of the arguments as binding specifications. */ while (list) { diff --git a/builtins/caller.def b/builtins/caller.def index 7ddbdad..965676b 100644 --- a/builtins/caller.def +++ b/builtins/caller.def @@ -2,6 +2,7 @@ This file is caller.def, from which is created caller.c. It implements the builtin "caller" in Bash. Copyright (C) 2002-2008 Rocky Bernstein for Free Software Foundation, Inc. +Copyright (C) 2008-2013 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -121,7 +122,7 @@ caller_builtin (list) { sh_invalidnum (list->word->word); builtin_usage (); - return (EXECUTION_FAILURE); + return (EX_USAGE); } return (EXECUTION_SUCCESS); diff --git a/builtins/cd.def b/builtins/cd.def index b1aae26..f66e68c 100644 --- a/builtins/cd.def +++ b/builtins/cd.def @@ -1,7 +1,7 @@ This file is cd.def, from which is created cd.c. It implements the builtins "cd" and "pwd" in Bash. -Copyright (C) 1987-2010 Free Software Foundation, Inc. +Copyright (C) 1987-2013 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -31,9 +31,10 @@ $PRODUCES cd.c #include "../bashtypes.h" #include "posixdir.h" #include "posixstat.h" -#ifndef _MINIX +#if defined (HAVE_SYS_PARAM_H) #include <sys/param.h> #endif +#include <fcntl.h> #include <stdio.h> @@ -60,7 +61,10 @@ extern const char * const bash_getcwd_errstr; static int bindpwd __P((int)); static int setpwd __P((char *)); static char *resetpwd __P((char *)); -static int change_to_directory __P((char *, int)); +static int change_to_directory __P((char *, int, int)); + +static int cdxattr __P((char *, char **)); +static void resetxattr __P((void)); /* Change this to 1 to get cd spelling correction by default. */ int cdspelling = 0; @@ -68,10 +72,12 @@ int cdspelling = 0; int cdable_vars; static int eflag; /* file scope so bindpwd() can see it */ +static int xattrflag; /* O_XATTR support for openat */ +static int xattrfd = -1; $BUILTIN cd $FUNCTION cd_builtin -$SHORT_DOC cd [-L|[-P [-e]]] [dir] +$SHORT_DOC cd [-L|[-P [-e]] [-@]] [dir] Change the shell working directory. Change the current directory to DIR. The default DIR is the value of the @@ -87,13 +93,21 @@ the word is assumed to be a variable name. If that variable has a value, its value is used for DIR. Options: - -L force symbolic links to be followed + -L force symbolic links to be followed: resolve symbolic links in + DIR after processing instances of `..' -P use the physical directory structure without following symbolic - links + links: resolve symbolic links in DIR before processing instances + of `..' -e if the -P option is supplied, and the current working directory cannot be determined successfully, exit with a non-zero status +#if defined (O_XATTR) + -@ on systems that support it, present a file with extended attributes + as a directory containing the file attributes +#endif The default is to follow symbolic links, as if `-L' were specified. +`..' is processed by removing the immediately previous pathname component +back to a slash or the beginning of DIR. Exit Status: Returns 0 if the directory is changed, and if $PWD is set successfully when @@ -173,6 +187,66 @@ resetpwd (caller) return (tdir); } +static int +cdxattr (dir, ndirp) + char *dir; /* don't assume we can always free DIR */ + char **ndirp; /* return new constructed directory name */ +{ +#if defined (O_XATTR) + int apfd, fd, r, e; + char buf[11+40+40]; /* construct new `fake' path for pwd */ + + apfd = openat (AT_FDCWD, dir, O_RDONLY|O_NONBLOCK); + if (apfd < 0) + return -1; + fd = openat (apfd, ".", O_XATTR); + e = errno; + close (apfd); /* ignore close error for now */ + errno = e; + if (fd < 0) + return -1; + r = fchdir (fd); /* assume fchdir exists everywhere with O_XATTR */ + if (r < 0) + { + close (fd); + return -1; + } + /* NFSv4 and ZFS extended attribute directories do not have names which are + visible in the standard Unix directory tree structure. To ensure we have + a valid name for $PWD, we synthesize one under /proc, but to keep that + path valid, we need to keep the file descriptor open as long as we are in + this directory. This imposes a certain structure on /proc. */ + if (ndirp) + { + sprintf (buf, "/proc/%d/fd/%d", getpid(), fd); + *ndirp = savestring (buf); + } + + if (xattrfd >= 0) + close (xattrfd); + xattrfd = fd; + + return r; +#else + return -1; +#endif +} + +/* Clean up the O_XATTR baggage. Currently only closes xattrfd */ +static void +resetxattr () +{ +#if defined (O_XATTR) + if (xattrfd >= 0) + { + close (xattrfd); + xattrfd = -1; + } +#else + xattrfd = -1; /* not strictly necessary */ +#endif +} + #define LCD_DOVARS 0x001 #define LCD_DOSPELL 0x002 #define LCD_PRINTPATH 0x004 @@ -199,8 +273,13 @@ cd_builtin (list) eflag = 0; no_symlinks = no_symbolic_links; + xattrflag = 0; reset_internal_getopt (); - while ((opt = internal_getopt (list, "LP")) != -1) +#if defined (O_XATTR) + while ((opt = internal_getopt (list, "eLP@")) != -1) +#else + while ((opt = internal_getopt (list, "eLP")) != -1) +#endif { switch (opt) { @@ -213,9 +292,14 @@ cd_builtin (list) case 'e': eflag = 1; break; +#if defined (O_XATTR) + case '@': + xattrflag = 1; + break; +#endif default: builtin_usage (); - return (EXECUTION_FAILURE); + return (EX_USAGE); } } list = loptend; @@ -237,6 +321,13 @@ cd_builtin (list) } lflag = 0; } +#if defined (CD_COMPLAINS) + else if (list->next) + { + builtin_error (_("too many arguments")); + return (EXECUTION_FAILURE); + } +#endif else if (list->word->word[0] == '-' && list->word->word[1] == '\0') { /* This is `cd -', equivalent to `cd $OLDPWD' */ @@ -268,7 +359,7 @@ cd_builtin (list) temp = sh_makepath (path, dirname, MP_DOTILDE); free (path); - if (change_to_directory (temp, no_symlinks)) + if (change_to_directory (temp, no_symlinks, xattrflag)) { /* POSIX.2 says that if a nonempty directory from CDPATH is used to find the directory to change to, the new @@ -290,7 +381,8 @@ cd_builtin (list) free (temp); } -#if 0 /* changed for bash-4.2 Posix cd description steps 5-6 */ +#if 0 + /* changed for bash-4.2 Posix cd description steps 5-6 */ /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't try the current directory, so we just punt now with an error message if POSIXLY_CORRECT is non-zero. The check for cdpath[0] @@ -308,7 +400,7 @@ cd_builtin (list) /* When we get here, DIRNAME is the directory to change to. If we chdir successfully, just return. */ - if (change_to_directory (dirname, no_symlinks)) + if (change_to_directory (dirname, no_symlinks, xattrflag)) { if (lflag & LCD_PRINTPATH) printf ("%s\n", dirname); @@ -321,7 +413,7 @@ cd_builtin (list) if (lflag & LCD_DOVARS) { temp = get_string_value (dirname); - if (temp && change_to_directory (temp, no_symlinks)) + if (temp && change_to_directory (temp, no_symlinks, xattrflag)) { printf ("%s\n", temp); return (bindpwd (no_symlinks)); @@ -334,9 +426,10 @@ cd_builtin (list) if (lflag & LCD_DOSPELL) { temp = dirspell (dirname); - if (temp && change_to_directory (temp, no_symlinks)) + if (temp && change_to_directory (temp, no_symlinks, xattrflag)) { printf ("%s\n", temp); + free (temp); return (bindpwd (no_symlinks)); } else @@ -391,7 +484,7 @@ pwd_builtin (list) break; default: builtin_usage (); - return (EXECUTION_FAILURE); + return (EX_USAGE); } } list = loptend; @@ -405,7 +498,11 @@ pwd_builtin (list) the file system has changed state underneath bash). */ if ((tcwd && directory == 0) || (posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0)) - directory = resetpwd ("pwd"); + { + if (directory && directory != tcwd) + free (directory); + directory = resetpwd ("pwd"); + } #undef tcwd @@ -431,11 +528,11 @@ pwd_builtin (list) to the working directory. Return 1 on success, 0 on failure. */ static int -change_to_directory (newdir, nolinks) +change_to_directory (newdir, nolinks, xattr) char *newdir; - int nolinks; + int nolinks, xattr; { - char *t, *tdir; + char *t, *tdir, *ndir; int err, canon_failed, r, ndlen, dlen; tdir = (char *)NULL; @@ -484,8 +581,34 @@ change_to_directory (newdir, nolinks) return (0); } +#if defined (O_XATTR) + if (xattrflag) + { + r = cdxattr (nolinks ? newdir : tdir, &ndir); + if (r >= 0) + { + canon_failed = 0; + free (tdir); + tdir = ndir; + } + else + { + err = errno; + free (tdir); + errno = err; + return (0); /* no xattr */ + } + } + else +#endif + { + r = chdir (nolinks ? newdir : tdir); + if (r >= 0) + resetxattr (); + } + /* If the chdir succeeds, update the_current_working_directory. */ - if (chdir (nolinks ? newdir : tdir) == 0) + if (r == 0) { /* If canonicalization failed, but the chdir succeeded, reset the shell's idea of the_current_working_directory. */ @@ -494,6 +617,8 @@ change_to_directory (newdir, nolinks) t = resetpwd ("cd"); if (t == 0) set_working_directory (tdir); + else + free (t); } else set_working_directory (tdir); diff --git a/builtins/common.c b/builtins/common.c index 737ace2..fb2b38c 100644 --- a/builtins/common.c +++ b/builtins/common.c @@ -500,7 +500,7 @@ get_exitstat (list) if (arg == 0 || legal_number (arg, &sval) == 0) { sh_neednumarg (list->word->word ? list->word->word : "`'"); - return 255; + return EX_BADUSAGE; } no_args (list->next); @@ -628,7 +628,7 @@ get_job_by_name (name, flags) if (this_shell_builtin) builtin_error (_("%s: ambiguous job spec"), name); else - report_error (_("%s: ambiguous job spec"), name); + internal_error (_("%s: ambiguous job spec"), name); return (DUP_JOB); } else diff --git a/builtins/common.h b/builtins/common.h index caeefea..b0c2f7d 100644 --- a/builtins/common.h +++ b/builtins/common.h @@ -145,6 +145,8 @@ extern void set_bashopts __P((void)); extern void parse_bashopts __P((char *)); extern void initialize_bashopts __P((int)); +extern void set_compatibility_opts __P((void)); + /* Functions from type.def */ extern int describe_command __P((char *, int)); @@ -153,6 +155,7 @@ extern int set_or_show_attributes __P((WORD_LIST *, int, int)); extern int show_all_var_attributes __P((int, int)); extern int show_var_attributes __P((SHELL_VAR *, int, int)); extern int show_name_attributes __P((char *, int)); +extern int show_func_attributes __P((char *, int)); extern void set_var_attribute __P((char *, int, int)); /* Functions from pushd.def */ @@ -163,6 +166,7 @@ extern WORD_LIST *get_directory_stack __P((int)); /* Functions from evalstring.c */ extern int parse_and_execute __P((char *, const char *, int)); +extern int evalstring __P((char *, const char *, int)); extern void parse_and_execute_cleanup __P((void)); extern int parse_string __P((char *, const char *, int, char **)); diff --git a/builtins/complete.def b/builtins/complete.def index b9f0a13..8499b7a 100644 --- a/builtins/complete.def +++ b/builtins/complete.def @@ -1,7 +1,7 @@ This file is complete.def, from which is created complete.c. It implements the builtins "complete", "compgen", and "compopt" in Bash. -Copyright (C) 1999-2010 Free Software Foundation, Inc. +Copyright (C) 1999-2011 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -112,7 +112,7 @@ static const struct _compacts { { "export", CA_EXPORT, 'e' }, { "file", CA_FILE, 'f' }, { "function", CA_FUNCTION, 0 }, - { "helptopic", CA_BUILTIN, 0 }, /* for now */ + { "helptopic", CA_HELPTOPIC, 0 }, { "hostname", CA_HOSTNAME, 0 }, { "group", CA_GROUP, 'g' }, { "job", CA_JOB, 'j' }, @@ -129,7 +129,7 @@ static const struct _compacts { }; /* This should be a STRING_INT_ALIST */ -const static struct _compopt { +static const struct _compopt { const char * const optname; int optflag; } compopts[] = { @@ -137,6 +137,7 @@ const static struct _compopt { { "default", COPT_DEFAULT }, { "dirnames", COPT_DIRNAMES }, { "filenames",COPT_FILENAMES}, + { "noquote", COPT_NOQUOTE }, { "nospace", COPT_NOSPACE }, { "plusdirs", COPT_PLUSDIRS }, { (char *)NULL, 0 }, @@ -728,6 +729,7 @@ compgen_builtin (list) if ((sl == 0 || sl->list_len == 0) && (copts & COPT_DEFAULT)) { matches = rl_completion_matches (word, rl_filename_completion_function); + strlist_dispose (sl); sl = completions_to_stringlist (matches); strvec_dispose (matches); } diff --git a/builtins/declare.def b/builtins/declare.def index 8b9b850..a634e7c 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -1,7 +1,7 @@ This file is declare.def, from which is created declare.c. It implements the builtins "declare" and "local" in Bash. -Copyright (C) 1987-2010 Free Software Foundation, Inc. +Copyright (C) 1987-2012 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -22,7 +22,7 @@ $PRODUCES declare.c $BUILTIN declare $FUNCTION declare_builtin -$SHORT_DOC declare [-aAfFgilrtux] [-p] [name[=value] ...] +$SHORT_DOC declare [-aAfFgilnrtux] [-p] [name[=value] ...] Set variable values and attributes. Declare variables and give them attributes. If no NAMEs are given, @@ -41,6 +41,7 @@ Options which set attributes: -A to make NAMEs associative arrays (if supported) -i to make NAMEs have the `integer' attribute -l to convert NAMEs to lower case on assignment + -n make NAME a reference to the variable named by its value -r to make NAMEs readonly -t to make NAMEs have the `trace' attribute -u to convert NAMEs to upper case on assignment @@ -55,7 +56,8 @@ When used in a function, `declare' makes NAMEs local, as with the `local' command. The `-g' option suppresses this behavior. Exit Status: -Returns success unless an invalid option is supplied or an error occurs. +Returns success unless an invalid option is supplied or a variable +assignment error occurs. $END $BUILTIN typeset @@ -110,8 +112,8 @@ Local variables can only be used within a function; they are visible only to the function where they are defined and its children. Exit Status: -Returns success unless an invalid option is supplied, an error occurs, -or the shell is not executing a function. +Returns success unless an invalid option is supplied, a variable +assignment error occurs, or the shell is not executing a function. $END int local_builtin (list) @@ -127,9 +129,9 @@ local_builtin (list) } #if defined (ARRAY_VARS) -# define DECLARE_OPTS "+acfgilprtuxAF" +# define DECLARE_OPTS "+acfgilnprtuxAF" #else -# define DECLARE_OPTS "+cfgilprtuxF" +# define DECLARE_OPTS "+cfgilnprtuxF" #endif /* The workhorse function. */ @@ -139,12 +141,13 @@ declare_internal (list, local_var) int local_var; { int flags_on, flags_off, *flags; - int any_failed, assign_error, pflag, nodefs, opt, mkglobal; + int any_failed, assign_error, pflag, nodefs, opt, mkglobal, onref, offref; char *t, *subscript_start; - SHELL_VAR *var; + SHELL_VAR *var, *refvar, *v; FUNCTION_DEF *shell_fn; flags_on = flags_off = any_failed = assign_error = pflag = nodefs = mkglobal = 0; + refvar = (SHELL_VAR *)NULL; reset_internal_getopt (); while ((opt = internal_getopt (list, DECLARE_OPTS)) != EOF) { @@ -186,6 +189,9 @@ declare_internal (list, local_var) case 'i': *flags |= att_integer; break; + case 'n': + *flags |= att_nameref; + break; case 'r': *flags |= att_readonly; break; @@ -258,7 +264,10 @@ declare_internal (list, local_var) { for (any_failed = 0; list; list = list->next) { - pflag = show_name_attributes (list->word->word, nodefs); + if (flags_on & att_function) + pflag = show_func_attributes (list->word->word, nodefs); + else + pflag = show_name_attributes (list->word->word, nodefs); if (pflag) { sh_notfound (list->word->word); @@ -296,6 +305,28 @@ declare_internal (list, local_var) else value = ""; + /* Do some lexical error checking on the LHS and RHS of the assignment + that is specific to nameref variables. */ + if (flags_on & att_nameref) + { +#if defined (ARRAY_VARIABLES) + if (valid_array_reference (name)) + { + builtin_error (_("%s: reference variable cannot be an array"), name); + assign_error++; + NEXT_VARIABLE (); + } + else +#endif + /* disallow self references at global scope */ + if (STREQ (name, value) && variable_context == 0) + { + builtin_error (_("%s: nameref variable self references not allowed"), name); + assign_error++; + NEXT_VARIABLE (); + } + } + #if defined (ARRAY_VARS) compound_array_assign = simple_array_assign = 0; subscript_start = (char *)NULL; @@ -334,16 +365,17 @@ declare_internal (list, local_var) /* XXX - this has consequences when we're making a local copy of a variable that was in the temporary environment. Watch out for this. */ + refvar = (SHELL_VAR *)NULL; if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0)) { #if defined (ARRAY_VARS) if (flags_on & att_assoc) var = make_local_assoc_variable (name); else if ((flags_on & att_array) || making_array_special) - var = make_local_array_variable (name); + var = make_local_array_variable (name, making_array_special); else #endif - var = make_local_variable (name); + var = make_local_variable (name); /* sets att_invisible for new vars */ if (var == 0) { any_failed++; @@ -415,6 +447,33 @@ declare_internal (list, local_var) else /* declare -[aAirx] name [name...] */ { /* Non-null if we just created or fetched a local variable. */ + /* Here's what ksh93 seems to do. If we are modifying an existing + nameref variable, we don't follow the nameref chain past the last + nameref, and we set the nameref variable's value so future + references to that variable will return the value of the variable + we're assigning right now. */ + if (var == 0 && (flags_on & att_nameref)) + { + /* See if we are trying to modify an existing nameref variable */ + var = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name); + if (var && nameref_p (var) == 0) + var = 0; + } + /* However, if we're turning off the nameref attribute on an existing + nameref variable, we first follow the nameref chain to the end, + modify the value of the variable this nameref variable references, + *CHANGING ITS VALUE AS A SIDE EFFECT* then turn off the nameref + flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */ + else if (var == 0 && (flags_off & att_nameref)) + { + /* See if we are trying to modify an existing nameref variable */ + refvar = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name); + if (refvar && nameref_p (refvar) == 0) + refvar = 0; + if (refvar) + var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar)); + } + if (var == 0) var = mkglobal ? find_global_variable (name) : find_variable (name); @@ -422,20 +481,40 @@ declare_internal (list, local_var) { #if defined (ARRAY_VARS) if (flags_on & att_assoc) - var = make_new_assoc_variable (name); + { + var = make_new_assoc_variable (name); + if (offset == 0) + VSETATTR (var, att_invisible); + } else if ((flags_on & att_array) || making_array_special) - var = make_new_array_variable (name); + { + var = make_new_array_variable (name); + if (offset == 0) + VSETATTR (var, att_invisible); + } else #endif if (offset) - var = bind_variable (name, "", 0); + var = mkglobal ? bind_global_variable (name, "", 0) : bind_variable (name, "", 0); else { - var = bind_variable (name, (char *)NULL, 0); + var = mkglobal ? bind_global_variable (name, (char *)NULL, 0) : bind_variable (name, (char *)NULL, 0); VSETATTR (var, att_invisible); } } + /* Can't take an existing array variable and make it a nameref */ + else if ((array_p (var) || assoc_p (var)) && (flags_on & att_nameref)) + { + builtin_error (_("%s: reference variable cannot be an array"), name); + assign_error++; + NEXT_VARIABLE (); + } + else if (flags_on & att_nameref) + { + /* ksh93 compat: turning on nameref attribute turns off -ilu */ + VUNSETATTR (var, att_integer|att_uppercase|att_lowercase|att_capcase); + } /* Cannot use declare +r to turn off readonly attribute. */ if (readonly_p (var) && (flags_off & att_readonly)) @@ -501,6 +580,25 @@ declare_internal (list, local_var) var = convert_var_to_array (var); #endif /* ARRAY_VARS */ + /* XXX - we note that we are turning on nameref attribute and defer + setting it until the assignment has been made so we don't do an + inadvertent nameref lookup. Might have to do the same thing for + flags_off&att_nameref. */ + /* XXX - ksh93 makes it an error to set a readonly nameref variable + using a single typeset command. */ + onref = (flags_on & att_nameref); + flags_on &= ~att_nameref; +#if defined (ARRAY_VARS) + if (array_p (var) || assoc_p (var) + || (offset && compound_array_assign) + || simple_array_assign) + onref = 0; /* array variables may not be namerefs */ +#endif + + /* ksh93 seems to do this */ + offref = (flags_off & att_nameref); + flags_off &= ~att_nameref; + VSETATTR (var, flags_on); VUNSETATTR (var, flags_off); @@ -516,6 +614,8 @@ declare_internal (list, local_var) if (var == 0) /* some kind of assignment error */ { assign_error++; + flags_on |= onref; + flags_off |= offref; NEXT_VARIABLE (); } } @@ -532,7 +632,19 @@ declare_internal (list, local_var) /* bind_variable_value duplicates the essential internals of bind_variable() */ if (offset) - bind_variable_value (var, value, aflags); + { + if (onref) + aflags |= ASS_NAMEREF; + v = bind_variable_value (var, value, aflags); + if (v == 0 && onref) + { + sh_invalidid (value); + assign_error++; + /* XXX - unset this variable? or leave it as normal var? */ + delete_var (var->name, mkglobal ? global_variables : shell_variables); + NEXT_VARIABLE (); + } + } /* If we found this variable in the temporary environment, as with `var=value declare -x var', make sure it is treated identically @@ -562,6 +674,17 @@ declare_internal (list, local_var) } } + /* Turn on nameref attribute we deferred above. */ + /* XXX - should we turn on the noassign attribute for consistency with + ksh93 when we turn on the nameref attribute? */ + VSETATTR (var, onref); + flags_on |= onref; + VUNSETATTR (var, offref); + flags_off |= offref; + /* Yuck. ksh93 compatibility */ + if (refvar) + VUNSETATTR (refvar, flags_off); + stupidly_hack_special_variables (name); NEXT_VARIABLE (); diff --git a/builtins/echo.def b/builtins/echo.def index 62c6199..f473826 100644 --- a/builtins/echo.def +++ b/builtins/echo.def @@ -38,7 +38,8 @@ $DEPENDS_ON V9_ECHO $SHORT_DOC echo [-neE] [arg ...] Write arguments to the standard output. -Display the ARGs on the standard output followed by a newline. +Display the ARGs, separated by a single space character and followed by a +newline, on the standard output. Options: -n do not append a newline @@ -50,6 +51,7 @@ Options: \b backspace \c suppress further output \e escape character + \E escape character \f form feed \n new line \r carriage return diff --git a/builtins/eval.def b/builtins/eval.def index ee9a23d..5e824c9 100644 --- a/builtins/eval.def +++ b/builtins/eval.def @@ -53,6 +53,5 @@ eval_builtin (list) return (EX_USAGE); list = loptend; /* skip over possible `--' */ - /* Note that parse_and_execute () frees the string it is passed. */ - return (list ? parse_and_execute (string_list (list), "eval", SEVAL_NOHIST) : EXECUTION_SUCCESS); + return (list ? evalstring (string_list (list), "eval", SEVAL_NOHIST) : EXECUTION_SUCCESS); } diff --git a/builtins/evalfile.c b/builtins/evalfile.c index 4d69acb..058d99d 100644 --- a/builtins/evalfile.c +++ b/builtins/evalfile.c @@ -109,11 +109,16 @@ _evalfile (filename, flags) GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a); # endif #endif - + fd = open (filename, O_RDONLY); if (fd < 0 || (fstat (fd, &finfo) == -1)) { + i = errno; + if (fd >= 0) + close (fd); + errno = i; + file_error_and_exit: if (((flags & FEVAL_ENOENTOK) == 0) || errno != ENOENT) file_error (filename); @@ -133,11 +138,13 @@ file_error_and_exit: if (S_ISDIR (finfo.st_mode)) { (*errfunc) (_("%s: is a directory"), filename); + close (fd); return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); } else if ((flags & FEVAL_REGFILE) && S_ISREG (finfo.st_mode) == 0) { (*errfunc) (_("%s: not a regular file"), filename); + close (fd); return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); } @@ -146,6 +153,7 @@ file_error_and_exit: if (file_size != finfo.st_size || file_size + 1 < file_size) { (*errfunc) (_("%s: file is too large"), filename); + close (fd); return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); } @@ -251,7 +259,7 @@ file_error_and_exit: if (flags & FEVAL_BUILTIN) result = EXECUTION_SUCCESS; - return_val = setjmp (return_catch); + return_val = setjmp_nosigs (return_catch); /* If `return' was seen outside of a function, but in the script, then force parse_and_execute () to clean up. */ diff --git a/builtins/evalstring.c b/builtins/evalstring.c index 333a56e..ce5b4d6 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -1,6 +1,6 @@ /* evalstring.c - evaluate a string as one or more shell commands. */ -/* Copyright (C) 1996-2010 Free Software Foundation, Inc. +/* Copyright (C) 1996-2012 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -61,7 +61,7 @@ extern int errno; #define IS_BUILTIN(s) (builtin_address_internal(s, 0) != (struct builtin *)NULL) extern int indirection_level, subshell_environment; -extern int line_number; +extern int line_number, line_number_for_err_trap; extern int current_token, shell_eof_token; extern int last_command_exit_value; extern int running_trap; @@ -69,7 +69,9 @@ extern int loop_level; extern int executing_list; extern int comsub_ignore_return; extern int posixly_correct; +extern int return_catch_flag, return_catch_value; extern sh_builtin_func_t *this_shell_builtin; +extern char *the_printed_command_except_trap; int parse_and_execute_level = 0; @@ -86,6 +88,14 @@ set_history_remembering () } #endif +static void +restore_lastcom (x) + char *x; +{ + FREE (the_printed_command_except_trap); + the_printed_command_except_trap = x; +} + /* How to force parse_and_execute () to clean up after itself. */ void parse_and_execute_cleanup () @@ -108,7 +118,7 @@ parse_prologue (string, flags, tag) int flags; char *tag; { - char *orig_string; + char *orig_string, *lastcom; int x; orig_string = string; @@ -118,6 +128,7 @@ parse_prologue (string, flags, tag) unwind_protect_jmp_buf (top_level); unwind_protect_int (indirection_level); unwind_protect_int (line_number); + unwind_protect_int (line_number_for_err_trap); unwind_protect_int (loop_level); unwind_protect_int (executing_list); unwind_protect_int (comsub_ignore_return); @@ -140,8 +151,17 @@ parse_prologue (string, flags, tag) x = get_current_prompt_level (); add_unwind_protect (set_current_prompt_level, x); } - + + if (the_printed_command_except_trap) + { + lastcom = savestring (the_printed_command_except_trap); + add_unwind_protect (restore_lastcom, lastcom); + } + add_unwind_protect (pop_stream, (char *)NULL); + if (parser_expanding_alias ()) + add_unwind_protect (parser_restore_alias, (char *)NULL); + if (orig_string && ((flags & SEVAL_NOFREE) == 0)) add_unwind_protect (xfree, orig_string); end_unwind_frame (); @@ -175,6 +195,7 @@ parse_and_execute (string, from_file, flags) int code, lreset; volatile int should_jump_to_top_level, last_result; COMMAND *volatile command; + volatile sigset_t pe_sigmask; parse_prologue (string, flags, PE_TAG); @@ -182,11 +203,21 @@ parse_and_execute (string, from_file, flags) lreset = flags & SEVAL_RESETLINE; +#if defined (HAVE_POSIX_SIGNALS) + /* If we longjmp and are going to go on, use this to restore signal mask */ + sigemptyset (&pe_sigmask); + sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &pe_sigmask); +#endif + /* Reset the line number if the caller wants us to. If we don't reset the line number, we have to subtract one, because we will add one just before executing the next command (resetting the line number sets it to 0; the first line number is 1). */ push_stream (lreset); + if (parser_expanding_alias ()) + /* push current shell_input_line */ + parser_save_alias (); + if (lreset == 0) line_number--; @@ -209,15 +240,28 @@ parse_and_execute (string, from_file, flags) /* Provide a location for functions which `longjmp (top_level)' to jump to. This prevents errors in substitution from restarting the reader loop directly, for example. */ - code = setjmp (top_level); + code = setjmp_nosigs (top_level); if (code) { should_jump_to_top_level = 0; switch (code) { - case FORCE_EOF: case ERREXIT: + /* variable_context -> 0 is what eval.c:reader_loop() does in + these circumstances. Don't bother with cleanup here because + we don't want to run the function execution cleanup stuff + that will cause pop_context and other functions to run. + XXX - change that if we want the function context to be + unwound. */ + if (exit_immediately_on_error && variable_context) + { + discard_unwind_frame ("pe_dispose"); + variable_context = 0; /* not in a function */ + } + should_jump_to_top_level = 1; + goto out; + case FORCE_EOF: case EXITPROG: if (command) run_unwind_frame ("pe_dispose"); @@ -240,6 +284,9 @@ parse_and_execute (string, from_file, flags) #if 0 dispose_command (command); /* pe_dispose does this */ #endif +#if defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_SETMASK, &pe_sigmask, (sigset_t *)NULL); +#endif continue; } @@ -308,7 +355,8 @@ parse_and_execute (string, from_file, flags) command->value.Simple->words == 0 && command->value.Simple->redirects && command->value.Simple->redirects->next == 0 && - command->value.Simple->redirects->instruction == r_input_direction) + command->value.Simple->redirects->instruction == r_input_direction && + command->value.Simple->redirects->redirector.dest == 0) { int r; r = cat_file (command->value.Simple->redirects); @@ -317,7 +365,6 @@ parse_and_execute (string, from_file, flags) else last_result = execute_command_internal (command, 0, NO_PIPE, NO_PIPE, bitmap); - dispose_command (command); dispose_fd_bitmap (bitmap); discard_unwind_frame ("pe_dispose"); @@ -377,15 +424,26 @@ parse_string (string, from_file, flags, endp) volatile int should_jump_to_top_level; COMMAND *volatile command, *oglobal; char *ostring; + volatile sigset_t ps_sigmask; parse_prologue (string, flags, PS_TAG); +#if defined (HAVE_POSIX_SIGNALS) + /* If we longjmp and are going to go on, use this to restore signal mask */ + sigemptyset (&ps_sigmask); + sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &ps_sigmask); +#endif + +/* itrace("parse_string: `%s'", string); */ /* Reset the line number if the caller wants us to. If we don't reset the line number, we have to subtract one, because we will add one just before executing the next command (resetting the line number sets it to 0; the first line number is 1). */ push_stream (0); - + if (parser_expanding_alias ()) + /* push current shell_input_line */ + parser_save_alias (); + code = should_jump_to_top_level = 0; oglobal = global_command; ostring = string; @@ -402,7 +460,7 @@ parse_string (string, from_file, flags, endp) /* Provide a location for functions which `longjmp (top_level)' to jump to. */ - code = setjmp (top_level); + code = setjmp_nosigs (top_level); if (code) { @@ -424,6 +482,9 @@ itrace("parse_string: longjmp executed: code = %d", code); goto out; default: +#if defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_SETMASK, &ps_sigmask, (sigset_t *)NULL); +#endif command_error ("parse_string", CMDERR_BADJUMP, code, 0); break; } @@ -506,3 +567,49 @@ cat_file (r) return (rval); } + +int +evalstring (string, from_file, flags) + char *string; + const char *from_file; + int flags; +{ + volatile int r, rflag, rcatch; + + rcatch = 0; + rflag = return_catch_flag; + /* If we are in a place where `return' is valid, we have to catch + `eval "... return"' and make sure parse_and_execute cleans up. Then + we can trampoline to the previous saved return_catch location. */ + if (rflag) + { + begin_unwind_frame ("evalstring"); + + unwind_protect_int (return_catch_flag); + unwind_protect_jmp_buf (return_catch); + + return_catch_flag++; /* increment so we have a counter */ + rcatch = setjmp_nosigs (return_catch); + } + + if (rcatch) + { + parse_and_execute_cleanup (); + r = return_catch_value; + } + else + /* Note that parse_and_execute () frees the string it is passed. */ + r = parse_and_execute (string, from_file, flags); + + if (rflag) + { + run_unwind_frame ("evalstring"); + if (rcatch && return_catch_flag) + { + return_catch_value = r; + longjmp (return_catch, 1); + } + } + + return (r); +} diff --git a/builtins/exec.def b/builtins/exec.def index 5d1e625..9cf76d5 100644 --- a/builtins/exec.def +++ b/builtins/exec.def @@ -1,7 +1,7 @@ This file is exec.def, from which is created exec.c. It implements the builtin "exec" in Bash. -Copyright (C) 1987-2010 Free Software Foundation, Inc. +Copyright (C) 1987-2012 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -144,7 +144,7 @@ exec_builtin (list) args = strvec_from_word_list (list, 1, 0, (int *)NULL); /* A command with a slash anywhere in its name is not looked up in $PATH. */ - command = absolute_program (args[0]) ? args[0] : search_for_command (args[0]); + command = absolute_program (args[0]) ? args[0] : search_for_command (args[0], 1); if (command == 0) { diff --git a/builtins/fc.def b/builtins/fc.def index 9b298cb..cf6b72c 100644 --- a/builtins/fc.def +++ b/builtins/fc.def @@ -1,7 +1,7 @@ This file is fc.def, from which is created fc.c. It implements the builtin "fc" in Bash. -Copyright (C) 1987-2010 Free Software Foundation, Inc. +Copyright (C) 1987-2011 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -52,7 +52,7 @@ $END #include <config.h> #if defined (HISTORY) -#ifndef _MINIX +#if defined (HAVE_SYS_PARAM_H) # include <sys/param.h> #endif #include "../bashtypes.h" @@ -85,7 +85,7 @@ $END extern int errno; #endif /* !errno */ -extern int current_command_line_count, saved_command_line_count; +extern int current_command_line_count; extern int literal_history; extern int posixly_correct; extern int subshell_environment, interactive_shell; @@ -173,7 +173,7 @@ fc_builtin (list) register int i; register char *sep; int numbering, reverse, listing, execute; - int histbeg, histend, last_hist, retval, opt, rh; + int histbeg, histend, last_hist, retval, opt, rh, real_last; FILE *stream; REPL *rlist, *rl; char *ename, *command, *newcom, *fcedit; @@ -303,6 +303,14 @@ fc_builtin (list) rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list); last_hist = i - rh - hist_last_line_added; + /* Make sure that real_last is calculated the same way here and in + fc_gethnum. The return value from fc_gethnum is treated specially if + it is == real_last and we are listing commands. */ + real_last = i; + /* back up from the end to the last non-null history entry */ + while (hlist[real_last] == 0 && real_last > 0) + real_last--; + /* XXX */ if (i == last_hist && hlist[last_hist] == 0) while (last_hist >= 0 && hlist[last_hist] == 0) @@ -320,6 +328,8 @@ fc_builtin (list) if (list) histend = fc_gethnum (list->word->word, hlist); + else if (histbeg == real_last) + histend = listing ? real_last : histbeg; else histend = listing ? last_hist : histbeg; } @@ -475,7 +485,7 @@ fc_gethnum (command, hlist) HIST_ENTRY **hlist; { int sign, n, clen, rh; - register int i, j, last_hist; + register int i, j, last_hist, real_last; register char *s; sign = 1; @@ -503,12 +513,17 @@ fc_gethnum (command, hlist) if (last_hist < 0) return (-1); + real_last = i; i = last_hist; /* No specification defaults to most recent command. */ if (command == NULL) return (i); + /* back up from the end to the last non-null history entry */ + while (hlist[real_last] == 0 && real_last > 0) + real_last--; + /* Otherwise, there is a specification. It can be a number relative to the current position, or an absolute history number. */ s = command; @@ -533,7 +548,7 @@ fc_gethnum (command, hlist) return (n < 0 ? 0 : n); } else if (n == 0) - return (i); + return ((sign == -1) ? real_last : i); else { n -= history_base; diff --git a/builtins/gen-helpfiles.c b/builtins/gen-helpfiles.c new file mode 100644 index 0000000..fac34ed --- /dev/null +++ b/builtins/gen-helpfiles.c @@ -0,0 +1,197 @@ +/* gen-helpfiles - create files containing builtin help text */ + +/* Copyright (C) 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/>. +*/ + +/* This links with a specially-generated version of builtins.c and takes + the long_doc members of each struct builtin element and writes those to + the file named by the `handle' member of the struct builtin element. */ + +#if !defined (CROSS_COMPILING) +# include <config.h> +#else /* CROSS_COMPILING */ +/* A conservative set of defines based on POSIX/SUS3/XPG6 */ +# define HAVE_UNISTD_H +# define HAVE_STRING_H +# define HAVE_STDLIB_H + +# define HAVE_RENAME +#endif /* CROSS_COMPILING */ + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif +# include <unistd.h> +#endif + +#ifndef _MINIX +# include "../bashtypes.h" +# if defined (HAVE_SYS_FILE_H) +# include <sys/file.h> +# endif +#endif + +#include "posixstat.h" +#include "filecntl.h" + +#include "../bashansi.h" +#include <stdio.h> +#include <errno.h> + +#include "stdc.h" + +#include "../builtins.h" +#include "tmpbuiltins.h" + +#if defined (USING_BASH_MALLOC) +#undef xmalloc +#undef xrealloc +#undef xfree + +#undef free /* defined in xmalloc.h */ +#endif + +#ifndef errno +extern int errno; +#endif + +#if !defined (__STDC__) && !defined (strcpy) +extern char *strcpy (); +#endif /* !__STDC__ && !strcpy */ + +#define whitespace(c) (((c) == ' ') || ((c) == '\t')) + +/* Flag values that builtins can have. */ +#define BUILTIN_FLAG_SPECIAL 0x01 +#define BUILTIN_FLAG_ASSIGNMENT 0x02 +#define BUILTIN_FLAG_POSIX_BUILTIN 0x04 + +#define BASE_INDENT 4 + +/* Non-zero means to produce separate help files for each builtin, named by + the builtin name, in `./helpfiles'. */ +int separate_helpfiles = 0; + +/* Non-zero means to create single C strings for each `longdoc', with + embedded newlines, for ease of translation. */ +int single_longdoc_strings = 1; + +/* The name of a directory into which the separate external help files will + eventually be installed. */ +char *helpfile_directory; + +/* Forward declarations. */ + +int write_helpfiles __P((struct builtin *)); + +/* For each file mentioned on the command line, process it and + write the information to STRUCTFILE and EXTERNFILE, while + creating the production file if neccessary. */ +int +main (argc, argv) + int argc; + char **argv; +{ + int arg_index = 1; + + while (arg_index < argc && argv[arg_index][0] == '-') + { + char *arg = argv[arg_index++]; + + if (strcmp (arg, "-noproduction") == 0) + ; + else if (strcmp (arg, "-H") == 0) + helpfile_directory = argv[arg_index++]; + else if (strcmp (arg, "-S") == 0) + single_longdoc_strings = 0; + else + { + fprintf (stderr, "%s: Unknown flag %s.\n", argv[0], arg); + exit (2); + } + } + + write_helpfiles(shell_builtins); + + exit (0); +} + +/* Write DOCUMENTATION to STREAM, perhaps surrounding it with double-quotes + and quoting special characters in the string. Handle special things for + internationalization (gettext) and the single-string vs. multiple-strings + issues. */ +void +write_documentation (stream, documentation, indentation) + FILE *stream; + char *documentation; + int indentation; +{ + if (stream == 0) + return; + + if (documentation) + fprintf (stream, "%*s%s\n", indentation, " ", documentation); +} + +int +write_helpfiles (builtins) + struct builtin *builtins; +{ + char *helpfile, *bname, *fname; + FILE *helpfp; + int i, hdlen; + struct builtin b; + + i = mkdir ("helpfiles", 0777); + if (i < 0 && errno != EEXIST) + { + fprintf (stderr, "write_helpfiles: helpfiles: cannot create directory\n"); + return -1; + } + + hdlen = strlen ("helpfiles/"); + for (i = 0; i < num_shell_builtins; i++) + { + b = builtins[i]; + + fname = (char *)b.handle; + helpfile = (char *)malloc (hdlen + strlen (fname) + 1); + if (helpfile == 0) + { + fprintf (stderr, "gen-helpfiles: cannot allocate memory\n"); + exit (1); + } + sprintf (helpfile, "helpfiles/%s", fname); + + helpfp = fopen (helpfile, "w"); + if (helpfp == 0) + { + fprintf (stderr, "write_helpfiles: cannot open %s\n", helpfile); + free (helpfile); + continue; + } + + write_documentation (helpfp, b.long_doc[0], 4); + + fflush (helpfp); + fclose (helpfp); + free (helpfile); + } + return 0; +} diff --git a/builtins/hash.def b/builtins/hash.def index 6724ad1..85ef364 100644 --- a/builtins/hash.def +++ b/builtins/hash.def @@ -1,7 +1,7 @@ This file is hash.def, from which is created hash.c. It implements the builtin "hash" in Bash. -Copyright (C) 1987-2010 Free Software Foundation, Inc. +Copyright (C) 1987-2013 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -31,7 +31,7 @@ no arguments are given, information about remembered commands is displayed. Options: -d forget the remembered location of each NAME -l display in a format that may be reused as input - -p pathname use PATHNAME is the full pathname of NAME + -p pathname use PATHNAME as the full pathname of NAME -r forget all remembered locations -t print the remembered location of each NAME, preceding each location with the corresponding NAME if multiple @@ -276,6 +276,7 @@ list_hashed_filename_targets (list, fmt) printf ("%s\t", l->word->word); printf ("%s\n", target); } + free (target); } return (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE); diff --git a/builtins/help.def b/builtins/help.def index 8fb0e2b..1894f17 100644 --- a/builtins/help.def +++ b/builtins/help.def @@ -1,7 +1,7 @@ This file is help.def, from which is created help.c. It implements the builtin "help" in Bash. -Copyright (C) 1987-2009 Free Software Foundation, Inc. +Copyright (C) 1987-2013 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -92,7 +92,7 @@ help_builtin (list) { register int i; char *pattern, *name; - int plen, match_found, sflag, dflag, mflag; + int plen, match_found, sflag, dflag, mflag, m, pass, this_found; dflag = sflag = mflag = 0; reset_internal_getopt (); @@ -137,29 +137,43 @@ help_builtin (list) pattern = list->word->word; plen = strlen (pattern); - for (i = 0; name = shell_builtins[i].name; i++) + for (pass = 1, this_found = 0; pass < 3; pass++) { - QUIT; - if ((strncmp (pattern, name, plen) == 0) || - (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH)) + for (i = 0; name = shell_builtins[i].name; i++) { - match_found++; - if (dflag) - { - show_desc (name, i); - continue; - } - else if (mflag) - { - show_manpage (name, i); - continue; - } - - printf ("%s: %s\n", name, _(shell_builtins[i].short_doc)); - - if (sflag == 0) - show_longdoc (i); + QUIT; + + /* First pass: look for exact string or pattern matches. + Second pass: look for prefix matches like bash-4.2 */ + if (pass == 1) + m = (strcmp (pattern, name) == 0) || + (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH); + else + m = strncmp (pattern, name, plen) == 0; + + if (m) + { + this_found = 1; + match_found++; + if (dflag) + { + show_desc (name, i); + continue; + } + else if (mflag) + { + show_manpage (name, i); + continue; + } + + printf ("%s: %s\n", name, _(shell_builtins[i].short_doc)); + + if (sflag == 0) + show_longdoc (i); + } } + if (pass == 1 && this_found == 1) + break; } } @@ -209,7 +223,7 @@ show_longdoc (i) zcatfd (fd, 1, doc[0]); close (fd); } - else + else if (doc) for (j = 0; doc[j]; j++) printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j])); } @@ -327,6 +341,140 @@ show_manpage (name, i) } static void +dispcolumn (i, buf, bufsize, width, height) + int i; + char *buf; + size_t bufsize; + int width, height; +{ + int j; + int displen; + char *helpdoc; + + /* first column */ + helpdoc = _(shell_builtins[i].short_doc); + + buf[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*'; + strncpy (buf + 1, helpdoc, width - 2); + buf[width - 2] = '>'; /* indicate truncation */ + buf[width - 1] = '\0'; + printf ("%s", buf); + if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins)) + { + printf ("\n"); + return; + } + + displen = strlen (buf); + /* two spaces */ + for (j = displen; j < width; j++) + putc (' ', stdout); + + /* second column */ + helpdoc = _(shell_builtins[i+height].short_doc); + + buf[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*'; + strncpy (buf + 1, helpdoc, width - 3); + buf[width - 3] = '>'; /* indicate truncation */ + buf[width - 2] = '\0'; + + printf ("%s\n", buf); +} + +#if defined (HANDLE_MULTIBYTE) +static void +wdispcolumn (i, buf, bufsize, width, height) + int i; + char *buf; + size_t bufsize; + int width, height; +{ + int j; + int displen; + char *helpdoc; + wchar_t *wcstr; + size_t slen, n; + int wclen; + + /* first column */ + helpdoc = _(shell_builtins[i].short_doc); + + wcstr = 0; + slen = mbstowcs ((wchar_t *)0, helpdoc, 0); + if (slen == -1) + { + dispcolumn (i, buf, bufsize, width, height); + return; + } + + /* No bigger than the passed max width */ + if (slen >= width) + slen = width - 2; + wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (width + 2)); + n = mbstowcs (wcstr+1, helpdoc, slen + 1); + wcstr[n+1] = L'\0'; + + /* Turn tabs and newlines into spaces for column display, since wcwidth + returns -1 for them */ + for (j = 1; j < n; j++) + if (wcstr[j] == L'\n' || wcstr[j] == L'\t') + wcstr[j] = L' '; + + displen = wcsnwidth (wcstr+1, slen, width - 2) + 1; /* +1 for ' ' or '*' */ + + wcstr[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? L' ' : L'*'; + + /* This assumes each wide char takes up one column position when displayed */ + wcstr[width - 2] = L'>'; /* indicate truncation */ + wcstr[width - 1] = L'\0'; + + printf ("%ls", wcstr); + if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins)) + { + printf ("\n"); + return; + } + + /* at least one space */ + for (j = displen; j < width; j++) + putc (' ', stdout); + + /* second column */ + helpdoc = _(shell_builtins[i+height].short_doc); + slen = mbstowcs ((wchar_t *)0, helpdoc, 0); + if (slen == -1) + { + /* for now */ + printf ("%c%s\n", (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*', helpdoc); + return; + } + + /* Reuse wcstr since it is already width wide chars long */ + if (slen >= width) + slen = width - 2; + n = mbstowcs (wcstr+1, helpdoc, slen + 1); + wcstr[n+1] = L'\0'; /* make sure null-terminated */ + + /* Turn tabs and newlines into spaces for column display */ + for (j = 1; j < n; j++) + if (wcstr[j] == L'\n' || wcstr[j] == L'\t') + wcstr[j] = L' '; + + displen = wcsnwidth (wcstr+1, slen, width - 2); + + wcstr[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? L' ' : L'*'; + + /* This assumes each wide char takes up one column position when displayed */ + wcstr[width - 3] = L'>'; /* indicate truncation */ + wcstr[width - 2] = L'\0'; + + printf ("%ls\n", wcstr); + + free (wcstr); +} +#endif /* HANDLE_MULTIBYTE */ + +static void show_builtin_command_help () { int i, j; @@ -358,28 +506,12 @@ A star (*) next to a name means that the command is disabled.\n\ { QUIT; - /* first column */ - blurb[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*'; - strncpy (blurb + 1, _(shell_builtins[i].short_doc), width - 2); - blurb[width - 2] = '>'; /* indicate truncation */ - blurb[width - 1] = '\0'; - printf ("%s", blurb); - if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins)) - { - printf ("\n"); - break; - } - - /* two spaces */ - for (j = strlen (blurb); j < width; j++) - putc (' ', stdout); - - /* second column */ - blurb[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*'; - strncpy (blurb + 1, _(shell_builtins[i+height].short_doc), width - 3); - blurb[width - 3] = '>'; /* indicate truncation */ - blurb[width - 2] = '\0'; - printf ("%s\n", blurb); +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1) + wdispcolumn (i, blurb, sizeof (blurb), width, height); + else +#endif + dispcolumn (i, blurb, sizeof (blurb), width, height); } } #endif /* HELP_BUILTIN */ diff --git a/builtins/history.def b/builtins/history.def index e8249e9..4cf7308 100644 --- a/builtins/history.def +++ b/builtins/history.def @@ -324,9 +324,10 @@ push_history (list) If you don't want history -s to remove the compound command from the history, change #if 0 to #if 1 below. */ #if 0 - if (hist_last_line_pushed == 0 && hist_last_line_added && bash_delete_last_history () == 0) + if (remember_on_history && hist_last_line_pushed == 0 && + hist_last_line_added && bash_delete_last_history () == 0) #else - if (hist_last_line_pushed == 0 && + if (remember_on_history && hist_last_line_pushed == 0 && (hist_last_line_added || (current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history)) && bash_delete_last_history () == 0) diff --git a/builtins/jobs.def b/builtins/jobs.def index b14e91f..47da58e 100644 --- a/builtins/jobs.def +++ b/builtins/jobs.def @@ -31,7 +31,7 @@ Without options, the status of all active jobs is displayed. Options: -l lists process IDs in addition to the normal information - -n list only processes that have changed status since the last + -n lists only processes that have changed status since the last notification -p lists process IDs only -r restrict output to running jobs diff --git a/builtins/kill.def b/builtins/kill.def index adf022c..2e68f03 100644 --- a/builtins/kill.def +++ b/builtins/kill.def @@ -57,6 +57,8 @@ $END #include "../bashansi.h" #include "../bashintl.h" +#include <signal.h> + #include "../shell.h" #include "../trap.h" #include "../jobs.h" @@ -92,7 +94,7 @@ kill_builtin (list) if (list == 0) { builtin_usage (); - return (EXECUTION_FAILURE); + return (EX_USAGE); } any_succeeded = listing = saw_signal = 0; @@ -137,7 +139,7 @@ kill_builtin (list) else if (ISOPTION (word, '?')) { builtin_usage (); - return (EXECUTION_SUCCESS); + return (EX_USAGE); } /* If this is a signal specification then process it. We only process the first one seen; other arguments may signify process groups (e.g, @@ -166,7 +168,7 @@ kill_builtin (list) if (list == 0) { builtin_usage (); - return (EXECUTION_FAILURE); + return (EX_USAGE); } while (list) diff --git a/builtins/mapfile.def b/builtins/mapfile.def index a5064a3..2e6a643 100644 --- a/builtins/mapfile.def +++ b/builtins/mapfile.def @@ -2,7 +2,7 @@ This file is mapfile.def, from which is created mapfile.c. It implements the builtin "mapfile" in Bash. Copyright (C) 2005-2006 Rocky Bernstein for Free Software Foundation, Inc. -Copyright (C) 2008-2010 Free Software Foundation, Inc. +Copyright (C) 2008-2012 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -125,7 +125,7 @@ run_callback (callback, curindex, curline) #endif snprintf (execstr, execlen, "%s %d %s", callback, curindex, qline); free (qline); - return parse_and_execute (execstr, NULL, flags); + return evalstring (execstr, NULL, flags); } static void @@ -172,6 +172,8 @@ mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_n builtin_error (_("%s: not an indexed array"), array_name); return (EXECUTION_FAILURE); } + else if (invisible_p (entry)) + VUNSETATTR (entry, att_invisible); /* no longer invisible */ if (flags & MAPF_CLEARARRAY) array_flush (array_cell (entry)); @@ -193,7 +195,6 @@ mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_n line_length = 0; /* Reset the buffer for bash own stream */ - interrupt_immediately++; for (array_index = origin, line_count = 1; zgetline (fd, &line, &line_length, unbuffered_read) != -1; array_index++) @@ -212,6 +213,8 @@ mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_n zsyncfd (fd); } + /* XXX - bad things can happen if the callback modifies ENTRY, e.g., + unsetting it or changing it to a non-indexed-array type. */ bind_array_element (entry, array_index, line, 0); /* Have we exceeded # of lines to store? */ @@ -225,7 +228,6 @@ mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_n if (unbuffered_read == 0) zsyncfd (fd); - interrupt_immediately--; return EXECUTION_SUCCESS; } diff --git a/builtins/mkbuiltins.c b/builtins/mkbuiltins.c index cdfdfb1..15bb80f 100644 --- a/builtins/mkbuiltins.c +++ b/builtins/mkbuiltins.c @@ -1,7 +1,7 @@ /* mkbuiltins.c - Create builtins.c, builtext.h, and builtdoc.c from a single source file called builtins.def. */ -/* Copyright (C) 1987-2010 Free Software Foundation, Inc. +/* Copyright (C) 1987-2011 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -85,6 +85,10 @@ int only_documentation = 0; /* Non-zero means to not do any productions. */ int inhibit_production = 0; +/* Non-zero means to not add functions (xxx_builtin) to the members of the + produced `struct builtin []' */ +int inhibit_functions = 0; + /* Non-zero means to produce separate help files for each builtin, named by the builtin name, in `./helpfiles'. */ int separate_helpfiles = 0; @@ -198,7 +202,7 @@ void remove_trailing_whitespace (); /* For each file mentioned on the command line, process it and write the information to STRUCTFILE and EXTERNFILE, while - creating the production file if neccessary. */ + creating the production file if necessary. */ int main (argc, argv) int argc; @@ -222,6 +226,8 @@ main (argc, argv) struct_filename = argv[arg_index++]; else if (strcmp (arg, "-noproduction") == 0) inhibit_production = 1; + else if (strcmp (arg, "-nofunctions") == 0) + inhibit_functions = 1; else if (strcmp (arg, "-document") == 0) documentation_file = fopen (documentation_filename, "w"); else if (strcmp (arg, "-D") == 0) @@ -322,10 +328,13 @@ main (argc, argv) fclose (externfile); } +#if 0 + /* This is now done by a different program */ if (separate_helpfiles) { write_helpfiles (saved_builtins); } +#endif if (documentation_file) { @@ -390,7 +399,7 @@ copy_string_array (array) return (copy); } -/* Add ELEMENT to ARRAY, growing the array if neccessary. */ +/* Add ELEMENT to ARRAY, growing the array if necessary. */ void array_add (element, array) char *element; @@ -519,6 +528,7 @@ extract_info (filename, structfile, externfile) if (nr == 0) { fprintf (stderr, "mkbuiltins: %s: skipping zero-length file\n", filename); + free (buffer); return; } @@ -537,7 +547,7 @@ extract_info (filename, structfile, externfile) { array_add (&buffer[i], defs->lines); - while (buffer[i] != '\n' && i < file_size) + while (i < file_size && buffer[i] != '\n') i++; buffer[i++] = '\0'; } @@ -1092,7 +1102,7 @@ char *structfile_header[] = { "/* This file is manufactured by ./mkbuiltins, and should not be", " edited by hand. See the source to mkbuiltins for details. */", "", - "/* Copyright (C) 1987-2009 Free Software Foundation, Inc.", + "/* Copyright (C) 1987-2012 Free Software Foundation, Inc.", "", " This file is part of GNU Bash, the Bourne Again SHell.", "", @@ -1138,7 +1148,7 @@ char *structfile_footer[] = { (char *)NULL }; -/* Write out any neccessary opening information for +/* Write out any necessary opening information for STRUCTFILE and EXTERNFILE. */ void write_file_headers (structfile, externfile) @@ -1224,7 +1234,7 @@ write_builtins (defs, structfile, externfile) { fprintf (structfile, " { \"%s\", ", builtin->name); - if (builtin->function) + if (builtin->function && inhibit_functions == 0) fprintf (structfile, "%s, ", builtin->function); else fprintf (structfile, "(sh_builtin_func_t *)0x0, "); @@ -1236,9 +1246,15 @@ write_builtins (defs, structfile, externfile) (builtin->flags & BUILTIN_FLAG_POSIX_BUILTIN) ? " | POSIX_BUILTIN" : "", document_name (builtin)); - fprintf - (structfile, " N_(\"%s\"), (char *)NULL },\n", - builtin->shortdoc ? builtin->shortdoc : builtin->name); + if (inhibit_functions) + fprintf + (structfile, " N_(\"%s\"), \"%s\" },\n", + builtin->shortdoc ? builtin->shortdoc : builtin->name, + document_name (builtin)); + else + fprintf + (structfile, " N_(\"%s\"), (char *)NULL },\n", + builtin->shortdoc ? builtin->shortdoc : builtin->name); } @@ -1247,7 +1263,7 @@ write_builtins (defs, structfile, externfile) long documentation strings. */ save_builtin (builtin); - /* Write out the matching #endif, if neccessary. */ + /* Write out the matching #endif, if necessary. */ if (builtin->dependencies) { if (externfile) @@ -1308,6 +1324,26 @@ write_longdocs (stream, builtins) } } +void +write_dummy_declarations (stream, builtins) + FILE *stream; + ARRAY *builtins; +{ + register int i; + BUILTIN_DESC *builtin; + + for (i = 0; structfile_header[i]; i++) + fprintf (stream, "%s\n", structfile_header[i]); + + for (i = 0; i < builtins->sindex; i++) + { + builtin = (BUILTIN_DESC *)builtins->array[i]; + + /* How to guarantee that no builtin is written more than once? */ + fprintf (stream, "int %s () { return (0); }\n", builtin->function); + } +} + /* Write an #ifdef string saying what needs to be defined (or not defined) in order to allow compilation of the code that will follow. STREAM is the stream to write the information to, @@ -1407,7 +1443,7 @@ write_documentation (stream, documentation, indentation, flags) base_indent = (string_array && single_longdoc_strings && filename_p == 0) ? BASE_INDENT : 0; - for (i = 0, texinfo = (flags & TEXINFO); line = documentation[i]; i++) + for (i = 0, texinfo = (flags & TEXINFO); documentation && (line = documentation[i]); i++) { /* Allow #ifdef's to be written out verbatim, but don't put them into separate help files. */ diff --git a/builtins/printf.def b/builtins/printf.def index 71a7c00..7f29126 100644 --- a/builtins/printf.def +++ b/builtins/printf.def @@ -35,14 +35,19 @@ sequences, which are converted and copied to the standard output; and format specifications, each of which causes printing of the next successive argument. -In addition to the standard format specifications described in printf(1) -and printf(3), printf interprets: +In addition to the standard format specifications described in printf(1), +printf interprets: %b expand backslash escape sequences in the corresponding argument %q quote the argument in a way that can be reused as shell input %(fmt)T output the date-time string resulting from using FMT as a format string for strftime(3) +The format is re-used as necessary to consume all of the arguments. If +there are fewer arguments than the format requires, extra format +specifications behave as if a zero value or null string, as appropriate, +had been supplied. + Exit Status: Returns success unless an invalid option is given or a write or assignment error occurs. @@ -158,7 +163,8 @@ extern int errno; else if (vbuf) \ vbuf[0] = 0; \ terminate_immediately--; \ - fflush (stdout); \ + if (ferror (stdout) == 0) \ + fflush (stdout); \ if (ferror (stdout)) \ { \ sh_wrerror (); \ @@ -460,7 +466,8 @@ printf_builtin (list) timefmt[2] = '\0'; } /* argument is seconds since the epoch with special -1 and -2 */ - arg = getintmax (); + /* default argument is equivalent to -1; special case */ + arg = garglist ? getintmax () : -1; if (arg == -1) secs = NOW; /* roughly date +%s */ else if (arg == -2) @@ -471,7 +478,12 @@ printf_builtin (list) sv_tz ("TZ"); /* XXX -- just make sure */ #endif tm = localtime (&secs); - n = strftime (timebuf, sizeof (timebuf), timefmt, tm); + if (tm == 0) + { + secs = 0; + tm = localtime (&secs); + } + n = tm ? strftime (timebuf, sizeof (timebuf), timefmt, tm) : 0; free (timefmt); if (n == 0) timebuf[0] = '\0'; @@ -483,8 +495,11 @@ printf_builtin (list) n = printstr (start, timebuf, strlen (timebuf), fieldwidth, precision); /* XXX - %s for now */ if (n < 0) { - sh_wrerror (); - clearerr (stdout); + if (ferror (stdout) == 0) + { + sh_wrerror (); + clearerr (stdout); + } PRETURN (EXECUTION_FAILURE); } break; @@ -524,8 +539,11 @@ printf_builtin (list) r = printstr (start, xp, rlen, fieldwidth, precision); if (r < 0) { - sh_wrerror (); - clearerr (stdout); + if (ferror (stdout) == 0) + { + sh_wrerror (); + clearerr (stdout); + } retval = EXECUTION_FAILURE; } free (xp); @@ -548,7 +566,7 @@ printf_builtin (list) else if (ansic_shouldquote (p)) xp = ansic_quote (p, 0, (int *)0); else - xp = sh_backslash_quote (p); + xp = sh_backslash_quote (p, 0, 1); if (xp) { /* Use printstr to get fieldwidth and precision right. */ @@ -647,8 +665,7 @@ printf_builtin (list) if (ferror (stdout)) { - sh_wrerror (); - clearerr (stdout); + /* PRETURN will print error message. */ PRETURN (EXECUTION_FAILURE); } } @@ -681,12 +698,9 @@ printstr (fmt, string, len, fieldwidth, precision) #endif int padlen, nc, ljust, i; int fw, pr; /* fieldwidth and precision */ + intmax_t mfw, mpr; -#if 0 - if (string == 0 || *string == '\0') -#else if (string == 0 || len == 0) -#endif return 0; #if 0 @@ -697,6 +711,8 @@ printstr (fmt, string, len, fieldwidth, precision) ljust = fw = 0; pr = -1; + mfw = 0; + mpr = -1; /* skip flags */ while (strchr (SKIP1, *fmt)) @@ -706,7 +722,7 @@ printstr (fmt, string, len, fieldwidth, precision) fmt++; } - /* get fieldwidth, if present */ + /* get fieldwidth, if present. rely on caller to clamp fieldwidth at INT_MAX */ if (*fmt == '*') { fmt++; @@ -719,9 +735,11 @@ printstr (fmt, string, len, fieldwidth, precision) } else if (DIGIT (*fmt)) { - fw = *fmt++ - '0'; + mfw = *fmt++ - '0'; while (DIGIT (*fmt)) - fw = (fw * 10) + (*fmt++ - '0'); + mfw = (mfw * 10) + (*fmt++ - '0'); + /* Error if fieldwidth > INT_MAX here? */ + fw = (mfw < 0 || mfw > INT_MAX) ? INT_MAX : mfw; } /* get precision, if present */ @@ -735,9 +753,11 @@ printstr (fmt, string, len, fieldwidth, precision) } else if (DIGIT (*fmt)) { - pr = *fmt++ - '0'; + mpr = *fmt++ - '0'; while (DIGIT (*fmt)) - pr = (pr * 10) + (*fmt++ - '0'); + mpr = (mpr * 10) + (*fmt++ - '0'); + /* Error if precision > INT_MAX here? */ + pr = (mpr < 0 || mpr > INT_MAX) ? INT_MAX : mpr; } } @@ -745,7 +765,7 @@ printstr (fmt, string, len, fieldwidth, precision) /* If we remove this, get rid of `s'. */ if (*fmt != 'b' && *fmt != 'q') { - internal_error ("format parsing problem: %s", s); + internal_error (_("format parsing problem: %s"), s); fw = pr = 0; } #endif @@ -861,7 +881,7 @@ tescape (estart, cp, lenp, sawc) *cp = '\\'; return 0; } - if (uvalue <= UCHAR_MAX) + if (uvalue <= 0x7f) /* <= 0x7f translates directly */ *cp = uvalue; else { @@ -1089,6 +1109,9 @@ getint () ret = getintmax (); + if (garglist == 0) + return ret; + if (ret > INT_MAX) { printf_erange (garglist->word->word); @@ -1229,12 +1252,19 @@ bind_printf_variable (name, value, flags) char *value; int flags; { + SHELL_VAR *v; + #if defined (ARRAY_VARS) if (valid_array_reference (name) == 0) - return (bind_variable (name, value, flags)); + v = bind_variable (name, value, flags); else - return (assign_array_element (name, value, flags)); + v = assign_array_element (name, value, flags); #else /* !ARRAY_VARS */ - return bind_variable (name, value, flags); + v = bind_variable (name, value, flags); #endif /* !ARRAY_VARS */ + + if (v && readonly_p (v) == 0 && noassign_p (v) == 0) + VUNSETATTR (v, att_invisible); + + return v; } diff --git a/builtins/psize.sh b/builtins/psize.sh index c4d73e1..29bc115 100644 --- a/builtins/psize.sh +++ b/builtins/psize.sh @@ -27,7 +27,7 @@ echo "" # # Try to avoid tempfile races. We can't really check for the file's -# existance before we run psize.aux, because `test -e' is not portable, +# existence before we run psize.aux, because `test -e' is not portable, # `test -h' (test for symlinks) is not portable, and `test -f' only # checks for regular files. If we used mktemp(1), we're ahead of the # game. diff --git a/builtins/pushd.def b/builtins/pushd.def index 05b7529..9c6548f 100644 --- a/builtins/pushd.def +++ b/builtins/pushd.def @@ -1,7 +1,7 @@ This file is pushd.def, from which is created pushd.c. It implements the builtins "pushd", "popd", and "dirs" in Bash. -Copyright (C) 1987-2009 Free Software Foundation, Inc. +Copyright (C) 1987-2013 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -115,7 +115,7 @@ $END #if defined (PUSHD_AND_POPD) #include <stdio.h> -#ifndef _MINIX +#if defined (HAVE_SYS_PARAM_H) # include <sys/param.h> #endif @@ -228,7 +228,7 @@ pushd_builtin (list) { sh_invalidnum (list->word->word); builtin_usage (); - return (EXECUTION_FAILURE); + return (EX_USAGE); } if (direction == '-') @@ -245,7 +245,7 @@ pushd_builtin (list) { sh_invalidopt (list->word->word); builtin_usage (); - return (EXECUTION_FAILURE); + return (EX_USAGE); } else break; @@ -339,7 +339,7 @@ popd_builtin (list) { sh_invalidnum (list->word->word); builtin_usage (); - return (EXECUTION_FAILURE); + return (EX_USAGE); } which_word = list->word->word; } @@ -347,7 +347,13 @@ popd_builtin (list) { sh_invalidopt (list->word->word); builtin_usage (); - return (EXECUTION_FAILURE); + return (EX_USAGE); + } + else if (*list->word->word) + { + builtin_error (_("%s: invalid argument"), list->word->word); + builtin_usage (); + return (EX_USAGE); } else break; @@ -426,7 +432,7 @@ dirs_builtin (list) { sh_invalidnum (list->word->word); builtin_usage (); - return (EXECUTION_FAILURE); + return (EX_USAGE); } sign = (*list->word->word == '+') ? 1 : -1; desired_index = get_dirstack_index (i, sign, &index_flag); @@ -435,7 +441,7 @@ dirs_builtin (list) { sh_invalidopt (list->word->word); builtin_usage (); - return (EXECUTION_FAILURE); + return (EX_USAGE); } } diff --git a/builtins/read.def b/builtins/read.def index d407857..56945b9 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -1,7 +1,7 @@ This file is read.def, from which is created read.c. It implements the builtin "read" in Bash. -Copyright (C) 1987-2010 Free Software Foundation, Inc. +Copyright (C) 1987-2012 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -51,15 +51,17 @@ Options: -r do not allow backslashes to escape any characters -s do not echo input coming from a terminal -t timeout time out and return failure if a complete line of input is - not read withint TIMEOUT seconds. The value of the TMOUT + not read within TIMEOUT seconds. The value of the TMOUT variable is the default timeout. TIMEOUT may be a - fractional number. If TIMEOUT is 0, read returns success only - if input is available on the specified file descriptor. The + fractional number. If TIMEOUT is 0, read returns immediately, + without trying to read any data, returning success only if + input is available on the specified file descriptor. The exit status is greater than 128 if the timeout is exceeded -u fd read from file descriptor FD instead of the standard input Exit Status: -The return code is zero, unless end-of-file is encountered, read times out, +The return code is zero, unless end-of-file is encountered, read times out +(in which case it's greater than 128), a variable assignment error occurs, or an invalid file descriptor is supplied as the argument to -u. $END @@ -101,10 +103,17 @@ $END # include "input.h" #endif +#include "shmbutil.h" + #if !defined(errno) extern int errno; #endif +extern void run_pending_traps __P((void)); + +extern int posixly_correct; +extern int trapped_signal_received; + struct ttsave { int fd; @@ -127,15 +136,26 @@ static void ttyrestore __P((struct ttsave *)); static sighandler sigalrm __P((int)); static void reset_alarm __P((void)); -static procenv_t alrmbuf; +/* Try this to see what the rest of the shell can do with the information. */ +procenv_t alrmbuf; +int sigalrm_seen; + +static int reading; static SigHandler *old_alrm; static unsigned char delim; +/* In all cases, SIGALRM just sets a flag that we check periodically. This + avoids problems with the semi-tricky stuff we do with the xfree of + input_string at the top of the unwind-protect list (see below). */ + +/* Set a flag that CHECK_ALRM can check. This relies on zread calling + trap.c:check_signals_and_traps(), which knows about sigalrm_seen and + alrmbuf. */ static sighandler sigalrm (s) int s; { - longjmp (alrmbuf, 1); + sigalrm_seen = 1; } static void @@ -158,7 +178,7 @@ read_builtin (list) register char *varname; int size, i, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2; int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc, skip_ctlnul; - int raw, edit, nchars, silent, have_timeout, ignore_delim, fd; + int raw, edit, nchars, silent, have_timeout, ignore_delim, fd, lastsig, t_errno; unsigned int tmsec, tmusec; long ival, uval; intmax_t intval; @@ -199,6 +219,9 @@ read_builtin (list) #endif USE_VAR(list); USE_VAR(ps2); + USE_VAR(lastsig); + + sigalrm_seen = reading = 0; i = 0; /* Index into the string that we are reading. */ raw = edit = 0; /* Not reading raw input by default. */ @@ -306,6 +329,18 @@ read_builtin (list) return (input_avail (fd) ? EXECUTION_SUCCESS : EXECUTION_FAILURE); #endif + /* Convenience: check early whether or not the first of possibly several + variable names is a valid identifier, and bail early if so. */ +#if defined (ARRAY_VARS) + if (list && legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word) == 0) +#else + if (list && legal_identifier (list->word->word) == 0) +#endif + { + sh_invalidid (list->word->word); + return (EXECUTION_FAILURE); + } + /* If we're asked to ignore the delimiter, make sure we do. */ if (ignore_delim) delim = -1; @@ -380,14 +415,15 @@ read_builtin (list) if (tmsec > 0 || tmusec > 0) { - code = setjmp (alrmbuf); + code = setjmp_nosigs (alrmbuf); if (code) { + sigalrm_seen = 0; /* Tricky. The top of the unwind-protect stack is the free of input_string. We want to run all the rest and use input_string, so we have to save input_string temporarily, run the unwind- - protects, then restore input_string so we can use it later. */ - + protects, then restore input_string so we can use it later */ + orig_input_string = 0; input_string[i] = '\0'; /* make sure it's terminated */ if (i == 0) { @@ -464,10 +500,12 @@ read_builtin (list) /* This *must* be the top unwind-protect on the stack, so the manipulation of the unwind-protect stack after the realloc() works right. */ add_unwind_protect (xfree, input_string); - interrupt_immediately++; - terminate_immediately++; - unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe; + CHECK_ALRM; + if ((nchars > 0) && (input_is_tty == 0) && ignore_delim) /* read -N */ + unbuffered_read = 2; + else if ((nchars > 0) || (delim != '\n') || input_is_pipe) + unbuffered_read = 1; if (prompt && edit == 0) { @@ -482,6 +520,8 @@ read_builtin (list) ps2 = 0; for (print_ps2 = eof = retval = 0;;) { + CHECK_ALRM; + #if defined (READLINE) if (edit) { @@ -492,7 +532,9 @@ read_builtin (list) } if (rlbuf == 0) { + reading = 1; rlbuf = edit_line (prompt ? prompt : "", itext); + reading = 0; rlind = 0; } if (rlbuf == 0) @@ -515,26 +557,58 @@ read_builtin (list) print_ps2 = 0; } - if (unbuffered_read) - retval = zread (fd, &c, 1); +#if 0 + if (posixly_correct == 0) + interrupt_immediately++; +#endif + reading = 1; + if (unbuffered_read == 2) + retval = posixly_correct ? zreadintr (fd, &c, 1) : zreadn (fd, &c, nchars - nr); + else if (unbuffered_read) + retval = posixly_correct ? zreadintr (fd, &c, 1) : zread (fd, &c, 1); else - retval = zreadc (fd, &c); + retval = posixly_correct ? zreadcintr (fd, &c) : zreadc (fd, &c); + reading = 0; +#if 0 + if (posixly_correct == 0) + interrupt_immediately--; +#endif if (retval <= 0) { + if (retval < 0 && errno == EINTR) + { + lastsig = LASTSIG(); + if (lastsig == 0) + lastsig = trapped_signal_received; + run_pending_traps (); /* because interrupt_immediately is not set */ + } + else + lastsig = 0; + CHECK_TERMSIG; eof = 1; break; } + CHECK_ALRM; + #if defined (READLINE) } #endif + CHECK_ALRM; if (i + 4 >= size) /* XXX was i + 2; use i + 4 for multibyte/read_mbchar */ { - input_string = (char *)xrealloc (input_string, size += 128); - remove_unwind_protect (); - add_unwind_protect (xfree, input_string); + char *t; + t = (char *)xrealloc (input_string, size += 128); + + /* Only need to change unwind-protect if input_string changes */ + if (t != input_string) + { + input_string = t; + remove_unwind_protect (); + add_unwind_protect (xfree, input_string); + } } /* If the next character is to be accepted verbatim, a backslash @@ -565,9 +639,12 @@ read_builtin (list) continue; } - if ((unsigned char)c == delim) + if (ignore_delim == 0 && (unsigned char)c == delim) break; + if (c == '\0' && delim != '\0') + continue; /* skip NUL bytes in input */ + if ((skip_ctlesc == 0 && c == CTLESC) || (skip_ctlnul == 0 && c == CTLNUL)) { saw_escape++; @@ -576,9 +653,10 @@ read_builtin (list) add_char: input_string[i++] = c; + CHECK_ALRM; #if defined (HANDLE_MULTIBYTE) - if (nchars > 0 && MB_CUR_MAX > 1) + if (nchars > 0 && MB_CUR_MAX > 1 && is_basic (c) == 0) { input_string[i] = '\0'; /* for simplicity and debugging */ i += read_mbchar (fd, input_string, i, c, unbuffered_read); @@ -591,15 +669,16 @@ add_char: break; } input_string[i] = '\0'; + CHECK_ALRM; -#if 1 if (retval < 0) { - builtin_error (_("read error: %d: %s"), fd, strerror (errno)); + t_errno = errno; + if (errno != EINTR) + builtin_error (_("read error: %d: %s"), fd, strerror (errno)); run_unwind_frame ("read_builtin"); - return (EXECUTION_FAILURE); + return ((t_errno != EINTR) ? EXECUTION_FAILURE : 128+lastsig); } -#endif if (tmsec > 0 || tmusec > 0) reset_alarm (); @@ -631,9 +710,6 @@ add_char: assign_vars: - interrupt_immediately--; - terminate_immediately--; - #if defined (ARRAY_VARS) /* If -a was given, take the string read, break it into a list of words, an assign them to `arrayname' in turn. */ @@ -658,6 +734,8 @@ assign_vars: xfree (input_string); return EXECUTION_FAILURE; /* existing associative array */ } + else if (invisible_p (var)) + VUNSETATTR (var, att_invisible); array_flush (array_cell (var)); alist = list_string (input_string, ifs_chars, 0); @@ -703,7 +781,7 @@ assign_vars: var = bind_variable ("REPLY", input_string, 0); VUNSETATTR (var, att_invisible); - free (input_string); + xfree (input_string); return (retval); } @@ -829,6 +907,7 @@ bind_read_variable (name, value) char *name, *value; { SHELL_VAR *v; + #if defined (ARRAY_VARS) if (valid_array_reference (name) == 0) v = bind_variable (name, value, 0); @@ -867,6 +946,7 @@ read_mbchar (fd, string, ind, ch, unbuffered) if (ret == (size_t)-2) { ps = ps_back; + /* We don't want to be interrupted during a multibyte char read */ if (unbuffered) r = zread (fd, &c, 1); else @@ -947,7 +1027,9 @@ edit_line (p, itext) rl_startup_hook = set_itext; deftext = itext; } + ret = readline (p); + rl_attempted_completion_function = old_attempted_completion_function; old_attempted_completion_function = (rl_completion_func_t *)NULL; diff --git a/builtins/return.def b/builtins/return.def index 641ee16..e6674df 100644 --- a/builtins/return.def +++ b/builtins/return.def @@ -60,9 +60,11 @@ int return_builtin (list) WORD_LIST *list; { +#if 0 if (no_options (list)) return (EX_USAGE); list = loptend; /* skip over possible `--' */ +#endif return_catch_value = get_exitstat (list); diff --git a/builtins/set.def b/builtins/set.def index 6e69eb6..c4a7001 100644 --- a/builtins/set.def +++ b/builtins/set.def @@ -1,7 +1,7 @@ This file is set.def, from which is created set.c. It implements the "set" and "unset" builtins in Bash. -Copyright (C) 1987-2009 Free Software Foundation, Inc. +Copyright (C) 1987-2012 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -96,12 +96,16 @@ Options: interactive-comments allow comments to appear in interactive commands keyword same as -k +#if defined (JOB_CONTROL) monitor same as -m +#endif noclobber same as -C noexec same as -n noglob same as -f nolog currently accepted but ignored +#if defined (JOB_CONTROL) notify same as -b +#endif nounset same as -u onecmd same as -t physical same as -P @@ -135,7 +139,7 @@ Options: -H Enable ! style history substitution. This flag is on by default when the shell is interactive. #endif /* BANG_HISTORY */ - -P If set, do not follow symbolic links when executing commands + -P If set, do not resolve symbolic links when executing commands such as cd which change the current directory. -T If set, the DEBUG trap is inherited by shell functions. -- Assign any remaining arguments to the positional parameters. @@ -205,7 +209,9 @@ const struct { { "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL }, { "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "keyword", 'k', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, +#if defined (JOB_CONTROL) { "monitor", 'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, +#endif { "noclobber", 'C', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "noexec", 'n', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "noglob", 'f', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, @@ -718,7 +724,7 @@ set_builtin (list) $BUILTIN unset $FUNCTION unset_builtin -$SHORT_DOC unset [-f] [-v] [name ...] +$SHORT_DOC unset [-f] [-v] [-n] [name ...] Unset values and attributes of shell variables and functions. For each NAME, remove the corresponding variable or function. @@ -726,6 +732,8 @@ For each NAME, remove the corresponding variable or function. Options: -f treat each NAME as a shell function -v treat each NAME as a shell variable + -n treat each NAME as a name reference and unset the variable itself + rather than the variable it references Without options, unset first tries to unset a variable, and if that fails, tries to unset a function. @@ -742,13 +750,13 @@ int unset_builtin (list) WORD_LIST *list; { - int unset_function, unset_variable, unset_array, opt, any_failed; + int unset_function, unset_variable, unset_array, opt, nameref, any_failed; char *name; - unset_function = unset_variable = unset_array = any_failed = 0; + unset_function = unset_variable = unset_array = nameref = any_failed = 0; reset_internal_getopt (); - while ((opt = internal_getopt (list, "fv")) != -1) + while ((opt = internal_getopt (list, "fnv")) != -1) { switch (opt) { @@ -758,6 +766,9 @@ unset_builtin (list) case 'v': unset_variable = 1; break; + case 'n': + nameref = 1; + break; default: builtin_usage (); return (EX_USAGE); @@ -771,6 +782,8 @@ unset_builtin (list) builtin_error (_("cannot simultaneously unset a function and a variable")); return (EXECUTION_FAILURE); } + else if (unset_function && nameref) + nameref = 0; while (list) { @@ -791,6 +804,8 @@ unset_builtin (list) unset_array++; } #endif + /* Get error checking out of the way first. The low-level functions + just perform the unset, relying on the caller to verify. */ /* Bash allows functions with names which are not valid identifiers to be created when not in posix mode, so check only when in posix @@ -801,19 +816,32 @@ unset_builtin (list) NEXT_VARIABLE (); } - var = unset_function ? find_function (name) : find_variable (name); + /* Only search for functions here if -f supplied. */ + var = unset_function ? find_function (name) + : (nameref ? find_variable_last_nameref (name) : find_variable (name)); - if (var && !unset_function && non_unsettable_p (var)) + /* Some variables (but not functions yet) cannot be unset, period. */ + if (var && unset_function == 0 && non_unsettable_p (var)) { builtin_error (_("%s: cannot unset"), name); NEXT_VARIABLE (); } + /* Posix.2 says try variables first, then functions. If we would + find a function after unsuccessfully searching for a variable, + note that we're acting on a function now as if -f were + supplied. The readonly check below takes care of it. */ + if (var == 0 && unset_variable == 0 && unset_function == 0) + { + if (var = find_function (name)) + unset_function = 1; + } + /* Posix.2 says that unsetting readonly variables is an error. */ if (var && readonly_p (var)) { builtin_error (_("%s: cannot unset: readonly %s"), - name, unset_function ? "function" : "variable"); + var->name, unset_function ? "function" : "variable"); NEXT_VARIABLE (); } @@ -823,7 +851,7 @@ unset_builtin (list) { if (array_p (var) == 0 && assoc_p (var) == 0) { - builtin_error (_("%s: not an array variable"), name); + builtin_error (_("%s: not an array variable"), var->name); NEXT_VARIABLE (); } else @@ -835,13 +863,13 @@ unset_builtin (list) } else #endif /* ARRAY_VARS */ - tem = unset_function ? unbind_func (name) : unbind_variable (name); + tem = unset_function ? unbind_func (name) : (nameref ? unbind_nameref (name) : unbind_variable (name)); - /* This is what Posix.2 draft 11+ says. ``If neither -f nor -v + /* This is what Posix.2 says: ``If neither -f nor -v is specified, the name refers to a variable; if a variable by that name does not exist, a function by that name, if any, shall be unset.'' */ - if (tem == -1 && !unset_function && !unset_variable) + if (tem == -1 && unset_function == 0 && unset_variable == 0) tem = unbind_func (name); /* SUSv3, POSIX.1-2001 say: ``Unsetting a variable or function that diff --git a/builtins/setattr.def b/builtins/setattr.def index b3ca317..3be3189 100644 --- a/builtins/setattr.def +++ b/builtins/setattr.def @@ -1,7 +1,7 @@ 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. +Copyright (C) 1987-2012 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -93,7 +93,8 @@ 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 + -p display a list of all readonly variables or functions, depending on + whether or not the -f option is given An argument of `--' disables further option processing. @@ -368,6 +369,9 @@ show_var_attributes (var, pattr, nodefs) if (integer_p (var)) flags[i++] = 'i'; + if (nameref_p (var)) + flags[i++] = 'n'; + if (readonly_p (var)) flags[i++] = 'r'; @@ -451,7 +455,11 @@ show_name_attributes (name, nodefs) { SHELL_VAR *var; - var = find_variable_internal (name, 1); +#if 0 + var = find_variable_tempenv (name); +#else + var = find_variable_noref (name); +#endif if (var && invisible_p (var) == 0) { @@ -462,12 +470,30 @@ show_name_attributes (name, nodefs) return (1); } +int +show_func_attributes (name, nodefs) + char *name; + int nodefs; +{ + SHELL_VAR *var; + + var = find_function (name); + + if (var) + { + 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; + SHELL_VAR *var, *tv, *v; char *tvalue; if (undo) @@ -484,7 +510,18 @@ set_var_attribute (name, attribute, undo) var = bind_variable (tv->name, tvalue, 0); var->attributes |= tv->attributes & ~att_tempvar; - VSETATTR (tv, att_propagate); + /* This avoids an error message when propagating a read-only var + later on. */ + if (var->context == 0 && (attribute & att_readonly)) + { + /* Don't bother to set the `propagate to the global variables + table' flag if we've just bound the variable in that table */ + v = find_global_variable (tv->name); + if (v != var) + VSETATTR (tv, att_propagate); + } + else + VSETATTR (tv, att_propagate); if (var->context != 0) VSETATTR (var, att_propagate); SETVARATTR (tv, attribute, undo); /* XXX */ @@ -495,7 +532,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); diff --git a/builtins/shopt.def b/builtins/shopt.def index 6cd8c4f..6050a14 100644 --- a/builtins/shopt.def +++ b/builtins/shopt.def @@ -1,7 +1,7 @@ This file is shopt.def, from which is created shopt.c. It implements the Bash `shopt' builtin. -Copyright (C) 1994-2010 Free Software Foundation, Inc. +Copyright (C) 1994-2012 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -88,6 +88,7 @@ extern int gnu_error_format; extern int check_jobs_at_exit; extern int autocd; extern int glob_star; +extern int glob_asciirange; extern int lastpipe_opt; #if defined (EXTENDED_GLOB) @@ -99,6 +100,7 @@ extern int hist_verify, history_reediting, perform_hostname_completion; extern int no_empty_command_completion; extern int force_fignore; extern int dircomplete_spelling, dircomplete_expand; +extern int complete_fullquote; extern int enable_hostname_completion __P((int)); #endif @@ -134,6 +136,7 @@ static int shopt_compat31; static int shopt_compat32; static int shopt_compat40; static int shopt_compat41; +static int shopt_compat42; typedef int shopt_set_func_t __P((char *, int)); @@ -157,7 +160,9 @@ static struct { { "compat32", &shopt_compat32, set_compatibility_level }, { "compat40", &shopt_compat40, set_compatibility_level }, { "compat41", &shopt_compat41, set_compatibility_level }, + { "compat42", &shopt_compat41, set_compatibility_level }, #if defined (READLINE) + { "complete_fullquote", &complete_fullquote, (shopt_set_func_t *)NULL}, { "direxpand", &dircomplete_expand, shopt_set_complete_direxpand }, { "dirspell", &dircomplete_spelling, (shopt_set_func_t *)NULL }, #endif @@ -176,6 +181,7 @@ static struct { { "force_fignore", &force_fignore, (shopt_set_func_t *)NULL }, #endif { "globstar", &glob_star, (shopt_set_func_t *)NULL }, + { "globasciiranges", &glob_asciirange, (shopt_set_func_t *)NULL }, { "gnu_errfmt", &gnu_error_format, (shopt_set_func_t *)NULL }, #if defined (HISTORY) { "histappend", &force_append_history, (shopt_set_func_t *)NULL }, @@ -298,10 +304,12 @@ reset_shopt_options () allow_null_glob_expansion = glob_dot_filenames = 0; cdable_vars = mail_warning = 0; no_exit_on_failed_exec = print_shift_error = 0; - check_hashed_filenames = cdspelling = expand_aliases = check_window_size = 0; + check_hashed_filenames = cdspelling = expand_aliases = 0; source_uses_path = promptvars = 1; + check_window_size = CHECKWINSIZE_DEFAULT; + #if defined (EXTENDED_GLOB) extended_glob = 0; #endif @@ -521,16 +529,18 @@ set_compatibility_level (option_name, mode) char *option_name; int mode; { - /* Need to change logic here as we add more compatibility levels */ + int ind; - /* First, check option_name so we can turn off other compat options when - one is set. */ - if (mode && option_name[6] == '3' && option_name[7] == '1') - shopt_compat32 = shopt_compat40 = 0; - else if (mode && option_name[6] == '3' && option_name[7] == '2') - shopt_compat31 = shopt_compat40 = 0; - else if (mode && option_name[6] == '4' && option_name[7] == '0') - shopt_compat31 = shopt_compat32 = 0; + /* If we're setting something, redo some of the work we did above in + toggle_shopt(). Unset everything and reset the appropriate option + based on OPTION_NAME. */ + if (mode) + { + shopt_compat31 = shopt_compat32 = 0; + shopt_compat40 = shopt_compat41 = shopt_compat42 = 0; + ind = find_shopt (option_name); + *shopt_vars[ind].value = mode; + } /* Then set shell_compatibility_level based on what remains */ if (shopt_compat31) @@ -539,11 +549,39 @@ set_compatibility_level (option_name, mode) shell_compatibility_level = 32; else if (shopt_compat40) shell_compatibility_level = 40; + else if (shopt_compat41) + shell_compatibility_level = 41; + else if (shopt_compat42) + shell_compatibility_level = 42; else shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + return 0; } +/* Set and unset the various compatibility options from the value of + shell_compatibility_level; used by sv_shcompat */ +void +set_compatibility_opts () +{ + shopt_compat31 = shopt_compat32 = shopt_compat40 = shopt_compat41 = shopt_compat42 = 0; + switch (shell_compatibility_level) + { + case DEFAULT_COMPAT_LEVEL: + break; + case 42: + shopt_compat42 = 1; break; + case 41: + shopt_compat41 = 1; break; + case 40: + shopt_compat40 = 1; break; + case 32: + shopt_compat32 = 1; break; + case 31: + shopt_compat31 = 1; break; + } +} + #if defined (READLINE) static int shopt_set_complete_direxpand (option_name, mode) diff --git a/builtins/test.def b/builtins/test.def index 1ebc818..f144400 100644 --- a/builtins/test.def +++ b/builtins/test.def @@ -84,6 +84,7 @@ Other operators: -o OPTION True if the shell option OPTION is enabled. -v VAR True if the shell variable VAR is set + -R VAR True if the shell variable VAR is set and is a name reference. ! EXPR True if expr is false. EXPR1 -a EXPR2 True if both expr1 AND expr2 are true. EXPR1 -o EXPR2 True if either expr1 OR expr2 is true. diff --git a/builtins/type.def b/builtins/type.def index ee341bb..bd9ecfc 100644 --- a/builtins/type.def +++ b/builtins/type.def @@ -1,7 +1,7 @@ This file is type.def, from which is created type.c. It implements the builtin "type" in Bash. -Copyright (C) 1987-2009 Free Software Foundation, Inc. +Copyright (C) 1987-2011 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -353,7 +353,7 @@ describe_command (command, dflags) user_command_matches (command, FS_EXEC_ONLY, found_file); /* XXX - should that be FS_EXEC_PREFERRED? */ - if (!full_path) + if (full_path == 0) break; /* If we found the command as itself by looking through $PATH, it @@ -375,7 +375,9 @@ describe_command (command, dflags) else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY|CDESC_SHORTDESC)) { f = MP_DOCWD | ((dflags & CDESC_ABSPATH) ? MP_RMDOT : 0); - full_path = sh_makepath ((char *)NULL, full_path, f); + x = sh_makepath ((char *)NULL, full_path, f); + free (full_path); + full_path = x; } } /* If we require a full path and don't have one, make one */ diff --git a/builtins/ulimit.def b/builtins/ulimit.def index 03cbe8a..e551cff 100644 --- a/builtins/ulimit.def +++ b/builtins/ulimit.def @@ -23,7 +23,7 @@ $PRODUCES ulimit.c $BUILTIN ulimit $FUNCTION ulimit_builtin $DEPENDS_ON !_MINIX -$SHORT_DOC ulimit [-SHacdefilmnpqrstuvx] [limit] +$SHORT_DOC ulimit [-SHabcdefilmnpqrstuvxT] [limit] Modify shell resource limits. Provides control over the resources available to the shell and processes @@ -50,6 +50,9 @@ Options: -u the maximum number of user processes -v the size of virtual memory -x the maximum number of file locks + -T the maximum number of threads + +Not all options are available on all platforms. If LIMIT is given, it is the new value of the specified resource; the special LIMIT values `soft', `hard', and `unlimited' stand for the @@ -70,7 +73,7 @@ $END #include <config.h> #include "../bashtypes.h" -#ifndef _MINIX +#if defined (HAVE_SYS_PARAM_H) # include <sys/param.h> #endif @@ -167,6 +170,10 @@ extern int errno; # define RLIMIT_MAXUPROC 260 #endif +#if !defined (RLIMIT_PTHREAD) && defined (RLIMIT_NTHR) +# define RLIMIT_PTHREAD RLIMIT_NTHR +#endif + #if !defined (RLIM_INFINITY) # define RLIM_INFINITY 0x7fffffff #endif diff --git a/builtins/umask.def b/builtins/umask.def index 289a0f5..d9aa041 100644 --- a/builtins/umask.def +++ b/builtins/umask.def @@ -61,10 +61,6 @@ $END #include "common.h" #include "bashgetopt.h" -#ifdef __LCC__ -#define mode_t int -#endif - /* **************************************************************** */ /* */ /* UMASK Builtin and Helpers */ diff --git a/builtins/wait.def b/builtins/wait.def index 0206926..fe6d53d 100644 --- a/builtins/wait.def +++ b/builtins/wait.def @@ -1,7 +1,7 @@ This file is wait.def, from which is created wait.c. It implements the builtin "wait" in Bash. -Copyright (C) 1987-2009 Free Software Foundation, Inc. +Copyright (C) 1987-2013 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -22,33 +22,36 @@ $BUILTIN wait $FUNCTION wait_builtin $DEPENDS_ON JOB_CONTROL $PRODUCES wait.c -$SHORT_DOC wait [id] +$SHORT_DOC wait [-n] [id ...] Wait for job completion and return exit status. -Waits for the process identified by ID, which may be a process ID or a +Waits for each process identified by an ID, which may be a process ID or a job specification, and reports its termination status. If ID is not given, waits for all currently active child processes, and the return status is zero. If ID is a a job specification, waits for all processes -in the job's pipeline. +in that job's pipeline. + +If the -n option is supplied, waits for the next job to terminate and +returns its exit status. Exit Status: -Returns the status of ID; fails if ID is invalid or an invalid option is -given. +Returns the status of the last ID; fails if ID is invalid or an invalid +option is given. $END $BUILTIN wait $FUNCTION wait_builtin $DEPENDS_ON !JOB_CONTROL -$SHORT_DOC wait [pid] +$SHORT_DOC wait [pid ...] Wait for process completion and return exit status. -Waits for the specified process and reports its termination status. If -PID is not given, all currently active child processes are waited for, -and the return code is zero. PID must be a process ID. +Waits for each process specified by a PID and reports its termination status. +If PID is not given, waits for all currently active child processes, +and the return status is zero. PID must be a process ID. Exit Status: -Returns the status of ID; fails if ID is invalid or an invalid option is -given. +Returns the status of the last PID; fails if PID is invalid or an invalid +option is given. $END #include <config.h> @@ -82,6 +85,7 @@ procenv_t wait_intr_buf; do \ { \ interrupt_immediately = old_interrupt_immediately;\ + wait_signal_received = 0; \ return (s);\ } \ while (0) @@ -90,17 +94,33 @@ int wait_builtin (list) WORD_LIST *list; { - int status, code; + int status, code, opt, nflag; volatile int old_interrupt_immediately; USE_VAR(list); - if (no_options (list)) - return (EX_USAGE); + nflag = 0; + reset_internal_getopt (); + while ((opt = internal_getopt (list, "n")) != -1) + { + switch (opt) + { +#if defined (JOB_CONTROL) + case 'n': + nflag = 1; + break; +#endif + default: + builtin_usage (); + return (EX_USAGE); + } + } list = loptend; old_interrupt_immediately = interrupt_immediately; +#if 0 interrupt_immediately++; +#endif /* POSIX.2 says: When the shell is waiting (by means of the wait utility) for asynchronous commands to complete, the reception of a signal for @@ -120,6 +140,16 @@ wait_builtin (list) /* We support jobs or pids. wait <pid-or-job> [pid-or-job ...] */ +#if defined (JOB_CONTROL) + if (nflag) + { + status = wait_for_any_job (); + if (status < 0) + status = 127; + WAIT_RETURN (status); + } +#endif + /* But wait without any arguments means to wait for all of the shell's currently active background processes. */ if (list == 0) |