rc

[fork] interactive rc shell
Log | Files | Refs | README | LICENSE

commit a8699a58d8632f21e897ea5c4900a15483a9a8ca
parent d884971193ef4934424b77ae862e8b0ecf70bab3
Author: Toby Goodwin <toby@paccrat.org>
Date:   Tue,  2 Sep 2014 08:01:39 +0100

release: rc-1.7.2

Diffstat:
M.gitignore | 14++++++++++++++
MAUTHORS | 29+++++++++++++++--------------
MChangeLog | 24++++++++++++++++++++++++
MINSTALL | 528+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
MMakefile.am | 14++++++--------
MNEWS | 33++++++++++++++++++---------------
MREADME | 8++++----
ARELDATE | 1+
AReleaseTime | 7+++++++
Macinclude.m4 | 20++++++++++----------
Aaclocal.m4 | 1069+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abootstrap | 2++
Mbuiltins.c | 16++++++----------
Achldign | 0
Achldign.c | 9+++++++++
Mconfigure.ac | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Aconfigure.scan | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Aedit-bsd.c | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aedit-gnu.c | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aedit-null.c | 35+++++++++++++++++++++++++++++++++++
Aedit.h | 12++++++++++++
Mexcept.c | 1+
Mfn.c | 1+
Mfootobar.c | 5++++-
Mglob.c | 2+-
Mhash.c | 11-----------
Mheredoc.c | 6++++--
Minput.c | 328+++++++++++++++++++++++++++++++++++++------------------------------------------
Ainput.h | 35+++++++++++++++++++++++++++++++++++
Mlex.c | 40++++++++++++++++++++++++++++------------
Mmain.c | 32+++++++++++++++++++++++++++++---
Amkinstalldirs | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anonblock.c | 14++++++++++++++
Aparse.c | 1117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aparse.h | 37+++++++++++++++++++++++++++++++++++++
Arandom.pl | 15+++++++++++++++
Mrc.1 | 13++++++++++---
Mrc.h | 61+++++++------------------------------------------------------
Arc.spec | 31+++++++++++++++++++++++++++++++
Msignal.c | 19+++++++------------
Aslow | 11+++++++++++
Astamp-h | 1+
Astamp-h.in | 1+
Atestcld.c | 19+++++++++++++++++++
Atmp | 2++
Mtree.c | 3++-
Mtrip.rc | 141++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mutils.c | 8++++----
Mvar.c | 8++++----
Mwhich.c | 23++++++++++++++++++++---
50 files changed, 3677 insertions(+), 620 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,14 @@ +*~ +.deps/ +Makefile +autom4te.cache/ +config.h +config.log +config.status +configure +depcomp +missing +sigmsgs.c +sigmsgs.h +stamp-h1 +statval.h diff --git a/AUTHORS b/AUTHORS @@ -1,4 +1,4 @@ -The current maintainer of rc is Tim Goodwin <tjg@star.le.ac.uk>. Please +The current maintainer of rc is Toby Goodwin <toby@paccrat.org>. Please send all bug reports to him. This shell was written by me, Byron Rakitzis, but kudos go to Paul Haahr @@ -7,8 +7,8 @@ bits and pieces to rc (notably the limits code, print.c, most of which.c and the backquote redirection code), and to Hugh Redelmeier for running rc through his fussy ANSI compiler and thereby provoking interesting discussions about portability, and also for providing many valuable -suggestions for improving rc's code in general. Finally, many thanks -go to David Sanderson, for reworking the man page to format well with +suggestions for improving rc's code in general. Finally, many thanks go +to David Sanderson, for reworking the man page to format well with troff, and for providing many suggestions both for rc and its man page. Thanks to Boyd Roberts for the original history.c, and to Hugh again for @@ -16,22 +16,23 @@ re-working parts of that code. Of course, without Tom Duff's design of the original rc, I could not have written this shell (though I probably would have written *a* -shell). Almost all of the features, with minor exceptions, have been -implemented as described in the Unix v10 manuals. Hats off to td for +shell). Almost all of the features, with minor exceptions, have been +implemented as described in the Unix v10 manuals. Hats off to td for designing a C-like, minimal but very useful shell. Tom Duff has kindly given permission for the paper he wrote for UKUUG to be distributed with this version of rc (called "plan9.ps" in the same -FTP or HTTP directory as the shell). Please read this paper bearing in +FTP or HTTP directory as the shell). Please read this paper bearing in mind that it describes a program that was written at AT&T and that the version of rc presented here differs in some respects. -Tim would like to thank these people for their contributions since he -took over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt +Toby would like to thank these people for their contributions since he +took over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt Kleberg, Brynjulv Hauksson, Byron Rakitzis, Callum Gibson, Chris -Siebenmann, Dale Scheetz, Dan Moniz, David Luyer, David Swasey, -Decklin Foster, Donn Cave, Erik Quanstrom, Gary Carvell, Gerry -Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jeremy Fitzhardinge, Marc -Moorcroft, Mark H Wilkinson, Mark K Gardner, Raymond Venneker, Rich -$alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, Steve Simon, Thomas -Nordin, Tom Culliton, Tom Tromey, Vincent Broman, Wolfgang Zekoll. +Siebenmann, Christian Neukirchen, Dale Scheetz, Dan Moniz, David Luyer, +David Swasey, Decklin Foster, Donn Cave, Erik Quanstrom, Gary Carvell, +Gerry Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jakub Wilk, Jeremy +Fitzhardinge, Marc Moorcroft, Mark H Wilkinson, Mark K Gardner, Raymond +Venneker, Rich $alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, Steve +Simon, Thomas Nordin, Tom Culliton, Tom Tromey, Vincent Broman, Wolfgang +Zekoll. diff --git a/ChangeLog b/ChangeLog @@ -830,3 +830,27 @@ Changes since rc-1.5b2 2003-07-22 Release: rc-1.7.1. + +2003-09-24 + + Tidiness: minor improvements to input.c. + +2014-02-26 + + Bug: fix for CVE-2014-1936 from Jakub Wilk. + +2014-06-29 + + Documentation: update email and web addresses. + +2014-08-31 + + Feature: support quoting for filename completion in GNU readline. + +2014-09-01 + + Bug: quoting of glob characters was broken (thanks Christian + Neukirchen); fix the "sneaky parens" bug properly (thanks Wolfgang + Zekoll). + + Feature: allow $"x as a synonym for $^x diff --git a/INSTALL b/INSTALL @@ -1,182 +1,370 @@ -COMPILING +Installation Instructions +************************* + +Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, +Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `<wchar.h>' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ -rc uses GNU autoconf and automake. The following commands are all you -need to configure, build, test, and install rc. + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. - $ sh configure - $ make - $ make trip - # make install +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: -This will build rc in the source directory (see below for details on how -to build rc in a different directory). + ./configure CC=/usr/local2/bin/gcc +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). -BUILD AND CONFIGURATION OPTIONS +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf limitation. Until the limitation is lifted, you can use +this workaround: -There are lots of options you can give to configure to modify rc's -behaviour. You can also select a command line history library to link -against---see the rc web page for details of where to find these -libraries. For a summary of all options, run `sh configure --help'. + CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash -You can specify Makefile variables by setting the corresponding -environment variables. For example, you might want to set `CC=cc', to -prevent configure looking for gcc, or set an initial value for -`LDFLAGS', as in the example below. It is a good idea to specify -static linking (unless you are linking against a dynamic readline -library)---if you are using gcc, you can do this by setting -`CFLAGS=-static'. +`configure' Invocation +====================== -Here are the configure options you may want to use, in approximately -descending order of usefulness. + `configure' recognizes the following options to control how it +operates. - --with-editline +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. - This option tells rc to use the editline package (see the web page - for details) to provide EMACS style command line editing and - history. If the editline library is not installed in a standard - place, you can tell configure where to find it by setting the - environment variable LDFLAGS. For example, you might copy libedit.a - into the rc source directory and then run this configure command. +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. - LDFLAGS=-L. sh configure --with-editline +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. - --with-vrl - - This option tells rc to use the vrl package (see the web page for - details) to provide EMACS style command line editing and history. As - for `--with-editline', you may need to set the environment variable - LDFLAGS appropriately. - - --with-readline - - This option tells rc to use the GNU readline package, which is similar - to editline or vrl, but has many more features. The readline package - is over 6 times the size of editline (whether you count lines of code, - or the library itself). As for editline, you can set the environment - variable LDFLAGS if your readline library is not installed in a - standard place. - - LDFLAGS=-L/usr/gnu/lib sh configure --with-readline - - --with-history - - Use this option if you want to build and install the programs that - support a crude command-line history mechanism. - -You can't use more than one of `--with-editline', `--with-vrl', and -`--with-readline' at the same time. If you have any of these you -probably don't want to bother with `--with-history'. - - --prefix=/path - - By default, `prefix' is /usr/local, which means that `make install' - installs rc (and possibly the history programs) in /usr/local/bin, and - man pages in /usr/local/man/man1. Use this option to change where - `make install' puts things. - - --disable-builtin-echo - - By default, the `echo' command is builtin to rc for reasons of - efficiency and portability (of rc scripts). It is the only builtin - which is not essential, and purists may wish to omit it. Note that - `make trip' will fail if you disable builtin echo and your system's - `echo' does not understand `-n' to suppress newline. - - --with-addon - --with-addon=foo.c - - On the other hand, non-purists may wish to add extra builtin commands. - An example is included in the files addon.c and addon.h, which will - only be built if you specify `--with-addon'. If your addons are - in another file, you can specify that instead (but beware that the - interface file is still addon.h). - - --disable-def-interp - --enable-def-interp=/bin/foo - - By default, a program that fails with ENOEXEC (Exec format error) is - handed to /bin/sh. This does the Right Thing for scripts that start - with `:' to indicate that they are sh scripts. You can disable this - behaviour entirely, or specify a different default interpreter. - - --disable-def-path - --enable-def-path "/usr/local/bin","/usr/bin" - - By default, if rc is started with no PATH, it uses a default path. - The default path is constructed at configure time, and consists - of each of the following directories that exist, in order. - - /usr/local/bin /usr/bin /usr/bsd /usr/ucb /bin . - - You can disable this, or specify a different default path. Note that - the quote marks (") must be seen by configure; unless you are already - using rc, you will probably need to quote them to your shell. - - --disable-job - - By default, rc puts backgrounded processes into a new process group, - as though it were a job control shell (it isn't). This is usually - needed to work around bugs in application programs which install - signal handlers for the keyboard signals without checking whether the - signal was being ignored. This option disables the default behaviour, - making rc behave like a traditional sh. You are unlikely to want this - option on any Unix system. - - --disable-protect-env - - By default, rc encodes special characters in environment variables. - This is necessary on all known Unix systems to prevent sh either - dying or discarding the variables. This option disables the default - behaviour. You are unlikely to want this option on any Unix system. - -After you've built rc, I recommend that you run it through the test -script to gain some confidence that all is working well. Type `make -trip' to do this. This will produce some output, and should end with -"trip is complete". If the trip instead ends with "trip took a wrong -turn..." please contact the maintainer. - -In this release, `make trip' will fail on a file system which does not -implement Unix semantics (specifically permissions bits). This means -that `make trip' is not useful under CygWin, for instance. - - -BUILDING IN ANOTHER DIRECTORY - -If you have a suitable `make', you can build rc in a different directory -from where the sources are held. This is particularly useful if you -are building rc for multiple architectures. All you need do is specify -the path to the configure script in the first step. Suitable `make's -include GNU, HP-UX, and SunOS, but not Irix, nor Ultrix, nor UnixWare. - - -COMPILATION WARNINGS - -If your C compiler is gcc, the option `-Wall' is turned on. This may -produce a few warnings. - -Warnings about "implicit declaration" of system functions may occur if -your system's include files are deficient---they are usually harmless. - -Some older versions of gcc warn about "variable `n' might be -clobbered" in walk.c. As far as I can tell, this is gcc telling you -that it might not be compiling the code correctly! I don't know how -to eliminate the warning, but it doesn't appear to cause any problems -in practice. - -On some systems there are warnings about "passing arg 2 of `getgroups' -from incompatible pointer type" in which.c. I believe this is due to an -incorrect declaration of `getgroups()' in those systems' header files. - -The warning "left shift count >= width of type" in tripping.c may -occur if off_t is only 32 bits. - -Any other warnings should be reported to the maintainer. - - -OLD C - -rc needs an ISO C (89) compiler, or at least one that has a reasonable -understanding of function prototypes, `<stdarg.h>', `void', and -`volatile'. If you really need to compile rc with an ancient C -compiler, please contact the maintainer. +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. diff --git a/Makefile.am b/Makefile.am @@ -1,5 +1,7 @@ ## Process this file with automake to produce Makefile.in +EDIT=@EDIT@ + if AMC_HISTORY man_MANS = rc.1 history.1 HISTORY = history @@ -11,10 +13,6 @@ if AMC_NO_HASHBANG EXECVE = execve.o endif -if AMC_READLINE -READLINE = readline.o -endif - if AMC_RESTART SYSTEM = system-bsd.o else @@ -26,12 +24,12 @@ noinst_PROGRAMS = mksignal mkstatval tripping $(HISTORY) rc_SOURCES = builtins.c except.c exec.c fn.c footobar.c getopt.c glob.c glom.c hash.c heredoc.c input.c lex.c list.c main.c match.c nalloc.c open.c parse.c print.c redir.c signal.c status.c tree.c utils.c var.c wait.c walk.c which.c -EXTRA_rc_SOURCES = addon.c execve.c readline.c system.c system-bsd.c +EXTRA_rc_SOURCES = addon.c edit-bsd.c edit-gnu.c edit-null.c execve.c system.c system-bsd.c -rc_DEPENDENCIES = sigmsgs.o $(ADDON) $(EXECVE) $(READLINE) $(SYSTEM) -rc_LDADD = sigmsgs.o $(ADDON) $(EXECVE) $(READLINE) $(SYSTEM) +rc_DEPENDENCIES = sigmsgs.o $(ADDON) $(EDIT) $(EXECVE) $(SYSTEM) +rc_LDADD = sigmsgs.o $(ADDON) $(EDIT) $(EXECVE) $(SYSTEM) -noinst_HEADERS = getgroups.h jbwrap.h parse.h proto.h rc.h rlimit.h stat.h wait.h +noinst_HEADERS = edit.h getgroups.h input.h jbwrap.h parse.h proto.h rc.h rlimit.h stat.h wait.h BUILT_SOURCES = sigmsgs.c diff --git a/NEWS b/NEWS @@ -1,20 +1,23 @@ -Highlights of changes since rc-1.7. See ChangeLog for further details. +Highlights of changes since rc-1.7. See ChangeLog for further details. -Portability. A fix to the autoconfiguration means that the nasty -longjmp() code is now omitted for all modern Unix systems; previously -rc only did the Right Thing on Linux. The test for large files in -trip.rc was removed, as this causes indigestion on file systems that -don't support sparse files (the configuration and implementation of -large file support is still present of course). +Portability. A fix to the autoconfiguration means that the nasty +longjmp() code is now omitted for all modern Unix systems; previously rc +only did the Right Thing on Linux. The test for large files in trip.rc +was removed, as this causes indigestion on file systems that don't +support sparse files (the configuration and implementation of large file +support is still present of course). -Bug fixes. Broken symlinks now glob correctly. The variables $prompt -and $version are now exported if they are inherited from the -environment when rc starts. EIO handling is now enabled for readline -too. A few bogosities in the history program were fixed. +Bug fixes. Fix for CVE-2014-1936. Broken symlinks now glob correctly. +The variables $prompt and $version are now exported if they are +inherited from the environment when rc starts. EIO handling is now +enabled for readline too. A few bogosities in the history program were +fixed. A regression introduced by the fix for the $(a.b) quoting bug was +fixed, and that bug was correctly fixed. -New features. None - this is a bugfix release. +New features. Filename completion with GNU readline now quotes special +characters. -Documentation. Minor updates only. +Documentation. Minor updates only. -Tim Goodwin -2003-07-17 +Toby Goodwin +2014-09-01 diff --git a/README b/README @@ -1,15 +1,15 @@ -This is release rc-1.7.1. +This is release rc-1.7.2. See COPYING for copying information. All files are - Copyright 1991, 2001, 2002, 2003 Byron Rakitzis. + Copyright 1991, 2001, 2002, 2003, 2014 Byron Rakitzis. See INSTALL for build and installation information. BUGS -Send bug reports to <tjg@star.le.ac.uk>. If a core dump is generated, +Send bug reports to <toby@paccrat.org>. If a core dump is generated, sending a backtrace will help a great deal. You can get a backtrace like this. @@ -35,4 +35,4 @@ WWW More information on releases of rc can be found at this web page. - http://www.star.le.ac.uk/~tjg/rc/ + http://tobold.org/article/rc diff --git a/RELDATE b/RELDATE @@ -0,0 +1 @@ +2014-09-01 diff --git a/ReleaseTime b/ReleaseTime @@ -0,0 +1,7 @@ +#! /usr/bin/sed 1d +ChangeLog +NEWS +README +RELDATE +configure.ac +rc.1 diff --git a/acinclude.m4 b/acinclude.m4 @@ -1,6 +1,6 @@ dnl This macro sets HAVE_POSIX_GETGROUPS if the dnl getgroups() function accepts a zero first argument. -AC_DEFUN(RC_FUNC_GETGROUPS, [ +AC_DEFUN([RC_FUNC_GETGROUPS], [ AC_CACHE_CHECK(for POSIX getgroups, rc_cv_func_posix_getgroups, AC_TRY_RUN([ #include <sys/types.h> #include <unistd.h> @@ -16,7 +16,7 @@ int main(void) { dnl We can't use AC_CHECK_FUNCS for sigsetjmp(), since it's a macro in dnl some places. -AC_DEFUN(RC_FUNC_SIGSETJMP, [ +AC_DEFUN([RC_FUNC_SIGSETJMP], [ AC_CACHE_CHECK(for sigsetjmp, rc_cv_sigsetjmp, AC_TRY_LINK([ #include <setjmp.h> @@ -30,7 +30,7 @@ sigsetjmp(e, 1); ]) dnl Similarly, AC_CHECK_FUNCS doesn't find strerror() on NetBSD. -AC_DEFUN(RC_FUNC_STRERROR, [ +AC_DEFUN([RC_FUNC_STRERROR], [ AC_CACHE_CHECK(for strerror, rc_cv_strerror, AC_TRY_LINK([ #include <string.h> @@ -43,7 +43,7 @@ strerror(0); ]) dnl HPUX needs _KERNEL defined to pick up RLIMIT_foo defines. (Why?) -AC_DEFUN(RC_NEED_KERNEL, [ +AC_DEFUN([RC_NEED_KERNEL], [ AC_CACHE_CHECK(if _KERNEL is required for RLIMIT defines, rc_cv_kernel_rlimit, AC_TRY_COMPILE([ #include <sys/types.h> @@ -66,7 +66,7 @@ f = RLIMIT_DATA; ]) dnl Look for rlim_t in sys/types.h and sys/resource.h -AC_DEFUN(RC_TYPE_RLIM_T, [ +AC_DEFUN([RC_TYPE_RLIM_T], [ AC_CACHE_CHECK(for rlim_t, rc_cv_have_rlim_t, AC_EGREP_CPP(rlim_t, [ #include <sys/types.h> @@ -118,7 +118,7 @@ main(){ dnl Check type of sig_atomic_t. -AC_DEFUN(RC_TYPE_SIG_ATOMIC_T, [ +AC_DEFUN([RC_TYPE_SIG_ATOMIC_T], [ AC_CACHE_CHECK(for sig_atomic_t, rc_cv_sig_atomic_t, AC_EGREP_HEADER(sig_atomic_t, signal.h, rc_cv_sig_atomic_t=yes, rc_cv_sig_atomic_t=no)) @@ -135,7 +135,7 @@ dnl semantics, but if the parent calls wait() before the child calls dnl exit(), wait() returns with the PID of the child as normal. (Real dnl SysV waits for all children to exit, then returns with ECHILD.) dnl Anyway, this is why the `sleep(1)' is there. -AC_DEFUN(RC_SYS_V_SIGCLD, [ +AC_DEFUN([RC_SYS_V_SIGCLD], [ AC_CACHE_CHECK(for SysV SIGCLD semantics, rc_cv_sysv_sigcld, AC_TRY_RUN([ #include <errno.h> @@ -165,7 +165,7 @@ int main(void) { dnl Do we have /dev/fd or /proc/self/fd? -AC_DEFUN(RC_SYS_DEV_FD, [ +AC_DEFUN([RC_SYS_DEV_FD], [ AC_CACHE_CHECK(for /dev/fd, rc_cv_sys_dev_fd, if test -d /dev/fd && test -r /dev/fd/0; then rc_cv_sys_dev_fd=yes @@ -179,7 +179,7 @@ AC_DEFUN(RC_SYS_DEV_FD, [ dnl Can mknod make FIFOs? -AC_DEFUN(RC_SYS_MKNOD_FIFO, [ +AC_DEFUN([RC_SYS_MKNOD_FIFO], [ AC_CACHE_CHECK(for mknod FIFOs, rc_cv_sys_fifo, AC_TRY_RUN([ #include <sys/types.h> @@ -196,7 +196,7 @@ main() { ]) dnl Where is tgetent()? -AC_DEFUN(RC_LIB_TGETENT, [ +AC_DEFUN([RC_LIB_TGETENT], [ AC_CHECK_LIB(termcap, tgetent, rc_lib_tgetent=-ltermcap, AC_CHECK_LIB(ncurses, tgetent, diff --git a/aclocal.m4 b/aclocal.m4 @@ -0,0 +1,1069 @@ +# generated automatically by aclocal 1.13.4 -*- Autoconf -*- + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +# Copyright (C) 2002-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.13' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.13.4], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.13.4])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each '.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.65])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html> +# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html> +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it is modern enough. +# If it is, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# -*- Autoconf -*- +# Obsolete and "removed" macros, that must however still report explicit +# error messages when used, to smooth transition. +# +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +AC_DEFUN([AM_CONFIG_HEADER], +[AC_DIAGNOSE([obsolete], +['$0': this macro is obsolete. +You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl +AC_CONFIG_HEADERS($@)]) + +AC_DEFUN([AM_PROG_CC_STDC], +[AC_PROG_CC +am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc +AC_DIAGNOSE([obsolete], +['$0': this macro is obsolete. +You should simply use the 'AC][_PROG_CC' macro instead. +Also, your code should no longer depend upon 'am_cv_prog_cc_stdc', +but upon 'ac_cv_prog_cc_stdc'.])]) + +AC_DEFUN([AM_C_PROTOTYPES], + [AC_FATAL([automatic de-ANSI-fication support has been removed])]) +AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +# +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar <conftest.tar]) + AM_RUN_LOG([cat conftest.dir/file]) + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) + AC_MSG_RESULT([$am_cv_prog_tar_$1])]) + +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([acinclude.m4]) diff --git a/bootstrap b/bootstrap @@ -0,0 +1,2 @@ +#! /bin/sh +autoreconf --force --install diff --git a/builtins.c b/builtins.c @@ -15,6 +15,7 @@ #include <errno.h> #include "addon.h" +#include "input.h" #include "jbwrap.h" #include "rlimit.h" #include "sigmsgs.h" @@ -87,12 +88,12 @@ extern void funcall(char **av) { } static void arg_count(char *name) { - fprint(2, "too many arguments to %s\n", name); + fprint(2, RC "too many arguments to %s\n", name); set(FALSE); } static void badnum(char *num) { - fprint(2, "%s is a bad number\n", num); + fprint(2, RC "`%s' is a bad number\n", num); set(FALSE); } @@ -389,18 +390,13 @@ extern void b_dot(char **av) { return; fd = rc_open(*av, rFrom); if (fd < 0) { - if (rcrc) /* on rc -l, don't flag nonexistence of .rcrc */ - rcrc = FALSE; - else { - uerror(*av); - set(FALSE); - } + uerror(*av); + set(FALSE); return; } - rcrc = FALSE; starassign(*av, av+1, TRUE); - pushfd(fd); interactive = i; + pushfd(fd); star.name = "*"; except(eVarstack, star, &e); doit(TRUE); diff --git a/chldign b/chldign Binary files differ. diff --git a/chldign.c b/chldign.c @@ -0,0 +1,9 @@ +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> + +int main(int argc, char **argv) { + int i; + signal(SIGCHLD, SIG_IGN); + execvp(argv[1], &argv[1]); +} diff --git a/configure.ac b/configure.ac @@ -1,14 +1,13 @@ -dnl Get things going... -AC_INIT(rc.h) +dnl Our package name, version, ... +AC_INIT([rc], [1.7.2]) -RELDATE=`cat $srcdir/RELDATE` +dnl ... and release date +RELDATE=`date -I` AC_DEFINE_UNQUOTED(RELDATE, "$RELDATE", [Release date]) -dnl Automake stuff. -dnl Use this one for snapshots... -dnl AM_INIT_AUTOMAKE(rc, 1.7s`echo $RELDATE |sed 's/-//g'`) -dnl ...and this one for releases -AM_INIT_AUTOMAKE(rc, 1.7.1) +dnl Get things going... +AC_CONFIG_SRCDIR([rc.h]) +AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) @@ -90,7 +89,7 @@ no) RC_SYS_MKNOD_FIFO ;; esac dnl Now handle arguments. -AC_ARG_ENABLE(builtin-echo, [ --disable-builtin-echo Don't include \`echo' as a builtin], +AC_ARG_ENABLE(builtin-echo, [ --disable-builtin-echo Don't include `echo' as a builtin], test "x$enableval" != "xno" && AC_DEFINE(RC_ECHO, 1, [Define to 1 to include `echo' as a builtin.]), AC_DEFINE(RC_ECHO)) @@ -104,7 +103,7 @@ AC_ARG_ENABLE(protect-env, [ --disable-protect-env Don't protect environment AC_ARG_ENABLE(def-interp, [ --enable-def-interp=/bin/foo - Use /bin/foo as default interpreter [/bin/sh]], + Use /bin/foo as default interpreter [[/bin/sh]]], [ case "$enableval" in no) @@ -120,8 +119,8 @@ AC_ARG_ENABLE(def-interp, AC_ARG_ENABLE(def-path, [ --enable-def-path=\"/usr/local/bin/\",\"/usr/bin\" - Default path [All of these that exist - (/usr/local/bin /usr/bin /usr/bsd /usr/ucb /bin .)]], + Default path [[All of these that exist + (/usr/local/bin /usr/bin /usr/bsd /usr/ucb /bin .)]]], [ case "$enableval" in no|yes) ;; @@ -156,7 +155,7 @@ AC_ARG_WITH(history, AM_CONDITIONAL(AMC_HISTORY, test "$rc_history" = yes) -AC_ARG_WITH(addon, [ --with-addon[=foo.c] Extra builtins, from addon.c by default ],[ +AC_ARG_WITH(addon, [ --with-addon[[=foo.c]] Extra builtins, from addon.c by default ],[ case "$withval" in yes) ADDON=addon.o ;; no) ADDON='' ;; @@ -170,32 +169,69 @@ esac AC_SUBST(ADDON) -AC_ARG_WITH(editline, [ --with-editline Simmule Turner's line editing], - AC_CHECK_LIB(edit, readline, - AC_DEFINE(EDITLINE, 1, [Define to 1 if you are using `editline' or `vrl'.]) LIBS="$LIBS -ledit", - AC_MSG_ERROR(editline library not found))) +EDIT=edit-null.o +AC_ARG_WITH(edit, [ --with-edit=(bsd,edit,gnu,vrl) Command line editing library], [ + case $withval in + yes) + AC_MSG_ERROR(must specify which library) + # might consider searching + ;; + bsd) + EDIT=edit-bsd.o + RC_LIB_TGETENT + AC_CHECK_LIB(edit, el_init, [ + LIBS="$LIBS -ledit $rc_lib_tgetent" + ], AC_MSG_ERROR(editline library not found), $rc_lib_tgetent) + ;; + gnu) + EDIT=edit-gnu.o + RC_LIB_TGETENT + AC_CHECK_LIB(readline, readline, [ + LIBS="$LIBS -lreadline $rc_lib_tgetent" + ], AC_MSG_ERROR(readline library not found), $rc_lib_tgetent) + AC_TRY_LINK([ + #include <stdio.h> + #include <readline/readline.h> + ], [ + rl_catch_signals = 0; + ], [], AC_MSG_ERROR(readline >= 4.0 not found)) + ;; + no|null) + ;; + edit|vrl) + EDIT=edit-$withval.o + ;; + *) + AC_MSG_ERROR(unknown editing library $withval) + ;; + esac +]) +AC_SUBST(EDIT) +dnl AC_CHECK_LIB(edit, readline, +dnl AC_DEFINE(EDITLINE, 1, [Define to 1 if you are using `editline' or `vrl'.]) LIBS="$LIBS -ledit", +dnl AC_MSG_ERROR(editline library not found))) -if test "${with_vrl+set}" = set -o "${with_readline+set}" = set; then - RC_LIB_TGETENT -fi +dnl if test "${with_vrl+set}" = set -o "${with_readline+set}" = set; then +dnl RC_LIB_TGETENT +dnl fi -AC_ARG_WITH(vrl, [ --with-vrl Gert-Jan Vons's line editing], - AC_CHECK_LIB(vrl, readline, - AC_DEFINE(EDITLINE) LIBS="$LIBS -lvrl $rc_lib_tgetent", - AC_MSG_ERROR(vrl library not found), $rc_lib_tgetent)) +dnl AC_ARG_WITH(vrl, [ --with-vrl Gert-Jan Vons's line editing], +dnl AC_CHECK_LIB(vrl, readline, +dnl AC_DEFINE(EDITLINE) LIBS="$LIBS -lvrl $rc_lib_tgetent", +dnl AC_MSG_ERROR(vrl library not found), $rc_lib_tgetent)) dnl There are (at least) two incompatible versions of readline, and we dnl need to know which one we are using. We don't support readline 2.0. -AC_ARG_WITH(readline, [ --with-readline Bloated GNU line editing], [ - AC_CHECK_LIB(readline, readline, [ - AC_DEFINE(READLINE, 1, [Define to 1 if you are using GNU `readline'.]) - LIBS="$LIBS -lreadline $rc_lib_tgetent" - AC_CHECK_LIB(readline, _rl_clean_up_for_exit, , AC_DEFINE(READLINE_OLD, 1, [Define to 1 for older versions GNU `readline'.]), $rc_lib_tgetent) - ], AC_MSG_ERROR(readline library not found), $rc_lib_tgetent) -]) -AM_CONDITIONAL(AMC_READLINE, test "${with_readline+set}" = set) +dnl AC_ARG_WITH(readline, [ --with-readline Bloated GNU line editing], [ +dnl AC_CHECK_LIB(readline, readline, [ +dnl AC_DEFINE(READLINE, 1, [Define to 1 if you are using GNU `readline'.]) +dnl LIBS="$LIBS -lreadline $rc_lib_tgetent" +dnl AC_CHECK_LIB(readline, _rl_clean_up_for_exit, , AC_DEFINE(READLINE_OLD, 1, [Define to 1 for older versions GNU `readline'.]), $rc_lib_tgetent) +dnl ], AC_MSG_ERROR(readline library not found), $rc_lib_tgetent) +dnl ]) +dnl AM_CONDITIONAL(AMC_READLINE, test "${with_readline+set}" = set) dnl For some reason CPPFLAGS doesn't get propagated. -AC_SUBST(CPPFLAGS) +dnl AC_SUBST(CPPFLAGS) AC_OUTPUT(Makefile) diff --git a/configure.scan b/configure.scan @@ -0,0 +1,49 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.56) +AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) +AC_CONFIG_SRCDIR([parse.c]) +AC_CONFIG_HEADER([config.h]) + +# Checks for programs. +AC_PROG_AWK +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_CPP + +# Checks for libraries. + +# Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h sys/ioctl.h sys/param.h sys/time.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_HEADER_STDBOOL +AC_C_CONST +AC_TYPE_UID_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_C_VOLATILE + +# Checks for library functions. +AC_FUNC_CLOSEDIR_VOID +AC_FUNC_FORK +AC_FUNC_GETGROUPS +AC_FUNC_GETPGRP +AC_FUNC_LSTAT +AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK +AC_FUNC_MALLOC +AC_FUNC_REALLOC +AC_TYPE_SIGNAL +AC_FUNC_STAT +AC_CHECK_FUNCS([dup2 memset mkfifo strchr strerror strrchr strspn]) + +AC_CONFIG_FILES([Makefile + rc-1.7s20020820/Makefile + rc-1.7s20021127/=build/Makefile + rc-1.7s20021127/Makefile]) +AC_OUTPUT diff --git a/edit-bsd.c b/edit-bsd.c @@ -0,0 +1,91 @@ +#include "rc.h" + +#include <stdio.h> + +#include <histedit.h> + +#include "edit.h" + +bool editing = 1; + +struct cookie { + EditLine *el; + History *hist; +}; + +static char *prompt; + +void *edit_begin(int fd) { + FILE *f; + HistEvent he; + struct cookie *c; + + c = ealloc(sizeof *c); + if (fd == 0) + f = stdin; + else + f = fdopen(fd, "r"); + c->el = el_init("rc", f, stdout, stderr); + el_set(c->el, EL_SIGNAL, 0); + el_source(c->el, NULL); + + c->hist = history_init(); + history(c->hist, &he, H_SETSIZE, 20); + el_set(c->el, EL_HIST, history, c->hist); + + return c; +} + + +static void edit_catcher(int sig) { + write(2, "\n", 1); + rc_raise(eError); +} + +char *edit_alloc(void *cookie, size_t *count) { + const char *r; + HistEvent he; + struct cookie *c = cookie; + void (*oldint)(int), (*oldquit)(int); + + oldint = sys_signal(SIGINT, edit_catcher); + oldquit = sys_signal(SIGQUIT, edit_catcher); + + r = el_gets(c->el, count); + + sys_signal(SIGINT, oldint); + sys_signal(SIGQUIT, oldquit); + + if (r) + history(c->hist, &he, H_ENTER, r); + return (char *)r; /* cast to avoid gcc warning */ +} + +static char *edit_prompter(EditLine *e) { + return prompt; +} + +void edit_prompt(void *cookie, char *pr) { + struct cookie *c = cookie; + + prompt = pr; + el_set(c->el, EL_PROMPT, edit_prompter); +} + +void edit_free(void *cookie) { + /* this function deliberately left blank */ +} + +void edit_end(void *cookie) { + struct cookie *c = cookie; + + el_end(c->el); + history_end(c->hist); + efree(c); +} + +void edit_reset(void *cookie) { + struct cookie *c = cookie; + + el_set(c->el, EL_TERMINAL, NULL); +} diff --git a/edit-gnu.c b/edit-gnu.c @@ -0,0 +1,87 @@ +#include "rc.h" + +#include <errno.h> +#include <stdio.h> +#include <readline/readline.h> +#include <readline/history.h> +#include <readline/rltypedefs.h> + +#include "edit.h" + +bool editing = 1; + +struct cookie { + char *buffer; +}; + +void *edit_begin(int fd) { + List *hist; + struct cookie *c; + + rl_catch_signals = 0; + rl_completer_quote_characters = "'"; + rl_filename_quote_characters = "\t\n !#$&'()*;<=>?@[\\]^`{|}~"; + + hist = varlookup("history"); + if (hist != NULL) + if (read_history(hist->w) != 0 && errno != ENOENT) /* ignore if missing */ + uerror(hist->w); + + c = ealloc(sizeof *c); + c->buffer = NULL; + return c; +} + +static void edit_catcher(int sig) { + write(2, "\n", 1); + rc_raise(eError); +} + +static char *prompt; + +char *edit_alloc(void *cookie, size_t *count) { + struct cookie *c = cookie; + void (*oldint)(int), (*oldquit)(int); + + oldint = sys_signal(SIGINT, edit_catcher); + oldquit = sys_signal(SIGQUIT, edit_catcher); + + c->buffer = readline(prompt); + + sys_signal(SIGINT, oldint); + sys_signal(SIGQUIT, oldquit); + + if (c->buffer) { + *count = strlen(c->buffer); + if (*count) + add_history(c->buffer); + c->buffer[*count] = '\n'; + ++*count; /* include the \n */ + } + return c->buffer; +} + +void edit_prompt(void *cookie, char *pr) { + prompt = pr; +} + +void edit_free(void *cookie) { + struct cookie *c = cookie; + + efree(c->buffer); + /* Set c->buffer to NULL, allowing us to "overfree" it. This + is a bit of a kludge, but it's otherwise hard to deal with + the case where a signal causes an early return from + readline. */ + c->buffer = NULL; +} + +void edit_end(void *cookie) { + struct cookie *c = cookie; + + efree(c); +} + +void edit_reset(void *cookie) { + rl_reset_terminal(NULL); +} diff --git a/edit-null.c b/edit-null.c @@ -0,0 +1,35 @@ +#include "rc.h" + +#include <errno.h> + +#include <sys/types.h> + +#include "edit.h" + +bool editing = 0; + +void *edit_begin(int fd) { + assert(0); /* should never be called */ + return NULL; +} + +char *edit_alloc(void *cookie, size_t *count) { + assert(0); /* should never be called */ + return NULL; +} + +void edit_prompt(void *cookie, char *prompt) { + assert(0); /* should never be called */ +} + +void edit_free(void *buffer) { + assert(0); /* should never be called */ +} + +void edit_end(void *cookie) { + assert(0); /* should never be called */ +} + +void edit_reset(void *cookie) { + assert(0); /* should never be called */ +} diff --git a/edit.h b/edit.h @@ -0,0 +1,12 @@ +extern bool editing; + +extern void *edit_begin(int fd); + +extern char *edit_alloc(void *, size_t *); +extern void edit_free(void *); + +extern void edit_prompt(void *, char *); + +extern void edit_end(void *); + +extern void edit_reset(void *); diff --git a/except.c b/except.c @@ -3,6 +3,7 @@ #include <setjmp.h> #include <signal.h> +#include "input.h" #include "jbwrap.h" /* diff --git a/fn.c b/fn.c @@ -8,6 +8,7 @@ #include <signal.h> #include <errno.h> +#include "input.h" #include "sigmsgs.h" static void fn_handler(int), dud_handler(int); diff --git a/footobar.c b/footobar.c @@ -5,6 +5,8 @@ #include "rc.h" +#include "input.h" + /* protect an exported name from brain-dead shells */ #if PROTECT_ENV @@ -73,7 +75,8 @@ static bool Tconv(Format *f, int ignore) { case nForin: fmtprint(f, "for(%T in %T)%T", n->u[0].p, n->u[1].p, n->u[2].p); break; case nVarsub: fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p); break; case nWord: - fmtprint(f, quotep(n->u[0].s, dollar) ? "%#S" : "%S", n->u[0].s); + fmtprint(f, n->u[2].i && quotep(n->u[0].s, dollar) ? + "%#S" : "%S", n->u[0].s); break; case nLappend: { static bool inlist; diff --git a/glob.c b/glob.c @@ -143,7 +143,7 @@ static List *dmatch(char *d, char *p, char *m) { } /* - lglob() globs a pattern agains a list of directory roots. e.g., (/tmp /usr /bin) "*" + lglob() globs a pattern against a list of directory roots. e.g., (/tmp /usr /bin) "*" will return a list with all the files in /tmp, /usr, and /bin. NULL on no match. slashcount indicates the number of slashes to stick between the directory and the matched name. e.g., for matching ////tmp/////foo* diff --git a/hash.c b/hash.c @@ -315,14 +315,3 @@ extern void whatare_all_vars(bool showfn, bool showvar) { if (fp[i].name != NULL && fp[i].name != dead) prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name)); } - -/* fake getenv() for readline() follows: */ - -#if EDITLINE || READLINE -extern char *getenv(const char *name) { - List *s; - if (name == NULL || vp == NULL || (s = varlookup((char *) name)) == NULL) - return NULL; - return s->w; -} -#endif diff --git a/heredoc.c b/heredoc.c @@ -2,6 +2,8 @@ #include "rc.h" +#include "input.h" + struct Hq { Node *doc; char *name; @@ -40,7 +42,7 @@ static char *readheredoc(char *eof) { bufend = &buf[bufsize]; \ } for (;;) { - print_prompt2(); + nextline(); for (s = (unsigned char *) eof; (c = gchar()) == *s; s++) ; if (*s == '\0' && (c == '\n' || c == EOF)) { @@ -142,7 +144,7 @@ extern int qdoc(Node *name, Node *n) { Hq *new, **prev; if (name->type != nWord) { yyerror("eof-marker not a single literal word"); - flushu(); + skiptonl(); return FALSE; } for (prev = &hq; (new = *prev) != NULL; prev = &new->n) diff --git a/input.c b/input.c @@ -4,161 +4,166 @@ #include <errno.h> +#include "edit.h" +#include "input.h" #include "jbwrap.h" -/* - NB: character unget is supported for up to two characters, but NOT - in the case of EOF. Since EOF does not fit in a char, it is easiest - to support only one unget of EOF. -*/ +/* How many characters can we unget? */ +enum { UNGETSIZE = 2 }; + +typedef enum inputtype { + iFd, iString, iEdit +} inputtype; typedef struct Input { + bool saved; inputtype t; + int fd, index, read, ungetcount, lineno, last; char *ibuf; - int fd, index, read, lineno, last; - bool saved, eofread; + void *cookie; + int ungetbuf[UNGETSIZE]; + int (*gchar)(void); } Input; #define BUFSIZE ((size_t) 256) -static char *prompt2; -bool rcrc; - -static int dead(void); -static int fdgchar(void); -static int stringgchar(void); -static void history(void); -static void ugdead(int); -static void pushcommon(void); - static char *inbuf; static size_t istacksize, chars_out, chars_in; -static bool eofread = FALSE, save_lineno = TRUE; +static bool save_lineno = TRUE; static Input *istack, *itop; -static int (*realgchar)(void); -static void (*realugchar)(int); - int lastchar; -#if EDITLINE || READLINE -static char *rlinebuf, *prompt; -#endif +static char *prompt, *prompt2; + +extern void ugchar(int c) { + assert(istack->ungetcount < UNGETSIZE); + istack->ungetbuf[istack->ungetcount++] = c; +} extern int gchar() { int c; - if (eofread) { - eofread = FALSE; - return lastchar = EOF; - } + if (istack->ungetcount) + return lastchar = istack->ungetbuf[--istack->ungetcount]; - while ((c = (*realgchar)()) == '\0') + while ((c = (*istack->gchar)()) == '\0') pr_error("warning: null character ignored", 0); return c; } -extern void ugchar(int c) { - (*realugchar)(c); -} -static int dead() { - return lastchar = EOF; -} +/* get the next character from a string. */ -static void ugdead(int ignore) { - return; +static int stringgchar() { + return lastchar = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]); } -static void ugalive(int c) { - if (c == EOF) - eofread = TRUE; - else - inbuf[--chars_out] = c; -} -/* get the next character from a string. */ +/* write last command out to a file if interactive && $history is set */ -static int stringgchar() { - return lastchar = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]); +static void history() { + List *hist; + size_t a; + + if (!interactive || (hist = varlookup("history")) == NULL) + return; + + for (a = 0; a < chars_in; a++) { + char c = inbuf[a]; + + /* skip empty lines and comments */ + if (c == '#' || c == '\n') + break; + + /* line matches [ \t]*[^#\n] so it's ok to write out */ + if (c != ' ' && c != '\t') { + char *name = hist->w; + int fd = rc_open(name, rAppend); + if (fd < 0) + uerror(name); + else { + writeall(fd, inbuf, chars_in); + close(fd); + } + break; + } + } } -/* - read a character from a file-descriptor. If GNU readline is defined, - add a newline and doctor the buffer to look like a regular fdgchar - buffer. -*/ -static int fdgchar() { +/* read a character from a file descriptor */ - if (chars_out >= chars_in + 2) { /* has the buffer been exhausted? if so, replenish it */ - while (1) { -#if EDITLINE || READLINE - if (interactive && istack->t == iFd && isatty(istack->fd)) { - /* The readline library doesn't handle - * read() returning EAGAIN or EIO. */ - makeblocking(istack->fd); - makesamepgrp(istack->fd); - rlinebuf = rc_readline(prompt); - if (rlinebuf == NULL) { - chars_in = 0; - } else { - if (*rlinebuf != '\0') - add_history(rlinebuf); - chars_in = strlen(rlinebuf) + 1; - efree(inbuf); - inbuf = ealloc(chars_in + 3); - strcpy(inbuf+2, rlinebuf); - strcat(inbuf+2, "\n"); - efree(rlinebuf); - } - } else -#endif - { - ssize_t r; - do { - r = rc_read(istack->fd, inbuf + 2, BUFSIZE); - sigchk(); - switch (errno) { - case EAGAIN: - if (!makeblocking(istack->fd)) - panic("not O_NONBLOCK"); +static int fdgchar() { + if (chars_out >= chars_in) { /* replenish empty buffer */ + ssize_t r; + do { + r = rc_read(istack->fd, inbuf, BUFSIZE); + sigchk(); + if (r == -1) + switch (errno) { + case EAGAIN: + if (!makeblocking(istack->fd)) + panic("not O_NONBLOCK"); + errno = EINTR; + break; + case EIO: + if (makesamepgrp(istack->fd)) errno = EINTR; - break; - case EIO: - if (makesamepgrp(istack->fd)) - errno = EINTR; - else - errno = EIO; - break; - } - } while (r < 0 && errno == EINTR); - if (r < 0) { - uerror("read"); - rc_raise(eError); + else + errno = EIO; + break; } - chars_in = (size_t) r; - } - break; + } while (r < 0 && errno == EINTR); + if (r < 0) { + uerror("read"); + rc_raise(eError); } + chars_in = (size_t) r; if (chars_in == 0) return lastchar = EOF; - chars_out = 2; + chars_out = 0; if (dashvee) - writeall(2, inbuf + 2, chars_in); + writeall(2, inbuf, chars_in); history(); } + return lastchar = inbuf[chars_out++]; } +/* read a character from a line-editing file descriptor */ + +static int editgchar() { + if (chars_out >= chars_in) { /* replenish empty buffer */ + edit_free(istack->cookie); + inbuf = edit_alloc(istack->cookie, &chars_in); + if (inbuf == NULL) { + chars_in = 0; + fprint(2, "exit\n"); + return lastchar = EOF; + } + + chars_out = 0; + if (dashvee) + writeall(2, inbuf, chars_in); + history(); + } + + return lastchar = inbuf[chars_out++]; +} + +void termchange(void) { + if (istack->t == iEdit) + edit_reset(istack->cookie); +} + + /* set up the input stack, and put a "dead" input at the bottom, so that yyparse will always read eof */ extern void initinput() { istack = itop = ealloc(istacksize = 256 * sizeof (Input)); - istack->t = iFd; - istack->fd = -1; - realugchar = ugalive; + ugchar(EOF); } /* push an input source onto the stack. set up a new input buffer, and set gchar() */ @@ -171,54 +176,56 @@ static void pushcommon() { istack->lineno = lineno; istack->saved = save_lineno; istack->last = lastchar; - istack->eofread = eofread; istack++; idiff = istack - itop; if (idiff >= istacksize / sizeof (Input)) { itop = erealloc(itop, istacksize *= 2); istack = itop + idiff; } - realugchar = ugalive; - chars_out = 2; + chars_out = 0; chars_in = 0; + istack->ungetcount = 0; } extern void pushfd(int fd) { pushcommon(); - istack->t = iFd; save_lineno = TRUE; istack->fd = fd; - realgchar = fdgchar; - inbuf = ealloc(BUFSIZE + 2); lineno = 1; + if (editing && interactive && isatty(fd)) { + istack->t = iEdit; + istack->gchar = editgchar; + istack->cookie = edit_begin(fd); + } else { + istack->t = iFd; + istack->gchar = fdgchar; + inbuf = ealloc(BUFSIZE); + } } extern void pushstring(char **a, bool save) { pushcommon(); istack->t = iString; save_lineno = save; - inbuf = mprint("..%A", a); - realgchar = stringgchar; + inbuf = mprint("%A", a); + istack->gchar = stringgchar; if (save_lineno) lineno = 1; else --lineno; } -/* remove an input source from the stack. restore the right kind of getchar (string,fd) etc. */ + +/* remove an input source from the stack. restore associated variables etc. */ extern void popinput() { - if (istack->t == iFd) + if (istack->t == iEdit) + edit_end(istack->cookie); + if (istack->t == iFd || istack->t == iEdit) close(istack->fd); efree(inbuf); --istack; - realgchar = (istack->t == iString ? stringgchar : fdgchar); - if (istack->t == iFd && istack->fd == -1) { /* top of input stack */ - realgchar = dead; - realugchar = ugdead; - } lastchar = istack->last; - eofread = istack->eofread; inbuf = istack->ibuf; chars_out = istack->index; chars_in = istack->read; @@ -229,9 +236,10 @@ extern void popinput() { save_lineno = istack->saved; } -/* flush input characters upto newline. Used by scanerror() */ -extern void flushu() { +/* flush input characters up to newline. Used by scanerror() */ + +extern void skiptonl() { int c; if (lastchar == '\n' || lastchar == EOF) return; @@ -241,6 +249,7 @@ extern void flushu() { ugchar(c); } + /* the wrapper loop in rc: prompt for commands until EOF, calling yyparse and walk() */ extern Node *doit(bool clobberexecit) { @@ -259,17 +268,11 @@ extern Node *doit(bool clobberexecit) { for (eof = FALSE; !eof;) { Edata block; Estack e2; + block.b = newblock(); except(eArena, block, &e2); sigchk(); - if (dashell) { - char *fname[3]; - fname[1] = concat(varlookup("home"), word("/.rcrc", NULL))->w; - fname[2] = NULL; - rcrc = TRUE; - dashell = FALSE; - b_dot(fname); - } + if (interactive) { List *s; if (!dashen && fnlookup("prompt") != NULL) { @@ -282,15 +285,20 @@ extern Node *doit(bool clobberexecit) { } died = FALSE; } - if ((s = varlookup("prompt")) != NULL) { -#if EDITLINE || READLINE - if (istack->t == iFd && isatty(istack->fd)) - prompt = s->w; + s = varlookup("prompt"); + if (s != NULL) { + prompt = s->w; + if (s->n != NULL) + prompt2 = s->n->w; else -#endif - fprint(2, "%s", s->w); - prompt2 = (s->n == NULL ? "" : s->n->w); + prompt2 = ""; + } else { + prompt = prompt2 = ""; } + if (istack->t == iFd) + fprint(2, "%s", prompt); + else if (istack->t == iEdit) + edit_prompt(istack->cookie, prompt); } inityy(); if (yyparse() == 1 && execit) @@ -312,7 +320,7 @@ extern Node *doit(bool clobberexecit) { /* parse a function imported from the environment */ extern Node *parseline(char *extdef) { - int i = interactive; + bool i = interactive; char *in[2]; Node *fun; in[0] = extdef; @@ -324,38 +332,6 @@ extern Node *parseline(char *extdef) { return fun; } -/* write last command out to a file if interactive && $history is set */ - -static void history() { - List *hist; - size_t a; - - if (!interactive || (hist = varlookup("history")) == NULL) - return; - - for (a = 0; a < chars_in; a++) { - char c = inbuf[a+2]; - - /* skip empty lines and comments */ - if (c == '#' || c == '\n') - break; - - /* line matches [ \t]*[^#\n] so it's ok to write out */ - if (c != ' ' && c != '\t') { - char *name = hist->w; - int fd = rc_open(name, rAppend); - if (fd < 0) { - uerror(name); - varrm(name, TRUE); - } else { - writeall(fd, inbuf + 2, chars_in); - close(fd); - } - break; - } - } -} - /* close file descriptors after a fork() */ extern void closefds() { @@ -367,14 +343,14 @@ extern void closefds() { } } -extern void print_prompt2() { +/* print (or set) prompt(2) */ + +extern void nextline() { lineno++; if (interactive) { -#if EDITLINE || READLINE - if (istack->t == iFd && isatty(istack->fd)) - prompt = prompt2; - else -#endif + if (istack->t == iFd) fprint(2, "%s", prompt2); + else if (istack->t == iEdit) + edit_prompt(istack->cookie, prompt2); } } diff --git a/input.h b/input.h @@ -0,0 +1,35 @@ +/* initialize the input stack */ +extern void initinput(void); + +/* push an input onto the stack */ +extern void pushfd(int); +/* the Boolean argument affects line number reporting */ +extern void pushstring(char **, bool); + +/* pop the stack */ +extern void popinput(void); + +/* get / unget the next character */ +extern int gchar(void); +extern void ugchar(int); + +/* $TERM or $TERMCAP has changed */ +extern void termchange(void); + +/* parse a function from the environment */ +extern Node *parseline(char *); + +/* main parsing loop; Boolean says whether to exec also */ +extern Node *doit(bool); + +/* error recovery: skip to the next newline */ +extern void skiptonl(void); + +/* prepare for next line of input */ +extern void nextline(void); + +/* close all file descriptors on the stack */ +extern void closefds(void); + +/* the last character read */ +extern int lastchar; diff --git a/lex.c b/lex.c @@ -1,6 +1,8 @@ /* lex.c: rc's lexical analyzer */ #include "rc.h" + +#include "input.h" #include "parse.h" /* @@ -33,6 +35,7 @@ static void getpair(int); int lineno; +/* lookup table for non-word characters */ const char nw[] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, @@ -44,6 +47,7 @@ const char nw[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +/* lookup table for non-word characters in variable names */ const char dnw[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, @@ -55,6 +59,18 @@ const char dnw[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; +/* lookup table for quotable characters: nw + glob metachars */ +const char q[] = { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + static size_t bufsize = BUFSIZE; static char *realbuf = NULL; static bool newline = FALSE; @@ -74,7 +90,7 @@ extern bool quotep(char *s, bool dollar) { unsigned char c; const char *meta; - meta = dollar ? dnw : nw; + meta = dollar ? dnw : q; while ((c = *s++)) if (meta[c]) return TRUE; @@ -95,14 +111,14 @@ extern int yylex() { } /* rc variable-names may contain only alnum, '*' and '_', so use dnw if we are scanning one. */ meta = (dollar ? dnw : nw); - dollar = FALSE; if (newline) { - --lineno; /* slight space optimization; print_prompt2() always increments lineno */ - print_prompt2(); + --lineno; /* slight space optimization; nextline() always increments lineno */ + nextline(); newline = FALSE; } top: while ((c = gchar()) == ' ' || c == '\t') w = NW; + if (c != '(') dollar = FALSE; if (c == EOF) return END; if (!meta[(unsigned char) c]) { /* it's a word or keyword. */ @@ -118,7 +134,7 @@ top: while ((c = gchar()) == ' ' || c == '\t') } while ((c = gchar()) != EOF && !meta[(unsigned char) c]); while (c == '\\') { if ((c = gchar()) == '\n') { - print_prompt2(); + nextline(); c = ' '; /* Pretend a space was read */ break; } else { @@ -185,7 +201,7 @@ top: while ((c = gchar()) == ' ' || c == '\t') c = gchar(); if (c == '#') return COUNT; - if (c == '^') + if (c == '^' || c == '"') return FLAT; ugchar(c); return '$'; @@ -196,7 +212,7 @@ top: while ((c = gchar()) == ' ' || c == '\t') while ((c = gchar()) != '\'' || (c = gchar()) == '\'') { buf[i++] = c; if (c == '\n') - print_prompt2(); + nextline(); if (c == EOF) { w = NW; scanerror("eof in quoted string"); @@ -213,7 +229,7 @@ top: while ((c = gchar()) == ' ' || c == '\t') return WORD; case '\\': if ((c = gchar()) == '\n') { - print_prompt2(); + nextline(); goto top; /* Pretend it was just another space. */ } ugchar(c); @@ -223,7 +239,7 @@ top: while ((c = gchar()) == ' ' || c == '\t') i = 0; goto bs; case '(': - if (w == RW) /* SUB's happen only after real words, not keyowrds, so if () and while () work */ + if (w == RW) /* SUB's happen only after real words, not keywords, so if () and while () work */ c = SUB; w = NW; return c; @@ -327,13 +343,13 @@ extern void yyerror(const char *s) { tok = "end of line"; else tok = nprint((lastchar < 32 || lastchar > 126) ? "(decimal %d)" : "'%c'", lastchar); - fprint(2, "line %d: %s near %s\n", lineno - (lastchar == '\n'), s, tok); + fprint(2, "rc: line %d: %s near %s\n", lineno - (lastchar == '\n'), s, tok); } else - fprint(2, "%s\n", s); + fprint(2, "rc: %s\n", s); } extern void scanerror(char *s) { - flushu(); /* flush upto newline */ + skiptonl(); /* flush upto newline */ yyerror(s); errset = prerror = TRUE; } diff --git a/main.c b/main.c @@ -2,11 +2,15 @@ #include "rc.h" -bool dashdee, dashee, dashvee, dashex, dashell, dashEYE, dasheye, - dashen, dashpee, dashess, interactive; +#include <errno.h> + +#include "input.h" + +bool dashdee, dashee, dashvee, dashex, dasheye, + dashen, dashpee, interactive; pid_t rc_pid; -static bool dashoh; +static bool dashEYE, dashell, dashoh, dashess; static void assigndefault(char *,...); static void checkfd(int, enum redirtype); @@ -86,6 +90,28 @@ quitopts: null[0] = NULL; starassign(dollarzero, null, FALSE); /* assign $0 to $* */ inithandler(); + + if (dashell) { + char *rcrc; + int fd; + + rcrc = concat(varlookup("home"), word("/.rcrc", NULL))->w; + fd = rc_open(rcrc, rFrom); + if (fd == -1) { + if (errno != ENOENT) + uerror(rcrc); + } else { + bool push_interactive; + + pushfd(fd); + push_interactive = interactive; + interactive = FALSE; + doit(TRUE); + interactive = push_interactive; + close(fd); + } + } + if (dashsee[0] != NULL || dashess) { /* input from -c or -s? */ if (*argv != NULL) starassign(dollarzero, argv, FALSE); diff --git a/mkinstalldirs b/mkinstalldirs @@ -0,0 +1,162 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy + +scriptversion=2009-04-28.21; # UTC + +# Original author: Noah Friedman <friedman@prep.ai.mit.edu> +# Created: 1993-05-16 +# Public domain. +# +# This file is maintained in Automake, please report +# bugs to <bug-automake@gnu.org> or send patches to +# <automake-patches@gnu.org>. + +nl=' +' +IFS=" "" $nl" +errstatus=0 +dirmode= + +usage="\ +Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... + +Create each directory DIR (with mode MODE, if specified), including all +leading file name components. + +Report bugs to <bug-automake@gnu.org>." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" + exit $? + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --version) + echo "$0 $scriptversion" + exit $? + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and +# mkdir -p a/c at the same time, both will detect that a is missing, +# one will create a, then the other will try to create a and die with +# a "File exists" error. This is a problem when calling mkinstalldirs +# from a parallel make. We use --version in the probe to restrict +# ourselves to GNU mkdir, which is thread-safe. +case $dirmode in + '') + if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + else + # On NextStep and OpenStep, the 'mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because '.' already + # exists. + test -d ./-p && rmdir ./-p + test -d ./--version && rmdir ./--version + fi + ;; + *) + if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && + test ! -d ./--version; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + else + # Clean up after NextStep and OpenStep mkdir. + for d in ./-m ./-p ./--version "./$dirmode"; + do + test -d $d && rmdir $d + done + fi + ;; +esac + +for file +do + case $file in + /*) pathcomp=/ ;; + *) pathcomp= ;; + esac + oIFS=$IFS + IFS=/ + set fnord $file + shift + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr= + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp=$pathcomp/ + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/nonblock.c b/nonblock.c @@ -0,0 +1,14 @@ +/* Set stdin to nonblocking. */ +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +int main(void) { + int flags; + flags = fcntl(0, F_GETFL); + flags |= O_NONBLOCK; + fcntl(0, F_SETFL, (long) flags); + flags = read(0, &flags, 1); + printf("read returns %d, errno == %d\n", flags, errno); + return 0; +} diff --git a/parse.c b/parse.c @@ -0,0 +1,1117 @@ +#ifndef lint +static char const +yyrcsid[] = "$FreeBSD: src/usr.bin/yacc/skeleton.c,v 1.28 2000/01/17 02:04:06 bde Exp $"; +#endif +#include "rc.h" +#include <stdlib.h> +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define YYLEX yylex() +#define YYEMPTY -1 +#define yyclearin (yychar=(YYEMPTY)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING() (yyerrflag!=0) +static int yygrowstack(); +#define YYPREFIX "yy" +#line 8 "parse.y" + +static Node *star, *nolist; +Node *parsetree; /* not using yylval because bison declares it as an auto */ +#line 26 "parse.y" +typedef union { + struct Node *node; + struct Redir redir; + struct Pipe pipe; + struct Dup dup; + struct Word word; + char *keyword; +} YYSTYPE; +#line 31 "y.tab.c" +#define YYERRCODE 256 +#define ANDAND 257 +#define BACKBACK 258 +#define BANG 259 +#define CASE 260 +#define COUNT 261 +#define DUP 262 +#define ELSE 263 +#define END 264 +#define FLAT 265 +#define FN 266 +#define FOR 267 +#define IF 268 +#define IN 269 +#define OROR 270 +#define PIPE 271 +#define REDIR 272 +#define SREDIR 273 +#define SUB 274 +#define SUBSHELL 275 +#define SWITCH 276 +#define TWIDDLE 277 +#define WHILE 278 +#define WORD 279 +#define HUH 280 +const short yylhs[] = { -1, + 0, 0, 22, 22, 8, 8, 13, 13, 3, 3, + 9, 9, 4, 15, 2, 11, 11, 16, 16, 16, + 5, 5, 6, 6, 6, 19, 19, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 24, 24, 18, 18, 18, + 12, 12, 17, 17, 20, 20, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 21, 21, + 14, 14, 14, 23, 23, +}; +const short yylen[] = { 2, + 2, 2, 1, 1, 2, 2, 1, 2, 1, 2, + 1, 2, 3, 3, 3, 0, 2, 1, 2, 2, + 3, 3, 1, 2, 2, 1, 4, 0, 1, 2, + 4, 8, 6, 4, 8, 4, 4, 4, 4, 2, + 2, 3, 3, 3, 2, 0, 1, 1, 2, 2, + 1, 3, 1, 1, 1, 3, 2, 5, 2, 2, + 2, 2, 3, 3, 3, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, + 0, 2, 2, 0, 2, +}; +const short yydefred[] = { 0, + 0, 0, 0, 0, 18, 0, 79, 0, 0, 0, + 0, 0, 0, 0, 0, 67, 0, 0, 81, 0, + 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, + 3, 4, 2, 77, 75, 74, 73, 68, 71, 69, + 0, 78, 72, 76, 70, 54, 53, 55, 0, 47, + 0, 59, 60, 0, 0, 0, 84, 66, 0, 0, + 0, 0, 0, 84, 0, 0, 0, 11, 0, 0, + 62, 61, 0, 0, 30, 0, 84, 84, 84, 5, + 6, 8, 0, 0, 1, 0, 50, 0, 0, 63, + 64, 0, 44, 0, 0, 0, 0, 0, 0, 0, + 0, 79, 13, 12, 10, 65, 82, 0, 17, 0, + 0, 0, 0, 52, 56, 79, 84, 14, 85, 0, + 0, 31, 84, 0, 0, 0, 0, 0, 39, 0, + 0, 84, 0, 58, 84, 0, 0, 0, 0, 0, + 79, 0, 0, 0, 0, 0, 0, 24, 35, 25, + 22, 21, +}; +const short yydgoto[] = { 21, + 46, 22, 66, 23, 142, 143, 67, 68, 69, 47, + 75, 27, 28, 70, 57, 29, 48, 30, 122, 94, + 54, 33, 97, 51, +}; +const short yysindex[] = { 874, + 24, 1001, -82, 1001, 0, 1001, 0, -27, -26, 900, + 1001, -82, -20, -82, -26, 0, 1001, 1134, 0, 900, + 0, 1134, -203, -30, 1134, 0, -55, 24, 1134, 826, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -66, 0, 0, 0, 0, 0, 0, 0, 849, 0, + 1134, 0, 0, 900, 1001, 1134, 0, 0, -52, -52, + 1134, 1001, 1001, 0, -212, -58, 154, 0, 1134, 426, + 0, 0, -196, 1001, 0, -203, 0, 0, 0, 0, + 0, 0, 1001, 1001, 0, -196, 0, -52, 1001, 0, + 0, -196, 0, -52, -38, 36, 502, -196, -36, -52, + 502, 0, 0, 0, 0, 0, 0, -52, 0, 502, + 502, 502, -52, 0, 0, 0, 0, 0, 0, -97, + -234, 0, 0, 1001, -234, 922, -196, -196, 0, 944, + 502, 0, -9, 0, 0, -234, 502, 967, 502, -234, + 0, 967, -45, 154, 967, -234, 448, 0, 0, 0, + 0, 0, +}; +const short yyrindex[] = { 134, + 0, 0, 356, 0, 0, 0, 0, 0, 0, 0, + 0, 356, 0, 1024, 0, 0, 0, 571, 0, 0, + 0, 487, 529, 54, 134, 0, 62, 0, 487, 548, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 487, 0, 0, 712, 0, 142, 0, 0, 14, 38, + 487, 0, 0, 0, -10, 0, -32, 0, 744, 0, + 0, 0, 749, 0, 0, 529, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 763, 0, 86, 0, 0, + 0, 779, 0, 110, 0, 0, -34, 788, 0, 380, + -34, 0, 0, 0, 0, 0, 0, 470, 0, -34, + -34, -34, 404, 0, 0, 0, 0, 0, 0, 529, + 6, 0, 0, 724, 30, 0, 805, 813, 0, 0, + -34, 0, 0, 0, 0, 119, -34, 571, -34, 187, + 0, 571, 0, -44, 571, 396, 0, 0, 0, 0, + 0, 0, +}; +const short yygindex[] = { 0, + 0, 0, -23, 12, 0, -104, 1319, 2, -127, 1307, + 7, 0, 57, 0, 70, -13, 84, 0, 0, 420, + -81, 59, 369, 31, +}; +#define YYTABLESIZE 1464 +const short yytable[] = { 57, + 119, 25, 117, 28, 123, 83, 28, 81, 9, 76, + 145, 50, 55, 56, 145, 26, 87, 145, 124, 62, + 126, 58, 77, 19, 28, 57, 25, 57, 80, 57, + 57, 71, 96, 32, 130, 78, 79, 148, 84, 34, + 150, 89, 61, 26, 63, 105, 26, 20, 57, 19, + 57, 19, 58, 19, 19, 89, 18, 89, 5, 147, + 90, 102, 76, 7, 26, 93, 103, 34, 74, 11, + 34, 48, 19, 20, 79, 20, 118, 20, 20, 149, + 23, 82, 109, 57, 64, 57, 85, 52, 34, 53, + 28, 0, 9, 0, 0, 49, 20, 48, 0, 48, + 65, 48, 48, 72, 0, 0, 76, 0, 120, 19, + 0, 0, 57, 138, 57, 0, 0, 0, 0, 80, + 48, 49, 0, 49, 0, 49, 49, 0, 33, 0, + 26, 0, 91, 20, 0, 0, 19, 0, 19, 0, + 0, 0, 0, 28, 49, 80, 0, 80, 0, 80, + 80, 28, 0, 0, 34, 0, 33, 48, 0, 33, + 20, 0, 20, 104, 5, 132, 0, 114, 80, 0, + 0, 28, 115, 0, 74, 11, 0, 33, 0, 28, + 0, 49, 28, 0, 0, 0, 48, 0, 0, 0, + 0, 81, 28, 0, 0, 0, 27, 0, 0, 0, + 28, 0, 0, 0, 0, 80, 0, 0, 0, 0, + 49, 0, 80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 28, 0, 27, 0, 77, 27, 0, 28, + 116, 0, 80, 0, 80, 28, 28, 0, 0, 78, + 79, 0, 0, 33, 0, 27, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 0, 57, 57, 57, 57, 57, 26, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 31, 19, 19, + 19, 19, 19, 34, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 27, 20, 20, 20, 20, 20, 7, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, + 48, 0, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 0, + 49, 49, 49, 49, 49, 46, 80, 80, 80, 80, + 80, 0, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 33, 0, 80, 80, 80, 80, 80, 79, + 28, 46, 0, 46, 0, 46, 46, 28, 28, 0, + 0, 0, 0, 28, 28, 32, 0, 0, 0, 0, + 77, 28, 28, 15, 46, 79, 0, 79, 0, 79, + 79, 49, 0, 78, 79, 0, 0, 0, 0, 59, + 60, 0, 101, 32, 0, 107, 32, 0, 79, 15, + 0, 15, 0, 15, 15, 110, 111, 112, 0, 88, + 27, 46, 0, 0, 32, 0, 0, 151, 0, 0, + 0, 17, 15, 0, 0, 19, 106, 0, 0, 0, + 0, 0, 0, 0, 95, 79, 0, 0, 46, 83, + 46, 99, 100, 17, 0, 131, 0, 19, 0, 108, + 0, 133, 0, 59, 0, 0, 28, 0, 0, 15, + 137, 0, 113, 139, 79, 83, 152, 0, 0, 83, + 83, 119, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 20, 0, 0, 28, 0, 15, 28, 15, 0, + 0, 0, 0, 0, 0, 0, 0, 17, 16, 0, + 0, 19, 0, 20, 0, 28, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, + 0, 0, 0, 0, 0, 83, 16, 0, 0, 16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 28, 0, 0, 0, 0, 29, 0, 16, 29, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, + 0, 0, 0, 0, 0, 0, 29, 0, 28, 0, + 0, 28, 46, 46, 46, 0, 46, 46, 0, 46, + 46, 46, 46, 46, 18, 46, 46, 46, 46, 28, + 46, 46, 46, 46, 46, 0, 79, 79, 79, 79, + 79, 0, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 0, 16, 79, 79, 79, 79, 79, 32, + 15, 15, 15, 0, 15, 15, 0, 15, 15, 15, + 15, 15, 29, 15, 15, 15, 15, 0, 15, 15, + 15, 15, 15, 2, 34, 35, 4, 0, 36, 0, + 6, 37, 38, 39, 40, 28, 0, 41, 0, 0, + 42, 43, 44, 45, 16, 2, 34, 35, 4, 0, + 36, 0, 6, 37, 38, 39, 40, 0, 0, 41, + 0, 45, 42, 43, 44, 45, 16, 83, 83, 83, + 83, 0, 83, 36, 83, 83, 83, 83, 83, 0, + 0, 83, 0, 28, 83, 83, 83, 83, 83, 45, + 28, 0, 45, 28, 0, 0, 28, 28, 41, 2, + 3, 36, 4, 5, 36, 0, 6, 7, 8, 9, + 45, 0, 40, 10, 11, 0, 12, 13, 14, 15, + 16, 28, 36, 0, 28, 16, 41, 0, 42, 41, + 0, 0, 16, 0, 0, 0, 0, 43, 16, 16, + 40, 0, 28, 40, 29, 0, 0, 41, 0, 0, + 0, 29, 0, 0, 37, 0, 42, 29, 29, 42, + 0, 40, 38, 0, 0, 43, 0, 28, 43, 0, + 0, 0, 0, 0, 0, 0, 45, 42, 0, 0, + 28, 28, 37, 0, 0, 37, 43, 0, 36, 0, + 38, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 17, 0, 37, 0, 19, 0, 0, 28, 0, + 0, 38, 0, 41, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 40, 19, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 42, 0, 0, 0, 0, 0, 17, + 0, 0, 43, 19, 0, 0, 0, 0, 0, 0, + 0, 20, 0, 0, 0, 0, 0, 0, 0, 37, + 0, 0, 0, 0, 0, 17, 0, 38, 0, 19, + 0, 0, 89, 0, 20, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, + 0, 19, 134, 0, 0, 0, 0, 0, 45, 20, + 0, 18, 0, 0, 0, 45, 0, 0, 0, 17, + 36, 45, 45, 19, 135, 0, 0, 36, 0, 0, + 0, 0, 0, 36, 36, 20, 18, 0, 0, 0, + 28, 0, 17, 0, 0, 41, 19, 0, 0, 0, + 0, 0, 41, 28, 28, 0, 0, 20, 41, 40, + 0, 0, 18, 0, 0, 0, 40, 0, 0, 0, + 0, 0, 40, 0, 0, 42, 17, 0, 0, 20, + 19, 0, 42, 0, 43, 0, 0, 0, 42, 0, + 0, 43, 0, 0, 0, 0, 0, 43, 0, 46, + 0, 37, 20, 46, 0, 0, 0, 0, 37, 38, + 0, 0, 0, 0, 37, 0, 38, 0, 0, 0, + 0, 0, 38, 2, 34, 35, 4, 5, 36, 18, + 6, 37, 38, 39, 40, 0, 20, 10, 11, 0, + 42, 43, 44, 45, 16, 0, 2, 34, 35, 4, + 0, 36, 0, 6, 37, 38, 39, 40, 0, 46, + 41, 0, 0, 42, 43, 44, 45, 16, 0, 1, + 0, 2, 3, 0, 4, 5, 0, 0, 6, 7, + 8, 9, 0, 0, 0, 10, 11, 0, 12, 13, + 14, 15, 16, 0, 0, 0, 0, 2, 34, 35, + 4, 0, 36, 0, 6, 37, 38, 39, 40, 17, + 0, 41, 0, 19, 42, 43, 44, 45, 16, 2, + 34, 35, 4, 0, 36, 0, 6, 37, 38, 39, + 40, 0, 0, 41, 0, 0, 42, 43, 44, 45, + 16, 2, 34, 35, 4, 0, 36, 0, 6, 37, + 38, 39, 40, 0, 0, 41, 0, 0, 42, 43, + 44, 45, 16, 0, 2, 3, 141, 4, 5, 20, + 0, 6, 7, 8, 9, 0, 0, 0, 10, 11, + 0, 12, 13, 14, 15, 16, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 18, 0, 2, 34, + 35, 4, 0, 36, 0, 6, 37, 38, 39, 40, + 0, 0, 41, 0, 0, 42, 43, 44, 45, 16, + 0, 46, 46, 46, 46, 0, 46, 0, 46, 46, + 46, 46, 46, 0, 0, 46, 0, 0, 46, 46, + 46, 46, 46, 0, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, + 0, 0, 0, 0, 26, 0, 0, 0, 26, 0, + 0, 26, 0, 0, 0, 26, 0, 0, 0, 0, + 73, 0, 0, 24, 0, 0, 0, 86, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, + 0, 0, 26, 0, 0, 0, 0, 26, 0, 92, + 0, 0, 0, 0, 0, 26, 0, 0, 0, 98, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 3, 0, 4, 5, 0, 0, 6, 7, + 8, 9, 0, 26, 0, 10, 11, 26, 12, 13, + 14, 15, 16, 0, 0, 121, 26, 26, 26, 125, + 0, 0, 0, 0, 0, 0, 0, 0, 127, 128, + 129, 0, 0, 0, 0, 0, 0, 26, 0, 0, + 0, 0, 0, 26, 26, 26, 0, 0, 26, 136, + 0, 26, 0, 0, 0, 140, 144, 146, 0, 0, + 144, 0, 0, 144, +}; +const short yycheck[] = { 10, + 10, 0, 41, 38, 41, 61, 41, 38, 41, 23, + 138, 94, 40, 40, 142, 10, 30, 145, 100, 40, + 102, 10, 257, 10, 59, 36, 25, 38, 59, 40, + 41, 20, 56, 10, 116, 270, 271, 142, 94, 10, + 145, 94, 12, 38, 14, 69, 41, 10, 59, 36, + 61, 38, 41, 40, 41, 94, 123, 94, 262, 141, + 49, 274, 76, 10, 59, 54, 125, 38, 272, 273, + 41, 10, 59, 36, 271, 38, 41, 40, 41, 125, + 125, 25, 76, 94, 15, 96, 28, 4, 59, 6, + 125, -1, 125, -1, -1, 10, 59, 36, -1, 38, + 17, 40, 41, 20, -1, -1, 120, -1, 97, 96, + -1, -1, 123, 123, 125, -1, -1, -1, -1, 10, + 59, 36, -1, 38, -1, 40, 41, -1, 10, -1, + 125, -1, 49, 96, -1, -1, 123, -1, 125, -1, + -1, -1, -1, 10, 59, 36, -1, 38, -1, 40, + 41, 10, -1, -1, 125, -1, 38, 96, -1, 41, + 123, -1, 125, 10, 262, 263, -1, 84, 59, -1, + -1, 38, 89, -1, 272, 273, -1, 59, -1, 38, + -1, 96, 41, -1, -1, -1, 125, -1, -1, -1, + -1, 38, 59, -1, -1, -1, 10, -1, -1, -1, + 59, -1, -1, -1, -1, 96, -1, -1, -1, -1, + 125, -1, 59, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 257, -1, 38, -1, 257, 41, -1, 264, + 269, -1, 123, -1, 125, 270, 271, -1, -1, 270, + 271, -1, -1, 125, -1, 59, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, -1, 275, 276, 277, 278, 279, 264, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 264, 275, 276, + 277, 278, 279, 264, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 125, 275, 276, 277, 278, 279, 264, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, -1, 275, 276, 277, 278, + 279, -1, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, -1, + 275, 276, 277, 278, 279, 10, 257, 258, 259, 260, + 261, -1, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 264, -1, 275, 276, 277, 278, 279, 10, + 257, 36, -1, 38, -1, 40, 41, 264, 257, -1, + -1, -1, -1, 270, 271, 10, -1, -1, -1, -1, + 257, 270, 271, 10, 59, 36, -1, 38, -1, 40, + 41, 2, -1, 270, 271, -1, -1, -1, -1, 10, + 11, -1, 64, 38, -1, 10, 41, -1, 59, 36, + -1, 38, -1, 40, 41, 77, 78, 79, -1, 30, + 264, 96, -1, -1, 59, -1, -1, 10, -1, -1, + -1, 36, 59, -1, -1, 40, 41, -1, -1, -1, + -1, -1, -1, -1, 55, 96, -1, -1, 123, 10, + 125, 62, 63, 36, -1, 117, -1, 40, -1, 70, + -1, 123, -1, 74, -1, -1, 10, -1, -1, 96, + 132, -1, 83, 135, 125, 36, 59, -1, -1, 40, + 41, 10, -1, -1, -1, -1, -1, -1, -1, -1, + 125, 96, -1, -1, 38, -1, 123, 41, 125, -1, + -1, -1, -1, -1, -1, -1, -1, 36, 10, -1, + -1, 40, -1, 96, -1, 59, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, + -1, -1, -1, -1, -1, 96, 38, -1, -1, 41, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 10, -1, -1, -1, -1, 38, -1, 59, 41, -1, + -1, -1, -1, -1, -1, -1, -1, 96, -1, -1, + -1, -1, -1, -1, -1, -1, 59, -1, 38, -1, + -1, 125, 257, 258, 259, -1, 261, 262, -1, 264, + 265, 266, 267, 268, 123, 270, 271, 272, 273, 59, + 275, 276, 277, 278, 279, -1, 257, 258, 259, 260, + 261, -1, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, -1, 125, 275, 276, 277, 278, 279, 264, + 257, 258, 259, -1, 261, 262, -1, 264, 265, 266, + 267, 268, 125, 270, 271, 272, 273, -1, 275, 276, + 277, 278, 279, 258, 259, 260, 261, -1, 263, -1, + 265, 266, 267, 268, 269, 125, -1, 272, -1, -1, + 275, 276, 277, 278, 279, 258, 259, 260, 261, -1, + 263, -1, 265, 266, 267, 268, 269, -1, -1, 272, + -1, 10, 275, 276, 277, 278, 279, 258, 259, 260, + 261, -1, 263, 10, 265, 266, 267, 268, 269, -1, + -1, 272, -1, 257, 275, 276, 277, 278, 279, 38, + 264, -1, 41, 10, -1, -1, 270, 271, 10, 258, + 259, 38, 261, 262, 41, -1, 265, 266, 267, 268, + 59, -1, 10, 272, 273, -1, 275, 276, 277, 278, + 279, 38, 59, -1, 41, 257, 38, -1, 10, 41, + -1, -1, 264, -1, -1, -1, -1, 10, 270, 271, + 38, -1, 59, 41, 257, -1, -1, 59, -1, -1, + -1, 264, -1, -1, 10, -1, 38, 270, 271, 41, + -1, 59, 10, -1, -1, 38, -1, 257, 41, -1, + -1, -1, -1, -1, -1, -1, 125, 59, -1, -1, + 270, 271, 38, -1, -1, 41, 59, -1, 125, -1, + 38, -1, -1, 41, -1, -1, -1, -1, -1, -1, + -1, 36, -1, 59, -1, 40, -1, -1, 125, -1, + -1, 59, -1, 125, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 36, -1, -1, 125, 40, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 125, -1, -1, -1, -1, -1, 36, + -1, -1, 125, 40, -1, -1, -1, -1, -1, -1, + -1, 96, -1, -1, -1, -1, -1, -1, -1, 125, + -1, -1, -1, -1, -1, 36, -1, 125, -1, 40, + -1, -1, 94, -1, 96, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, + -1, 40, 41, -1, -1, -1, -1, -1, 257, 96, + -1, 123, -1, -1, -1, 264, -1, -1, -1, 36, + 257, 270, 271, 40, 41, -1, -1, 264, -1, -1, + -1, -1, -1, 270, 271, 96, 123, -1, -1, -1, + 257, -1, 36, -1, -1, 257, 40, -1, -1, -1, + -1, -1, 264, 270, 271, -1, -1, 96, 270, 257, + -1, -1, 123, -1, -1, -1, 264, -1, -1, -1, + -1, -1, 270, -1, -1, 257, 36, -1, -1, 96, + 40, -1, 264, -1, 257, -1, -1, -1, 270, -1, + -1, 264, -1, -1, -1, -1, -1, 270, -1, 36, + -1, 257, 96, 40, -1, -1, -1, -1, 264, 257, + -1, -1, -1, -1, 270, -1, 264, -1, -1, -1, + -1, -1, 270, 258, 259, 260, 261, 262, 263, 123, + 265, 266, 267, 268, 269, -1, 96, 272, 273, -1, + 275, 276, 277, 278, 279, -1, 258, 259, 260, 261, + -1, 263, -1, 265, 266, 267, 268, 269, -1, 96, + 272, -1, -1, 275, 276, 277, 278, 279, -1, 256, + -1, 258, 259, -1, 261, 262, -1, -1, 265, 266, + 267, 268, -1, -1, -1, 272, 273, -1, 275, 276, + 277, 278, 279, -1, -1, -1, -1, 258, 259, 260, + 261, -1, 263, -1, 265, 266, 267, 268, 269, 36, + -1, 272, -1, 40, 275, 276, 277, 278, 279, 258, + 259, 260, 261, -1, 263, -1, 265, 266, 267, 268, + 269, -1, -1, 272, -1, -1, 275, 276, 277, 278, + 279, 258, 259, 260, 261, -1, 263, -1, 265, 266, + 267, 268, 269, -1, -1, 272, -1, -1, 275, 276, + 277, 278, 279, -1, 258, 259, 260, 261, 262, 96, + -1, 265, 266, 267, 268, -1, -1, -1, 272, 273, + -1, 275, 276, 277, 278, 279, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 123, -1, 258, 259, + 260, 261, -1, 263, -1, 265, 266, 267, 268, 269, + -1, -1, 272, -1, -1, 275, 276, 277, 278, 279, + -1, 258, 259, 260, 261, -1, 263, -1, 265, 266, + 267, 268, 269, -1, -1, 272, -1, -1, 275, 276, + 277, 278, 279, -1, -1, -1, 0, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, + -1, -1, -1, -1, 18, -1, -1, -1, 22, -1, + -1, 25, -1, -1, -1, 29, -1, -1, -1, -1, + 22, -1, -1, 25, -1, -1, -1, 29, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 51, -1, -1, + -1, -1, 56, -1, -1, -1, -1, 61, -1, 51, + -1, -1, -1, -1, -1, 69, -1, -1, -1, 61, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 258, 259, -1, 261, 262, -1, -1, 265, 266, + 267, 268, -1, 97, -1, 272, 273, 101, 275, 276, + 277, 278, 279, -1, -1, 97, 110, 111, 112, 101, + -1, -1, -1, -1, -1, -1, -1, -1, 110, 111, + 112, -1, -1, -1, -1, -1, -1, 131, -1, -1, + -1, -1, -1, 137, 138, 139, -1, -1, 142, 131, + -1, 145, -1, -1, -1, 137, 138, 139, -1, -1, + 142, -1, -1, 145, +}; +#define YYFINAL 21 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 280 +#if YYDEBUG +const char * const yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,"'$'",0,"'&'",0,"'('","')'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"';'",0, +"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'^'",0, +"'`'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,"ANDAND","BACKBACK","BANG","CASE","COUNT","DUP","ELSE","END", +"FLAT","FN","FOR","IF","IN","OROR","PIPE","REDIR","SREDIR","SUB","SUBSHELL", +"SWITCH","TWIDDLE","WHILE","WORD","HUH", +}; +const char * const yyrule[] = { +"$accept : rc", +"rc : line end", +"rc : error end", +"end : END", +"end : '\\n'", +"cmdsa : cmd ';'", +"cmdsa : cmd '&'", +"line : cmd", +"line : cmdsa line", +"body : cmd", +"body : cmdsan body", +"cmdsan : cmdsa", +"cmdsan : cmd '\\n'", +"brace : '{' body '}'", +"paren : '(' body ')'", +"assign : first '=' word", +"epilog :", +"epilog : redir epilog", +"redir : DUP", +"redir : REDIR word", +"redir : SREDIR word", +"case : CASE words ';'", +"case : CASE words '\\n'", +"cbody : cmd", +"cbody : case cbody", +"cbody : cmdsan cbody", +"iftail : cmd", +"iftail : brace ELSE optnl cmd", +"cmd :", +"cmd : simple", +"cmd : brace epilog", +"cmd : IF paren optnl iftail", +"cmd : FOR '(' word IN words ')' optnl cmd", +"cmd : FOR '(' word ')' optnl cmd", +"cmd : WHILE paren optnl cmd", +"cmd : SWITCH '(' word ')' optnl '{' cbody '}'", +"cmd : TWIDDLE optcaret word words", +"cmd : cmd ANDAND optnl cmd", +"cmd : cmd OROR optnl cmd", +"cmd : cmd PIPE optnl cmd", +"cmd : redir cmd", +"cmd : assign cmd", +"cmd : BANG optcaret cmd", +"cmd : SUBSHELL optcaret cmd", +"cmd : FN words brace", +"cmd : FN words", +"optcaret :", +"optcaret : '^'", +"simple : first", +"simple : simple word", +"simple : simple redir", +"first : comword", +"first : first '^' sword", +"sword : comword", +"sword : keyword", +"word : sword", +"word : word '^' sword", +"comword : '$' sword", +"comword : '$' sword SUB words ')'", +"comword : COUNT sword", +"comword : FLAT sword", +"comword : '`' sword", +"comword : '`' brace", +"comword : BACKBACK word brace", +"comword : BACKBACK word sword", +"comword : '(' nlwords ')'", +"comword : REDIR brace", +"comword : WORD", +"keyword : FOR", +"keyword : IN", +"keyword : WHILE", +"keyword : IF", +"keyword : SWITCH", +"keyword : FN", +"keyword : ELSE", +"keyword : CASE", +"keyword : TWIDDLE", +"keyword : BANG", +"keyword : SUBSHELL", +"words :", +"words : words word", +"nlwords :", +"nlwords : nlwords '\\n'", +"nlwords : nlwords word", +"optnl :", +"optnl : optnl '\\n'", +}; +#endif +#if YYDEBUG +#include <stdio.h> +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 10000 +#define YYMAXDEPTH 10000 +#endif +#endif +#define YYINITSTACKSIZE 200 +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short *yyss; +short *yysslim; +YYSTYPE *yyvs; +int yystacksize; +#line 167 "parse.y" + +void initparse() { + star = treecpy(mk(nVar, mk(nWord,"*", NULL, FALSE)), ealloc); + nolist = treecpy(mk(nVar, mk(nWord,"ifs", NULL, FALSE)), ealloc); +} + +#line 583 "y.tab.c" +/* allocate initial stack or double stack size, up to YYMAXDEPTH */ +static int yygrowstack() +{ + int newsize, i; + short *newss; + YYSTYPE *newvs; + + if ((newsize = yystacksize) == 0) + newsize = YYINITSTACKSIZE; + else if (newsize >= YYMAXDEPTH) + return -1; + else if ((newsize *= 2) > YYMAXDEPTH) + newsize = YYMAXDEPTH; + i = yyssp - yyss; + newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) : + (short *)malloc(newsize * sizeof *newss); + if (newss == NULL) + return -1; + yyss = newss; + yyssp = newss + i; + newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) : + (YYSTYPE *)malloc(newsize * sizeof *newvs); + if (newvs == NULL) + return -1; + yyvs = newvs; + yyvsp = newvs + i; + yystacksize = newsize; + yysslim = yyss + newsize - 1; + return 0; +} + +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab + +#ifndef YYPARSE_PARAM +#if defined(__cplusplus) || __STDC__ +#define YYPARSE_PARAM_ARG void +#define YYPARSE_PARAM_DECL +#else /* ! ANSI-C/C++ */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* ANSI-C/C++ */ +#else /* YYPARSE_PARAM */ +#ifndef YYPARSE_PARAM_TYPE +#define YYPARSE_PARAM_TYPE void * +#endif +#if defined(__cplusplus) || __STDC__ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM_TYPE YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* ! ANSI-C/C++ */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL YYPARSE_PARAM_TYPE YYPARSE_PARAM; +#endif /* ANSI-C/C++ */ +#endif /* ! YYPARSE_PARAM */ + +int +yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int yym, yyn, yystate; +#if YYDEBUG + register const char *yys; + + if ((yys = getenv("YYDEBUG"))) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + if (yyss == NULL && yygrowstack()) goto yyoverflow; + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if ((yyn = yydefred[yystate])) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#if defined(lint) || defined(__GNUC__) + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#if defined(lint) || defined(__GNUC__) + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 1: +#line 47 "parse.y" +{ parsetree = yyvsp[-1].node; YYACCEPT; } +break; +case 2: +#line 48 "parse.y" +{ yyerrok; parsetree = NULL; YYABORT; } +break; +case 3: +#line 51 "parse.y" +{ if (!heredoc(1)) YYABORT; } +break; +case 4: +#line 52 "parse.y" +{ if (!heredoc(0)) YYABORT; } +break; +case 6: +#line 56 "parse.y" +{ yyval.node = (yyvsp[-1].node != NULL ? mk(nNowait,yyvsp[-1].node) : yyvsp[-1].node); } +break; +case 8: +#line 60 "parse.y" +{ yyval.node = (yyvsp[-1].node != NULL ? mk(nBody,yyvsp[-1].node,yyvsp[0].node) : yyvsp[0].node); } +break; +case 10: +#line 64 "parse.y" +{ yyval.node = (yyvsp[-1].node == NULL ? yyvsp[0].node : yyvsp[0].node == NULL ? yyvsp[-1].node : mk(nBody,yyvsp[-1].node,yyvsp[0].node)); } +break; +case 12: +#line 67 "parse.y" +{ yyval.node = yyvsp[-1].node; if (!heredoc(0)) YYABORT; } +break; +case 13: +#line 69 "parse.y" +{ yyval.node = yyvsp[-1].node; } +break; +case 14: +#line 71 "parse.y" +{ yyval.node = yyvsp[-1].node; } +break; +case 15: +#line 73 "parse.y" +{ yyval.node = mk(nAssign,yyvsp[-2].node,yyvsp[0].node); } +break; +case 16: +#line 75 "parse.y" +{ yyval.node = NULL; } +break; +case 17: +#line 76 "parse.y" +{ yyval.node = mk(nEpilog,yyvsp[-1].node,yyvsp[0].node); } +break; +case 18: +#line 79 "parse.y" +{ yyval.node = mk(nDup,yyvsp[0].dup.type,yyvsp[0].dup.left,yyvsp[0].dup.right); } +break; +case 19: +#line 80 "parse.y" +{ yyval.node = mk(nRedir,yyvsp[-1].redir.type,yyvsp[-1].redir.fd,yyvsp[0].node); + if (yyvsp[-1].redir.type == rHeredoc && !qdoc(yyvsp[0].node, yyval.node)) YYABORT; /* queue heredocs up */ + } +break; +case 20: +#line 83 "parse.y" +{ yyval.node = mk(nRedir,yyvsp[-1].redir.type,yyvsp[-1].redir.fd,yyvsp[0].node); + if (yyvsp[-1].redir.type == rHeredoc && !qdoc(yyvsp[0].node, yyval.node)) YYABORT; /* queue heredocs up */ + } +break; +case 21: +#line 87 "parse.y" +{ yyval.node = mk(nCase, yyvsp[-1].node); } +break; +case 22: +#line 88 "parse.y" +{ yyval.node = mk(nCase, yyvsp[-1].node); } +break; +case 23: +#line 90 "parse.y" +{ yyval.node = mk(nCbody, yyvsp[0].node, NULL); } +break; +case 24: +#line 91 "parse.y" +{ yyval.node = mk(nCbody, yyvsp[-1].node, yyvsp[0].node); } +break; +case 25: +#line 92 "parse.y" +{ yyval.node = mk(nCbody, yyvsp[-1].node, yyvsp[0].node); } +break; +case 27: +#line 95 "parse.y" +{ yyval.node = mk(nElse,yyvsp[-3].node,yyvsp[0].node); } +break; +case 28: +#line 97 "parse.y" +{ yyval.node = NULL; } +break; +case 30: +#line 99 "parse.y" +{ yyval.node = mk(nBrace,yyvsp[-1].node,yyvsp[0].node); } +break; +case 31: +#line 100 "parse.y" +{ yyval.node = mk(nIf,yyvsp[-2].node,yyvsp[0].node); } +break; +case 32: +#line 101 "parse.y" +{ yyval.node = mk(nForin,yyvsp[-5].node,yyvsp[-3].node,yyvsp[0].node); } +break; +case 33: +#line 102 "parse.y" +{ yyval.node = mk(nForin,yyvsp[-3].node,star,yyvsp[0].node); } +break; +case 34: +#line 103 "parse.y" +{ yyval.node = mk(nWhile,yyvsp[-2].node,yyvsp[0].node); } +break; +case 35: +#line 104 "parse.y" +{ yyval.node = mk(nSwitch,yyvsp[-5].node,yyvsp[-1].node); } +break; +case 36: +#line 105 "parse.y" +{ yyval.node = mk(nMatch,yyvsp[-1].node,yyvsp[0].node); } +break; +case 37: +#line 106 "parse.y" +{ yyval.node = mk(nAndalso,yyvsp[-3].node,yyvsp[0].node); } +break; +case 38: +#line 107 "parse.y" +{ yyval.node = mk(nOrelse,yyvsp[-3].node,yyvsp[0].node); } +break; +case 39: +#line 108 "parse.y" +{ yyval.node = mk(nPipe,yyvsp[-2].pipe.left,yyvsp[-2].pipe.right,yyvsp[-3].node,yyvsp[0].node); } +break; +case 40: +#line 109 "parse.y" +{ yyval.node = (yyvsp[0].node != NULL ? mk(nPre,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node); } +break; +case 41: +#line 110 "parse.y" +{ yyval.node = (yyvsp[0].node != NULL ? mk(nPre,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node); } +break; +case 42: +#line 111 "parse.y" +{ yyval.node = mk(nBang,yyvsp[0].node); } +break; +case 43: +#line 112 "parse.y" +{ yyval.node = mk(nSubshell,yyvsp[0].node); } +break; +case 44: +#line 113 "parse.y" +{ yyval.node = mk(nNewfn,yyvsp[-1].node,yyvsp[0].node); } +break; +case 45: +#line 114 "parse.y" +{ yyval.node = mk(nRmfn,yyvsp[0].node); } +break; +case 49: +#line 120 "parse.y" +{ yyval.node = (yyvsp[0].node != NULL ? mk(nArgs,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node); } +break; +case 50: +#line 121 "parse.y" +{ yyval.node = mk(nArgs,yyvsp[-1].node,yyvsp[0].node); } +break; +case 52: +#line 124 "parse.y" +{ yyval.node = mk(nConcat,yyvsp[-2].node,yyvsp[0].node); } +break; +case 54: +#line 127 "parse.y" +{ yyval.node = mk(nWord, yyvsp[0].keyword, NULL, FALSE); } +break; +case 56: +#line 130 "parse.y" +{ yyval.node = mk(nConcat,yyvsp[-2].node,yyvsp[0].node); } +break; +case 57: +#line 132 "parse.y" +{ yyval.node = mk(nVar,yyvsp[0].node); } +break; +case 58: +#line 133 "parse.y" +{ yyval.node = mk(nVarsub,yyvsp[-3].node,yyvsp[-1].node); } +break; +case 59: +#line 134 "parse.y" +{ yyval.node = mk(nCount,yyvsp[0].node); } +break; +case 60: +#line 135 "parse.y" +{ yyval.node = mk(nFlat, yyvsp[0].node); } +break; +case 61: +#line 136 "parse.y" +{ yyval.node = mk(nBackq,nolist,yyvsp[0].node); } +break; +case 62: +#line 137 "parse.y" +{ yyval.node = mk(nBackq,nolist,yyvsp[0].node); } +break; +case 63: +#line 138 "parse.y" +{ yyval.node = mk(nBackq,yyvsp[-1].node,yyvsp[0].node); } +break; +case 64: +#line 139 "parse.y" +{ yyval.node = mk(nBackq,yyvsp[-1].node,yyvsp[0].node); } +break; +case 65: +#line 140 "parse.y" +{ yyval.node = yyvsp[-1].node; } +break; +case 66: +#line 141 "parse.y" +{ yyval.node = mk(nNmpipe,yyvsp[-1].redir.type,yyvsp[-1].redir.fd,yyvsp[0].node); } +break; +case 67: +#line 142 "parse.y" +{ yyval.node = mk(nWord, yyvsp[0].word.w, yyvsp[0].word.m, yyvsp[0].word.q); } +break; +case 68: +#line 144 "parse.y" +{ yyval.keyword = "for"; } +break; +case 69: +#line 145 "parse.y" +{ yyval.keyword = "in"; } +break; +case 70: +#line 146 "parse.y" +{ yyval.keyword = "while"; } +break; +case 71: +#line 147 "parse.y" +{ yyval.keyword = "if"; } +break; +case 72: +#line 148 "parse.y" +{ yyval.keyword = "switch"; } +break; +case 73: +#line 149 "parse.y" +{ yyval.keyword = "fn"; } +break; +case 74: +#line 150 "parse.y" +{ yyval.keyword = "else"; } +break; +case 75: +#line 151 "parse.y" +{ yyval.keyword = "case"; } +break; +case 76: +#line 152 "parse.y" +{ yyval.keyword = "~"; } +break; +case 77: +#line 153 "parse.y" +{ yyval.keyword = "!"; } +break; +case 78: +#line 154 "parse.y" +{ yyval.keyword = "@"; } +break; +case 79: +#line 156 "parse.y" +{ yyval.node = NULL; } +break; +case 80: +#line 157 "parse.y" +{ yyval.node = (yyvsp[-1].node != NULL ? (yyvsp[0].node != NULL ? mk(nLappend,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node) : yyvsp[0].node); } +break; +case 81: +#line 159 "parse.y" +{ yyval.node = NULL; } +break; +case 83: +#line 161 "parse.y" +{ yyval.node = (yyvsp[-1].node != NULL ? (yyvsp[0].node != NULL ? mk(nLappend,yyvsp[-1].node,yyvsp[0].node) : yyvsp[-1].node) : yyvsp[0].node); } +break; +#line 1062 "y.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/parse.h b/parse.h @@ -0,0 +1,37 @@ +#ifndef YYERRCODE +#define YYERRCODE 256 +#endif + +#define ANDAND 257 +#define BACKBACK 258 +#define BANG 259 +#define CASE 260 +#define COUNT 261 +#define DUP 262 +#define ELSE 263 +#define END 264 +#define FLAT 265 +#define FN 266 +#define FOR 267 +#define IF 268 +#define IN 269 +#define OROR 270 +#define PIPE 271 +#define REDIR 272 +#define SREDIR 273 +#define SUB 274 +#define SUBSHELL 275 +#define SWITCH 276 +#define TWIDDLE 277 +#define WHILE 278 +#define WORD 279 +#define HUH 280 +typedef union { + struct Node *node; + struct Redir redir; + struct Pipe pipe; + struct Dup dup; + struct Word word; + char *keyword; +} YYSTYPE; +extern YYSTYPE yylval; diff --git a/random.pl b/random.pl @@ -0,0 +1,15 @@ +#! /usr/bin/perl + +$count = 10; +$size = rand(1000); + +for ($i = 0; $i < $count; ++$i) { + open OUT, "> t$i" or die; + for ($j = 0; $j < $size; ++$j) { + printf OUT "%c", rand(256); + } + close OUT; + $cmd = "./rc t$i"; + print $cmd, "\n"; + system $cmd; +} diff --git a/rc.1 b/rc.1 @@ -161,7 +161,7 @@ .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" .if "\\$4"" \\$3\fR\s10 .. -.TH RC 1 "2003-07-17" +.TH RC 1 "2014-09-01" .SH NAME rc \- shell .SH SYNOPSIS @@ -2056,8 +2056,15 @@ The .Cr limit builtin silently ignores extra arguments. .PP +Backquote substitution never produces empty strings - multiple +consecutive occurrences of the separator are treated the same as a +single occurrence. +.Ds +.Cr "ifs=! { x = `{echo -n a!!b}; whatis x }" +.Cr "x=(a b) # NOT x=(a '' b)" +.PP Bug reports should be mailed to -.Cr "<tjg@star.le.ac.uk>" . +.Cr "<toby@paccrat.org>" . .SH INCOMPATIBILITIES Here is a list of features which distinguish this incarnation of .I rc @@ -2143,7 +2150,7 @@ Unix Research System, Tenth Edition, Volume 2. (Saunders College Publishing) .PP -.Cr http://www.star.le.ac.uk/~tjg/rc/misc/td , +.Cr http://static.tobold.org/rc/rc-duff.html , an updated version of the above paper. .PP .IR history (1) diff --git a/rc.h b/rc.h @@ -4,6 +4,10 @@ #include <assert.h> +#define RC "rc: " + +#include <assert.h> + /* datatypes */ #define ENV_SEP '\001' @@ -46,10 +50,6 @@ typedef enum bool { FALSE, TRUE } bool; -typedef enum inputtype { - iFd, iString -} inputtype; - typedef enum redirtype { rFrom, rCreate, rAppend, rHeredoc, rHerestring } redirtype; @@ -128,7 +128,7 @@ struct Format { /* for the formatting routines */ va_list args; long flags, f1, f2; - /* for the buffer maintainence routines */ + /* for the buffer maintenance routines */ char *buf, *bufbegin, *bufend; int flushed; void (*grow)(Format *, size_t); @@ -172,8 +172,7 @@ enum { /* main.c */ extern Rq *redirq; -extern bool dashdee, dashee, dashvee, dashex, dashell, - dasheye, dashen, dashpee, interactive; +extern bool dashdee, dashee, dashvee, dashex, dasheye, dashen, dashpee, interactive; extern pid_t rc_pid; extern int lineno; @@ -265,23 +264,6 @@ extern int heredoc(int); extern int qdoc(Node *, Node *); extern Hq *hq; - -/* input.c */ -extern void initinput(void); -extern Node *parseline(char *); -extern int gchar(void); -extern void ugchar(int); -extern Node *doit(bool); -extern void flushu(void); -extern void print_prompt2(void); -extern void pushfd(int); -extern void pushstring(char **, bool); -extern void popinput(void); -extern void closefds(void); -extern int lastchar; -extern bool rcrc; - - /* lex.c */ extern bool quotep(char *, bool); extern int yylex(void); @@ -344,38 +326,8 @@ extern int yyparse(void); extern void initparse(void); /* readline */ - -#if READLINE - -/* Including the real readline .h files is too complicated, so we just -declare what we actually use. */ - -extern void add_history(char *); -extern char *readline(char *); -extern int rl_clear_signals(void); -extern int rl_pending_input; -extern int rl_reset_terminal(char *); - -#if READLINE_OLD -extern void rl_clean_up_for_exit(void); -extern void rl_deprep_terminal(void); -#else -extern void _rl_clean_up_for_exit(void); -extern void (*rl_deprep_term_function)(void); -#endif - -extern char *rc_readline(char *); - extern volatile sig_atomic_t rl_active; extern struct Jbwrap rl_buf; -#endif - -#if EDITLINE -extern char *readline(char *); -extern void add_history(char *); -#define rc_readline readline -#endif - /* redir.c */ extern void doredirs(void); @@ -386,6 +338,7 @@ extern void initsignal(void); extern void catcher(int); extern void sigchk(void); extern void (*rc_signal(int, void (*)(int)))(int); +extern void (*sys_signal(int, void (*)(int)))(int); extern void (*sighandlers[])(int); diff --git a/rc.spec b/rc.spec @@ -0,0 +1,31 @@ +%define name rc +%define version 1.7.1 +%define release 1 + +Summary: rc - the Plan 9 and Tenth Edition shell +Name: %name +Version: %version +Release: %release +Group: Shells +License: distributable +Source0: http://www.libra-aries-books.co.uk/software/rc/release/%name-%version.tar.gz +Buildroot: /var/tmp/%{name}-rpmroot + +%description +This is a reimplementation for Unix, by Byron Rakitzis, of the Plan 9 +shell. rc offers much the same capabilities as a traditional Bourne +shell, but with a much cleaner syntax. + +%prep +%setup + +%build +sh configure --with-readline --prefix "$RPM_BUILD_ROOT" --mandir "$RPM_BUILD_ROOT/usr/share/man" +make + +%install +make install + +%files +/bin/rc +/usr/share/man/man1/rc.1.gz diff --git a/signal.c b/signal.c @@ -9,7 +9,7 @@ #include "jbwrap.h" #if HAVE_SIGACTION -static void (*sys_signal(int signum, void (*handler)(int)))(int) { +void (*sys_signal(int signum, void (*handler)(int)))(int) { struct sigaction new, old; new.sa_handler = handler; @@ -19,7 +19,9 @@ static void (*sys_signal(int signum, void (*handler)(int)))(int) { return old.sa_handler; } #else -#define sys_signal(sig, func) (signal((sig), (func))) +void (*sys_signal(int signum, void (*handler)(int)))(int) { + return signal(signum, handler); +} #endif void (*sighandlers[NUMOFSIGNALS])(int); @@ -33,11 +35,6 @@ extern void catcher(int s) { } sys_signal(s, catcher); -#if READLINE - if (rl_active) - siglongjmp(rl_buf.j, s); -#endif /* READLINE */ - #if HAVE_RESTARTABLE_SYSCALLS if (slow) { siglongjmp(slowbuf.j, s); @@ -73,13 +70,11 @@ extern void (*rc_signal(int s, void (*h)(int)))(int) { void (*old)(int); sigchk(); old = sighandlers[s]; - if (h == SIG_DFL || h == SIG_IGN) { - sighandlers[s] = h; + sighandlers[s] = h; + if (h == SIG_DFL || h == SIG_IGN) sys_signal(s, h); - } else { - sighandlers[s] = h; + else sys_signal(s, catcher); - } return old; } diff --git a/slow b/slow @@ -0,0 +1,11 @@ +for (i in 0 1 2 3 4 5 6 7 8 9) { + x=() + y=() + for (j in 0 1 2 3 4 5 6 7 8 9) + for (k in 0 1 2 3 4 5 6 7 8 9) + for (l in 0 1 2 3 4 5 6 7 8 9) { + x = $x^. + y = ($y $x) + } + echo $#y +} diff --git a/stamp-h b/stamp-h @@ -0,0 +1 @@ +timestamp diff --git a/stamp-h.in b/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/testcld.c b/testcld.c @@ -0,0 +1,19 @@ +#include <errno.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +int main(void) { + int i; + sigset(SIGCLD, SIG_IGN); + switch (fork()) { + case -1: + return 1; + case 0: + return 0; + default: + sleep(1); + if (wait(&i) == -1 && errno == ECHILD) return 0; + else return 1; + } +} diff --git a/tmp b/tmp @@ -0,0 +1,2 @@ +x=('#' '#' '#') +eval z^`{whatis -v x} >[2]/dev/null diff --git a/tree.c b/tree.c @@ -81,7 +81,7 @@ extern Node *treecpy(Node *s, void *(*alloc)(size_t)) { n->u[2].i = s->u[2].i; break; case nWord: - n = (*alloc)(offsetof(Node, u[2])); + n = (*alloc)(offsetof(Node, u[3])); n->u[0].s = strcpy((char *) (*alloc)(strlen(s->u[0].s) + 1), s->u[0].s); if (s->u[1].s != NULL) { size_t i = strlen(s->u[0].s); @@ -89,6 +89,7 @@ extern Node *treecpy(Node *s, void *(*alloc)(size_t)) { memcpy(n->u[1].s, s->u[1].s, i); } else n->u[1].s = NULL; + n->u[2].i = s->u[2].i; break; case nBang: case nNowait: case nCase: case nCount: case nFlat: case nRmfn: case nSubshell: case nVar: diff --git a/trip.rc b/trip.rc @@ -4,9 +4,10 @@ rc=$0 echo tripping $rc $version +tmpdir='' fn fail { echo >[1=2] trip took a wrong turn: $* - rm -f $tmp + rm -rf $tmpdir fn sigexit exit 1 } @@ -23,8 +24,8 @@ fn sigexit sigint sigquit sigsegv fn sigexit { echo trip complete } -tmp=/tmp/trip.$pid -rm -f $tmp +tmpdir=`{ mktemp -t -d rc-trip.XXXXXX } +tmp=$tmpdir/tmp nl=' ' @@ -51,19 +52,19 @@ if (false) { # WARNING: this differs from sh umask 0 > $tmp x=`{ls -l $tmp} -if (!~ $x(1) '-rw-rw-rw-') fail umask 0 produced incorrect result: $x(1) +if (!~ $x(1) -rw-rw-rw-*) fail umask 0 produced incorrect result: $x(1) rm -f $tmp umask 027 > $tmp y=`{ls -l $tmp} -if (!~ $y(1) '-rw-r-----') fail umask 027 produced incorrect file: $y(1) +if (!~ $y(1) -rw-r-----*) fail umask 027 produced incorrect file: $y(1) rm -f $tmp if (!~ `umask 027) fail umask reported bad value: `umask submatch 'umask bad' 'bad umask' 'bad umask' submatch 'umask -027' 'bad umask' 'bad umask' submatch 'umask 999999' 'bad umask' 'bad umask' -submatch 'umask hi there' 'too many arguments to umask' 'umask arg count' +submatch 'umask hi there' 'rc: too many arguments to umask' 'umask arg count' if (!~ `umask 027) fail bad umask changed umask value to `umask @@ -85,8 +86,8 @@ rm -f 1 2 expect error from cat, closing stdin cat >[0=] -submatch 'cat>(1 2 3)' 'multi-word filename in redirection' 'redirection error' -submatch 'cat>()' 'null filename in redirection' 'redirection error' +submatch 'cat>(1 2 3)' 'rc: multi-word filename in redirection' 'redirection error' +submatch 'cat>()' 'rc: null filename in redirection' 'redirection error' # # blow the input stack @@ -111,7 +112,7 @@ eval eval eval eval eval eval eval eval eval eval eval echo hi # heredocs and herestrings # -bigfile=/tmp/big.$pid +bigfile=$tmpdir/big.$pid od $rc | sed 5000q > $bigfile abc=(this is a) x=() @@ -140,11 +141,11 @@ eof } '$') fail quoting '$' in heredoc -submatch 'cat<<eof' 'heredoc incomplete' 'incomplete heredoc' +submatch 'cat<<eof' 'rc: heredoc incomplete' 'incomplete heredoc' submatch 'cat<<eof -' 'heredoc incomplete' 'incomplete heredoc' +' 'rc: heredoc incomplete' 'incomplete heredoc' -submatch 'cat<<(eof eof)' 'eof-marker not a single literal word' 'bad heredoc marker' +submatch 'cat<<(eof eof)' 'rc: eof-marker not a single literal word' 'bad heredoc marker' # # lexical analysis @@ -155,27 +156,27 @@ expect warning $rc $tmp rm -f $tmp -echo here_is_a_really_long_word.It_has_got_to_be_longer_than_1000_characters_for_the_lexical_analyzers_buffer_to_overflow_but_that_should_not_be_too_difficult_to_do.Let_me_start_writing_some_Lewis_Carroll.Twas_brillig_and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe.All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.Beware_the_Jabberwock_my_son,The_jaws_that_bite,the_claws_that_catch.Beware_the_Jub-jub_bird,and_shun_The_frumious_Bandersnatch.He_took_his_vorpal_sword_in_hand,Long_time_the_manxome_foe_he_sought,So_rested_he_by_the_Tumtum_tree,And_stood_awhile_in_thought.And_as_in_uffish_thought_he_stood,The_Jabberwock,with_eyes_of_flame,Came_whiffling_through_the_tulgey_wood,And_burbled_as_it_came.One_two,one_two.And_through_and_through_The_vorpal_blade_went_snicker-snack.He_left_it_dead_and_with_its_head,He_went_galumphing_back.And_hast_thou_slain_the_Jabberwock?Come_to_my_arms,my_beamish_boy,Oh_frabjous_day.Callooh_callay.He_chortled_in_his_joy.Twas_brillig,and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe,All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe. > /tmp/$pid.lw +echo here_is_a_really_long_word.It_has_got_to_be_longer_than_1000_characters_for_the_lexical_analyzers_buffer_to_overflow_but_that_should_not_be_too_difficult_to_do.Let_me_start_writing_some_Lewis_Carroll.Twas_brillig_and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe.All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.Beware_the_Jabberwock_my_son,The_jaws_that_bite,the_claws_that_catch.Beware_the_Jub-jub_bird,and_shun_The_frumious_Bandersnatch.He_took_his_vorpal_sword_in_hand,Long_time_the_manxome_foe_he_sought,So_rested_he_by_the_Tumtum_tree,And_stood_awhile_in_thought.And_as_in_uffish_thought_he_stood,The_Jabberwock,with_eyes_of_flame,Came_whiffling_through_the_tulgey_wood,And_burbled_as_it_came.One_two,one_two.And_through_and_through_The_vorpal_blade_went_snicker-snack.He_left_it_dead_and_with_its_head,He_went_galumphing_back.And_hast_thou_slain_the_Jabberwock?Come_to_my_arms,my_beamish_boy,Oh_frabjous_day.Callooh_callay.He_chortled_in_his_joy.Twas_brillig,and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe,All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe. > $tmpdir/$pid.lw -echo 'here_is_a_really_long_word.It_has_got_to_be_longer_than_1000_characters_for_the_lexical_analyzers_buffer_to_overflow_but_that_should_not_be_too_difficult_to_do.Let_me_start_writing_some_Lewis_Carroll.Twas_brillig_and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe.All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.Beware_the_Jabberwock_my_son,The_jaws_that_bite,the_claws_that_catch.Beware_the_Jub-jub_bird,and_shun_The_frumious_Bandersnatch.He_took_his_vorpal_sword_in_hand,Long_time_the_manxome_foe_he_sought,So_rested_he_by_the_Tumtum_tree,And_stood_awhile_in_thought.And_as_in_uffish_thought_he_stood,The_Jabberwock,with_eyes_of_flame,Came_whiffling_through_the_tulgey_wood,And_burbled_as_it_came.One_two,one_two.And_through_and_through_The_vorpal_blade_went_snicker-snack.He_left_it_dead_and_with_its_head,He_went_galumphing_back.And_hast_thou_slain_the_Jabberwock?Come_to_my_arms,my_beamish_boy,Oh_frabjous_day.Callooh_callay.He_chortled_in_his_joy.Twas_brillig,and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe,All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.' > /tmp/$pid.lq +echo 'here_is_a_really_long_word.It_has_got_to_be_longer_than_1000_characters_for_the_lexical_analyzers_buffer_to_overflow_but_that_should_not_be_too_difficult_to_do.Let_me_start_writing_some_Lewis_Carroll.Twas_brillig_and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe.All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.Beware_the_Jabberwock_my_son,The_jaws_that_bite,the_claws_that_catch.Beware_the_Jub-jub_bird,and_shun_The_frumious_Bandersnatch.He_took_his_vorpal_sword_in_hand,Long_time_the_manxome_foe_he_sought,So_rested_he_by_the_Tumtum_tree,And_stood_awhile_in_thought.And_as_in_uffish_thought_he_stood,The_Jabberwock,with_eyes_of_flame,Came_whiffling_through_the_tulgey_wood,And_burbled_as_it_came.One_two,one_two.And_through_and_through_The_vorpal_blade_went_snicker-snack.He_left_it_dead_and_with_its_head,He_went_galumphing_back.And_hast_thou_slain_the_Jabberwock?Come_to_my_arms,my_beamish_boy,Oh_frabjous_day.Callooh_callay.He_chortled_in_his_joy.Twas_brillig,and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe,All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.' > $tmpdir/$pid.lq -if (!~ ``(){cat /tmp/$pid.lw} ``(){cat /tmp/$pid.lq}) +if (!~ ``(){cat $tmpdir/$pid.lw} ``(){cat $tmpdir/$pid.lq}) fail expected long string and long word to be identical -if (! x=`{wc -c /tmp/$pid.lw} ~ $x(1) 1088) +if (! x=`{wc -c $tmpdir/$pid.lw} ~ $x(1) 1088) fail expected long word to be 1088 bytes -if (! x=`{wc -c /tmp/$pid.lq} ~ $x(1) 1088) +if (! x=`{wc -c $tmpdir/$pid.lq} ~ $x(1) 1088) fail expected long quote to be 1088 bytes -rm /tmp/$pid.lw -rm /tmp/$pid.lq +rm $tmpdir/$pid.lw +rm $tmpdir/$pid.lq -submatch 'echo hi |[2' 'expected ''='' or '']'' after digit' 'scan error' -submatch 'echo hi |[92=]' 'expected digit after ''=''' 'scan error' -submatch 'echo hi |[a]' 'expected digit after ''[''' 'scan error' -submatch 'echo hi |[2-' 'expected ''='' or '']'' after digit' 'scan error' -submatch 'echo hi |[2=99a]' 'expected '']'' after digit' 'scan error' -submatch 'echo hi |[2=a99]' 'expected digit or '']'' after ''=''' 'scan error' -submatch 'echo ''hi' 'eof in quoted string' 'scan error' +submatch 'echo hi |[2' 'rc: expected ''='' or '']'' after digit' 'scan error' +submatch 'echo hi |[92=]' 'rc: expected digit after ''=''' 'scan error' +submatch 'echo hi |[a]' 'rc: expected digit after ''[''' 'scan error' +submatch 'echo hi |[2-' 'rc: expected ''='' or '']'' after digit' 'scan error' +submatch 'echo hi |[2=99a]' 'rc: expected '']'' after digit' 'scan error' +submatch 'echo hi |[2=a99]' 'rc: expected digit or '']'' after ''=''' 'scan error' +submatch 'echo ''hi' 'rc: eof in quoted string' 'scan error' ifs='' { if (!~ 'h i' `{echo -n h\ @@ -197,7 +198,7 @@ if (! $rc -c '# eof in comment') # test the syntax error printer -prompt='' if (!~ `` $nl {$rc -cif>[2=1]} 'line 1: '*' error near if') +prompt='' if (!~ `` $nl {$rc -cif>[2=1]} 'rc: line 1: '*' error near if') fail print syntax error prompt='' if (!~ `` $nl {$rc -icif>[2=1]} *' error') @@ -226,9 +227,9 @@ bar if (!~ $i 3) fail return inside loop inside function failed -submatch return 'return outside of function' 'return outside of function' -submatch 'break 1' 'too many arguments to break' 'break arg count' -submatch break 'break outside of loop' 'break outside of loop' +submatch return 'rc: return outside of function' 'return outside of function' +submatch 'break 1' 'rc: too many arguments to break' 'break arg count' +submatch break 'rc: break outside of loop' 'break outside of loop' for (i in 1 2 3 4 5) if (~ $i 2) @@ -236,7 +237,7 @@ for (i in 1 2 3 4 5) if (!~ $i 2) fail break out of loop -submatch 'wait foo' 'foo is a bad number' 'bogus argument to wait' +submatch 'wait foo' 'rc: `foo'' is a bad number' 'bogus argument to wait' if (~ `{echo -n} ?) fail echo -n @@ -303,7 +304,7 @@ if (~ `{whatis limit >[2]/dev/null} builtin) { fn cd -submatch 'cd a b c' 'too many arguments to cd' 'cd arg count' +submatch 'cd a b c' 'rc: too many arguments to cd' 'cd arg count' $rc -c 'cdpath=() cd /frobnatz' >[2]/dev/null && fail 'cd to /frobnatz succeeded!?' submatch 'cdpath='''' cd frobnatz' 'couldn''t cd to frobnatz' 'cd to frobnatz succeeded!?' @@ -315,7 +316,7 @@ submatch 'cdpath='''' cd frobnatz' 'couldn''t cd to frobnatz' 'cd to frobnatz su # wait # -submatch 'wait 1 2 3' 'too many arguments to wait' 'arg count' +submatch 'wait 1 2 3' 'rc: too many arguments to wait' 'wait arg count' $rc -c 'wait 1' >[2]/dev/null && fail wait 1 sleep 3& @@ -329,9 +330,9 @@ if (~ `` '' {wait} ?) # # matching # -touch /tmp/abc.$pid /tmp/bbc.$pid -mkdir /tmp/dir.$pid /tmp/dip.$pid -touch /tmp/dir.$pid/^(a b c) /tmp/dip.$pid/^(a b c) +touch $tmpdir/abc.$pid $tmpdir/bbc.$pid +mkdir $tmpdir/dir.$pid $tmpdir/dip.$pid +touch $tmpdir/dir.$pid/^(a b c) $tmpdir/dip.$pid/^(a b c) if (!~ 123 [~x]?[0-9]) fail match @@ -352,18 +353,18 @@ if (~ x [y]) if (~ x x?) fail too many characters in pattern -sh -c 'test -f /////tmp//////a?c.'^$pid || fail glob with many slashes -if (!~ /////tmp//////a*.$pid /////tmp//////a?c.$pid) +sh -c 'test -f /////$tmpdir//////a?c.'^$pid || fail glob with many slashes +if (!~ /////$tmpdir//////a*.$pid /////$tmpdir//////a?c.$pid) fail glob with many slashes -if (!~ ////tmp////di?.$pid////* ////tmp////dir.$pid////*b*) +if (!~ ////$tmpdir////di?.$pid////* ////$tmpdir////dir.$pid////*b*) fail glob with more slashes -if (! @{cd /; ~ */a*.$pid tmp/a*}) +if (! @{cd $tmpdir; ~ *.$pid/a d*/*}) fail glob in current directory -if (!~ /tmp/?bc.$pid /tmp/bbc.$pid) +if (!~ $tmpdir/?bc.$pid $tmpdir/bbc.$pid) fail match of bbc.$pid against '('abc.$pid bbc.$pid')' -rm /tmp/abc.$pid /tmp/bbc.$pid -rm -rf /tmp/dir.$pid /tmp/dip.$pid +rm $tmpdir/abc.$pid $tmpdir/bbc.$pid +rm -rf $tmpdir/dir.$pid $tmpdir/dip.$pid # # signals @@ -377,12 +378,12 @@ fn sigint # $rc -c /frobnatz >[2]/dev/null && fail 'search error' -touch /tmp/noexec.$pid -chmod a-x /tmp/noexec.$pid -$rc -c /tmp/noexec.$pid >[2]/dev/null && fail /tmp/noexec.$pid is found!? -rm /tmp/noexec.$pid +touch $tmpdir/noexec.$pid +chmod a-x $tmpdir/noexec.$pid +$rc -c $tmpdir/noexec.$pid >[2]/dev/null && fail $tmpdir/noexec.$pid is found!? +rm $tmpdir/noexec.$pid -submatch 'path='''' frobnatz' 'frobnatz not found' 'search error' +submatch 'path='''' frobnatz' 'rc: cannot find `frobnatz''' 'search error' {path=() /bin/sh -c 'exit 0'} || fail abs pathname with path set to null @@ -409,15 +410,15 @@ if (~ `` '' . ?*) if (~ `` '' {. -i} ?*) fail null dot -i -cat > /tmp/dot.$pid << eof +cat > $tmpdir/dot.$pid << eof echo hi eof -prompt=';' if (!~ `` '' {. -i /tmp/dot.$pid>[2=1]} ';hi'^$nl';') +prompt=';' if (!~ `` '' {. -i $tmpdir/dot.$pid>[2=1]} ';hi'^$nl';') fail dot -i -submatch .' '/tmp/dot.$pid hi dot +submatch .' '$tmpdir/dot.$pid hi dot -rm /tmp/dot.$pid +rm $tmpdir/dot.$pid $rc -c '. /frobnatz' >[2]/dev/null && fail 'dot of a nonexistent file' @@ -459,7 +460,7 @@ foo=nest *=nest { ~ $* bar || fail restore of '$*' after local group ~ `{exec>[2=1];$rc -xc 'foo=()'} 'foo=()' || fail -x echo of variable deletion -fn_ff='{' prompt='' if (!~ `` $nl {$rc -cff>[2=1]} 'line 1: '*' error near eof') +fn_ff='{' prompt='' if (!~ `` $nl {$rc -cff>[2=1]} 'rc: line 1: '*' error near eof') fail 'bogus function in environment' # @@ -509,8 +510,8 @@ switch (nothing) { ~ $i frobnatz || fail match '*' in switch -submatch '()=()' 'null variable name' 'assignment diagnostic' -submatch 'fn () {eval}' 'null function name' 'assigning null function name' +submatch '()=()' 'rc: null variable name' 'assignment diagnostic' +submatch 'fn () {eval}' 'rc: null function name' 'assigning null function name' # # prompt @@ -522,19 +523,19 @@ fn prompt # # history # -history=/tmp/hist.$pid prompt='' echo 'history=()' | $rc -i +history=$tmpdir/hist.$pid prompt='' echo 'history=()' | $rc -i -if (!~ `{cat /tmp/hist.$pid} 'history=()') +if (!~ `{cat $tmpdir/hist.$pid} 'history=()') fail output to history file -history=/tmp/hist.$pid prompt='' echo 'history=()' | $rc -i +history=$tmpdir/hist.$pid prompt='' echo 'history=()' | $rc -i -if (!~ `` () {cat /tmp/hist.$pid} 'history=() +if (!~ `` () {cat $tmpdir/hist.$pid} 'history=() history=() ') fail append to history file -rm /tmp/hist.$pid +rm $tmpdir/hist.$pid if (!~ `{history=/frobnatz/foo prompt='' echo eval | $rc -i >[2=1]} ?*) fail accessing bad history file @@ -564,7 +565,7 @@ x=/* # fn sigexit should be cleared in children x = () -expect nonesuch not found +expect rc: cannot find '`nonesuch''' x = `{true | nonesuch}; if (~ $x trip) fail sigexit in children x = `{ < /dev/null wc |grep xxx }; if (~ $x trip) fail sigexit in children x = `{{ wc | wc } < /dev/null }; if (~ $x trip) fail sigexit in children @@ -575,7 +576,7 @@ x = `{{ wc | wc } < /dev/null }; if (~ $x trip) fail sigexit in children # check for ctrl-a bug x=`{./tripping a} -# ~ `{$rc -c 'echo $x'} $x || fail ctrl-a bug detected +~ `{$rc -c 'echo $x'} $x || fail ctrl-a bug detected # check for hilarious quoting bug introduced while fixing ctrl-a x=('#' '#' '#') @@ -584,13 +585,15 @@ eval z^`{whatis -v x} # parens bypass quote detector bug fn x {echo x.y $(x.y)} -~ ``''{whatis -f x} 'fn x {echo x.y $''x.y''} +~ ``''{whatis -f x} 'fn x {echo x.y $(x^.y)} ' || fail sneaky parens bug # before rc-1.7.1, certain glob patterns could fail on broken symlinks -mkdir $tmp.qux -ln -s /frobnatz $tmp.qux/foo -x=$tmp.qux/foo* -~ $x $tmp.qux/foo || { rm -rf $tmp.qux; fail broken symlink globbing } -x=$tmp.qux*/foo -~ $x $tmp.qux/foo || { rm -rf $tmp.qux; fail broken symlink globbing } +mkdir $tmpdir/qux +ln -s /frobnatz $tmpdir/qux/foo +x=$tmpdir/qux/foo* +~ $x $tmpdir/qux/foo || { rm -rf $tmpdir/qux; fail broken symlink globbing } +x=$tmpdir/qux*/foo +~ $x $tmpdir/qux/foo || { rm -rf $tmpdir/qux; fail broken symlink globbing } + +rm -rf $tmpdir diff --git a/utils.c b/utils.c @@ -12,9 +12,9 @@ extern void pr_error(char *s, int offset) { if (s != NULL) { if (interactive) - fprint(2, "%s\n", s); + fprint(2, RC "%s\n", s); else - fprint(2, "line %d: %s\n", lineno + offset, s); + fprint(2, RC "line %d: %s\n", lineno + offset, s); } } @@ -27,9 +27,9 @@ extern void uerror(char *s) { if (!err) err = "unknown error"; if (s) - fprint(2, "%s: %s\n", s, err); + fprint(2, RC "%s: %s\n", s, err); else - fprint(2, "%s\n", err); + fprint(2, RC "%s\n", err); } /* Die horribly. This should never get called. Please let me know if it does. */ diff --git a/var.c b/var.c @@ -2,6 +2,8 @@ #include "rc.h" +#include "input.h" + static void colonassign(char *, List *, bool); static void listassign(char *, List *, bool); static int hasalias(char *); @@ -19,10 +21,8 @@ extern void varassign(char *name, List *def, bool stack) { new->def = newdef; new->extdef = NULL; set_exportable(name, TRUE); -#if READLINE - if (interactive && (streq(name, "TERM") || streq(name, "TERMCAP"))) - rl_reset_terminal(NULL); -#endif + if (streq(name, "TERM") || streq(name, "TERMCAP")) + termchange(); } /* assign a variable in string form. Check to see if it is aliased (e.g., PATH and path) */ diff --git a/which.c b/which.c @@ -1,7 +1,7 @@ /* which.c: check to see if a file is executable. This function was originally written with Maarten Litmaath's which.c as - a template, but was changed in order to accomodate the possibility of + a template, but was changed in order to accommodate the possibility of rc's running setuid or the possibility of executing files not in the primary group. Much of this file has been re-vamped by Paul Haahr. I re-re-vamped the functions that Paul supplied to correct minor bugs @@ -10,6 +10,7 @@ #include "rc.h" +#include <ctype.h> #include <errno.h> #include <sys/stat.h> @@ -70,6 +71,19 @@ static bool rc_access(char *path, bool verbose) { return FALSE; } +/* replace non-printing characters with question marks in a freshly + * allocated string */ +static char *protect(char *in) { + int l = strlen(in); + char *out = ealloc(l + 1); + int i; + + for (i = 0; i < l; ++i) + out[i] = isprint(in[i]) ? in[i] : '?'; + out[i] = '\0'; + return out; +} + /* return a full pathname by searching $path, and by checking the status of the file */ extern char *which(char *name, bool verbose) { @@ -119,7 +133,10 @@ extern char *which(char *name, bool verbose) { if (rc_access(test, FALSE)) return test; } - if (verbose) - fprint(2, "%s not found\n", name); + if (verbose) { + char *n = protect(name); + fprint(2, RC "cannot find `%s'\n", n); + efree(n); + } return NULL; }