Imported Upstream version 0.5.7 upstream/0.5.7
authorAnas Nashif <anas.nashif@intel.com>
Tue, 30 Oct 2012 22:54:32 +0000 (15:54 -0700)
committerAnas Nashif <anas.nashif@intel.com>
Tue, 30 Oct 2012 22:54:32 +0000 (15:54 -0700)
79 files changed:
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
aclocal.m4 [new file with mode: 0644]
config.h.in [new file with mode: 0644]
configure [new file with mode: 0755]
configure.ac [new file with mode: 0644]
depcomp [new file with mode: 0755]
install-sh [new file with mode: 0755]
missing [new file with mode: 0755]
src/Makefile.am [new file with mode: 0644]
src/Makefile.in [new file with mode: 0644]
src/alias.c [new file with mode: 0644]
src/alias.h [new file with mode: 0644]
src/arith_yacc.c [new file with mode: 0644]
src/arith_yacc.h [new file with mode: 0644]
src/arith_yylex.c [new file with mode: 0644]
src/bltin/bltin.h [new file with mode: 0644]
src/bltin/printf.c [new file with mode: 0644]
src/bltin/test.c [new file with mode: 0644]
src/bltin/times.c [new file with mode: 0644]
src/builtins.def.in [new file with mode: 0644]
src/cd.c [new file with mode: 0644]
src/cd.h [new file with mode: 0644]
src/dash.1 [new file with mode: 0644]
src/error.c [new file with mode: 0644]
src/error.h [new file with mode: 0644]
src/eval.c [new file with mode: 0644]
src/eval.h [new file with mode: 0644]
src/exec.c [new file with mode: 0644]
src/exec.h [new file with mode: 0644]
src/expand.c [new file with mode: 0644]
src/expand.h [new file with mode: 0644]
src/hetio.h [new file with mode: 0644]
src/histedit.c [new file with mode: 0644]
src/init.h [new file with mode: 0644]
src/input.c [new file with mode: 0644]
src/input.h [new file with mode: 0644]
src/jobs.c [new file with mode: 0644]
src/jobs.h [new file with mode: 0644]
src/machdep.h [new file with mode: 0644]
src/mail.c [new file with mode: 0644]
src/mail.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/main.h [new file with mode: 0644]
src/memalloc.c [new file with mode: 0644]
src/memalloc.h [new file with mode: 0644]
src/miscbltin.c [new file with mode: 0644]
src/miscbltin.h [new file with mode: 0644]
src/mkbuiltins [new file with mode: 0644]
src/mkinit.c [new file with mode: 0644]
src/mknodes.c [new file with mode: 0644]
src/mksignames.c [new file with mode: 0644]
src/mksyntax.c [new file with mode: 0644]
src/mktokens [new file with mode: 0644]
src/myhistedit.h [new file with mode: 0644]
src/mystring.c [new file with mode: 0644]
src/mystring.h [new file with mode: 0644]
src/nodes.c.pat [new file with mode: 0644]
src/nodetypes [new file with mode: 0644]
src/options.c [new file with mode: 0644]
src/options.h [new file with mode: 0644]
src/output.c [new file with mode: 0644]
src/output.h [new file with mode: 0644]
src/parser.c [new file with mode: 0644]
src/parser.h [new file with mode: 0644]
src/redir.c [new file with mode: 0644]
src/redir.h [new file with mode: 0644]
src/shell.h [new file with mode: 0644]
src/show.c [new file with mode: 0644]
src/show.h [new file with mode: 0644]
src/system.c [new file with mode: 0644]
src/system.h [new file with mode: 0644]
src/trap.c [new file with mode: 0644]
src/trap.h [new file with mode: 0644]
src/var.c [new file with mode: 0644]
src/var.h [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..37f8189
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,56 @@
+Copyright (c) 1989-1994
+       The Regents of the University of California.  All rights reserved.
+Copyright (c) 1997 Christos Zoulas.  All rights reserved.
+Copyright (c) 1997-2005
+       Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by Kenneth Almquist.
+
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+mksignames.c:
+
+This file is not directly linked with dash.  However, its output is.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This file is part of GNU Bash, the Bourne Again SHell.
+
+Bash is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License with
+your Debian GNU/Linux system, in /usr/share/common-licenses/GPL, or with the
+Debian GNU/Linux hello source package as the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+Boston, MA 02111 USA.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..d3a4acf
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,664 @@
+2011-07-08  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Release 0.5.7.
+
+2011-07-07  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Optimize dash -c "command" to avoid a fork.
+       * Eliminate unnecessary promotion in echocmd.
+
+2011-05-25  Jim Meyering  <meyering@redhat.com>
+
+       * Avoid using undefined handler.
+
+2011-05-23  Jim Meyering  <meyering@redhat.com>
+
+       * Avoid gcc warning: variable 'oldstackp' set but not used.
+       * Avoid clang warning about dead store to "size".
+
+2011-05-22  Jonathan Nieder <jrnieder@gmail.com>
+
+       * Make outc an inline function.
+
+2011-05-02  Kalle Olavi Niemitalo <kon@iki.fi>
+
+       * Remove spurious space in descriptions of PS1, PS2, PS4.
+
+2011-04-10  Jonathan Nieder <jrnieder@gmail.com>
+       * Remove unused EV_BACKCMD flag.
+
+2011-03-15  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix clobbering of checkkwd.
+
+2011-03-15  Jonathan Nieder <jrnieder@gmail.com>
+
+       * Free IFS state after here document expansion.
+       * Use va_copy when reusing a va_list.
+
+2011-03-15  Harald van Dijk <harald@gigawatt.nl>
+
+       * Let funcnode refer to a function definition, not its first command.
+       * Improve LINENO support.
+
+2011-03-15  Brian Koropoff <bkoropoff@gmail.com>
+
+       * Port to Solaris.
+
+2011-03-11  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix backslash handling in read(1).
+
+2011-03-10  Jonathan Nieder <jrnieder@gmail.com>
+
+       * Dotcmd should exit with zero when doing nothing.
+
+2011-03-10  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix CTLESC clobbering by read(1).
+
+2011-03-10  Brian Koropoff <bkoropoff@gmail.com>
+
+       * Port to AIX.
+
+2011-03-10  Jilles Tjoelker <jilles@stack.nl>
+
+       * Replace GPL noclobberopen code with the FreeBSD version.
+       * Do not split the result of tilde expansion.
+
+2010-11-28  Maciej Å»enczykowski <zenczykowski@gmail.com>
+
+       * Mark status as volatile in exitshell.
+
+2010-11-28  Jonathan Nieder <jrnieder@gmail.com>
+
+       * Use EXEXIT in place of EXEXEC.
+       * Stop documenting EXSHELLPROC.
+
+2010-11-28  Gerrit Pape <pape@smarden.org>
+
+       * Use exit status 127 when the script to run does not exist.
+
+2010-11-28  Philipp Weis <pweis@pweis.com>
+
+       * Document optional open parenthesis for case patterns.
+
+2010-11-28  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fixed trap/return regression due to SKIPEVAL removal.
+       * Allow the originator of EXERROR to set the exit status.
+       * Free IFS state in evalbackcmd.
+
+2010-10-18  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix ifsfirst/ifslastp leak in casematch.
+
+2010-10-07  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix EXEXEC status clobbering.
+
+2010-09-08  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix ifsfirst/ifslastp leak.
+       * Fix trailing field bug in read(1).
+
+2010-09-08  maximilian attems <max@stro.at>
+
+       * Debug compile fix.
+
+2010-09-08  Jilles Tjoelker <jilles@stack.nl>
+
+       * Fix varinit ordering that broke fc.
+
+2010-07-06  Gerrit Pape <pape@smarden.org>
+
+       * Check exit for eval NSUBSHELL.
+
+2010-07-06  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix loss of variables when hash collides.
+       * Removed dead code for eval NPIPE.
+
+2010-06-28  Gerrit Pape <pape@smarden.org>
+
+       * Don't clear eflag in evalbackcmd.
+
+2010-05-29  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Continue after EINTR in read(1) with no pending signals.
+
+2010-05-27  Jilles Tjoelker <jilles@stack.nl>
+
+       * Force fork if any trap is set, not just on EXIT.
+       * Fix corruption of redirections with byte 0x81.
+
+2010-05-27  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix poplocalvar on abnormal exit from function.
+       * Do not poplocalvars prematurely on regular utilities.
+       * Move null redirect checks into caller.
+       * Fix popredir on abnormal exit from built-in.
+       * Fix wait regression where it does not wait for all jobs.
+
+2010-05-26  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Replace cmdenviron with localvars.
+
+2010-05-25  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix poplocalvar leak.
+       * Move unsetvar functionality into setvareq.
+
+2010-05-24  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Add localvars nesting, local now fails outside functions.
+
+2010-05-03  Gerrit Pape <pape@smarden.org>
+
+       * Fix command -- crash.
+
+2010-04-15  H. Peter Anvin <hpa@zytor.com>
+
+       * Fix for job control off warning.
+
+2010-04-02  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Use faccessat if available.
+
+2010-04-02  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Make trap signal name/number errors non-fatal.
+       * Release 0.5.6.
+
+2010-04-02  maximilian attems <max@stro.at>
+
+       * Use TMPDIR in mkbuiltins.
+
+2010-03-10  Jilles Tjoelker <jilles@stack.nl>
+
+       * Fix logical or result value.
+
+2010-03-09  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix binary operator parsing.
+
+2009-11-26  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix off-by-one recordregion in readcmd.
+
+2009-09-28  Jim Meyering  <meyering@redhat.com>
+
+       don't read-uninitialized for \177 in a here-doc
+       A DEL (0177, dec 127) byte in a here-document would cause dash to
+       access uninitialized memory at the end of one of the syntax.c tables,
+       since those tables are sized to accommodate a maximum index of
+       BASESYNTAX + 126.  Make the generated tables one byte larger.
+       printf ':<<\\E\n\200y\nE'|./dash
+       * src/mksyntax.c (filltable): Use 258, not 257 as the size,
+       so that BASESYNTAX(=130) + 127 is a valid index.
+       (print): Likewise.
+       Don't emit explicit array dimension in declaration.
+
+2009-08-31  Eric Blake <ebb9@byu.net>
+
+       * Avoid compiler warnings on isdigit.
+
+2009-08-31  Matthew Burgess <matthew@linuxfromscratch.org>
+
+       * Add another missing LC_COLLATE to mkbuiltins.
+
+2009-08-31  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix NUL termination in readcmd.
+       * Lookup PWD after going through CDPATH.
+
+2009-08-11  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Pass EV_TESTED into evalcmd.
+       * Revert SKIPEVAL into EXEXIT.
+
+2009-08-11  Rocky Bernstein <rocky.bernstein@gmail.com>
+
+       * Add preliminary LINENO support.
+
+2009-08-11  Stefan Potyra <stefan.potyra@informatik.uni-erlangen.de>
+
+       * Honor tab as IFS whitespace when splitting fields in readcmd.
+
+2009-06-30  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Do not truncate file for FROMTO redirection.
+
+2009-06-27  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix quoted pattern patch breakage.
+
+2009-05-23  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix incorrect savefd conversions.
+
+2009-02-22  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix dowait signal race.
+       * Remove EXSIG.
+       * Do not close stderr when /dev/tty fails to open.
+       * Allow newlines after var name in for statements.
+       * Use CHKNL to parse case statements.
+
+2009-02-22  Gerrit Pape <pape@smarden.org>
+
+       * Update manual page to differentiate dash from ash.
+
+2009-01-14  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Add arith_yacc.h to dash_SOURCES.
+       * Release 0.5.5.1.
+
+2009-01-13  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Release 0.5.5.
+
+2009-01-13  Mark Mentovai <mmentovai@gmail.com>
+
+       * Fixed build on OS X.
+
+2008-12-26  Aleksey Cheusov <vle@gmx.net>
+
+       * Fixed build on NetBSD.
+
+2008-10-17  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Removed obsolete for loop syntax in manual.
+
+2008-08-05  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fixed getcwd build error for the non-glibc case.
+
+2008-06-13  Gerrit Pape <pape@smarden.org>
+
+       * Added missing right parenthesis in manual page.
+
+2008-06-13  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fixed 3,4-argument cases for test per POSIX.
+       * Made aexpr/oexpr non-recursive.
+       * Made t_lex reentrant.
+       * Made setinputfd static.
+       * Expand ENV before using it.
+       * Added support for -l.
+
+2008-05-19  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fixed non-leading slash treatment in expmeta.
+
+2008-05-07  Gerrit Pape <pape@smarden.org>
+
+       * Fixed lexical error in arithmetic expansion of & and |.
+
+2008-05-03  Dan McGee <dpmcgee@gmail.com>
+
+       * Fixed klibc/klcc build problems.
+       * Added gitignore.
+
+2008-05-03  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fixed _PATH_BSHELL warning.
+       * Test __GLIBC__ instead of _GNU_SOURCE.
+       * Restored warning when getcwd fails.
+       * Set default exvwarning2 arg0 for errors during early initialisation.
+       * Use uninitialized_var to silence bogus warnings.
+
+2008-05-02  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Restored non-glibc getcwd support.
+
+2008-03-07  Larry Doolittle <ldoolitt@recycle.lbl.gov>
+
+       * Fix cmdtxt crash on if statements.
+
+2008-01-01  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix slash treatment in expmeta.
+
+2007-12-27  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Add FAKEEOFMARK for expandstr.
+       * Do not show prompts in expandstr.
+
+2007-12-23  Gerrit Pape <pape@smarden.org>
+
+       * If imaxdiv() isn't available, use / and % operators.
+
+2007-12-23  Richard M Kreuter <kreuter@progn.net>
+
+       * Add set +o support.
+
+2007-12-23  Steve Langasek <steve.langasek@canonical.com>
+
+       * Fixed bad pointer arithmetic in evalcommand.
+
+2007-11-11  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Removed noexpand/length check on eofmark.
+       * Removed herefd hack.
+       * Expand here-documents in the current shell environment.
+
+2007-10-20  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Added configure --enable-glob and --enable-fnmatch options.
+       * Fix here-doc corruption.
+
+2007-10-17  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Replace shared illnum message by badnum function.
+
+2007-10-17  Oleg Verych <olecom@flower.upol.cz>
+
+       * Disallow completely blank strings in non-arithmetic context.
+
+2007-10-15  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fixed execing of scripts with no hash-bang.
+
+2007-10-11  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Add assignment support in arithmetic expansions.
+       * Size optimisations in arithmetic lexer.
+       * Add likely flags in expari.
+       * Use setvarint to set OPTIND.
+
+2007-10-08  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Report substition errors at expansion time.
+
+2007-10-06  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Add pushstackmark.
+       * Treat OPTIND=0 in the same way as OPTIND=1.
+       * Remove setvarsafe.
+       * Use intmax_t arithmetic in test.
+
+2007-10-05  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Made grabstackblock an inline wrapper for stalloc.
+
+2007-10-04  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix parsing of ${##1}.
+       * Size optimisations in parameter expansion parser.
+
+2007-10-04  Alexey Gladkov <legion@altlinux.org>
+
+       * Add --enable-static option to configure.
+
+2007-09-26  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Recognise here-doc delimiters terminated by EOF.
+
+2007-09-26  Roy Marples <uberlord@gentoo.org>
+
+       * Refresh stack pointers after makestrspace in _rmescapes.
+
+2007-09-25  Gerrit Pape <pape@smarden.org>
+
+       * Clarify description of -nt, -ot options to test builtin.
+       * Clarify syntax of the for command.
+
+2007-09-25  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Do not expand tilde in parameter expansion within quotes.
+       * Move parse-time quote flag detection to run-time.
+
+2007-09-24  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Do not quote back slashes in parameter expansions outside quotes.
+       * Perform tilde expansion in all parameter expansion words.
+       * Remove superfluous arinest test in CENDQUOTE.
+       * Remove superfluous arinest test for dqvarnest.
+       * Remove superfluous dblquote settings when ending arith.
+       * Remove arithmetic expansion collapsing at parse time.
+
+2007-09-22  Oleg Verych <olecom@flower.upol.cz>
+
+       * White space fixes for test(1).
+       * Use direct comparison instead of strcmp in test(1).
+
+2007-09-22  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Move flushall to the point just before _exit.
+
+2007-09-21  Denis Vlasenko <vda.linux@googlemail.com>
+
+       * Restore foreground process group on exit.
+
+2007-07-12  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Release 0.5.4.
+
+2007-05-12  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix redirect restore on closed file descriptors.
+       * Size optimisations in redir.c.
+
+2007-05-06  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Removed unnecessary inclusion of redir.h from parser.c.
+       * Invoke sh_error on error in copyfd.
+       * Use dup2 instead of copyfd in evalbackcmd.
+       * Replace copyfd by savefd and dup2.
+       * Removed redundant CLOEXEC calls.
+
+2007-05-05  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fixed typo in parser.h comment.
+
+2007-04-28  Dan Nicholson <dbn.lists@gmail.com>
+
+       * Set LC_COLLATE for sort in mkbuiltin.
+
+2006-10-22  Gerrit Pape <pape@smarden.org>
+
+       * Fixed command -v segmentation fault.
+
+2006-10-13  Alexey Gladkov <legion@altlinux.org>
+
+       * Check return code for getgroups and fwrite.
+
+2006-10-04  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fixed inverted char class matching.
+
+2006-05-23  Alexey Gladkov <legion@altlinux.org>
+
+       * Added --with-libedit option to configure.
+
+2006-03-29  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Removed useless parsebackquote flag.
+       * Use alloca to get rid of setjmp in parse.c.
+       * Only use signed char for syntax arrays.
+
+2006-01-12  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fixed eval exit status with empty arguments.
+
+2005-11-26  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Release 0.5.3.
+
+2005-11-14  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fix \c spillage across echo commands.
+
+2005-11-13  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Remove unnecessary truncation in _STPUTC.
+       * Always call conv_escape_str in echocmd.
+
+2005-11-04  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Use mktemp if tempfile is not available.
+
+2005-10-30  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fixed support for disabling job control.
+
+2005-10-29  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Updated BSD licence to 3-clause version per NetBSD.
+       * Updated copyright.
+       * Removed CVS IDs and inclusion of sys/cdefs.h.
+       * Removed use of __P from error.h.
+       * Use bsd_signal if it exists and signal does not.
+       * Stop using sysexits.h in commandcmd.
+       * Use stat if stat64 does not exist.
+       * Added default implementation of bsearch.
+       * Added getpwhome as a wrapper for getpwnam.
+       * Fixed gcc 4.0 compilation problems.
+       * Added missing system.h inclusion for mempcpy.
+       * Added default implementation of strsignal.
+       * Added default implementation of killpg.
+       * Disable ulimit if there is no getrlimit.
+       * Disable histcmd completely when SMALL is defined.
+       * Added default definition for SSIZE_MAX.
+       * Removed standalone/csh support from printf.
+       * Added dummy strtod implementation.
+       * Removed standalone/csh support from test.
+       * Added dummy sysconf implementation.
+       * Include system.h for stpcpy in nodes.c.
+       * Added out-of-line ctypes functions for klibc.
+       * Fixed fallback stpcpy implementation.
+
+2005-10-26  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Size optimisations in preadbuffer().
+
+2005-10-01  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Skip NUL characters properly in input.c.
+
+2005-03-28  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Removed some unnecessary inclusions of input.h.
+       * Removed unnecessary inclusion of main.h from eval.c.
+       * Removed unnecessary inclusion of eval.h from parser.c.
+       * Generalise setinputfile for use in read_profile/readcmdfile.
+       * Handle SKIPEVAL in read_profile by exiting.
+       * Let evaltree handle traps from cmdloop.
+       * Reset evalskip after minusc is executed.
+       * Stop executing traps once SKIPEVAL is seen.
+       * Only handle each signal once in dotrap.
+
+2005-03-25  Gerrit Pape <pape@smarden.org>
+
+       * Add trailing equal sign in setvar for variables set to null.
+
+2005-03-25  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Cleaned up src/Makefile.am.
+       * Get rid of duplicate -g -O2 in CFLAGS.
+       * Eliminate first null termination in setvar.
+       * Turn evalskip into a bit field.
+
+2005-03-25  Gilles Chanteperdrix <gilles.chanteperdrix@laposte.net>
+
+       * Fixed support for cross-compilation.
+
+2005-03-03  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Removed qflag.
+       * Removed redundant setstackmark from dotcmd.
+       * Do not clobber exit status in dotcmd.
+
+2005-03-02  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Renamed symbols to avoid conflict with libc.
+       * Optimisations in bltin/test.c.
+
+2005-02-28  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Replaced EXEVAL with SKIPEVAL.
+       * Update funcnest atomically.
+       * Only set skipcount for break and continue.
+       * Removed expcmd built-in.
+       * Normalise input in likely/unlikely macros.
+
+2005-02-28  A Costa <agcosta@gis.net>
+
+       * Corrected that/than typo in manual page.
+
+2005-02-25  A Costa <agcosta@gis.net>
+
+       * Corrected grammar in manual page.
+
+2005-02-25  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Changed boolean rootshell into shlvl counter.
+       * Catch set -e exits within built-in commands.
+       * Size optimisations with setjmp in main().
+       * Only reread exitstatus on EXEXIT in exitshell.
+       * Eliminated global exerrno.
+
+2005-01-31  Gerrit Pape <pape@smarden.org>
+
+       * Release 0.5.2.
+       * Corrected manual entry about ENV and non-interactive shells.
+
+2004-11-24  Gerrit Pape <pape@smarden.org>
+
+       * Spell behaviour consistently in manual page.
+
+2004-11-23  A Costa <agcosta@gis.net>
+
+       * Fixed spelling errors in manual page.
+
+2004-08-21  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Size optimisations around varvalue() in src/expand.c.
+       * Fixed signed char promotion in src/expand.c.
+
+2004-08-18  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fixed $@ expansion when leading argument is null in src/expand.c.
+
+2004-08-07  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Allow negative pid argument to kill(1) in src/jobs.c.
+
+2004-08-04  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fixed cd - when OLDPWD is unset in src/cd.c.
+
+2004-07-09  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Include system.h (Gerrit Pape):
+         . src/mystring.c
+         . src/var.c
+         . src/bltin/printf.c
+
+2004-07-03  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Release 0.5.1.
+       * Use automake and autoconf.
+       * Include stdlib.h for exit(3) in src/mksyntax.c.
+
+2004-06-29  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Added sigclearmask.
+       * Removed hack for _setjmp/_longjmp.
+       * Added default implementations of mempcpy/stpcpy/strchrnul.
+       * Use strtoll/strtoull if strtoimax/strtoumax are unavailable.
+       * Removed sh.1 to dash.1.
+
+2004-05-28  Herbert Xu <herbert@gondor.apana.org.au>
+
+       * Fixed vstype trim operator ordering in cmdputs.
+       * Fixed quote for CTLENDVAR in cmdputs.
+       * Fixed VSLENGTH crash in cmdputs.
+       * Turned vstype back into a 2-d array of chars.
+       * Added POSIX character class support in pmatch.
+
+For older ChangeLogs see ChangeLog.O.
+
+ChangeLog ends here
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..7d1c323
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,365 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008, 2009 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.
+
+   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
+================
+
+   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.
+
+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:
+
+     ./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).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--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.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--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
new file mode 100644 (file)
index 0000000..af437a6
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src
diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..fd7e3f5
--- /dev/null
@@ -0,0 +1,614 @@
+# Makefile.in generated by automake 1.10.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in 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.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+subdir = .
+DIST_COMMON = $(am__configure_deps) $(srcdir)/Makefile.am \
+       $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+       $(top_srcdir)/configure COPYING ChangeLog INSTALL depcomp \
+       install-sh missing
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+       html-recursive info-recursive install-data-recursive \
+       install-dvi-recursive install-exec-recursive \
+       install-html-recursive install-info-recursive \
+       install-pdf-recursive install-ps-recursive install-recursive \
+       installcheck-recursive installdirs-recursive pdf-recursive \
+       ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
+  distclean-recursive maintainer-clean-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  { test ! -d $(distdir) \
+    || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+         && rm -fr $(distdir); }; }
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = src
+all: config.h
+       $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh:
+       @:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
+             cd $(srcdir) && $(AUTOMAKE) --foreign  \
+               && exit 0; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  Makefile'; \
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           echo ' $(SHELL) ./config.status'; \
+           $(SHELL) ./config.status;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+
+config.h: stamp-h1
+       @if test ! -f $@; then \
+         rm -f stamp-h1; \
+         $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+       else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+       @rm -f stamp-h1
+       cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in:  $(am__configure_deps) 
+       cd $(top_srcdir) && $(AUTOHEADER)
+       rm -f stamp-h1
+       touch $@
+
+distclean-hdr:
+       -rm -f config.h stamp-h1
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       target=`echo $@ | sed s/-recursive//`; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           dot_seen=yes; \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done; \
+       if test "$$dot_seen" = "no"; then \
+         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+       fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       case "$@" in \
+         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+         *) list='$(SUBDIRS)' ;; \
+       esac; \
+       rev=''; for subdir in $$list; do \
+         if test "$$subdir" = "."; then :; else \
+           rev="$$subdir $$rev"; \
+         fi; \
+       done; \
+       rev="$$rev ."; \
+       target=`echo $@ | sed s/-recursive//`; \
+       for subdir in $$rev; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done && test -z "$$fail"
+tags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+       done
+ctags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+       done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+         include_option=--etags-include; \
+         empty_fix=.; \
+       else \
+         include_option=--include; \
+         empty_fix=; \
+       fi; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test ! -f $$subdir/TAGS || \
+             tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+         fi; \
+       done; \
+       list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+           $$tags $$unique; \
+       fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$tags $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && cd $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       $(am__remove_distdir)
+       test -d $(distdir) || mkdir $(distdir)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+       list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test -d "$(distdir)/$$subdir" \
+           || $(MKDIR_P) "$(distdir)/$$subdir" \
+           || exit 1; \
+           distdir=`$(am__cd) $(distdir) && pwd`; \
+           top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+           (cd $$subdir && \
+             $(MAKE) $(AM_MAKEFLAGS) \
+               top_distdir="$$top_distdir" \
+               distdir="$$distdir/$$subdir" \
+               am__remove_distdir=: \
+               am__skip_length_check=: \
+               distdir) \
+             || exit 1; \
+         fi; \
+       done
+       -find "$(distdir)" -type d ! -perm -755 \
+               -exec chmod u+rwx,go+rx {} \; -o \
+         ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+         ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+         ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+       || chmod -R a+r $(distdir)
+dist-gzip: distdir
+       tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+       $(am__remove_distdir)
+
+dist-bzip2: distdir
+       tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+       $(am__remove_distdir)
+
+dist-lzma: distdir
+       tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
+       $(am__remove_distdir)
+
+dist-tarZ: distdir
+       tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+       $(am__remove_distdir)
+
+dist-shar: distdir
+       shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+       $(am__remove_distdir)
+
+dist-zip: distdir
+       -rm -f $(distdir).zip
+       zip -rq $(distdir).zip $(distdir)
+       $(am__remove_distdir)
+
+dist dist-all: distdir
+       tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+       $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+       case '$(DIST_ARCHIVES)' in \
+       *.tar.gz*) \
+         GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+       *.tar.bz2*) \
+         bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+       *.tar.lzma*) \
+         unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\
+       *.tar.Z*) \
+         uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+       *.shar.gz*) \
+         GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+       *.zip*) \
+         unzip $(distdir).zip ;;\
+       esac
+       chmod -R a-w $(distdir); chmod a+w $(distdir)
+       mkdir $(distdir)/_build
+       mkdir $(distdir)/_inst
+       chmod a-w $(distdir)
+       dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+         && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+         && cd $(distdir)/_build \
+         && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+           $(DISTCHECK_CONFIGURE_FLAGS) \
+         && $(MAKE) $(AM_MAKEFLAGS) \
+         && $(MAKE) $(AM_MAKEFLAGS) dvi \
+         && $(MAKE) $(AM_MAKEFLAGS) check \
+         && $(MAKE) $(AM_MAKEFLAGS) install \
+         && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+         && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+         && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+               distuninstallcheck \
+         && chmod -R a-w "$$dc_install_base" \
+         && ({ \
+              (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+              && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+              && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+              && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+                   distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+             } || { rm -rf "$$dc_destdir"; exit 1; }) \
+         && rm -rf "$$dc_destdir" \
+         && $(MAKE) $(AM_MAKEFLAGS) dist \
+         && rm -rf $(DIST_ARCHIVES) \
+         && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+       $(am__remove_distdir)
+       @(echo "$(distdir) archives ready for distribution: "; \
+         list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+         sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+       @cd $(distuninstallcheck_dir) \
+       && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+          || { echo "ERROR: files left after uninstall:" ; \
+               if test -n "$(DESTDIR)"; then \
+                 echo "  (check DESTDIR support)"; \
+               fi ; \
+               $(distuninstallcheck_listfiles) ; \
+               exit 1; } >&2
+distcleancheck: distclean
+       @if test '$(srcdir)' = . ; then \
+         echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+         exit 1 ; \
+       fi
+       @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+         || { echo "ERROR: files left in build directory after distclean:" ; \
+              $(distcleancheck_listfiles) ; \
+              exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile config.h
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-recursive
+       -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+       -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+       -rm -rf $(top_srcdir)/autom4te.cache
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
+       install-strip
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+       all all-am am--refresh check check-am clean clean-generic \
+       ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \
+       dist-lzma dist-shar dist-tarZ dist-zip distcheck distclean \
+       distclean-generic distclean-hdr distclean-tags distcleancheck \
+       distdir distuninstallcheck dvi dvi-am html html-am info \
+       info-am install install-am install-data install-data-am \
+       install-dvi install-dvi-am install-exec install-exec-am \
+       install-html install-html-am install-info install-info-am \
+       install-man install-pdf install-pdf-am install-ps \
+       install-ps-am install-strip installcheck installcheck-am \
+       installdirs installdirs-am maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+       pdf-am ps ps-am tags tags-recursive uninstall uninstall-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644 (file)
index 0000000..93d6510
--- /dev/null
@@ -0,0 +1,903 @@
+# generated automatically by aclocal 1.10.3 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008, 2009  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_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],,
+[m4_warning([this file was generated for autoconf 2.68.
+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, 2003, 2005, 2006, 2007, 2008  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.10'
+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.10.3], [],
+      [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.10.3])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, 2003, 2005  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, 2000, 2001, 2003, 2004, 2005, 2006
+# 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.
+
+# serial 8
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$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
+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, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009
+# 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.
+
+# serial 10
+
+# 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", "GCJ", or "OBJC".
+# 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
+
+ifelse([$1], CC,   [depcc="$CC"   am_compiler_list=],
+       [$1], CXX,  [depcc="$CXX"  am_compiler_list=],
+       [$1], OBJC, [depcc="$OBJC" 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'.
+  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 8's {/usr,}/bin/sh.
+      touch 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
+      ;;
+    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,
+[  --disable-dependency-tracking  speeds up one-time build
+  --enable-dependency-tracking   do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+])
+
+# Generate code to set up dependency tracking.              -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# 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.
+
+#serial 5
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+  # Autoconf 2.62 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"`
+    # When using ansi2knr, U may be empty or an underscore; expand it
+    U=`sed -n 's/^U = //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' -e 's/\$U/'"$U"'/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, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2008, 2009 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.
+
+# serial 13
+
+# 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.60])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],
+[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], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
+  [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([AM_PROG_MKDIR_P])dnl
+# 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)],
+                  [define([AC_PROG_CC],
+                          defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+                  [_AM_DEPENDENCIES(CXX)],
+                  [define([AC_PROG_CXX],
+                          defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+                  [_AM_DEPENDENCIES(OBJC)],
+                  [define([AC_PROG_OBJC],
+                          defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
+])
+])
+
+
+# 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, 2003, 2005  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
+install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"}
+AC_SUBST(install_sh)])
+
+# Copyright (C) 2003, 2005  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.
+
+# serial 2
+
+# 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, 2002, 2003, 2005  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.
+
+# serial 3
+
+# 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 done
+.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
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+   am__include=include
+   am__quote=
+   _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+      am__include=.include
+      am__quote="\""
+      _am_result=BSD
+   fi
+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, 1999, 2000, 2001, 2003, 2004, 2005
+# 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.
+
+# serial 5
+
+# 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 supports --run.
+# If it does, 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
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+  am_missing_run="$MISSING --run "
+else
+  am_missing_run=
+  AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005, 2006  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_MKDIR_P
+# ---------------
+# Check for `mkdir -p'.
+AC_DEFUN([AM_PROG_MKDIR_P],
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p.  We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+  [[\\/$]]* | ?:[[\\/]]*) ;;
+  */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2008  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.
+
+# serial 4
+
+# _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, 1997, 2000, 2001, 2003, 2005
+# 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.
+
+# serial 4
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# 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 (
+   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
+   rm -f conftest.file
+   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
+
+   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)])
+
+# Copyright (C) 2001, 2003, 2005  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  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])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005  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.
+
+# serial 2
+
+# _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.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+     [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+     [m4_case([$1], [ustar],, [pax],,
+              [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+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])
+    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
+
diff --git a/config.h.in b/config.h.in
new file mode 100644 (file)
index 0000000..be66e70
--- /dev/null
@@ -0,0 +1,190 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if __attribute__((__alias__())) is supported */
+#undef HAVE_ALIAS_ATTRIBUTE
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#undef HAVE_ALLOCA_H
+
+/* Define to 1 if you have the `bsearch' function. */
+#undef HAVE_BSEARCH
+
+/* Define to 1 if you have the declaration of `isblank', and to 0 if you
+   don't. */
+#undef HAVE_DECL_ISBLANK
+
+/* Define to 1 if you have the `faccessat' function. */
+#undef HAVE_FACCESSAT
+
+/* Define to 1 if you have the `fnmatch' function. */
+#undef HAVE_FNMATCH
+
+/* Define to 1 if you have the `getpwnam' function. */
+#undef HAVE_GETPWNAM
+
+/* Define to 1 if you have the `getrlimit' function. */
+#undef HAVE_GETRLIMIT
+
+/* Define to 1 if you have the `glob' function. */
+#undef HAVE_GLOB
+
+/* Define to 1 if you have the `imaxdiv' function. */
+#undef HAVE_IMAXDIV
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `isalpha' function. */
+#undef HAVE_ISALPHA
+
+/* Define to 1 if you have the `killpg' function. */
+#undef HAVE_KILLPG
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mempcpy' function. */
+#undef HAVE_MEMPCPY
+
+/* Define to 1 if you have the <paths.h> header file. */
+#undef HAVE_PATHS_H
+
+/* Define to 1 if you have the `sigsetmask' function. */
+#undef HAVE_SIGSETMASK
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `stpcpy' function. */
+#undef HAVE_STPCPY
+
+/* Define to 1 if you have the `strchrnul' function. */
+#undef HAVE_STRCHRNUL
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strsignal' function. */
+#undef HAVE_STRSIGNAL
+
+/* Define to 1 if you have the `strtod' function. */
+#undef HAVE_STRTOD
+
+/* Define to 1 if you have the `strtoimax' function. */
+#undef HAVE_STRTOIMAX
+
+/* Define to 1 if you have the `strtoumax' function. */
+#undef HAVE_STRTOUMAX
+
+/* Define to 1 if you have the `sysconf' function. */
+#undef HAVE_SYSCONF
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to printf format string for intmax_t */
+#undef PRIdMAX
+
+/* The size of `intmax_t', as computed by sizeof. */
+#undef SIZEOF_INTMAX_T
+
+/* The size of `long long int', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG_INT
+
+/* Define if you build with -DSMALL */
+#undef SMALL
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to system shell path */
+#undef _PATH_BSHELL
+
+/* Define to devnull device node path */
+#undef _PATH_DEVNULL
+
+/* Define to tty device node path */
+#undef _PATH_TTY
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* 64-bit operations are the same as 32-bit */
+#undef fstat64
+
+/* 64-bit operations are the same as 32-bit */
+#undef lstat64
+
+/* 64-bit operations are the same as 32-bit */
+#undef open64
+
+/* klibc has bsd_signal instead of signal */
+#undef signal
+
+/* 64-bit operations are the same as 32-bit */
+#undef stat64
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..f66ad0c
--- /dev/null
+++ b/configure
@@ -0,0 +1,6153 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.68 for dash 0.5.7.
+#
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+        /*)
+          for as_base in sh bash ksh sh5; do
+            # Try only shells that exist, to save several forks.
+            as_shell=$as_dir/$as_base
+            if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+                   { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+                  if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+          done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+             { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  # We cannot yet assume a decent shell, so we have to provide a
+       # neutralization value for shells without unset; and this also
+       # works around shells that cannot unset nonexistent variables.
+       # Preserve -v and -x to the replacement shell.
+       BASH_ENV=/dev/null
+       ENV=/dev/null
+       (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+       export CONFIG_SHELL
+       case $- in # ((((
+         *v*x* | *x*v* ) as_opts=-vx ;;
+         *v* ) as_opts=-v ;;
+         *x* ) as_opts=-x ;;
+         * ) as_opts= ;;
+       esac
+       exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+       test -d "$1/.";
+      else
+       case $1 in #(
+       -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='dash'
+PACKAGE_TARNAME='dash'
+PACKAGE_VERSION='0.5.7'
+PACKAGE_STRING='dash 0.5.7'
+PACKAGE_BUGREPORT=''
+PACKAGE_URL=''
+
+ac_unique_file="src/main.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+CC_FOR_BUILD
+YFLAGS
+YACC
+EGREP
+GREP
+CPP
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_dependency_tracking
+enable_static
+enable_fnmatch
+enable_glob
+with_libedit
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+YACC
+YFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
+               datadir sysconfdir sharedstatedir localstatedir includedir \
+               oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+               libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used" >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_myself" : 'X\(//\)[^/]' \| \
+        X"$as_myself" : 'X\(//\)$' \| \
+        X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+       cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+       pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures dash 0.5.7 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/dash]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of dash 0.5.7:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --disable-dependency-tracking  speeds up one-time build
+  --enable-dependency-tracking   do not reject slow dependency extractors
+  --enable-static         Build statical linked program
+  --enable-fnmatch        Use fnmatch(3) from libc
+  --enable-glob           Use glob(3) from libc
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-libedit          Compile with libedit support
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+  YACC        The `Yet Another Compiler Compiler' implementation to use.
+              Defaults to the first program found out of: `bison -y', `byacc',
+              `yacc'.
+  YFLAGS      The list of arguments that will be passed by default to $YACC.
+              This script will default YFLAGS to the empty string to avoid a
+              default value of `-d' given by some make applications.
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+dash configure 0.5.7
+generated by GNU Autoconf 2.68
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
+# ---------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly.
+ac_fn_c_check_decl ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  as_decl_name=`echo $2|sed 's/ *(.*//'`
+  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+#ifndef $as_decl_name
+#ifdef __cplusplus
+  (void) $as_decl_use;
+#else
+  (void) $as_decl_name;
+#endif
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_decl
+
+# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES
+# --------------------------------------------
+# Tries to find the compile-time value of EXPR in a program that includes
+# INCLUDES, setting VAR accordingly. Returns whether the value could be
+# computed
+ac_fn_c_compute_int ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if test "$cross_compiling" = yes; then
+    # Depending upon the size, compute the lo and hi bounds.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid; break
+else
+  as_fn_arith $ac_mid + 1 && ac_lo=$as_val
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=$ac_mid; break
+else
+  as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  ac_lo= ac_hi=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid
+else
+  as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in #((
+?*) eval "$3=\$ac_lo"; ac_retval=0 ;;
+'') ac_retval=1 ;;
+esac
+  else
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+static long int longval () { return $2; }
+static unsigned long int ulongval () { return $2; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (($2) < 0)
+    {
+      long int i = longval ();
+      if (i != ($2))
+       return 1;
+      fprintf (f, "%ld", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ($2))
+       return 1;
+      fprintf (f, "%lu", i);
+    }
+  /* Do not output a trailing newline, as this causes \r\n confusion
+     on some platforms.  */
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  echo >>conftest.val; read $3 <conftest.val; ac_retval=0
+else
+  ac_retval=1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.val
+
+  fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_compute_int
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by dash $as_me 0.5.7, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+       ac_must_keep_next=false # Got value, back to normal.
+      else
+       case $ac_arg in
+         *=* | --config-cache | -C | -disable-* | --disable-* \
+         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+         | -with-* | --with-* | -without-* | --without-* | --x)
+           case "$ac_configure_args0 " in
+             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+           esac
+           ;;
+         -* ) ac_must_keep_next=true ;;
+       esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+       "s/'\''/'\''\\\\'\'''\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=\$$ac_var
+       case $ac_val in
+       *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+       esac
+       $as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+       # differences in whitespace do not lead to failure.
+       ac_old_val_w=`echo x $ac_old_val`
+       ac_new_val_w=`echo x $ac_new_val`
+       if test "$ac_old_val_w" != "$ac_new_val_w"; then
+         { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+         ac_cache_corrupted=:
+       else
+         { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+         eval $ac_var=\$ac_old_val
+       fi
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+am__api_version='1.10'
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+       if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+         if test $ac_prog = install &&
+           grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         elif test $ac_prog = install &&
+           grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # program-specific install script used by HP pwplus--don't use.
+           :
+         else
+           rm -rf conftest.one conftest.two conftest.dir
+           echo one > conftest.one
+           echo two > conftest.two
+           mkdir conftest.dir
+           if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+             test -s conftest.one && test -s conftest.two &&
+             test -s conftest.dir/conftest.one &&
+             test -s conftest.dir/conftest.two
+           then
+             ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+             break 3
+           fi
+         fi
+       fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# 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 (
+   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
+   rm -f conftest.file
+   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".
+      as_fn_error $? "ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" "$LINENO" 5
+   fi
+
+   test "$2" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+test "$program_prefix" != NONE &&
+  program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+  am_missing_run="$MISSING --run "
+else
+  am_missing_run=
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"}
+
+# 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.
+if test "$cross_compiling" != no; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+  if ${ac_cv_path_mkdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in mkdir gmkdir; do
+        for ac_exec_ext in '' $ac_executable_extensions; do
+          { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+          case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+            'mkdir (GNU coreutils) '* | \
+            'mkdir (coreutils) '* | \
+            'mkdir (fileutils) '4.1*)
+              ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+              break 3;;
+          esac
+        done
+       done
+  done
+IFS=$as_save_IFS
+
+fi
+
+  test -d ./--version && rmdir ./--version
+  if test "${ac_cv_path_mkdir+set}" = set; then
+    MKDIR_P="$ac_cv_path_mkdir -p"
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for MKDIR_P within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    MKDIR_P="$ac_install_sh -d"
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+mkdir_p="$MKDIR_P"
+case $mkdir_p in
+  [\\/$]* | ?:[\\/]*) ;;
+  */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+       @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+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
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  am__isrc=' -I$(srcdir)'
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+  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
+
+
+# Define the identity of the package.
+ PACKAGE='dash'
+ VERSION='0.5.7'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
+
+
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+       ;;
+    [ab].out )
+       # We found the default executable, but exeext='' is most
+       # certainly right.
+       break;;
+    *.* )
+       if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+       then :; else
+          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+       fi
+       # We set ac_cv_exeext here because the later test for it is not
+       # safe: cross compilers may not add the suffix if given an `-o'
+       # argument, so we may need to know it at that point already.
+       # Even if this section looks crufty: it has the advantage of
+       # actually working.
+       break;;
+    * )
+       break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+         break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+       cross_compiling=yes
+    else
+       { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+       @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+   am__include=include
+   am__quote=
+   _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+      am__include=.include
+      am__quote="\""
+      _am_result=BSD
+   fi
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+  enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+  AMDEP_TRUE=
+  AMDEP_FALSE='#'
+else
+  AMDEP_TRUE='#'
+  AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC"   am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  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'.
+  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_CC_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
+  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 8's {/usr,}/bin/sh.
+      touch 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
+      ;;
+    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_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+                  (('a' <= (c) && (c) <= 'i') \
+                    || ('j' <= (c) && (c) <= 'r') \
+                    || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+       || toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+                 inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+  ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
+if test "x$ac_cv_header_minix_config_h" = xyes; then :
+  MINIX=yes
+else
+  MINIX=
+fi
+
+
+  if test "$MINIX" = yes; then
+
+$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h
+
+
+$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h
+
+
+$as_echo "#define _MINIX 1" >>confdefs.h
+
+  fi
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
+$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
+if ${ac_cv_safe_to_define___extensions__+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#        define __EXTENSIONS__ 1
+         $ac_includes_default
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_safe_to_define___extensions__=yes
+else
+  ac_cv_safe_to_define___extensions__=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5
+$as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
+  test $ac_cv_safe_to_define___extensions__ = yes &&
+    $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h
+
+  $as_echo "#define _ALL_SOURCE 1" >>confdefs.h
+
+  $as_echo "#define _GNU_SOURCE 1" >>confdefs.h
+
+  $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
+
+  $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h
+
+
+
+for ac_prog in 'bison -y' byacc
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_YACC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_YACC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5
+$as_echo "$YACC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for build system compiler" >&5
+$as_echo_n "checking for build system compiler... " >&6; }
+if test "$cross_compiling" = yes; then
+       CC_FOR_BUILD=${CC_FOR_BUILD-cc}
+else
+       CC_FOR_BUILD=${CC}
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${CC_FOR_BUILD}" >&5
+$as_echo "${CC_FOR_BUILD}" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((__alias__()))" >&5
+$as_echo_n "checking for __attribute__((__alias__()))... " >&6; }
+dash_cv_have_attribute_alias=no
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+void t() {}
+                                 void a() __attribute__((__alias__("t")));
+int
+main ()
+{
+a();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  dash_cv_have_attribute_alias=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dash_cv_have_attribute_alias" >&5
+$as_echo "$dash_cv_have_attribute_alias" >&6; }
+if test "x$dash_cv_have_attribute_alias" = xyes; then
+
+$as_echo "#define HAVE_ALIAS_ATTRIBUTE 1" >>confdefs.h
+
+fi
+
+# Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+  enableval=$enable_static;
+fi
+
+if test "$enable_static" = "yes"; then
+       export LDFLAGS="-static -Wl,--fatal-warnings"
+fi
+
+# Check whether --enable-fnmatch was given.
+if test "${enable_fnmatch+set}" = set; then :
+  enableval=$enable_fnmatch;
+fi
+
+# Check whether --enable-glob was given.
+if test "${enable_glob+set}" = set; then :
+  enableval=$enable_glob;
+fi
+
+
+
+for ac_header in alloca.h paths.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+ac_fn_c_check_decl "$LINENO" "_PATH_BSHELL" "ac_cv_have_decl__PATH_BSHELL" "
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+"
+if test "x$ac_cv_have_decl__PATH_BSHELL" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define _PATH_BSHELL "/bin/sh"
+_ACEOF
+
+fi
+
+ac_fn_c_check_decl "$LINENO" "_PATH_DEVNULL" "ac_cv_have_decl__PATH_DEVNULL" "
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+"
+if test "x$ac_cv_have_decl__PATH_DEVNULL" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define _PATH_DEVNULL "/dev/null"
+_ACEOF
+
+fi
+
+ac_fn_c_check_decl "$LINENO" "_PATH_TTY" "ac_cv_have_decl__PATH_TTY" "
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+"
+if test "x$ac_cv_have_decl__PATH_TTY" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define _PATH_TTY "/dev/tty"
+_ACEOF
+
+fi
+
+
+ac_fn_c_check_decl "$LINENO" "isblank" "ac_cv_have_decl_isblank" "#include <ctype.h>
+"
+if test "x$ac_cv_have_decl_isblank" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_ISBLANK $ac_have_decl
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of intmax_t" >&5
+$as_echo_n "checking size of intmax_t... " >&6; }
+if ${ac_cv_sizeof_intmax_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (intmax_t))" "ac_cv_sizeof_intmax_t"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_intmax_t" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (intmax_t)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_intmax_t=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_intmax_t" >&5
+$as_echo "$ac_cv_sizeof_intmax_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_INTMAX_T $ac_cv_sizeof_intmax_t
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long int" >&5
+$as_echo_n "checking size of long long int... " >&6; }
+if ${ac_cv_sizeof_long_long_int+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long int))" "ac_cv_sizeof_long_long_int"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_long_long_int" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (long long int)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_long_long_int=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long_int" >&5
+$as_echo "$ac_cv_sizeof_long_long_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG_LONG_INT $ac_cv_sizeof_long_long_int
+_ACEOF
+
+
+
+if test "x$ac_cv_sizeof_intmax_t" = "x$ac_cv_sizeof_long_long_int"; then
+  intmax_fstr="lld"
+else
+  intmax_fstr="jd"
+fi
+
+ac_fn_c_check_decl "$LINENO" "PRIdMAX" "ac_cv_have_decl_PRIdMAX" "
+#include <inttypes.h>
+
+"
+if test "x$ac_cv_have_decl_PRIdMAX" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define PRIdMAX "$intmax_fstr"
+_ACEOF
+
+fi
+
+
+for ac_func in bsearch faccessat getpwnam getrlimit imaxdiv isalpha killpg \
+              mempcpy \
+              sigsetmask stpcpy strchrnul strsignal strtod strtoimax \
+              strtoumax sysconf
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+if test "$enable_fnmatch" = yes; then
+       use_fnmatch=
+       for ac_func in fnmatch
+do :
+  ac_fn_c_check_func "$LINENO" "fnmatch" "ac_cv_func_fnmatch"
+if test "x$ac_cv_func_fnmatch" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_FNMATCH 1
+_ACEOF
+ use_fnmatch=yes
+fi
+done
+
+fi
+
+if test "$use_fnmatch" = yes && test "$enable_glob" = yes; then
+       for ac_func in glob
+do :
+  ac_fn_c_check_func "$LINENO" "glob" "ac_cv_func_glob"
+if test "x$ac_cv_func_glob" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GLOB 1
+_ACEOF
+
+fi
+done
+
+fi
+
+ac_fn_c_check_func "$LINENO" "signal" "ac_cv_func_signal"
+if test "x$ac_cv_func_signal" = xyes; then :
+
+fi
+
+if test "$ac_cv_func_signal" != yes; then
+       ac_fn_c_check_func "$LINENO" "bsd_signal" "ac_cv_func_bsd_signal"
+if test "x$ac_cv_func_bsd_signal" = xyes; then :
+
+$as_echo "#define signal bsd_signal" >>confdefs.h
+
+fi
+
+fi
+
+ac_fn_c_check_func "$LINENO" "stat64" "ac_cv_func_stat64"
+if test "x$ac_cv_func_stat64" = xyes; then :
+
+else
+
+
+$as_echo "#define fstat64 fstat" >>confdefs.h
+
+
+$as_echo "#define lstat64 lstat" >>confdefs.h
+
+
+$as_echo "#define stat64 stat" >>confdefs.h
+
+
+fi
+
+
+ac_fn_c_check_func "$LINENO" "open64" "ac_cv_func_open64"
+if test "x$ac_cv_func_open64" = xyes; then :
+
+else
+
+
+$as_echo "#define open64 open" >>confdefs.h
+
+
+fi
+
+
+
+# Check whether --with-libedit was given.
+if test "${with_libedit+set}" = set; then :
+  withval=$with_libedit;
+fi
+
+use_libedit=
+if test "$with_libedit" = "yes"; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for history_init in -ledit" >&5
+$as_echo_n "checking for history_init in -ledit... " >&6; }
+if ${ac_cv_lib_edit_history_init+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ledit  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char history_init ();
+int
+main ()
+{
+return history_init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_edit_history_init=yes
+else
+  ac_cv_lib_edit_history_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_history_init" >&5
+$as_echo "$ac_cv_lib_edit_history_init" >&6; }
+if test "x$ac_cv_lib_edit_history_init" = xyes; then :
+
+               ac_fn_c_check_header_mongrel "$LINENO" "histedit.h" "ac_cv_header_histedit_h" "$ac_includes_default"
+if test "x$ac_cv_header_histedit_h" = xyes; then :
+  use_libedit="yes"
+else
+  as_fn_error $? "Can't find required header files." "$LINENO" 5
+fi
+
+
+fi
+
+fi
+if test "$use_libedit" != "yes"; then
+
+$as_echo "#define SMALL 1" >>confdefs.h
+
+else
+       export LIBS="$LIBS -ledit"
+fi
+ac_config_files="$ac_config_files Makefile src/Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+       "s/'/'\\\\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+       cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+         mv -f confcache "$cache_file"$$ &&
+         mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+         mv -f confcache "$cache_file" ;;
+       esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+  as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+       test -d "$1/.";
+      else
+       case $1 in #(
+       -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by dash $as_me 0.5.7, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+dash config.status 0.5.7
+configured by $0, generated by GNU Autoconf 2.68,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = "\a"
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[         ]*VPATH[        ]*=[    ]*/{
+h
+s///
+s/^/:/
+s/[     ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[  ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[      ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[    ]*#[    ]*define[       ][      ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[    ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[        ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[    ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[        ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = "\a"
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+        # (if the path is not absolute).  The absolute path cannot be DOS-style,
+        # because $ac_f cannot contain `:'.
+        test -f "$ac_f" ||
+          case $ac_f in
+          [\\/$]*) false;;
+          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+          esac ||
+          as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+         $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+       `' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$ac_file" : 'X\(//\)[^/]' \| \
+        X"$ac_file" : 'X\(//\)$' \| \
+        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+  ac_MKDIR_P=$MKDIR_P
+  case $MKDIR_P in
+  [\\/$]* | ?:[\\/]* ) ;;
+  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+       || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_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" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$_am_arg" : 'X\(//\)[^/]' \| \
+        X"$_am_arg" : 'X\(//\)$' \| \
+        X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+  # Autoconf 2.62 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" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$mf" : 'X\(//\)[^/]' \| \
+        X"$mf" : 'X\(//\)$' \| \
+        X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+    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"`
+    # When using ansi2knr, U may be empty or an underscore; expand it
+    U=`sed -n 's/^U = //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' -e 's/\$U/'"$U"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$file" : 'X\(//\)[^/]' \| \
+        X"$file" : 'X\(//\)$' \| \
+        X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      as_dir=$dirpart/$fdir; as_fn_mkdir_p
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+ ;;
+
+  esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..7eae954
--- /dev/null
@@ -0,0 +1,135 @@
+AC_INIT(dash, 0.5.7)
+AM_INIT_AUTOMAKE([foreign])
+AC_CONFIG_SRCDIR([src/main.c])
+
+AC_CONFIG_HEADERS(config.h)
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_GNU_SOURCE
+AC_PROG_YACC
+
+AC_MSG_CHECKING([for build system compiler])
+if test "$cross_compiling" = yes; then
+       CC_FOR_BUILD=${CC_FOR_BUILD-cc}
+else
+       CC_FOR_BUILD=${CC}
+fi
+AC_MSG_RESULT(${CC_FOR_BUILD})
+AC_SUBST(CC_FOR_BUILD)
+
+AC_MSG_CHECKING([for __attribute__((__alias__()))])
+dash_cv_have_attribute_alias=no
+AC_LINK_IFELSE([AC_LANG_PROGRAM([void t() {}
+                                 void a() __attribute__((__alias__("t")));],
+                                [a();])],
+               [dash_cv_have_attribute_alias=yes])
+AC_MSG_RESULT($dash_cv_have_attribute_alias)
+if test "x$dash_cv_have_attribute_alias" = xyes; then
+  AC_DEFINE([HAVE_ALIAS_ATTRIBUTE], 1,
+            [Define if __attribute__((__alias__())) is supported])
+fi
+
+AC_ARG_ENABLE(static, AS_HELP_STRING(--enable-static, \
+                                    [Build statical linked program]))
+if test "$enable_static" = "yes"; then
+       export LDFLAGS="-static -Wl,--fatal-warnings"
+fi
+
+AC_ARG_ENABLE(fnmatch, AS_HELP_STRING(--enable-fnmatch, \
+                                     [Use fnmatch(3) from libc]))
+AC_ARG_ENABLE(glob, AS_HELP_STRING(--enable-glob, [Use glob(3) from libc]))
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+AC_CHECK_HEADERS(alloca.h paths.h)
+
+dnl Check for declarations
+AC_CHECK_DECL([_PATH_BSHELL],,AC_DEFINE_UNQUOTED([_PATH_BSHELL], "/bin/sh", [Define to system shell path]),[
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+])
+AC_CHECK_DECL([_PATH_DEVNULL],,AC_DEFINE_UNQUOTED([_PATH_DEVNULL], "/dev/null", [Define to devnull device node path]),[
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+])
+AC_CHECK_DECL([_PATH_TTY],,AC_DEFINE_UNQUOTED([_PATH_TTY], "/dev/tty", [Define to tty device node path]),[
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+])
+
+dnl Some systems lack isblank
+AC_CHECK_DECLS([isblank],,,[#include <ctype.h>])
+
+dnl Check for sizes of types
+AC_CHECK_SIZEOF([intmax_t])
+AC_CHECK_SIZEOF([long long int])
+
+dnl Select a fallback format string for intmax_t in case we don't find PRIdMAX
+if test "x$ac_cv_sizeof_intmax_t" = "x$ac_cv_sizeof_long_long_int"; then
+  intmax_fstr="lld"
+else
+  intmax_fstr="jd"
+fi
+
+dnl Check for PRIdMAX and define it to a fallback if not found
+AC_CHECK_DECL([PRIdMAX],,
+       [AC_DEFINE_UNQUOTED([PRIdMAX], "$intmax_fstr",
+                                      [Define to printf format string for intmax_t])],
+        [
+#include <inttypes.h>
+])
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(bsearch faccessat getpwnam getrlimit imaxdiv isalpha killpg \
+              mempcpy \
+              sigsetmask stpcpy strchrnul strsignal strtod strtoimax \
+              strtoumax sysconf)
+
+if test "$enable_fnmatch" = yes; then
+       use_fnmatch=
+       AC_CHECK_FUNCS(fnmatch, use_fnmatch=yes)
+fi
+
+if test "$use_fnmatch" = yes && test "$enable_glob" = yes; then
+       AC_CHECK_FUNCS(glob)
+fi
+
+dnl Check for klibc signal.
+AC_CHECK_FUNC(signal)
+if test "$ac_cv_func_signal" != yes; then
+       AC_CHECK_FUNC(bsd_signal,
+                     [AC_DEFINE(signal, bsd_signal,
+                                [klibc has bsd_signal instead of signal])])
+fi
+
+dnl Check for stat64 (dietlibc/klibc).
+AC_CHECK_FUNC(stat64,, [
+       AC_DEFINE(fstat64, fstat, [64-bit operations are the same as 32-bit])
+       AC_DEFINE(lstat64, lstat, [64-bit operations are the same as 32-bit])
+       AC_DEFINE(stat64, stat, [64-bit operations are the same as 32-bit])
+])
+
+AC_CHECK_FUNC(open64,, [
+       AC_DEFINE(open64, open, [64-bit operations are the same as 32-bit])
+])
+
+AC_ARG_WITH(libedit, AS_HELP_STRING(--with-libedit, [Compile with libedit support]))
+use_libedit=
+if test "$with_libedit" = "yes"; then
+       AC_CHECK_LIB(edit, history_init, [
+               AC_CHECK_HEADER([histedit.h], [use_libedit="yes"],
+                               AC_MSG_ERROR(
+                                       [Can't find required header files.]))])
+fi
+if test "$use_libedit" != "yes"; then
+       AC_DEFINE([SMALL], 1, [Define if you build with -DSMALL])
+else
+       export LIBS="$LIBS -ledit"
+fi
+AC_CONFIG_FILES([Makefile src/Makefile])
+AC_OUTPUT
diff --git a/depcomp b/depcomp
new file mode 100755 (executable)
index 0000000..aeba4e8
--- /dev/null
+++ b/depcomp
@@ -0,0 +1,632 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2009-04-28.21; # UTC
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free
+# Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+  '')
+     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+  depmode     Dependency tracking mode.
+  source      Source file read by `PROGRAMS ARGS'.
+  object      Object file output by `PROGRAMS ARGS'.
+  DEPDIR      directory where to store dependencies.
+  depfile     Dependency file to output.
+  tmpdepfile  Temporary file to use when outputing dependencies.
+  libtool     Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "depcomp $scriptversion"
+    exit $?
+    ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+   # This is just like dashmstdout with a different argument.
+   dashmflag=-xM
+   depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+   # This is just like msvisualcpp but w/o cygpath translation.
+   # Just convert the backslash-escaped backslashes to single forward
+   # slashes to satisfy depend.m4
+   cygpath_u="sed s,\\\\\\\\,/,g"
+   depmode=msvisualcpp
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am.  Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+  for arg
+  do
+    case $arg in
+    -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+    *)  set fnord "$@" "$arg" ;;
+    esac
+    shift # fnord
+    shift # $arg
+  done
+  "$@"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+  tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'.  On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like `#:fec' to the end of the
+    # dependency line.
+    tr ' ' '
+' < "$tmpdepfile" \
+    | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+    tr '
+' ' ' >> "$depfile"
+    echo >> "$depfile"
+
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' '
+' < "$tmpdepfile" \
+   | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+   >> "$depfile"
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  In older versions, this file always lives in the
+  # current directory.  Also, the AIX compiler puts `$object:' at the
+  # start of each line; $object doesn't have directory information.
+  # Version 6 uses the directory in both cases.
+  dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+  test "x$dir" = "x$object" && dir=
+  base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$base.u
+    tmpdepfile3=$dir.libs/$base.u
+    "$@" -Wc,-M
+  else
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$dir$base.u
+    tmpdepfile3=$dir$base.u
+    "$@" -M
+  fi
+  stat=$?
+
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    # Each line is of the form `foo.o: dependent.h'.
+    # Do two passes, one to just change these to
+    # `$object: dependent.h' and one to simply `dependent.h:'.
+    sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+    # That's a tab and a space in the [].
+    sed -e 's,^.*\.[a-z]*:[     ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+icc)
+  # Intel's C compiler understands `-MD -MF file'.  However on
+  #    icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+  # ICC 7.0 will fill foo.d with something like
+  #    foo.o: sub/foo.c
+  #    foo.o: sub/foo.h
+  # which is wrong.  We want:
+  #    sub/foo.o: sub/foo.c
+  #    sub/foo.o: sub/foo.h
+  #    sub/foo.c:
+  #    sub/foo.h:
+  # ICC 7.1 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using \ :
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+
+  "$@" -MD -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each line is of the form `foo.o: dependent.h',
+  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # `$object: dependent.h' and one to simply `dependent.h:'.
+  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+    sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp2)
+  # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+  # compilers, which have integrated preprocessors.  The correct option
+  # to use with these is +Maked; it writes dependencies to a file named
+  # 'foo.d', which lands next to the object file, wherever that
+  # happens to be.
+  # Much of this is similar to the tru64 case; see comments there.
+  dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+  test "x$dir" = "x$object" && dir=
+  base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir.libs/$base.d
+    "$@" -Wc,+Maked
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    "$@" +Maked
+  fi
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+     rm -f "$tmpdepfile1" "$tmpdepfile2"
+     exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
+    # Add `dependent.h:' lines.
+    sed -ne '2,${
+              s/^ *//
+              s/ \\*$//
+              s/$/:/
+              p
+            }' "$tmpdepfile" >> "$depfile"
+  else
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile" "$tmpdepfile2"
+  ;;
+
+tru64)
+   # The Tru64 compiler uses -MD to generate dependencies as a side
+   # effect.  `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+   # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+   # dependencies in `foo.d' instead, so we check for that too.
+   # Subdirectories are respected.
+   dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+   test "x$dir" = "x$object" && dir=
+   base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+   if test "$libtool" = yes; then
+      # With Tru64 cc, shared objects can also be used to make a
+      # static library.  This mechanism is used in libtool 1.4 series to
+      # handle both shared and static libraries in a single compilation.
+      # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+      #
+      # With libtool 1.5 this exception was removed, and libtool now
+      # generates 2 separate objects for the 2 libraries.  These two
+      # compilations output dependencies in $dir.libs/$base.o.d and
+      # in $dir$base.o.d.  We have to check for both files, because
+      # one of the two compilations can be disabled.  We should prefer
+      # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+      # automatically cleaned when .libs/ is deleted, while ignoring
+      # the former would cause a distcleancheck panic.
+      tmpdepfile1=$dir.libs/$base.lo.d   # libtool 1.4
+      tmpdepfile2=$dir$base.o.d          # libtool 1.5
+      tmpdepfile3=$dir.libs/$base.o.d    # libtool 1.5
+      tmpdepfile4=$dir.libs/$base.d      # Compaq CCC V6.2-504
+      "$@" -Wc,-MD
+   else
+      tmpdepfile1=$dir$base.o.d
+      tmpdepfile2=$dir$base.d
+      tmpdepfile3=$dir$base.d
+      tmpdepfile4=$dir$base.d
+      "$@" -MD
+   fi
+
+   stat=$?
+   if test $stat -eq 0; then :
+   else
+      rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+      exit $stat
+   fi
+
+   for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+   do
+     test -f "$tmpdepfile" && break
+   done
+   if test -f "$tmpdepfile"; then
+      sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+      # That's a tab and a space in the [].
+      sed -e 's,^.*\.[a-z]*:[   ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+   else
+      echo "#dummy" > "$depfile"
+   fi
+   rm -f "$tmpdepfile"
+   ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove `-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  # Require at least two characters before searching for `:'
+  # in the target name.  This is to cope with DOS-style filenames:
+  # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+  "$@" $dashmflag |
+    sed 's:^[  ]*[^: ][^:][^:]*\:[    ]*:'"$object"'\: :' > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # Remove any Libtool call
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+  # X makedepend
+  shift
+  cleared=no eat=no
+  for arg
+  do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    if test $eat = yes; then
+      eat=no
+      continue
+    fi
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    # Strip any option that makedepend may not understand.  Remove
+    # the object too, otherwise makedepend will parse it as a source file.
+    -arch)
+      eat=yes ;;
+    -*|$object)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix=`echo "$object" | sed 's/^.*\././'`
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove `-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E |
+    sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+       -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+    sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+       set fnord "$@"
+       shift
+       shift
+       ;;
+    *)
+       set fnord "$@" "$arg"
+       shift
+       shift
+       ;;
+    esac
+  done
+  "$@" -E 2>/dev/null |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::     \1 \\:p' >> "$depfile"
+  echo "       " >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvcmsys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
+
+# 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/install-sh b/install-sh
new file mode 100755 (executable)
index 0000000..6781b98
--- /dev/null
@@ -0,0 +1,520 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2009-04-28.21; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" ""       $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+  doit_exec=exec
+else
+  doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+  test "$posix_glob" != "?" || {
+    if (set -f) 2>/dev/null; then
+      posix_glob=
+    else
+      posix_glob=:
+    fi
+  }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+     --help     display this help and exit.
+     --version  display version info and exit.
+
+  -c            (ignored)
+  -C            install only if different (preserve the last data modification time)
+  -d            create directories instead of installing files.
+  -g GROUP      $chgrpprog installed files to GROUP.
+  -m MODE       $chmodprog installed files to MODE.
+  -o USER       $chownprog installed files to USER.
+  -s            $stripprog installed files.
+  -t DIRECTORY  install into DIRECTORY.
+  -T            report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+  RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+  case $1 in
+    -c) ;;
+
+    -C) copy_on_change=true;;
+
+    -d) dir_arg=true;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+       shift;;
+
+    --help) echo "$usage"; exit $?;;
+
+    -m) mode=$2
+       case $mode in
+         *' '* | *'    '* | *'
+'*       | *'*'* | *'?'* | *'['*)
+           echo "$0: invalid mode: $mode" >&2
+           exit 1;;
+       esac
+       shift;;
+
+    -o) chowncmd="$chownprog $2"
+       shift;;
+
+    -s) stripcmd=$stripprog;;
+
+    -t) dst_arg=$2
+       shift;;
+
+    -T) no_target_directory=true;;
+
+    --version) echo "$0 $scriptversion"; exit $?;;
+
+    --)        shift
+       break;;
+
+    -*)        echo "$0: invalid option: $1" >&2
+       exit 1;;
+
+    *)  break;;
+  esac
+  shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+  # When -d is used, all remaining arguments are directories to create.
+  # When -t is used, the destination is already specified.
+  # Otherwise, the last argument is the destination.  Remove it from $@.
+  for arg
+  do
+    if test -n "$dst_arg"; then
+      # $@ is not empty: it contains at least $arg.
+      set fnord "$@" "$dst_arg"
+      shift # fnord
+    fi
+    shift # arg
+    dst_arg=$arg
+  done
+fi
+
+if test $# -eq 0; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call `install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+if test -z "$dir_arg"; then
+  trap '(exit $?); exit' 1 2 13 15
+
+  # Set umask so as not to create temps with too-generous modes.
+  # However, 'strip' requires both read and write access to temps.
+  case $mode in
+    # Optimize common cases.
+    *644) cp_umask=133;;
+    *755) cp_umask=22;;
+
+    *[0-7])
+      if test -z "$stripcmd"; then
+       u_plus_rw=
+      else
+       u_plus_rw='% 200'
+      fi
+      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+    *)
+      if test -z "$stripcmd"; then
+       u_plus_rw=
+      else
+       u_plus_rw=,u+rw
+      fi
+      cp_umask=$mode$u_plus_rw;;
+  esac
+fi
+
+for src
+do
+  # Protect names starting with `-'.
+  case $src in
+    -*) src=./$src;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    dstdir=$dst
+    test -d "$dstdir"
+    dstdir_status=$?
+  else
+
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dst_arg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+
+    dst=$dst_arg
+    # Protect names starting with `-'.
+    case $dst in
+      -*) dst=./$dst;;
+    esac
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test -n "$no_target_directory"; then
+       echo "$0: $dst_arg: Is a directory" >&2
+       exit 1
+      fi
+      dstdir=$dst
+      dst=$dstdir/`basename "$src"`
+      dstdir_status=0
+    else
+      # Prefer dirname, but fall back on a substitute if dirname fails.
+      dstdir=`
+       (dirname "$dst") 2>/dev/null ||
+       expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+            X"$dst" : 'X\(//\)[^/]' \| \
+            X"$dst" : 'X\(//\)$' \| \
+            X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+       echo X"$dst" |
+           sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+                  s//\1/
+                  q
+                }
+                /^X\(\/\/\)[^/].*/{
+                  s//\1/
+                  q
+                }
+                /^X\(\/\/\)$/{
+                  s//\1/
+                  q
+                }
+                /^X\(\/\).*/{
+                  s//\1/
+                  q
+                }
+                s/.*/./; q'
+      `
+
+      test -d "$dstdir"
+      dstdir_status=$?
+    fi
+  fi
+
+  obsolete_mkdir_used=false
+
+  if test $dstdir_status != 0; then
+    case $posix_mkdir in
+      '')
+       # Create intermediate dirs using mode 755 as modified by the umask.
+       # This is like FreeBSD 'install' as of 1997-10-28.
+       umask=`umask`
+       case $stripcmd.$umask in
+         # Optimize common cases.
+         *[2367][2367]) mkdir_umask=$umask;;
+         .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+         *[0-7])
+           mkdir_umask=`expr $umask + 22 \
+             - $umask % 100 % 40 + $umask % 20 \
+             - $umask % 10 % 4 + $umask % 2
+           `;;
+         *) mkdir_umask=$umask,go-w;;
+       esac
+
+       # With -d, create the new directory with the user-specified mode.
+       # Otherwise, rely on $mkdir_umask.
+       if test -n "$dir_arg"; then
+         mkdir_mode=-m$mode
+       else
+         mkdir_mode=
+       fi
+
+       posix_mkdir=false
+       case $umask in
+         *[123567][0-7][0-7])
+           # POSIX mkdir -p sets u+wx bits regardless of umask, which
+           # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+           ;;
+         *)
+           tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+           trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+           if (umask $mkdir_umask &&
+               exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+           then
+             if test -z "$dir_arg" || {
+                  # Check for POSIX incompatibilities with -m.
+                  # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+                  # other-writeable bit of parent directory when it shouldn't.
+                  # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+                  ls_ld_tmpdir=`ls -ld "$tmpdir"`
+                  case $ls_ld_tmpdir in
+                    d????-?r-*) different_mode=700;;
+                    d????-?--*) different_mode=755;;
+                    *) false;;
+                  esac &&
+                  $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+                    ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+                    test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+                  }
+                }
+             then posix_mkdir=:
+             fi
+             rmdir "$tmpdir/d" "$tmpdir"
+           else
+             # Remove any dirs left behind by ancient mkdir implementations.
+             rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+           fi
+           trap '' 0;;
+       esac;;
+    esac
+
+    if
+      $posix_mkdir && (
+       umask $mkdir_umask &&
+       $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+      )
+    then :
+    else
+
+      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # or it failed possibly due to a race condition.  Create the
+      # directory the slow way, step by step, checking for races as we go.
+
+      case $dstdir in
+       /*) prefix='/';;
+       -*) prefix='./';;
+       *)  prefix='';;
+      esac
+
+      eval "$initialize_posix_glob"
+
+      oIFS=$IFS
+      IFS=/
+      $posix_glob set -f
+      set fnord $dstdir
+      shift
+      $posix_glob set +f
+      IFS=$oIFS
+
+      prefixes=
+
+      for d
+      do
+       test -z "$d" && continue
+
+       prefix=$prefix$d
+       if test -d "$prefix"; then
+         prefixes=
+       else
+         if $posix_mkdir; then
+           (umask=$mkdir_umask &&
+            $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+           # Don't fail if two instances are running concurrently.
+           test -d "$prefix" || exit 1
+         else
+           case $prefix in
+             *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+             *) qprefix=$prefix;;
+           esac
+           prefixes="$prefixes '$qprefix'"
+         fi
+       fi
+       prefix=$prefix/
+      done
+
+      if test -n "$prefixes"; then
+       # Don't fail if two instances are running concurrently.
+       (umask $mkdir_umask &&
+        eval "\$doit_exec \$mkdirprog $prefixes") ||
+         test -d "$dstdir" || exit 1
+       obsolete_mkdir_used=true
+      fi
+    fi
+  fi
+
+  if test -n "$dir_arg"; then
+    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+  else
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+    # Copy the file name to the temp name.
+    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+    # and set any options; do chmod last to preserve setuid bits.
+    #
+    # If any of these fail, we abort the whole thing.  If we want to
+    # ignore errors from any of these, just make sure not to ignore
+    # errors from the above "$doit $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+    # If -C, don't bother to copy if it wouldn't change the file.
+    if $copy_on_change &&
+       old=`LC_ALL=C ls -dlL "$dst"    2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+       eval "$initialize_posix_glob" &&
+       $posix_glob set -f &&
+       set X $old && old=:$2:$4:$5:$6 &&
+       set X $new && new=:$2:$4:$5:$6 &&
+       $posix_glob set +f &&
+
+       test "$old" = "$new" &&
+       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+    then
+      rm -f "$dsttmp"
+    else
+      # Rename the file to the real destination.
+      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+      # The rename failed, perhaps because mv can't rename something else
+      # to itself, or perhaps because mv is so ancient that it does not
+      # support -f.
+      {
+       # Now remove or move aside any old file at destination location.
+       # We try this two ways since rm can't unlink itself on some
+       # systems and the destination file might be busy for other
+       # reasons.  In this case, the final cleanup might fail but the new
+       # file should still install successfully.
+       {
+         test ! -f "$dst" ||
+         $doit $rmcmd -f "$dst" 2>/dev/null ||
+         { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+           { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+         } ||
+         { echo "$0: cannot unlink or rename $dst" >&2
+           (exit 1); exit 1
+         }
+       } &&
+
+       # Now rename the file to the real destination.
+       $doit $mvcmd "$dsttmp" "$dst"
+      }
+    fi || exit 1
+
+    trap '' 0
+  fi
+done
+
+# Local variables:
+# 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/missing b/missing
new file mode 100755 (executable)
index 0000000..ac3d51c
--- /dev/null
+++ b/missing
@@ -0,0 +1,378 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2009-04-28.21; # UTC
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
+# 2008, 2009 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+run=:
+sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
+sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+  configure_ac=configure.ac
+else
+  configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case $1 in
+--run)
+  # Try to run requested program, and just exit if it succeeds.
+  run=
+  shift
+  "$@" && exit 0
+  # Exit code 63 means version mismatch.  This often happens
+  # when the user try to use an ancient version of a tool on
+  # a file that requires a minimum version.  In this case we
+  # we should proceed has if the program had been absent, or
+  # if --run hadn't been passed.
+  if test $? = 63; then
+    run=:
+    msg="probably too old"
+  fi
+  ;;
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+  --run           try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  autom4te     touch the output file, or create a stub one
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  help2man     touch the output file
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  tar          try tar, gnutar, gtar, then tar without non-portable flags
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
+\`g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+    exit $?
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    exit $?
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+esac
+
+# normalize program name to check for.
+program=`echo "$1" | sed '
+  s/^gnu-//; t
+  s/^gnu//; t
+  s/^g//; t'`
+
+# Now exit if we have it, but it failed.  Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program).  This is about non-GNU programs, so use $1 not
+# $program.
+case $1 in
+  lex*|yacc*)
+    # Not GNU programs, they don't have --version.
+    ;;
+
+  tar*)
+    if test -n "$run"; then
+       echo 1>&2 "ERROR: \`tar' requires --run"
+       exit 1
+    elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+       exit 1
+    fi
+    ;;
+
+  *)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+       # Could not run --version or --help.  This is probably someone
+       # running `$TOOL --version' or `$TOOL --help' to check whether
+       # $TOOL exists and not knowing $TOOL uses missing.
+       exit 1
+    fi
+    ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case $program in
+  aclocal*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acinclude.m4' or \`${configure_ac}'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`${configure_ac}'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acconfig.h' or \`${configure_ac}'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case $f in
+      *:*) touch_files="$touch_files "`echo "$f" |
+                                      sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+          sed 's/\.am$/.in/' |
+          while read f; do touch "$f"; done
+    ;;
+
+  autom4te*)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.
+         You can get \`$1' as part of \`Autoconf' from any GNU
+         archive site."
+
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -f "$file"; then
+       touch $file
+    else
+       test -z "$file" || exec >$file
+       echo "#! /bin/sh"
+       echo "# Created by GNU Automake missing as a replacement of"
+       echo "#  $ $@"
+       echo "exit 0"
+       chmod +x $file
+       exit 1
+    fi
+    ;;
+
+  bison*|yacc*)
+    echo 1>&2 "\
+WARNING: \`$1' $msg.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if test $# -ne 1; then
+        eval LASTARG="\${$#}"
+       case $LASTARG in
+       *.y)
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+           if test -f "$SRCFILE"; then
+                cp "$SRCFILE" y.tab.c
+           fi
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+           if test -f "$SRCFILE"; then
+                cp "$SRCFILE" y.tab.h
+           fi
+         ;;
+       esac
+    fi
+    if test ! -f y.tab.h; then
+       echo >y.tab.h
+    fi
+    if test ! -f y.tab.c; then
+       echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex*|flex*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if test $# -ne 1; then
+        eval LASTARG="\${$#}"
+       case $LASTARG in
+       *.l)
+           SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+           if test -f "$SRCFILE"; then
+                cp "$SRCFILE" lex.yy.c
+           fi
+         ;;
+       esac
+    fi
+    if test ! -f lex.yy.c; then
+       echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  help2man*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+        you modified a dependency of a manual page.  You may need the
+        \`Help2man' package in order for those modifications to take
+        effect.  You can get \`Help2man' from any GNU archive site."
+
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -f "$file"; then
+       touch $file
+    else
+       test -z "$file" || exec >$file
+       echo ".ab help2man is required to generate this page"
+       exit $?
+    fi
+    ;;
+
+  makeinfo*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    # The file to touch is that specified with -o ...
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -z "$file"; then
+      # ... or it is the one specified with @setfilename ...
+      infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '
+       /^@setfilename/{
+         s/.* \([^ ]*\) *$/\1/
+         p
+         q
+       }' $infile`
+      # ... or it is derived from the source name (dir/f.texi becomes f.info)
+      test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+    fi
+    # If the file does not exist, the user really needs makeinfo;
+    # let's fail without touching anything.
+    test -f $file || exit 1
+    touch $file
+    ;;
+
+  tar*)
+    shift
+
+    # We have already tried tar in the generic part.
+    # Look for gnutar/gtar before invocation to avoid ugly error
+    # messages.
+    if (gnutar --version > /dev/null 2>&1); then
+       gnutar "$@" && exit 0
+    fi
+    if (gtar --version > /dev/null 2>&1); then
+       gtar "$@" && exit 0
+    fi
+    firstarg="$1"
+    if shift; then
+       case $firstarg in
+       *o*)
+           firstarg=`echo "$firstarg" | sed s/o//`
+           tar "$firstarg" "$@" && exit 0
+           ;;
+       esac
+       case $firstarg in
+       *h*)
+           firstarg=`echo "$firstarg" | sed s/h//`
+           tar "$firstarg" "$@" && exit 0
+           ;;
+       esac
+    fi
+
+    echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+         You may want to install GNU tar or Free paxutils, or check the
+         command line arguments."
+    exit 1
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequisites for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
+
+# Local variables:
+# 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/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..2a37381
--- /dev/null
@@ -0,0 +1,72 @@
+AM_YFLAGS = -d
+
+COMMON_CFLAGS = -Wall
+COMMON_CPPFLAGS = \
+       -include $(top_builddir)/config.h \
+       -DBSD=1 -DSHELL \
+       -DIFS_BROKEN
+
+AM_CFLAGS = $(COMMON_CFLAGS)
+AM_CPPFLAGS = $(COMMON_CPPFLAGS)
+AM_CFLAGS_FOR_BUILD = -g -O2 $(COMMON_CFLAGS) 
+AM_CPPFLAGS_FOR_BUILD = $(COMMON_CPPFLAGS)
+
+COMPILE_FOR_BUILD = \
+       $(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(AM_CPPFLAGS_FOR_BUILD) \
+       $(CPPFLAGS_FOR_BUILD) \
+       $(AM_CFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) 
+
+bin_PROGRAMS = dash
+
+dash_CFILES = \
+       alias.c arith_yacc.c arith_yylex.c cd.c error.c eval.c exec.c expand.c \
+       histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
+       mystring.c options.c parser.c redir.c show.c trap.c output.c \
+       bltin/printf.c system.c bltin/test.c bltin/times.c var.c
+dash_SOURCES = \
+       $(dash_CFILES) \
+       alias.h arith_yacc.h bltin/bltin.h cd.h error.h eval.h exec.h \
+       expand.h hetio.h \
+       init.h input.h jobs.h machdep.h mail.h main.h memalloc.h miscbltin.h \
+       myhistedit.h mystring.h options.h output.h parser.h redir.h shell.h \
+       show.h system.h trap.h var.h
+dash_LDADD = builtins.o init.o nodes.o signames.o syntax.o
+
+HELPERS = mkinit mksyntax mknodes mksignames
+
+BUILT_SOURCES = builtins.h nodes.h syntax.h token.h token_vars.h
+CLEANFILES = \
+       $(BUILT_SOURCES) $(patsubst %.o,%.c,$(dash_LDADD)) \
+       $(HELPERS) builtins.def
+
+man_MANS = dash.1
+EXTRA_DIST = \
+       $(man_MANS) \
+       mktokens mkbuiltins builtins.def.in mkinit.c \
+       mknodes.c nodetypes nodes.c.pat mksyntax.c mksignames.c
+
+token.h token_vars.h: mktokens
+       sh $^
+
+builtins.def: builtins.def.in $(top_builddir)/config.h
+       $(COMPILE) -E -x c -o $@ $<
+
+builtins.c builtins.h: mkbuiltins builtins.def
+       sh $^
+
+init.c: mkinit $(dash_CFILES)
+       ./$^
+
+nodes.c nodes.h: mknodes nodetypes nodes.c.pat
+       ./$^
+
+syntax.c syntax.h: mksyntax
+       ./$^
+
+signames.c: mksignames
+       ./$^
+
+mksyntax: token.h
+
+$(HELPERS): %: %.c
+       $(COMPILE_FOR_BUILD) -o $@ $<
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644 (file)
index 0000000..6792d42
--- /dev/null
@@ -0,0 +1,638 @@
+# Makefile.in generated by automake 1.10.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+bin_PROGRAMS = dash$(EXEEXT)
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+am__objects_1 = alias.$(OBJEXT) arith_yacc.$(OBJEXT) \
+       arith_yylex.$(OBJEXT) cd.$(OBJEXT) error.$(OBJEXT) \
+       eval.$(OBJEXT) exec.$(OBJEXT) expand.$(OBJEXT) \
+       histedit.$(OBJEXT) input.$(OBJEXT) jobs.$(OBJEXT) \
+       mail.$(OBJEXT) main.$(OBJEXT) memalloc.$(OBJEXT) \
+       miscbltin.$(OBJEXT) mystring.$(OBJEXT) options.$(OBJEXT) \
+       parser.$(OBJEXT) redir.$(OBJEXT) show.$(OBJEXT) trap.$(OBJEXT) \
+       output.$(OBJEXT) printf.$(OBJEXT) system.$(OBJEXT) \
+       test.$(OBJEXT) times.$(OBJEXT) var.$(OBJEXT)
+am_dash_OBJECTS = $(am__objects_1)
+dash_OBJECTS = $(am_dash_OBJECTS)
+dash_DEPENDENCIES = builtins.o init.o nodes.o signames.o syntax.o
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(dash_SOURCES)
+DIST_SOURCES = $(dash_SOURCES)
+man1dir = $(mandir)/man1
+NROFF = nroff
+MANS = $(man_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_YFLAGS = -d
+COMMON_CFLAGS = -Wall
+COMMON_CPPFLAGS = \
+       -include $(top_builddir)/config.h \
+       -DBSD=1 -DSHELL \
+       -DIFS_BROKEN
+
+AM_CFLAGS = $(COMMON_CFLAGS)
+AM_CPPFLAGS = $(COMMON_CPPFLAGS)
+AM_CFLAGS_FOR_BUILD = -g -O2 $(COMMON_CFLAGS) 
+AM_CPPFLAGS_FOR_BUILD = $(COMMON_CPPFLAGS)
+COMPILE_FOR_BUILD = \
+       $(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(AM_CPPFLAGS_FOR_BUILD) \
+       $(CPPFLAGS_FOR_BUILD) \
+       $(AM_CFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) 
+
+dash_CFILES = \
+       alias.c arith_yacc.c arith_yylex.c cd.c error.c eval.c exec.c expand.c \
+       histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
+       mystring.c options.c parser.c redir.c show.c trap.c output.c \
+       bltin/printf.c system.c bltin/test.c bltin/times.c var.c
+
+dash_SOURCES = \
+       $(dash_CFILES) \
+       alias.h arith_yacc.h bltin/bltin.h cd.h error.h eval.h exec.h \
+       expand.h hetio.h \
+       init.h input.h jobs.h machdep.h mail.h main.h memalloc.h miscbltin.h \
+       myhistedit.h mystring.h options.h output.h parser.h redir.h shell.h \
+       show.h system.h trap.h var.h
+
+dash_LDADD = builtins.o init.o nodes.o signames.o syntax.o
+HELPERS = mkinit mksyntax mknodes mksignames
+BUILT_SOURCES = builtins.h nodes.h syntax.h token.h token_vars.h
+CLEANFILES = \
+       $(BUILT_SOURCES) $(patsubst %.o,%.c,$(dash_LDADD)) \
+       $(HELPERS) builtins.def
+
+man_MANS = dash.1
+EXTRA_DIST = \
+       $(man_MANS) \
+       mktokens mkbuiltins builtins.def.in mkinit.c \
+       mknodes.c nodetypes nodes.c.pat mksyntax.c mksignames.c
+
+all: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  src/Makefile'; \
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-binPROGRAMS: $(bin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+       @list='$(bin_PROGRAMS)'; for p in $$list; do \
+         p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+         if test -f $$p \
+         ; then \
+           f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+          echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+          $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+         else :; fi; \
+       done
+
+uninstall-binPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(bin_PROGRAMS)'; for p in $$list; do \
+         f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+         echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+         rm -f "$(DESTDIR)$(bindir)/$$f"; \
+       done
+
+clean-binPROGRAMS:
+       -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+dash$(EXEEXT): $(dash_OBJECTS) $(dash_DEPENDENCIES) 
+       @rm -f dash$(EXEEXT)
+       $(LINK) $(dash_OBJECTS) $(dash_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alias.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arith_yacc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arith_yylex.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eval.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/expand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/histedit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/input.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jobs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memalloc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/miscbltin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mystring.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/printf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/redir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/show.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/system.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/times.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/var.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+printf.o: bltin/printf.c
+@am__fastdepCC_TRUE@   $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT printf.o -MD -MP -MF $(DEPDIR)/printf.Tpo -c -o printf.o `test -f 'bltin/printf.c' || echo '$(srcdir)/'`bltin/printf.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/printf.Tpo $(DEPDIR)/printf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='bltin/printf.c' object='printf.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o printf.o `test -f 'bltin/printf.c' || echo '$(srcdir)/'`bltin/printf.c
+
+printf.obj: bltin/printf.c
+@am__fastdepCC_TRUE@   $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT printf.obj -MD -MP -MF $(DEPDIR)/printf.Tpo -c -o printf.obj `if test -f 'bltin/printf.c'; then $(CYGPATH_W) 'bltin/printf.c'; else $(CYGPATH_W) '$(srcdir)/bltin/printf.c'; fi`
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/printf.Tpo $(DEPDIR)/printf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='bltin/printf.c' object='printf.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o printf.obj `if test -f 'bltin/printf.c'; then $(CYGPATH_W) 'bltin/printf.c'; else $(CYGPATH_W) '$(srcdir)/bltin/printf.c'; fi`
+
+test.o: bltin/test.c
+@am__fastdepCC_TRUE@   $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test.o -MD -MP -MF $(DEPDIR)/test.Tpo -c -o test.o `test -f 'bltin/test.c' || echo '$(srcdir)/'`bltin/test.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/test.Tpo $(DEPDIR)/test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='bltin/test.c' object='test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test.o `test -f 'bltin/test.c' || echo '$(srcdir)/'`bltin/test.c
+
+test.obj: bltin/test.c
+@am__fastdepCC_TRUE@   $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test.obj -MD -MP -MF $(DEPDIR)/test.Tpo -c -o test.obj `if test -f 'bltin/test.c'; then $(CYGPATH_W) 'bltin/test.c'; else $(CYGPATH_W) '$(srcdir)/bltin/test.c'; fi`
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/test.Tpo $(DEPDIR)/test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='bltin/test.c' object='test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test.obj `if test -f 'bltin/test.c'; then $(CYGPATH_W) 'bltin/test.c'; else $(CYGPATH_W) '$(srcdir)/bltin/test.c'; fi`
+
+times.o: bltin/times.c
+@am__fastdepCC_TRUE@   $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT times.o -MD -MP -MF $(DEPDIR)/times.Tpo -c -o times.o `test -f 'bltin/times.c' || echo '$(srcdir)/'`bltin/times.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/times.Tpo $(DEPDIR)/times.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='bltin/times.c' object='times.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o times.o `test -f 'bltin/times.c' || echo '$(srcdir)/'`bltin/times.c
+
+times.obj: bltin/times.c
+@am__fastdepCC_TRUE@   $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT times.obj -MD -MP -MF $(DEPDIR)/times.Tpo -c -o times.obj `if test -f 'bltin/times.c'; then $(CYGPATH_W) 'bltin/times.c'; else $(CYGPATH_W) '$(srcdir)/bltin/times.c'; fi`
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/times.Tpo $(DEPDIR)/times.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='bltin/times.c' object='times.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o times.obj `if test -f 'bltin/times.c'; then $(CYGPATH_W) 'bltin/times.c'; else $(CYGPATH_W) '$(srcdir)/bltin/times.c'; fi`
+install-man1: $(man1_MANS) $(man_MANS)
+       @$(NORMAL_INSTALL)
+       test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
+       @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+       l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+       for i in $$l2; do \
+         case "$$i" in \
+           *.1*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         if test -f $$i; then file=$$i; \
+         else file=$(srcdir)/$$i; fi; \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         case "$$ext" in \
+           1*) ;; \
+           *) ext='1' ;; \
+         esac; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed -e 's/^.*\///'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+         $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
+       done
+uninstall-man1:
+       @$(NORMAL_UNINSTALL)
+       @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+       l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+       for i in $$l2; do \
+         case "$$i" in \
+           *.1*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         case "$$ext" in \
+           1*) ;; \
+           *) ext='1' ;; \
+         esac; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed -e 's/^.*\///'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
+         rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
+       done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+           $$tags $$unique; \
+       fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$tags $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && cd $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @list='$(MANS)'; if test -n "$$list"; then \
+         list=`for p in $$list; do \
+           if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+           if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \
+         if test -n "$$list" && \
+           grep 'ab help2man is required to generate this page' $$list >/dev/null; then \
+           echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \
+           grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/         /' >&2; \
+           echo "       to fix them, install help2man, remove and regenerate the man pages;" >&2; \
+           echo "       typically \`make maintainer-clean' will remove them" >&2; \
+           exit 1; \
+         else :; fi; \
+       else :; fi
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+installdirs:
+       for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+       done
+install: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man1
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+       clean-generic ctags distclean distclean-compile \
+       distclean-generic distclean-tags distdir dvi dvi-am html \
+       html-am info info-am install install-am install-binPROGRAMS \
+       install-data install-data-am install-dvi install-dvi-am \
+       install-exec install-exec-am install-html install-html-am \
+       install-info install-info-am install-man install-man1 \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
+       tags uninstall uninstall-am uninstall-binPROGRAMS \
+       uninstall-man uninstall-man1
+
+
+token.h token_vars.h: mktokens
+       sh $^
+
+builtins.def: builtins.def.in $(top_builddir)/config.h
+       $(COMPILE) -E -x c -o $@ $<
+
+builtins.c builtins.h: mkbuiltins builtins.def
+       sh $^
+
+init.c: mkinit $(dash_CFILES)
+       ./$^
+
+nodes.c nodes.h: mknodes nodetypes nodes.c.pat
+       ./$^
+
+syntax.c syntax.h: mksyntax
+       ./$^
+
+signames.c: mksignames
+       ./$^
+
+mksyntax: token.h
+
+$(HELPERS): %: %.c
+       $(COMPILE_FOR_BUILD) -o $@ $<
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/alias.c b/src/alias.c
new file mode 100644 (file)
index 0000000..daeacbb
--- /dev/null
@@ -0,0 +1,227 @@
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include "shell.h"
+#include "input.h"
+#include "output.h"
+#include "error.h"
+#include "memalloc.h"
+#include "mystring.h"
+#include "alias.h"
+#include "options.h"   /* XXX for argptr (should remove?) */
+
+#define ATABSIZE 39
+
+struct alias *atab[ATABSIZE];
+
+STATIC void setalias(const char *, const char *);
+STATIC struct alias *freealias(struct alias *);
+STATIC struct alias **__lookupalias(const char *);
+
+STATIC
+void
+setalias(const char *name, const char *val)
+{
+       struct alias *ap, **app;
+
+       app = __lookupalias(name);
+       ap = *app;
+       INTOFF;
+       if (ap) {
+               if (!(ap->flag & ALIASINUSE)) {
+                       ckfree(ap->val);
+               }
+               ap->val = savestr(val);
+               ap->flag &= ~ALIASDEAD;
+       } else {
+               /* not found */
+               ap = ckmalloc(sizeof (struct alias));
+               ap->name = savestr(name);
+               ap->val = savestr(val);
+               ap->flag = 0;
+               ap->next = 0;
+               *app = ap;
+       }
+       INTON;
+}
+
+int
+unalias(const char *name)
+{
+       struct alias **app;
+
+       app = __lookupalias(name);
+
+       if (*app) {
+               INTOFF;
+               *app = freealias(*app);
+               INTON;
+               return (0);
+       }
+
+       return (1);
+}
+
+void
+rmaliases(void)
+{
+       struct alias *ap, **app;
+       int i;
+
+       INTOFF;
+       for (i = 0; i < ATABSIZE; i++) {
+               app = &atab[i];
+               for (ap = *app; ap; ap = *app) {
+                       *app = freealias(*app);
+                       if (ap == *app) {
+                               app = &ap->next;
+                       }
+               }
+       }
+       INTON;
+}
+
+struct alias *
+lookupalias(const char *name, int check)
+{
+       struct alias *ap = *__lookupalias(name);
+
+       if (check && ap && (ap->flag & ALIASINUSE))
+               return (NULL);
+       return (ap);
+}
+
+/*
+ * TODO - sort output
+ */
+int
+aliascmd(int argc, char **argv)
+{
+       char *n, *v;
+       int ret = 0;
+       struct alias *ap;
+
+       if (argc == 1) {
+               int i;
+
+               for (i = 0; i < ATABSIZE; i++)
+                       for (ap = atab[i]; ap; ap = ap->next) {
+                               printalias(ap);
+                       }
+               return (0);
+       }
+       while ((n = *++argv) != NULL) {
+               if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
+                       if ((ap = *__lookupalias(n)) == NULL) {
+                               outfmt(out2, "%s: %s not found\n", "alias", n);
+                               ret = 1;
+                       } else
+                               printalias(ap);
+               } else {
+                       *v++ = '\0';
+                       setalias(n, v);
+               }
+       }
+
+       return (ret);
+}
+
+int
+unaliascmd(int argc, char **argv)
+{
+       int i;
+
+       while ((i = nextopt("a")) != '\0') {
+               if (i == 'a') {
+                       rmaliases();
+                       return (0);
+               }
+       }
+       for (i = 0; *argptr; argptr++) {
+               if (unalias(*argptr)) {
+                       outfmt(out2, "%s: %s not found\n", "unalias", *argptr);
+                       i = 1;
+               }
+       }
+
+       return (i);
+}
+
+STATIC struct alias *
+freealias(struct alias *ap) {
+       struct alias *next;
+
+       if (ap->flag & ALIASINUSE) {
+               ap->flag |= ALIASDEAD;
+               return ap;
+       }
+
+       next = ap->next;
+       ckfree(ap->name);
+       ckfree(ap->val);
+       ckfree(ap);
+       return next;
+}
+
+void
+printalias(const struct alias *ap) {
+       out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
+}
+
+STATIC struct alias **
+__lookupalias(const char *name) {
+       unsigned int hashval;
+       struct alias **app;
+       const char *p;
+       unsigned int ch;
+
+       p = name;
+
+       ch = (unsigned char)*p;
+       hashval = ch << 4;
+       while (ch) {
+               hashval += ch;
+               ch = (unsigned char)*++p;
+       }
+       app = &atab[hashval % ATABSIZE];
+
+       for (; *app; app = &(*app)->next) {
+               if (equal(name, (*app)->name)) {
+                       break;
+               }
+       }
+
+       return app;
+}
diff --git a/src/alias.h b/src/alias.h
new file mode 100644 (file)
index 0000000..fb841d6
--- /dev/null
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)alias.h     8.2 (Berkeley) 5/4/95
+ */
+
+#define ALIASINUSE     1
+#define ALIASDEAD      2
+
+struct alias {
+       struct alias *next;
+       char *name;
+       char *val;
+       int flag;
+};
+
+struct alias *lookupalias(const char *, int);
+int aliascmd(int, char **);
+int unaliascmd(int, char **);
+void rmaliases(void);
+int unalias(const char *);
+void printalias(const struct alias *);
diff --git a/src/arith_yacc.c b/src/arith_yacc.c
new file mode 100644 (file)
index 0000000..bf21830
--- /dev/null
@@ -0,0 +1,313 @@
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 2007
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include "arith_yacc.h"
+#include "expand.h"
+#include "shell.h"
+#include "error.h"
+#include "output.h"
+#include "var.h"
+
+#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
+#error Arithmetic tokens are out of order.
+#endif
+
+static const char *arith_startbuf;
+
+const char *arith_buf;
+union yystype yylval;
+
+static int last_token;
+
+#define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
+
+static const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
+       ARITH_PRECEDENCE(ARITH_MUL, 0),
+       ARITH_PRECEDENCE(ARITH_DIV, 0),
+       ARITH_PRECEDENCE(ARITH_REM, 0),
+       ARITH_PRECEDENCE(ARITH_ADD, 1),
+       ARITH_PRECEDENCE(ARITH_SUB, 1),
+       ARITH_PRECEDENCE(ARITH_LSHIFT, 2),
+       ARITH_PRECEDENCE(ARITH_RSHIFT, 2),
+       ARITH_PRECEDENCE(ARITH_LT, 3),
+       ARITH_PRECEDENCE(ARITH_LE, 3),
+       ARITH_PRECEDENCE(ARITH_GT, 3),
+       ARITH_PRECEDENCE(ARITH_GE, 3),
+       ARITH_PRECEDENCE(ARITH_EQ, 4),
+       ARITH_PRECEDENCE(ARITH_NE, 4),
+       ARITH_PRECEDENCE(ARITH_BAND, 5),
+       ARITH_PRECEDENCE(ARITH_BXOR, 6),
+       ARITH_PRECEDENCE(ARITH_BOR, 7),
+};
+
+#define ARITH_MAX_PREC 8
+
+static void yyerror(const char *s) __attribute__ ((noreturn));
+static void yyerror(const char *s)
+{
+       sh_error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
+       /* NOTREACHED */
+}
+
+static inline int arith_prec(int op)
+{
+       return prec[op - ARITH_BINOP_MIN];
+}
+
+static inline int higher_prec(int op1, int op2)
+{
+       return arith_prec(op1) < arith_prec(op2);
+}
+
+static intmax_t do_binop(int op, intmax_t a, intmax_t b)
+{
+#ifdef HAVE_IMAXDIV
+       imaxdiv_t div;
+#endif
+
+       switch (op) {
+       default:
+       case ARITH_REM:
+       case ARITH_DIV:
+               if (!b)
+                       yyerror("division by zero");
+#ifdef HAVE_IMAXDIV
+               div = imaxdiv(a, b);
+               return op == ARITH_REM ? div.rem : div.quot;
+#else
+               return op == ARITH_REM ? a % b : a / b;
+#endif
+       case ARITH_MUL:
+               return a * b;
+       case ARITH_ADD:
+               return a + b;
+       case ARITH_SUB:
+               return a - b;
+       case ARITH_LSHIFT:
+               return a << b;
+       case ARITH_RSHIFT:
+               return a >> b;
+       case ARITH_LT:
+               return a < b;
+       case ARITH_LE:
+               return a <= b;
+       case ARITH_GT:
+               return a > b;
+       case ARITH_GE:
+               return a >= b;
+       case ARITH_EQ:
+               return a == b;
+       case ARITH_NE:
+               return a != b;
+       case ARITH_BAND:
+               return a & b;
+       case ARITH_BXOR:
+               return a ^ b;
+       case ARITH_BOR:
+               return a | b;
+       }
+}
+
+static intmax_t assignment(int var, int noeval);
+
+static intmax_t primary(int token, union yystype *val, int op, int noeval)
+{
+       intmax_t result;
+
+again:
+       switch (token) {
+       case ARITH_LPAREN:
+               result = assignment(op, noeval);
+               if (last_token != ARITH_RPAREN)
+                       yyerror("expecting ')'");
+               last_token = yylex();
+               return result;
+       case ARITH_NUM:
+               last_token = op;
+               return val->val;
+       case ARITH_VAR:
+               last_token = op;
+               return noeval ? val->val : lookupvarint(val->name);
+       case ARITH_ADD:
+               token = op;
+               *val = yylval;
+               op = yylex();
+               goto again;
+       case ARITH_SUB:
+               *val = yylval;
+               return -primary(op, val, yylex(), noeval);
+       case ARITH_NOT:
+               *val = yylval;
+               return !primary(op, val, yylex(), noeval);
+       case ARITH_BNOT:
+               *val = yylval;
+               return ~primary(op, val, yylex(), noeval);
+       default:
+               yyerror("expecting primary");
+       }
+}
+
+static intmax_t binop2(intmax_t a, int op, int prec, int noeval)
+{
+       for (;;) {
+               union yystype val;
+               intmax_t b;
+               int op2;
+               int token;
+
+               token = yylex();
+               val = yylval;
+
+               b = primary(token, &val, yylex(), noeval);
+
+               op2 = last_token;
+               if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX &&
+                   higher_prec(op2, op)) {
+                       b = binop2(b, op2, arith_prec(op), noeval);
+                       op2 = last_token;
+               }
+
+               a = noeval ? b : do_binop(op, a, b);
+
+               if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX ||
+                   arith_prec(op2) >= prec)
+                       return a;
+
+               op = op2;
+       }
+}
+
+static intmax_t binop(int token, union yystype *val, int op, int noeval)
+{
+       intmax_t a = primary(token, val, op, noeval);
+
+       op = last_token;
+       if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX)
+               return a;
+
+       return binop2(a, op, ARITH_MAX_PREC, noeval);
+}
+
+static intmax_t and(int token, union yystype *val, int op, int noeval)
+{
+       intmax_t a = binop(token, val, op, noeval);
+       intmax_t b;
+
+       op = last_token;
+       if (op != ARITH_AND)
+               return a;
+
+       token = yylex();
+       *val = yylval;
+
+       b = and(token, val, yylex(), noeval | !a);
+
+       return a && b;
+}
+
+static intmax_t or(int token, union yystype *val, int op, int noeval)
+{
+       intmax_t a = and(token, val, op, noeval);
+       intmax_t b;
+
+       op = last_token;
+       if (op != ARITH_OR)
+               return a;
+
+       token = yylex();
+       *val = yylval;
+
+       b = or(token, val, yylex(), noeval | !!a);
+
+       return a || b;
+}
+
+static intmax_t cond(int token, union yystype *val, int op, int noeval)
+{
+       intmax_t a = or(token, val, op, noeval);
+       intmax_t b;
+       intmax_t c;
+
+       if (last_token != ARITH_QMARK)
+               return a;
+
+       b = assignment(yylex(), noeval | !a);
+
+       if (last_token != ARITH_COLON)
+               yyerror("expecting ':'");
+
+       token = yylex();
+       *val = yylval;
+
+       c = cond(token, val, yylex(), noeval | !!a);
+
+       return a ? b : c;
+}
+
+static intmax_t assignment(int var, int noeval)
+{
+       union yystype val = yylval;
+       int op = yylex();
+       intmax_t result;
+
+       if (var != ARITH_VAR)
+               return cond(var, &val, op, noeval);
+
+       if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX))
+               return cond(var, &val, op, noeval);
+
+       result = assignment(yylex(), noeval);
+       if (noeval)
+               return result;
+
+       return setvarint(val.name,
+                        op == ARITH_ASS ? result :
+                        do_binop(op - 11, lookupvarint(val.name), result), 0);
+}
+
+intmax_t arith(const char *s)
+{
+       intmax_t result;
+
+       arith_buf = arith_startbuf = s;
+
+       result = assignment(yylex(), 0);
+
+       if (last_token)
+               yyerror("expecting EOF");
+
+       return result;
+}
diff --git a/src/arith_yacc.h b/src/arith_yacc.h
new file mode 100644 (file)
index 0000000..ff34d52
--- /dev/null
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 2007
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define ARITH_ASS 1
+
+#define ARITH_OR 2
+#define ARITH_AND 3
+#define ARITH_BAD 4
+#define ARITH_NUM 5
+#define ARITH_VAR 6
+#define ARITH_NOT 7
+
+#define ARITH_BINOP_MIN 8
+#define ARITH_LE 8
+#define ARITH_GE 9
+#define ARITH_LT 10
+#define ARITH_GT 11
+#define ARITH_EQ 12
+#define ARITH_REM 13
+#define ARITH_BAND 14
+#define ARITH_LSHIFT 15
+#define ARITH_RSHIFT 16
+#define ARITH_MUL 17
+#define ARITH_ADD 18
+#define ARITH_BOR 19
+#define ARITH_SUB 20
+#define ARITH_BXOR 21
+#define ARITH_DIV 22
+#define ARITH_NE 23
+#define ARITH_BINOP_MAX 24
+
+#define ARITH_ASS_MIN 24
+#define ARITH_REMASS 24
+#define ARITH_BANDASS 25
+#define ARITH_LSHIFTASS 26
+#define ARITH_RSHIFTASS 27
+#define ARITH_MULASS 28
+#define ARITH_ADDASS 29
+#define ARITH_BORASS 30
+#define ARITH_SUBASS 31
+#define ARITH_BXORASS 32
+#define ARITH_DIVASS 33
+#define ARITH_ASS_MAX 34
+
+#define ARITH_LPAREN 34
+#define ARITH_RPAREN 35
+#define ARITH_BNOT 36
+#define ARITH_QMARK 37
+#define ARITH_COLON 38
+
+union yystype {
+       intmax_t val;
+       char *name;
+};
+
+extern union yystype yylval;
+
+int yylex(void);
diff --git a/src/arith_yylex.c b/src/arith_yylex.c
new file mode 100644 (file)
index 0000000..ec5b5b2
--- /dev/null
@@ -0,0 +1,240 @@
+/*-
+ * Copyright (c) 2002
+ *     Herbert Xu.
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include "arith_yacc.h"
+#include "expand.h"
+#include "error.h"
+#include "shell.h"
+#include "memalloc.h"
+#include "syntax.h"
+#include "system.h"
+
+#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
+#error Arithmetic tokens are out of order.
+#endif
+
+extern const char *arith_buf;
+
+int
+yylex()
+{
+       int value;
+       const char *buf = arith_buf;
+       const char *p;
+
+       for (;;) {
+               value = *buf;
+               switch (value) {
+               case ' ':
+               case '\t':
+               case '\n':
+                       buf++;
+                       continue;
+               default:
+                       return ARITH_BAD;
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                       yylval.val = strtoimax(buf, (char **)&arith_buf, 0);
+                       return ARITH_NUM;
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+                       p = buf;
+                       while (buf++, is_in_name(*buf))
+                               ;
+                       yylval.name = stalloc(buf - p + 1);
+                       *(char *)mempcpy(yylval.name, p, buf - p) = 0;
+                       value = ARITH_VAR;
+                       goto out;
+               case '=':
+                       value += ARITH_ASS - '=';
+checkeq:
+                       buf++;
+checkeqcur:
+                       if (*buf != '=')
+                               goto out;
+                       value += 11;
+                       break;
+               case '>':
+                       switch (*++buf) {
+                       case '=':
+                               value += ARITH_GE - '>';
+                               break;
+                       case '>':
+                               value += ARITH_RSHIFT - '>';
+                               goto checkeq;
+                       default:
+                               value += ARITH_GT - '>';
+                               goto out;
+                       }
+                       break;
+               case '<':
+                       switch (*++buf) {
+                       case '=':
+                               value += ARITH_LE - '<';
+                               break;
+                       case '<':
+                               value += ARITH_LSHIFT - '<';
+                               goto checkeq;
+                       default:
+                               value += ARITH_LT - '<';
+                               goto out;
+                       }
+                       break;
+               case '|':
+                       if (*++buf != '|') {
+                               value += ARITH_BOR - '|';
+                               goto checkeqcur;
+                       }
+                       value += ARITH_OR - '|';
+                       break;
+               case '&':
+                       if (*++buf != '&') {
+                               value += ARITH_BAND - '&';
+                               goto checkeqcur;
+                       }
+                       value += ARITH_AND - '&';
+                       break;
+               case '!':
+                       if (*++buf != '=') {
+                               value += ARITH_NOT - '!';
+                               goto out;
+                       }
+                       value += ARITH_NE - '!';
+                       break;
+               case 0:
+                       goto out;
+               case '(':
+                       value += ARITH_LPAREN - '(';
+                       break;
+               case ')':
+                       value += ARITH_RPAREN - ')';
+                       break;
+               case '*':
+                       value += ARITH_MUL - '*';
+                       goto checkeq;
+               case '/':
+                       value += ARITH_DIV - '/';
+                       goto checkeq;
+               case '%':
+                       value += ARITH_REM - '%';
+                       goto checkeq;
+               case '+':
+                       value += ARITH_ADD - '+';
+                       goto checkeq;
+               case '-':
+                       value += ARITH_SUB - '-';
+                       goto checkeq;
+               case '~':
+                       value += ARITH_BNOT - '~';
+                       break;
+               case '^':
+                       value += ARITH_BXOR - '^';
+                       goto checkeq;
+               case '?':
+                       value += ARITH_QMARK - '?';
+                       break;
+               case ':':
+                       value += ARITH_COLON - ':';
+                       break;
+               }
+               break;
+       }
+
+       buf++;
+out:
+       arith_buf = buf;
+       return value;
+}
diff --git a/src/bltin/bltin.h b/src/bltin/bltin.h
new file mode 100644 (file)
index 0000000..f5ac06f
--- /dev/null
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)bltin.h     8.1 (Berkeley) 5/31/93
+ */
+
+/*
+ * This file is included by programs which are optionally built into the
+ * shell.  If SHELL is defined, we try to map the standard UNIX library
+ * routines to ash routines using defines.
+ */
+
+#include "../shell.h"
+#include "../mystring.h"
+#include "../options.h"
+#ifdef SHELL
+#include "../memalloc.h"
+#include "../output.h"
+#include "../error.h"
+#ifndef USE_GLIBC_STDIO
+#undef stdout
+#undef stderr
+#undef putc
+#undef putchar
+#undef fileno
+#define stdout out1
+#define stderr out2
+#define printf out1fmt
+#define putc(c, file)  outc(c, file)
+#define putchar(c)     out1c(c)
+#define FILE struct output
+#define fprintf outfmt
+#define fputs outstr
+#define fflush flushout
+#define fileno(f) ((f)->fd)
+#define ferror outerr
+#endif
+#define INITARGS(argv)
+#define        error sh_error
+#define        warn sh_warn
+#define        warnx sh_warnx
+#define exit sh_exit
+#define setprogname(s)
+#define getprogname() commandname
+#define setlocate(l,s) 0
+
+#define getenv(p) bltinlookup((p),0)
+
+#else
+#undef NULL
+#include <stdio.h>
+#undef main
+#define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
+#endif
+
+int echocmd(int, char **);
+
+
+extern const char *commandname;
diff --git a/src/bltin/printf.c b/src/bltin/printf.c
new file mode 100644 (file)
index 0000000..893295c
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int      conv_escape_str(char *);
+static char    *conv_escape(char *, int *);
+static int      getchr(void);
+static double   getdouble(void);
+static intmax_t         getintmax(void);
+static uintmax_t getuintmax(void);
+static char    *getstr(void);
+static char    *mklong(const char *, const char *);
+static void      check_conversion(const char *, const char *);
+
+static int     rval;
+static char  **gargv;
+
+#define isodigit(c)    ((c) >= '0' && (c) <= '7')
+#define octtobin(c)    ((c) - '0')
+
+#include "bltin.h"
+#include "system.h"
+
+#define PF(f, func) { \
+       switch ((char *)param - (char *)array) { \
+       default: \
+               (void)printf(f, array[0], array[1], func); \
+               break; \
+       case sizeof(*param): \
+               (void)printf(f, array[0], func); \
+               break; \
+       case 0: \
+               (void)printf(f, func); \
+               break; \
+       } \
+}
+
+int printfcmd(int argc, char *argv[])
+{
+       char *fmt;
+       char *format;
+       int ch;
+
+       rval = 0;
+
+       nextopt(nullstr);
+
+       argv = argptr;
+       format = *argv;
+
+       if (!format) {
+               warnx("usage: printf format [arg ...]");
+               goto err;
+       }
+
+       gargv = ++argv;
+
+#define SKIP1  "#-+ 0"
+#define SKIP2  "*0123456789"
+       do {
+               /*
+                * Basic algorithm is to scan the format string for conversion
+                * specifications -- once one is found, find out if the field
+                * width or precision is a '*'; if it is, gather up value. 
+                * Note, format strings are reused as necessary to use up the
+                * provided arguments, arguments of zero/null string are 
+                * provided to use up the format string.
+                */
+
+               /* find next format specification */
+               for (fmt = format; (ch = *fmt++) ;) {
+                       char *start;
+                       char nextch;
+                       int array[2];
+                       int *param;
+
+                       if (ch == '\\') {
+                               int c_ch;
+                               fmt = conv_escape(fmt, &c_ch);
+                               ch = c_ch;
+                               goto pc;
+                       }
+                       if (ch != '%' || (*fmt == '%' && (++fmt || 1))) {
+pc:
+                               putchar(ch);
+                               continue;
+                       }
+
+                       /* Ok - we've found a format specification,
+                          Save its address for a later printf(). */
+                       start = fmt - 1;
+                       param = array;
+
+                       /* skip to field width */
+                       fmt += strspn(fmt, SKIP1);
+                       if (*fmt == '*')
+                               *param++ = getintmax();
+
+                       /* skip to possible '.', get following precision */
+                       fmt += strspn(fmt, SKIP2);
+                       if (*fmt == '.')
+                               ++fmt;
+                       if (*fmt == '*')
+                               *param++ = getintmax();
+
+                       fmt += strspn(fmt, SKIP2);
+
+                       ch = *fmt;
+                       if (!ch) {
+                               warnx("missing format character");
+                               goto err;
+                       }
+                       /* null terminate format string to we can use it
+                          as an argument to printf. */
+                       nextch = fmt[1];
+                       fmt[1] = 0;
+                       switch (ch) {
+
+                       case 'b': {
+                               int done = conv_escape_str(getstr());
+                               char *p = stackblock();
+                               *fmt = 's';
+                               PF(start, p);
+                               /* escape if a \c was encountered */
+                               if (done)
+                                       goto out;
+                               *fmt = 'b';
+                               break;
+                       }
+                       case 'c': {
+                               int p = getchr();
+                               PF(start, p);
+                               break;
+                       }
+                       case 's': {
+                               char *p = getstr();
+                               PF(start, p);
+                               break;
+                       }
+                       case 'd':
+                       case 'i': {
+                               intmax_t p = getintmax();
+                               char *f = mklong(start, fmt);
+                               PF(f, p);
+                               break;
+                       }
+                       case 'o':
+                       case 'u':
+                       case 'x':
+                       case 'X': {
+                               uintmax_t p = getuintmax();
+                               char *f = mklong(start, fmt);
+                               PF(f, p);
+                               break;
+                       }
+                       case 'e':
+                       case 'E':
+                       case 'f':
+                       case 'g':
+                       case 'G': {
+                               double p = getdouble();
+                               PF(start, p);
+                               break;
+                       }
+                       default:
+                               warnx("%s: invalid directive", start);
+                               goto err;
+                       }
+                       *++fmt = nextch;
+               }
+       } while (gargv != argv && *gargv);
+
+out:
+       return rval;
+err:
+       return 1;
+}
+
+
+/*
+ * Print SysV echo(1) style escape string 
+ *     Halts processing string if a \c escape is encountered.
+ */
+static int
+conv_escape_str(char *str)
+{
+       int ch;
+       char *cp;
+
+       /* convert string into a temporary buffer... */
+       STARTSTACKSTR(cp);
+
+       do {
+               int c;
+
+               ch = *str++;
+               if (ch != '\\')
+                       continue;
+
+               ch = *str++;
+               if (ch == 'c') {
+                       /* \c as in SYSV echo - abort all processing.... */
+                       ch = 0x100;
+                       continue;
+               }
+
+               /* 
+                * %b string octal constants are not like those in C.
+                * They start with a \0, and are followed by 0, 1, 2, 
+                * or 3 octal digits. 
+                */
+               if (ch == '0') {
+                       unsigned char i;
+                       i = 3;
+                       ch = 0;
+                       do {
+                               unsigned k = octtobin(*str);
+                               if (k > 7)
+                                       break;
+                               str++;
+                               ch <<= 3;
+                               ch += k;
+                       } while (--i);
+                       continue;
+               }
+
+               /* Finally test for sequences valid in the format string */
+               str = conv_escape(str - 1, &c);
+               ch = c;
+       } while (STPUTC(ch, cp), (char)ch);
+
+       return ch;
+}
+
+/*
+ * Print "standard" escape characters 
+ */
+static char *
+conv_escape(char *str, int *conv_ch)
+{
+       int value;
+       int ch;
+
+       ch = *str;
+
+       switch (ch) {
+       default:
+       case 0:
+               value = '\\';
+               goto out;
+
+       case '0': case '1': case '2': case '3':
+       case '4': case '5': case '6': case '7':
+               ch = 3;
+               value = 0;
+               do {
+                       value <<= 3;
+                       value += octtobin(*str++);
+               } while (isodigit(*str) && --ch);
+               goto out;
+
+       case '\\':      value = '\\';   break;  /* backslash */
+       case 'a':       value = '\a';   break;  /* alert */
+       case 'b':       value = '\b';   break;  /* backspace */
+       case 'f':       value = '\f';   break;  /* form-feed */
+       case 'n':       value = '\n';   break;  /* newline */
+       case 'r':       value = '\r';   break;  /* carriage-return */
+       case 't':       value = '\t';   break;  /* tab */
+       case 'v':       value = '\v';   break;  /* vertical-tab */
+       }
+
+       str++;
+out:
+       *conv_ch = value;
+       return str;
+}
+
+static char *
+mklong(const char *str, const char *ch)
+{
+       char *copy;
+       size_t len;     
+
+       len = ch - str + 3;
+       STARTSTACKSTR(copy);
+       copy = makestrspace(len, copy);
+       memcpy(copy, str, len - 3);
+       copy[len - 3] = 'j';
+       copy[len - 2] = *ch;
+       copy[len - 1] = '\0';
+       return (copy);  
+}
+
+static int
+getchr(void)
+{
+       int val = 0;
+
+       if (*gargv)
+               val = **gargv++;
+       return val;
+}
+
+static char *
+getstr(void)
+{
+       char *val = nullstr;
+
+       if (*gargv)
+               val = *gargv++;
+       return val;
+}
+
+static intmax_t
+getintmax(void)
+{
+       intmax_t val = 0;
+       char *cp, *ep;
+
+       cp = *gargv;
+       if (cp == NULL)
+               goto out;
+       gargv++;
+
+       val = (unsigned char) cp[1];
+       if (*cp == '\"' || *cp == '\'')
+               goto out;
+
+       errno = 0;
+       val = strtoimax(cp, &ep, 0);
+       check_conversion(cp, ep);
+out:
+       return val;
+}
+
+static uintmax_t
+getuintmax(void)
+{
+       uintmax_t val = 0;
+       char *cp, *ep;
+
+       cp = *gargv;
+       if (cp == NULL)
+               goto out;
+       gargv++;
+
+       val = (unsigned char) cp[1];
+       if (*cp == '\"' || *cp == '\'')
+               goto out;
+
+       errno = 0;
+       val = strtoumax(cp, &ep, 0);
+       check_conversion(cp, ep);
+out:
+       return val;
+}
+
+static double
+getdouble(void)
+{
+       double val;
+       char *cp, *ep;
+
+       cp = *gargv;
+       if (cp == NULL)
+               return 0;
+       gargv++;
+
+       if (*cp == '\"' || *cp == '\'')
+               return (unsigned char) cp[1];
+
+       errno = 0;
+       val = strtod(cp, &ep);
+       check_conversion(cp, ep);
+       return val;
+}
+
+static void
+check_conversion(const char *s, const char *ep)
+{
+       if (*ep) {
+               if (ep == s)
+                       warnx("%s: expected numeric value", s);
+               else
+                       warnx("%s: not completely converted", s);
+               rval = 1;
+       } else if (errno == ERANGE) {
+               warnx("%s: %s", s, strerror(ERANGE));
+               rval = 1;
+       }
+}
+
+int
+echocmd(int argc, char **argv)
+{
+       int nonl = 0;
+       struct output *outs = out1;
+
+       if (!*++argv)
+               goto end;
+       if (equal(*argv, "-n")) {
+               nonl = ~nonl;
+               if (!*++argv)
+                       goto end;
+       }
+
+       do {
+               int c;
+
+               nonl += conv_escape_str(*argv);
+               outstr(stackblock(), outs);
+               if (nonl > 0)
+                       break;
+
+               c = ' ';
+               if (!*++argv) {
+end:
+                       if (nonl) {
+                               break;
+                       }
+                       c = '\n';
+               }
+               outc(c, outs);
+       } while (*argv);
+       return 0;
+}
diff --git a/src/bltin/test.c b/src/bltin/test.c
new file mode 100644 (file)
index 0000000..90135e1
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * test(1); version 7-like  --  author Erik Baalbergen
+ * modified by Eric Gisin to be used as built-in.
+ * modified by Arnold Robbins to add SVR3 compatibility
+ * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
+ * modified by J.T. Conklin for NetBSD.
+ *
+ * This program is in the Public Domain.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include "bltin.h"
+
+/* test(1) accepts the following grammar:
+       oexpr   ::= aexpr | aexpr "-o" oexpr ;
+       aexpr   ::= nexpr | nexpr "-a" aexpr ;
+       nexpr   ::= primary | "!" primary
+       primary ::= unary-operator operand
+               | operand binary-operator operand
+               | operand
+               | "(" oexpr ")"
+               ;
+       unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
+               "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
+
+       binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
+                       "-nt"|"-ot"|"-ef";
+       operand ::= <any legal UNIX file name>
+*/
+
+enum token {
+       EOI,
+       FILRD,
+       FILWR,
+       FILEX,
+       FILEXIST,
+       FILREG,
+       FILDIR,
+       FILCDEV,
+       FILBDEV,
+       FILFIFO,
+       FILSOCK,
+       FILSYM,
+       FILGZ,
+       FILTT,
+       FILSUID,
+       FILSGID,
+       FILSTCK,
+       FILNT,
+       FILOT,
+       FILEQ,
+       FILUID,
+       FILGID,
+       STREZ,
+       STRNZ,
+       STREQ,
+       STRNE,
+       STRLT,
+       STRGT,
+       INTEQ,
+       INTNE,
+       INTGE,
+       INTGT,
+       INTLE,
+       INTLT,
+       UNOT,
+       BAND,
+       BOR,
+       LPAREN,
+       RPAREN,
+       OPERAND
+};
+
+enum token_types {
+       UNOP,
+       BINOP,
+       BUNOP,
+       BBINOP,
+       PAREN
+};
+
+static struct t_op {
+       const char *op_text;
+       short op_num, op_type;
+} const ops [] = {
+       {"-r",  FILRD,  UNOP},
+       {"-w",  FILWR,  UNOP},
+       {"-x",  FILEX,  UNOP},
+       {"-e",  FILEXIST,UNOP},
+       {"-f",  FILREG, UNOP},
+       {"-d",  FILDIR, UNOP},
+       {"-c",  FILCDEV,UNOP},
+       {"-b",  FILBDEV,UNOP},
+       {"-p",  FILFIFO,UNOP},
+       {"-u",  FILSUID,UNOP},
+       {"-g",  FILSGID,UNOP},
+       {"-k",  FILSTCK,UNOP},
+       {"-s",  FILGZ,  UNOP},
+       {"-t",  FILTT,  UNOP},
+       {"-z",  STREZ,  UNOP},
+       {"-n",  STRNZ,  UNOP},
+       {"-h",  FILSYM, UNOP},          /* for backwards compat */
+       {"-O",  FILUID, UNOP},
+       {"-G",  FILGID, UNOP},
+       {"-L",  FILSYM, UNOP},
+       {"-S",  FILSOCK,UNOP},
+       {"=",   STREQ,  BINOP},
+       {"!=",  STRNE,  BINOP},
+       {"<",   STRLT,  BINOP},
+       {">",   STRGT,  BINOP},
+       {"-eq", INTEQ,  BINOP},
+       {"-ne", INTNE,  BINOP},
+       {"-ge", INTGE,  BINOP},
+       {"-gt", INTGT,  BINOP},
+       {"-le", INTLE,  BINOP},
+       {"-lt", INTLT,  BINOP},
+       {"-nt", FILNT,  BINOP},
+       {"-ot", FILOT,  BINOP},
+       {"-ef", FILEQ,  BINOP},
+       {"!",   UNOT,   BUNOP},
+       {"-a",  BAND,   BBINOP},
+       {"-o",  BOR,    BBINOP},
+       {"(",   LPAREN, PAREN},
+       {")",   RPAREN, PAREN},
+       {0,     0,      0}
+};
+
+static char **t_wp;
+static struct t_op const *t_wp_op;
+
+static void syntax(const char *, const char *);
+static int oexpr(enum token);
+static int aexpr(enum token);
+static int nexpr(enum token);
+static int primary(enum token);
+static int binop(void);
+static int filstat(char *, enum token);
+static enum token t_lex(char **);
+static int isoperand(char **);
+static int newerf(const char *, const char *);
+static int olderf(const char *, const char *);
+static int equalf(const char *, const char *);
+#ifdef HAVE_FACCESSAT
+static int test_file_access(const char *, int);
+#else
+static int test_st_mode(const struct stat64 *, int);
+static int bash_group_member(gid_t);
+#endif
+
+static inline intmax_t getn(const char *s)
+{
+       return atomax10(s);
+}
+
+static const struct t_op *getop(const char *s)
+{
+       const struct t_op *op;
+
+       for (op = ops; op->op_text; op++) {
+               if (strcmp(s, op->op_text) == 0)
+                       return op;
+       }
+
+       return NULL;
+}
+
+int
+testcmd(int argc, char **argv)
+{
+       const struct t_op *op;
+       enum token n;
+       int res;
+
+       if (*argv[0] == '[') {
+               if (*argv[--argc] != ']')
+                       error("missing ]");
+               argv[argc] = NULL;
+       }
+
+       argv++;
+       argc--;
+
+       if (argc < 1)
+               return 1;
+
+       /*
+        * POSIX prescriptions: he who wrote this deserves the Nobel
+        * peace prize.
+        */
+       switch (argc) {
+       case 3:
+               op = getop(argv[1]);
+               if (op && op->op_type == BINOP) {
+                       n = OPERAND;
+                       goto eval;
+               }
+               /* fall through */
+
+       case 4:
+               if (!strcmp(argv[0], "(") && !strcmp(argv[argc - 1], ")")) {
+                       argv[--argc] = NULL;
+                       argv++;
+                       argc--;
+               }
+       }
+
+       n = t_lex(argv);
+
+eval:
+       t_wp = argv;
+       res = !oexpr(n);
+       argv = t_wp;
+
+       if (argv[0] != NULL && argv[1] != NULL)
+               syntax(argv[0], "unexpected operator");
+
+       return res;
+}
+
+static void
+syntax(const char *op, const char *msg)
+{
+       if (op && *op)
+               error("%s: %s", op, msg);
+       else
+               error("%s", msg);
+}
+
+static int
+oexpr(enum token n)
+{
+       int res = 0;
+
+       for (;;) {
+               res |= aexpr(n);
+               n = t_lex(t_wp + 1);
+               if (n != BOR)
+                       break;
+               n = t_lex(t_wp += 2);
+       }
+       return res;
+}
+
+static int
+aexpr(enum token n)
+{
+       int res = 1;
+
+       for (;;) {
+               if (!nexpr(n))
+                       res = 0;
+               n = t_lex(t_wp + 1);
+               if (n != BAND)
+                       break;
+               n = t_lex(t_wp += 2);
+       }
+       return res;
+}
+
+static int
+nexpr(enum token n)
+{
+       if (n == UNOT)
+               return !nexpr(t_lex(++t_wp));
+       return primary(n);
+}
+
+static int
+primary(enum token n)
+{
+       enum token nn;
+       int res;
+
+       if (n == EOI)
+               return 0;               /* missing expression */
+       if (n == LPAREN) {
+               if ((nn = t_lex(++t_wp)) == RPAREN)
+                       return 0;       /* missing expression */
+               res = oexpr(nn);
+               if (t_lex(++t_wp) != RPAREN)
+                       syntax(NULL, "closing paren expected");
+               return res;
+       }
+       if (t_wp_op && t_wp_op->op_type == UNOP) {
+               /* unary expression */
+               if (*++t_wp == NULL)
+                       syntax(t_wp_op->op_text, "argument expected");
+               switch (n) {
+               case STREZ:
+                       return strlen(*t_wp) == 0;
+               case STRNZ:
+                       return strlen(*t_wp) != 0;
+               case FILTT:
+                       return isatty(getn(*t_wp));
+#ifdef HAVE_FACCESSAT
+               case FILRD:
+                       return test_file_access(*t_wp, R_OK);
+               case FILWR:
+                       return test_file_access(*t_wp, W_OK);
+               case FILEX:
+                       return test_file_access(*t_wp, X_OK);
+#endif
+               default:
+                       return filstat(*t_wp, n);
+               }
+       }
+
+       if (t_lex(t_wp + 1), t_wp_op && t_wp_op->op_type == BINOP) {
+               return binop();
+       }
+
+       return strlen(*t_wp) > 0;
+}
+
+static int
+binop(void)
+{
+       const char *opnd1, *opnd2;
+       struct t_op const *op;
+
+       opnd1 = *t_wp;
+       (void) t_lex(++t_wp);
+       op = t_wp_op;
+
+       if ((opnd2 = *++t_wp) == (char *)0)
+               syntax(op->op_text, "argument expected");
+
+       switch (op->op_num) {
+       default:
+#ifdef DEBUG
+               abort();
+               /* NOTREACHED */
+#endif
+       case STREQ:
+               return strcmp(opnd1, opnd2) == 0;
+       case STRNE:
+               return strcmp(opnd1, opnd2) != 0;
+       case STRLT:
+               return strcmp(opnd1, opnd2) < 0;
+       case STRGT:
+               return strcmp(opnd1, opnd2) > 0;
+       case INTEQ:
+               return getn(opnd1) == getn(opnd2);
+       case INTNE:
+               return getn(opnd1) != getn(opnd2);
+       case INTGE:
+               return getn(opnd1) >= getn(opnd2);
+       case INTGT:
+               return getn(opnd1) > getn(opnd2);
+       case INTLE:
+               return getn(opnd1) <= getn(opnd2);
+       case INTLT:
+               return getn(opnd1) < getn(opnd2);
+       case FILNT:
+               return newerf (opnd1, opnd2);
+       case FILOT:
+               return olderf (opnd1, opnd2);
+       case FILEQ:
+               return equalf (opnd1, opnd2);
+       }
+}
+
+static int
+filstat(char *nm, enum token mode)
+{
+       struct stat64 s;
+
+       if (mode == FILSYM ? lstat64(nm, &s) : stat64(nm, &s))
+               return 0;
+
+       switch (mode) {
+#ifndef HAVE_FACCESSAT
+       case FILRD:
+               return test_st_mode(&s, R_OK);
+       case FILWR:
+               return test_st_mode(&s, W_OK);
+       case FILEX:
+               return test_st_mode(&s, X_OK);
+#endif
+       case FILEXIST:
+               return 1;
+       case FILREG:
+               return S_ISREG(s.st_mode);
+       case FILDIR:
+               return S_ISDIR(s.st_mode);
+       case FILCDEV:
+               return S_ISCHR(s.st_mode);
+       case FILBDEV:
+               return S_ISBLK(s.st_mode);
+       case FILFIFO:
+               return S_ISFIFO(s.st_mode);
+       case FILSOCK:
+               return S_ISSOCK(s.st_mode);
+       case FILSYM:
+               return S_ISLNK(s.st_mode);
+       case FILSUID:
+               return (s.st_mode & S_ISUID) != 0;
+       case FILSGID:
+               return (s.st_mode & S_ISGID) != 0;
+       case FILSTCK:
+               return (s.st_mode & S_ISVTX) != 0;
+       case FILGZ:
+               return !!s.st_size;
+       case FILUID:
+               return s.st_uid == geteuid();
+       case FILGID:
+               return s.st_gid == getegid();
+       default:
+               return 1;
+       }
+}
+
+static enum token t_lex(char **tp)
+{
+       struct t_op const *op;
+       char *s = *tp;
+
+       if (s == 0) {
+               t_wp_op = (struct t_op *)0;
+               return EOI;
+       }
+
+       op = getop(s);
+       if (op && !(op->op_type == UNOP && isoperand(tp)) &&
+           !(op->op_num == LPAREN && !tp[1])) {
+               t_wp_op = op;
+               return op->op_num;
+       }
+
+       t_wp_op = (struct t_op *)0;
+       return OPERAND;
+}
+
+static int isoperand(char **tp)
+{
+       struct t_op const *op;
+       char *s;
+
+       if (!(s = tp[1]))
+               return 1;
+       if (!tp[2])
+               return 0;
+
+       op = getop(s);
+       return op && op->op_type == BINOP;
+}
+
+static int
+newerf (const char *f1, const char *f2)
+{
+       struct stat b1, b2;
+
+       return (stat (f1, &b1) == 0 &&
+               stat (f2, &b2) == 0 &&
+               b1.st_mtime > b2.st_mtime);
+}
+
+static int
+olderf (const char *f1, const char *f2)
+{
+       struct stat b1, b2;
+
+       return (stat (f1, &b1) == 0 &&
+               stat (f2, &b2) == 0 &&
+               b1.st_mtime < b2.st_mtime);
+}
+
+static int
+equalf (const char *f1, const char *f2)
+{
+       struct stat b1, b2;
+
+       return (stat (f1, &b1) == 0 &&
+               stat (f2, &b2) == 0 &&
+               b1.st_dev == b2.st_dev &&
+               b1.st_ino == b2.st_ino);
+}
+
+#ifdef HAVE_FACCESSAT
+static int test_file_access(const char *path, int mode)
+{
+       return !faccessat(AT_FDCWD, path, mode, AT_EACCESS);
+}
+#else  /* HAVE_FACCESSAT */
+/*
+ * Similar to what access(2) does, but uses the effective uid and gid.
+ * Doesn't make the mistake of telling root that any file is executable.
+ * Returns non-zero if the file is accessible.
+ */
+static int
+test_st_mode(const struct stat64 *st, int mode)
+{
+       int euid = geteuid();
+
+       if (euid == 0) {
+               /* Root can read or write any file. */
+               if (mode != X_OK)
+                       return 1;
+
+               /* Root can execute any file that has any one of the execute
+                  bits set. */
+               mode = S_IXUSR | S_IXGRP | S_IXOTH;
+       } else if (st->st_uid == euid)
+               mode <<= 6;
+       else if (bash_group_member(st->st_gid))
+               mode <<= 3;
+
+       return st->st_mode & mode;
+}
+
+/* Return non-zero if GID is one that we have in our groups list. */
+static int
+bash_group_member(gid_t gid)
+{
+       register int i;
+       gid_t *group_array;
+       int ngroups;
+
+       /* Short-circuit if possible, maybe saving a call to getgroups(). */
+       if (gid == getgid() || gid == getegid())
+               return (1);
+
+       ngroups = getgroups(0, NULL);
+       group_array = stalloc(ngroups * sizeof(gid_t));
+       if ((getgroups(ngroups, group_array)) != ngroups)
+               return (0);
+
+       /* Search through the list looking for GID. */
+       for (i = 0; i < ngroups; i++)
+               if (gid == group_array[i])
+                       return (1);
+
+       return (0);
+}
+#endif /* HAVE_FACCESSAT */
diff --git a/src/bltin/times.c b/src/bltin/times.c
new file mode 100644 (file)
index 0000000..8eabc1f
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 1999 Herbert Xu <herbert@gondor.apana.org.au>
+ * This file contains code for the times builtin.
+ */
+
+#include <sys/times.h>
+#include <unistd.h>
+#ifdef USE_GLIBC_STDIO
+#include <stdio.h>
+#else
+#include "bltin.h"
+#endif
+#include "system.h"
+
+int timescmd() {
+       struct tms buf;
+       long int clk_tck = sysconf(_SC_CLK_TCK);
+
+       times(&buf);
+       printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
+              (int) (buf.tms_utime / clk_tck / 60),
+              ((double) buf.tms_utime) / clk_tck,
+              (int) (buf.tms_stime / clk_tck / 60),
+              ((double) buf.tms_stime) / clk_tck,
+              (int) (buf.tms_cutime / clk_tck / 60),
+              ((double) buf.tms_cutime) / clk_tck,
+              (int) (buf.tms_cstime / clk_tck / 60),
+              ((double) buf.tms_cstime) / clk_tck);
+       return 0;
+}
diff --git a/src/builtins.def.in b/src/builtins.def.in
new file mode 100644 (file)
index 0000000..4441fe4
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)builtins.def        8.4 (Berkeley) 5/4/95
+ */
+
+/*
+ * This file lists all the builtin commands.  The first column is the name
+ * of a C routine.
+ * The -a flag specifies that this is a posix 'assignment builtin' command.
+ * The -s flag specifies that this is a posix 'special builtin' command.
+ * The -u flag specifies that this is a posix 'standard utility'.
+ * The -n flag specifies that this command has a special entry point.
+ * The rest of the line specifies the command name or names used to run
+ * the command.
+ */
+
+#ifndef JOBS
+#define JOBS 1
+#endif
+
+#if JOBS
+bgcmd          -u bg
+fgcmd          -u fg
+#endif
+
+#ifndef SMALL
+histcmd                -u fc
+#endif
+
+breakcmd       -s break -s continue
+cdcmd          -u cd chdir
+commandcmd     -u command
+dotcmd         -s .
+echocmd                echo
+evalcmd                -ns eval
+execcmd                -s exec
+exitcmd                -s exit
+exportcmd      -as export -as readonly
+falsecmd       -u false
+getoptscmd     -u getopts
+hashcmd                hash
+jobscmd                -u jobs
+localcmd       -as local
+printfcmd      printf
+pwdcmd         pwd
+readcmd                -u read
+returncmd      -s return
+setcmd         -s set
+shiftcmd       -s shift
+timescmd       -s times
+trapcmd                -s trap
+truecmd                -s : -u true
+typecmd                type
+umaskcmd       -u umask
+unaliascmd     -u unalias
+unsetcmd       -s unset
+waitcmd                -u wait
+aliascmd       -au alias
+#ifdef HAVE_GETRLIMIT
+ulimitcmd      ulimit
+#endif
+testcmd                test [
+killcmd                -u kill
diff --git a/src/cd.c b/src/cd.c
new file mode 100644 (file)
index 0000000..2d9d4b5
--- /dev/null
+++ b/src/cd.c
@@ -0,0 +1,316 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+/*
+ * The cd and pwd commands.
+ */
+
+#include "shell.h"
+#include "var.h"
+#include "nodes.h"     /* for jobs.h */
+#include "jobs.h"
+#include "options.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "exec.h"
+#include "redir.h"
+#include "main.h"
+#include "mystring.h"
+#include "show.h"
+#include "cd.h"
+
+#define CD_PHYSICAL 1
+#define CD_PRINT 2
+
+STATIC int docd(const char *, int);
+STATIC const char *updatepwd(const char *);
+STATIC char *getpwd(void);
+STATIC int cdopt(void);
+
+STATIC char *curdir = nullstr;         /* current working directory */
+STATIC char *physdir = nullstr;                /* physical working directory */
+
+STATIC int
+cdopt()
+{
+       int flags = 0;
+       int i, j;
+
+       j = 'L';
+       while ((i = nextopt("LP"))) {
+               if (i != j) {
+                       flags ^= CD_PHYSICAL;
+                       j = i;
+               }
+       }
+
+       return flags;
+}
+
+int
+cdcmd(int argc, char **argv)
+{
+       const char *dest;
+       const char *path;
+       const char *p;
+       char c;
+       struct stat statb;
+       int flags;
+
+       flags = cdopt();
+       dest = *argptr;
+       if (!dest)
+               dest = bltinlookup(homestr);
+       else if (dest[0] == '-' && dest[1] == '\0') {
+               dest = bltinlookup("OLDPWD");
+               flags |= CD_PRINT;
+       }
+       if (!dest)
+               dest = nullstr;
+       if (*dest == '/')
+               goto step6;
+       if (*dest == '.') {
+               c = dest[1];
+dotdot:
+               switch (c) {
+               case '\0':
+               case '/':
+                       goto step6;
+               case '.':
+                       c = dest[2];
+                       if (c != '.')
+                               goto dotdot;
+               }
+       }
+       if (!*dest)
+               dest = ".";
+       path = bltinlookup("CDPATH");
+       while (path) {
+               c = *path;
+               p = padvance(&path, dest);
+               if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
+                       if (c && c != ':')
+                               flags |= CD_PRINT;
+docd:
+                       if (!docd(p, flags))
+                               goto out;
+                       goto err;
+               }
+       }
+
+step6:
+       p = dest;
+       goto docd;
+
+err:
+       sh_error("can't cd to %s", dest);
+       /* NOTREACHED */
+out:
+       if (flags & CD_PRINT)
+               out1fmt(snlfmt, curdir);
+       return 0;
+}
+
+
+/*
+ * Actually do the chdir.  We also call hashcd to let the routines in exec.c
+ * know that the current directory has changed.
+ */
+
+STATIC int
+docd(const char *dest, int flags)
+{
+       const char *dir = 0;
+       int err;
+
+       TRACE(("docd(\"%s\", %d) called\n", dest, flags));
+
+       INTOFF;
+       if (!(flags & CD_PHYSICAL)) {
+               dir = updatepwd(dest);
+               if (dir)
+                       dest = dir;
+       }
+       err = chdir(dest);
+       if (err)
+               goto out;
+       setpwd(dir, 1);
+       hashcd();
+out:
+       INTON;
+       return err;
+}
+
+
+/*
+ * Update curdir (the name of the current directory) in response to a
+ * cd command.
+ */
+
+STATIC const char *
+updatepwd(const char *dir)
+{
+       char *new;
+       char *p;
+       char *cdcomppath;
+       const char *lim;
+
+       cdcomppath = sstrdup(dir);
+       STARTSTACKSTR(new);
+       if (*dir != '/') {
+               if (curdir == nullstr)
+                       return 0;
+               new = stputs(curdir, new);
+       }
+       new = makestrspace(strlen(dir) + 2, new);
+       lim = stackblock() + 1;
+       if (*dir != '/') {
+               if (new[-1] != '/')
+                       USTPUTC('/', new);
+               if (new > lim && *lim == '/')
+                       lim++;
+       } else {
+               USTPUTC('/', new);
+               cdcomppath++;
+               if (dir[1] == '/' && dir[2] != '/') {
+                       USTPUTC('/', new);
+                       cdcomppath++;
+                       lim++;
+               }
+       }
+       p = strtok(cdcomppath, "/");
+       while (p) {
+               switch(*p) {
+               case '.':
+                       if (p[1] == '.' && p[2] == '\0') {
+                               while (new > lim) {
+                                       STUNPUTC(new);
+                                       if (new[-1] == '/')
+                                               break;
+                               }
+                               break;
+                       } else if (p[1] == '\0')
+                               break;
+                       /* fall through */
+               default:
+                       new = stputs(p, new);
+                       USTPUTC('/', new);
+               }
+               p = strtok(0, "/");
+       }
+       if (new > lim)
+               STUNPUTC(new);
+       *new = 0;
+       return stackblock();
+}
+
+
+/*
+ * Find out what the current directory is. If we already know the current
+ * directory, this routine returns immediately.
+ */
+inline
+STATIC char *
+getpwd()
+{
+#ifdef __GLIBC__
+       char *dir = getcwd(0, 0);
+
+       if (dir)
+               return dir;
+#else
+       char buf[PATH_MAX];
+
+       if (getcwd(buf, sizeof(buf)))
+               return savestr(buf);
+#endif
+
+       sh_warnx("getcwd() failed: %s", strerror(errno));
+       return nullstr;
+}
+
+int
+pwdcmd(int argc, char **argv)
+{
+       int flags;
+       const char *dir = curdir;
+
+       flags = cdopt();
+       if (flags) {
+               if (physdir == nullstr)
+                       setpwd(dir, 0);
+               dir = physdir;
+       }
+       out1fmt(snlfmt, dir);
+       return 0;
+}
+
+void
+setpwd(const char *val, int setold)
+{
+       char *oldcur, *dir;
+
+       oldcur = dir = curdir;
+
+       if (setold) {
+               setvar("OLDPWD", oldcur, VEXPORT);
+       }
+       INTOFF;
+       if (physdir != nullstr) {
+               if (physdir != oldcur)
+                       free(physdir);
+               physdir = nullstr;
+       }
+       if (oldcur == val || !val) {
+               char *s = getpwd();
+               physdir = s;
+               if (!val)
+                       dir = s;
+       } else
+               dir = savestr(val);
+       if (oldcur != dir && oldcur != nullstr) {
+               free(oldcur);
+       }
+       curdir = dir;
+       INTON;
+       setvar("PWD", dir, VEXPORT);
+}
diff --git a/src/cd.h b/src/cd.h
new file mode 100644 (file)
index 0000000..8763161
--- /dev/null
+++ b/src/cd.h
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 1995
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+int    cdcmd(int, char **);
+int    pwdcmd(int, char **);
+void   setpwd(const char *, int);
diff --git a/src/dash.1 b/src/dash.1
new file mode 100644 (file)
index 0000000..3847d98
--- /dev/null
@@ -0,0 +1,2352 @@
+.\" Copyright (c) 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\" Copyright (c) 1997-2005
+.\"    Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Kenneth Almquist.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    @(#)sh.1        8.6 (Berkeley) 5/4/95
+.\"
+.Dd January 19, 2003
+.Os
+.Dt DASH 1
+.Sh NAME
+.Nm dash
+.Nd command interpreter (shell)
+.Sh SYNOPSIS
+.Nm
+.Bk -words
+.Op Fl aCefnuvxIimqVEb
+.Op Cm +aCefnuvxIimqVEb
+.Ek
+.Bk -words
+.Op Fl o Ar option_name
+.Op Cm +o Ar option_name
+.Ek
+.Bk -words
+.Op Ar command_file Oo Ar argument ... Oc
+.Ek
+.Nm
+.Fl c
+.Bk -words
+.Op Fl aCefnuvxIimqVEb
+.Op Cm +aCefnuvxIimqVEb
+.Ek
+.Bk -words
+.Op Fl o Ar option_name
+.Op Cm +o Ar option_name
+.Ek
+.Bk -words
+.Ar command_string
+.Op Ar command_name Oo Ar argument ... Oc
+.Ek
+.Nm
+.Fl s
+.Bk -words
+.Op Fl aCefnuvxIimqVEb
+.Op Cm +aCefnuvxIimqVEb
+.Ek
+.Bk -words
+.Op Fl o Ar option_name
+.Op Cm +o Ar option_name
+.Ek
+.Bk -words
+.Op Ar argument ...
+.Ek
+.Sh DESCRIPTION
+.Nm
+is the standard command interpreter for the system.
+The current version of
+.Nm
+is in the process of being changed to conform with the
+.Tn POSIX
+1003.2 and 1003.2a specifications for the shell.
+This version has many
+features which make it appear similar in some respects to the Korn shell,
+but it is not a Korn shell clone (see
+.Xr ksh 1 ) .
+Only features designated by
+.Tn POSIX ,
+plus a few Berkeley extensions, are being incorporated into this shell.
+This man page is not intended
+to be a tutorial or a complete specification of the shell.
+.Ss Overview
+The shell is a command that reads lines from either a file or the
+terminal, interprets them, and generally executes other commands.
+It is the program that is running when a user logs into the system
+(although a user can select a different shell with the
+.Xr chsh 1
+command).
+The shell implements a language that has flow control
+constructs, a macro facility that provides a variety of features in
+addition to data storage, along with built in history and line editing
+capabilities.
+It incorporates many features to aid interactive use and
+has the advantage that the interpretative language is common to both
+interactive and non-interactive use (shell scripts).
+That is, commands
+can be typed directly to the running shell or can be put into a file and
+the file can be executed directly by the shell.
+.Ss Invocation
+If no args are present and if the standard input of the shell
+is connected to a terminal (or if the
+.Fl i
+flag is set),
+and the
+.Fl c
+option is not present, the shell is considered an interactive shell.
+An interactive shell generally prompts before each command and handles
+programming and command errors differently (as described below).
+When first starting,
+the shell inspects argument 0, and if it begins with a dash
+.Sq - ,
+the shell is also considered
+a login shell.
+This is normally done automatically by the system
+when the user first logs in.
+A login shell first reads commands
+from the files
+.Pa /etc/profile
+and
+.Pa .profile
+if they exist.
+If the environment variable
+.Ev ENV
+is set on entry to an interactive shell, or is set in the
+.Pa .profile
+of a login shell, the shell next reads
+commands from the file named in
+.Ev ENV .
+Therefore, a user should place commands that are to be executed only at
+login time in the
+.Pa .profile
+file, and commands that are executed for every interactive shell inside the
+.Ev ENV
+file.
+To set the
+.Ev ENV
+variable to some file, place the following line in your
+.Pa .profile
+of your home directory
+.Pp
+.Dl ENV=$HOME/.shinit; export ENV
+.Pp
+substituting for
+.Dq .shinit
+any filename you wish.
+.Pp
+If command line arguments besides the options have been specified, then
+the shell treats the first argument as the name of a file from which to
+read commands (a shell script), and the remaining arguments are set as the
+positional parameters of the shell ($1, $2, etc).
+Otherwise, the shell
+reads commands from its standard input.
+.Ss Argument List Processing
+All of the single letter options that have a corresponding name can be
+used as an argument to the
+.Fl o
+option.
+The set
+.Fl o
+name is provided next to the single letter option in
+the description below.
+Specifying a dash
+.Dq -
+turns the option on, while using a plus
+.Dq +
+disables the option.
+The following options can be set from the command line or
+with the
+.Ic set
+builtin (described later).
+.Bl -tag -width aaaallexportfoo -offset indent
+.It Fl a Em allexport
+Export all variables assigned to.
+.It Fl c
+Read commands from the
+.Ar command_string
+operand instead of from the standard input.
+Special parameter 0 will be set from the
+.Ar command_name
+operand and the positional parameters ($1, $2, etc.)
+set from the remaining argument operands.
+.It Fl C Em noclobber
+Don't overwrite existing files with
+.Dq \*[Gt] .
+.It Fl e Em errexit
+If not interactive, exit immediately if any untested command fails.
+The exit status of a command is considered to be
+explicitly tested if the command is used to control an
+.Ic if ,
+.Ic elif ,
+.Ic while ,
+or
+.Ic until ;
+or if the command is the left hand operand of an
+.Dq &&
+or
+.Dq ||
+operator.
+.It Fl f Em noglob
+Disable pathname expansion.
+.It Fl n Em noexec
+If not interactive, read commands but do not execute them.
+This is useful for checking the syntax of shell scripts.
+.It Fl u Em nounset
+Write a message to standard error when attempting to expand a variable
+that is not set, and if the shell is not interactive, exit immediately.
+.It Fl v Em verbose
+The shell writes its input to standard error as it is read.
+Useful for debugging.
+.It Fl x Em xtrace
+Write each command to standard error (preceded by a
+.Sq +\  )
+before it is executed.
+Useful for debugging.
+.It Fl I Em ignoreeof
+Ignore EOF's from input when interactive.
+.It Fl i Em interactive
+Force the shell to behave interactively.
+.It Fl l
+Make dash act as if it had been invoked as a login shell.
+.It Fl m Em monitor
+Turn on job control (set automatically when interactive).
+.It Fl s Em stdin
+Read commands from standard input (set automatically if no file arguments
+are present).
+This option has no effect when set after the shell has
+already started running (i.e. with
+.Ic set ) .
+.It Fl V Em vi
+Enable the built-in
+.Xr vi 1
+command line editor (disables
+.Fl E
+if it has been set).
+.It Fl E Em emacs
+Enable the built-in
+.Xr emacs 1
+command line editor (disables
+.Fl V
+if it has been set).
+.It Fl b Em notify
+Enable asynchronous notification of background job completion.
+(UNIMPLEMENTED for 4.4alpha)
+.El
+.Ss Lexical Structure
+The shell reads input in terms of lines from a file and breaks it up into
+words at whitespace (blanks and tabs), and at certain sequences of
+characters that are special to the shell called
+.Dq operators .
+There are two types of operators: control operators and redirection
+operators (their meaning is discussed later).
+Following is a list of operators:
+.Bl -ohang -offset indent
+.It "Control operators:"
+.Dl &  &&  \&(  \&)  \&;  ;; | || \*[Lt]newline\*[Gt]
+.It "Redirection operators:"
+.Dl \*[Lt]  \*[Gt]  \*[Gt]|  \*[Lt]\*[Lt]  \*[Gt]\*[Gt]  \*[Lt]&  \*[Gt]&  \*[Lt]\*[Lt]-  \*[Lt]\*[Gt]
+.El
+.Ss Quoting
+Quoting is used to remove the special meaning of certain characters or
+words to the shell, such as operators, whitespace, or keywords.
+There are three types of quoting: matched single quotes,
+matched double quotes, and backslash.
+.Ss Backslash
+A backslash preserves the literal meaning of the following
+character, with the exception of
+.Aq newline .
+A backslash preceding a
+.Aq newline
+is treated as a line continuation.
+.Ss Single Quotes
+Enclosing characters in single quotes preserves the literal meaning of all
+the characters (except single quotes, making it impossible to put
+single-quotes in a single-quoted string).
+.Ss Double Quotes
+Enclosing characters within double quotes preserves the literal
+meaning of all characters except dollarsign
+.Pq $ ,
+backquote
+.Pq ` ,
+and backslash
+.Pq \e .
+The backslash inside double quotes is historically weird, and serves to
+quote only the following characters:
+.Dl $  `  \*q  \e  \*[Lt]newline\*[Gt] .
+Otherwise it remains literal.
+.Ss Reserved Words
+Reserved words are words that have special meaning to the
+shell and are recognized at the beginning of a line and
+after a control operator.
+The following are reserved words:
+.Bl -column while while while while while -offset indent
+.It ! Ta elif Ta fi Ta while Ta case
+.It else Ta for Ta then Ta { Ta }
+.It do Ta done Ta until Ta if Ta esac
+.El
+.Pp
+Their meaning is discussed later.
+.Ss Aliases
+An alias is a name and corresponding value set using the
+.Xr alias 1
+builtin command.
+Whenever a reserved word may occur (see above),
+and after checking for reserved words, the shell
+checks the word to see if it matches an alias.
+If it does, it replaces it in the input stream with its value.
+For example, if there is an alias called
+.Dq lf
+with the value
+.Dq "ls -F" ,
+then the input:
+.Pp
+.Dl lf foobar Aq return
+.Pp
+would become
+.Pp
+.Dl ls -F foobar Aq return
+.Pp
+Aliases provide a convenient way for naive users to create shorthands for
+commands without having to learn how to create functions with arguments.
+They can also be used to create lexically obscure code.
+This use is discouraged.
+.Ss Commands
+The shell interprets the words it reads according to a language, the
+specification of which is outside the scope of this man page (refer to the
+BNF in the
+.Tn POSIX
+1003.2 document).
+Essentially though, a line is read and if the first
+word of the line (or after a control operator) is not a reserved word,
+then the shell has recognized a simple command.
+Otherwise, a complex
+command or some other special construct may have been recognized.
+.Ss Simple Commands
+If a simple command has been recognized, the shell performs
+the following actions:
+.Bl -enum -offset indent
+.It
+Leading words of the form
+.Dq name=value
+are stripped off and assigned to the environment of the simple command.
+Redirection operators and their arguments (as described below) are
+stripped off and saved for processing.
+.It
+The remaining words are expanded as described in
+the section called
+.Dq Expansions ,
+and the first remaining word is considered the command name and the
+command is located.
+The remaining words are considered the arguments of the command.
+If no command name resulted, then the
+.Dq name=value
+variable assignments recognized in item 1 affect the current shell.
+.It
+Redirections are performed as described in the next section.
+.El
+.Ss Redirections
+Redirections are used to change where a command reads its input or sends
+its output.
+In general, redirections open, close, or duplicate an
+existing reference to a file.
+The overall format used for redirection is:
+.Pp
+.Dl [n] Va redir-op Ar file
+.Pp
+where
+.Va redir-op
+is one of the redirection operators mentioned previously.
+Following is a list of the possible redirections.
+The
+.Bq n
+is an optional number, as in
+.Sq 3
+(not
+.Sq Bq 3 ) ,
+that refers to a file descriptor.
+.Bl -tag -width aaabsfiles -offset indent
+.It [n] Ns \*[Gt] file
+Redirect standard output (or n) to file.
+.It [n] Ns \*[Gt]| file
+Same, but override the
+.Fl C
+option.
+.It [n] Ns \*[Gt]\*[Gt] file
+Append standard output (or n) to file.
+.It [n] Ns \*[Lt] file
+Redirect standard input (or n) from file.
+.It [n1] Ns \*[Lt]& Ns n2
+Duplicate standard input (or n1) from file descriptor n2.
+.It [n] Ns \*[Lt]&-
+Close standard input (or n).
+.It [n1] Ns \*[Gt]& Ns n2
+Duplicate standard output (or n1) to n2.
+.It [n] Ns \*[Gt]&-
+Close standard output (or n).
+.It [n] Ns \*[Lt]\*[Gt] file
+Open file for reading and writing on standard input (or n).
+.El
+.Pp
+The following redirection is often called a
+.Dq here-document .
+.Bl -item -offset indent
+.It
+.Li [n]\*[Lt]\*[Lt] delimiter
+.Dl here-doc-text ...
+.Li delimiter
+.El
+.Pp
+All the text on successive lines up to the delimiter is saved away and
+made available to the command on standard input, or file descriptor n if
+it is specified.
+If the delimiter as specified on the initial line is
+quoted, then the here-doc-text is treated literally, otherwise the text is
+subjected to parameter expansion, command substitution, and arithmetic
+expansion (as described in the section on
+.Dq Expansions ) .
+If the operator is
+.Dq \*[Lt]\*[Lt]-
+instead of
+.Dq \*[Lt]\*[Lt] ,
+then leading tabs in the here-doc-text are stripped.
+.Ss Search and Execution
+There are three types of commands: shell functions, builtin commands, and
+normal programs -- and the command is searched for (by name) in that order.
+They each are executed in a different way.
+.Pp
+When a shell function is executed, all of the shell positional parameters
+(except $0, which remains unchanged) are set to the arguments of the shell
+function.
+The variables which are explicitly placed in the environment of
+the command (by placing assignments to them before the function name) are
+made local to the function and are set to the values given.
+Then the command given in the function definition is executed.
+The positional parameters are restored to their original values
+when the command completes.
+This all occurs within the current shell.
+.Pp
+Shell builtins are executed internally to the shell, without spawning a
+new process.
+.Pp
+Otherwise, if the command name doesn't match a function or builtin, the
+command is searched for as a normal program in the file system (as
+described in the next section).
+When a normal program is executed, the shell runs the program,
+passing the arguments and the environment to the program.
+If the program is not a normal executable file (i.e., if it does
+not begin with the "magic number" whose
+.Tn ASCII
+representation is "#!", so
+.Xr execve 2
+returns
+.Er ENOEXEC
+then) the shell will interpret the program in a subshell.
+The child shell will reinitialize itself in this case,
+so that the effect will be as if a
+new shell had been invoked to handle the ad-hoc shell script, except that
+the location of hashed commands located in the parent shell will be
+remembered by the child.
+.Pp
+Note that previous versions of this document and the source code itself
+misleadingly and sporadically refer to a shell script without a magic
+number as a "shell procedure".
+.Ss Path Search
+When locating a command, the shell first looks to see if it has a shell
+function by that name.
+Then it looks for a builtin command by that name.
+If a builtin command is not found, one of two things happen:
+.Bl -enum
+.It
+Command names containing a slash are simply executed without performing
+any searches.
+.It
+The shell searches each entry in
+.Ev PATH
+in turn for the command.
+The value of the
+.Ev PATH
+variable should be a series of entries separated by colons.
+Each entry consists of a directory name.
+The current directory may be indicated
+implicitly by an empty directory name, or explicitly by a single period.
+.El
+.Ss Command Exit Status
+Each command has an exit status that can influence the behaviour
+of other shell commands.
+The paradigm is that a command exits
+with zero for normal or success, and non-zero for failure,
+error, or a false indication.
+The man page for each command
+should indicate the various exit codes and what they mean.
+Additionally, the builtin commands return exit codes, as does
+an executed shell function.
+.Pp
+If a command consists entirely of variable assignments then the
+exit status of the command is that of the last command substitution
+if any, otherwise 0.
+.Ss Complex Commands
+Complex commands are combinations of simple commands with control
+operators or reserved words, together creating a larger complex command.
+More generally, a command is one of the following:
+.Bl -bullet
+.It
+simple command
+.It
+pipeline
+.It
+list or compound-list
+.It
+compound command
+.It
+function definition
+.El
+.Pp
+Unless otherwise stated, the exit status of a command is that of the last
+simple command executed by the command.
+.Ss Pipelines
+A pipeline is a sequence of one or more commands separated
+by the control operator |.
+The standard output of all but
+the last command is connected to the standard input
+of the next command.
+The standard output of the last
+command is inherited from the shell, as usual.
+.Pp
+The format for a pipeline is:
+.Pp
+.Dl [!] command1 [ | command2 ...]
+.Pp
+The standard output of command1 is connected to the standard input of
+command2.
+The standard input, standard output, or both of a command is
+considered to be assigned by the pipeline before any redirection specified
+by redirection operators that are part of the command.
+.Pp
+If the pipeline is not in the background (discussed later), the shell
+waits for all commands to complete.
+.Pp
+If the reserved word ! does not precede the pipeline, the exit status is
+the exit status of the last command specified in the pipeline.
+Otherwise, the exit status is the logical NOT of the exit status of the
+last command.
+That is, if the last command returns zero, the exit status
+is 1; if the last command returns greater than zero, the exit status is
+zero.
+.Pp
+Because pipeline assignment of standard input or standard output or both
+takes place before redirection, it can be modified by redirection.
+For example:
+.Pp
+.Dl $ command1 2\*[Gt]&1 | command2
+.Pp
+sends both the standard output and standard error of command1
+to the standard input of command2.
+.Pp
+A ; or
+.Aq newline
+terminator causes the preceding AND-OR-list (described
+next) to be executed sequentially; a & causes asynchronous execution of
+the preceding AND-OR-list.
+.Pp
+Note that unlike some other shells, each process in the pipeline is a
+child of the invoking shell (unless it is a shell builtin, in which case
+it executes in the current shell -- but any effect it has on the
+environment is wiped).
+.Ss Background Commands -- &
+If a command is terminated by the control operator ampersand (&), the
+shell executes the command asynchronously -- that is, the shell does not
+wait for the command to finish before executing the next command.
+.Pp
+The format for running a command in background is:
+.Pp
+.Dl command1 & [command2 & ...]
+.Pp
+If the shell is not interactive, the standard input of an asynchronous
+command is set to
+.Pa /dev/null .
+.Ss Lists -- Generally Speaking
+A list is a sequence of zero or more commands separated by newlines,
+semicolons, or ampersands, and optionally terminated by one of these three
+characters.
+The commands in a list are executed in the order they are written.
+If command is followed by an ampersand, the shell starts the
+command and immediately proceed onto the next command; otherwise it waits
+for the command to terminate before proceeding to the next one.
+.Ss Short-Circuit List Operators
+.Dq &&
+and
+.Dq ||
+are AND-OR list operators.
+.Dq &&
+executes the first command, and then executes the second command iff the
+exit status of the first command is zero.
+.Dq ||
+is similar, but executes the second command iff the exit status of the first
+command is nonzero.
+.Dq &&
+and
+.Dq ||
+both have the same priority.
+.Ss Flow-Control Constructs -- if, while, for, case
+The syntax of the if command is
+.Bd -literal -offset indent
+if list
+then list
+[ elif list
+then    list ] ...
+[ else list ]
+fi
+.Ed
+.Pp
+The syntax of the while command is
+.Bd -literal -offset indent
+while list
+do   list
+done
+.Ed
+.Pp
+The two lists are executed repeatedly while the exit status of the
+first list is zero.
+The until command is similar, but has the word
+until in place of while, which causes it to
+repeat until the exit status of the first list is zero.
+.Pp
+The syntax of the for command is
+.Bd -literal -offset indent
+for variable [ in [ word ... ] ]
+do   list
+done
+.Ed
+.Pp
+The words following
+.Pa in
+are expanded, and then the list is executed repeatedly with the
+variable set to each word in turn.
+Omitting in word ... is equivalent to in "$@".
+.Pp
+The syntax of the break and continue command is
+.Bd -literal -offset indent
+break [ num ]
+continue [ num ]
+.Ed
+.Pp
+Break terminates the num innermost for or while loops.
+Continue continues with the next iteration of the innermost loop.
+These are implemented as builtin commands.
+.Pp
+The syntax of the case command is
+.Bd -literal -offset indent
+case word in
+[(]pattern) list ;;
+\&...
+esac
+.Ed
+.Pp
+The pattern can actually be one or more patterns (see
+.Sx Shell Patterns
+described later), separated by
+.Dq \*(Ba
+characters.
+The
+.Do
+(
+.Dc
+character before the pattern is optional.
+.Ss Grouping Commands Together
+Commands may be grouped by writing either
+.Pp
+.Dl (list)
+.Pp
+or
+.Pp
+.Dl { list; }
+.Pp
+The first of these executes the commands in a subshell.
+Builtin commands grouped into a (list) will not affect the current shell.
+The second form does not fork another shell so is slightly more efficient.
+Grouping commands together this way allows you to redirect
+their output as though they were one program:
+.Pp
+.Bd -literal -offset indent
+{ printf \*q hello \*q ; printf \*q world\\n" ; } \*[Gt] greeting
+.Ed
+.Pp
+Note that
+.Dq }
+must follow a control operator (here,
+.Dq \&; )
+so that it is recognized as a reserved word and not as another command argument.
+.Ss Functions
+The syntax of a function definition is
+.Pp
+.Dl name ( ) command
+.Pp
+A function definition is an executable statement; when executed it
+installs a function named name and returns an exit status of zero.
+The command is normally a list enclosed between
+.Dq {
+and
+.Dq } .
+.Pp
+Variables may be declared to be local to a function by using a local
+command.
+This should appear as the first statement of a function, and the syntax is
+.Pp
+.Dl local [ variable | - ] ...
+.Pp
+Local is implemented as a builtin command.
+.Pp
+When a variable is made local, it inherits the initial value and exported
+and readonly flags from the variable with the same name in the surrounding
+scope, if there is one.
+Otherwise, the variable is initially unset.
+The shell uses dynamic scoping, so that if you make the variable x local to
+function f, which then calls function g, references to the variable x made
+inside g will refer to the variable x declared inside f, not to the global
+variable named x.
+.Pp
+The only special parameter that can be made local is
+.Dq - .
+Making
+.Dq -
+local any shell options that are changed via the set command inside the
+function to be restored to their original values when the function
+returns.
+.Pp
+The syntax of the return command is
+.Pp
+.Dl return [ exitstatus ]
+.Pp
+It terminates the currently executing function.
+Return is implemented as a builtin command.
+.Ss Variables and Parameters
+The shell maintains a set of parameters.
+A parameter denoted by a name is called a variable.
+When starting up, the shell turns all the environment
+variables into shell variables.
+New variables can be set using the form
+.Pp
+.Dl name=value
+.Pp
+Variables set by the user must have a name consisting solely of
+alphabetics, numerics, and underscores - the first of which must not be
+numeric.
+A parameter can also be denoted by a number or a special
+character as explained below.
+.Ss Positional Parameters
+A positional parameter is a parameter denoted by a number (n \*[Gt] 0).
+The shell sets these initially to the values of its command line arguments
+that follow the name of the shell script.
+The
+.Ic set
+builtin can also be used to set or reset them.
+.Ss Special Parameters
+A special parameter is a parameter denoted by one of the following special
+characters.
+The value of the parameter is listed next to its character.
+.Bl -tag -width thinhyphena
+.It *
+Expands to the positional parameters, starting from one.
+When the
+expansion occurs within a double-quoted string it expands to a single
+field with the value of each parameter separated by the first character of
+the
+.Ev IFS
+variable, or by a
+.Aq space
+if
+.Ev IFS
+is unset.
+.It @
+Expands to the positional parameters, starting from one.
+When the expansion occurs within double-quotes, each positional
+parameter expands as a separate argument.
+If there are no positional parameters, the
+expansion of @ generates zero arguments, even when @ is
+double-quoted.
+What this basically means, for example, is
+if $1 is
+.Dq abc
+and $2 is
+.Dq def ghi ,
+then
+.Qq $@
+expands to
+the two arguments:
+.Pp
+.Sm off
+.Dl \*q abc \*q \  \*q def\ ghi \*q
+.Sm on
+.It #
+Expands to the number of positional parameters.
+.It ?
+Expands to the exit status of the most recent pipeline.
+.It - (Hyphen.)
+Expands to the current option flags (the single-letter
+option names concatenated into a string) as specified on
+invocation, by the set builtin command, or implicitly
+by the shell.
+.It $
+Expands to the process ID of the invoked shell.
+A subshell retains the same value of $ as its parent.
+.It !
+Expands to the process ID of the most recent background
+command executed from the current shell.
+For a pipeline, the process ID is that of the last command in the pipeline.
+.It 0 (Zero.)
+Expands to the name of the shell or shell script.
+.El
+.Ss Word Expansions
+This clause describes the various expansions that are performed on words.
+Not all expansions are performed on every word, as explained later.
+.Pp
+Tilde expansions, parameter expansions, command substitutions, arithmetic
+expansions, and quote removals that occur within a single word expand to a
+single field.
+It is only field splitting or pathname expansion that can
+create multiple fields from a single word.
+The single exception to this
+rule is the expansion of the special parameter @ within double-quotes, as
+was described above.
+.Pp
+The order of word expansion is:
+.Bl -enum
+.It
+Tilde Expansion, Parameter Expansion, Command Substitution,
+Arithmetic Expansion (these all occur at the same time).
+.It
+Field Splitting is performed on fields
+generated by step (1) unless the
+.Ev IFS
+variable is null.
+.It
+Pathname Expansion (unless set
+.Fl f
+is in effect).
+.It
+Quote Removal.
+.El
+.Pp
+The $ character is used to introduce parameter expansion, command
+substitution, or arithmetic evaluation.
+.Ss Tilde Expansion (substituting a user's home directory)
+A word beginning with an unquoted tilde character (~) is
+subjected to tilde expansion.
+All the characters up to
+a slash (/) or the end of the word are treated as a username
+and are replaced with the user's home directory.
+If the username is missing (as in
+.Pa ~/foobar ) ,
+the tilde is replaced with the value of the
+.Va HOME
+variable (the current user's home directory).
+.Ss Parameter Expansion
+The format for parameter expansion is as follows:
+.Pp
+.Dl ${expression}
+.Pp
+where expression consists of all characters until the matching
+.Dq } .
+Any
+.Dq }
+escaped by a backslash or within a quoted string, and characters in
+embedded arithmetic expansions, command substitutions, and variable
+expansions, are not examined in determining the matching
+.Dq } .
+.Pp
+The simplest form for parameter expansion is:
+.Pp
+.Dl ${parameter}
+.Pp
+The value, if any, of parameter is substituted.
+.Pp
+The parameter name or symbol can be enclosed in braces, which are
+optional except for positional parameters with more than one digit or
+when parameter is followed by a character that could be interpreted as
+part of the name.
+If a parameter expansion occurs inside double-quotes:
+.Bl -enum
+.It
+Pathname expansion is not performed on the results of the expansion.
+.It
+Field splitting is not performed on the results of the
+expansion, with the exception of @.
+.El
+.Pp
+In addition, a parameter expansion can be modified by using one of the
+following formats.
+.Bl -tag -width aaparameterwordaaaaa
+.It ${parameter:-word}
+Use Default Values.
+If parameter is unset or null, the expansion of word
+is substituted; otherwise, the value of parameter is substituted.
+.It ${parameter:=word}
+Assign Default Values.
+If parameter is unset or null, the expansion of
+word is assigned to parameter.
+In all cases, the final value of parameter is substituted.
+Only variables, not positional parameters or special
+parameters, can be assigned in this way.
+.It ${parameter:?[word]}
+Indicate Error if Null or Unset.
+If parameter is unset or null, the
+expansion of word (or a message indicating it is unset if word is omitted)
+is written to standard error and the shell exits with a nonzero exit status.
+Otherwise, the value of parameter is substituted.
+An interactive shell need not exit.
+.It ${parameter:+word}
+Use Alternative Value.
+If parameter is unset or null, null is
+substituted; otherwise, the expansion of word is substituted.
+.El
+.Pp
+In the parameter expansions shown previously, use of the colon in the
+format results in a test for a parameter that is unset or null; omission
+of the colon results in a test for a parameter that is only unset.
+.Bl -tag -width aaparameterwordaaaaa
+.It ${#parameter}
+String Length.
+The length in characters of the value of parameter.
+.El
+.Pp
+The following four varieties of parameter expansion provide for substring
+processing.
+In each case, pattern matching notation (see
+.Sx Shell Patterns ) ,
+rather than regular expression notation, is used to evaluate the patterns.
+If parameter is * or @, the result of the expansion is unspecified.
+Enclosing the full parameter expansion string in double-quotes does not
+cause the following four varieties of pattern characters to be quoted,
+whereas quoting characters within the braces has this effect.
+.Bl -tag -width aaparameterwordaaaaa
+.It ${parameter%word}
+Remove Smallest Suffix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the
+smallest portion of the suffix matched by the pattern deleted.
+.It ${parameter%%word}
+Remove Largest Suffix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the largest
+portion of the suffix matched by the pattern deleted.
+.It ${parameter#word}
+Remove Smallest Prefix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the
+smallest portion of the prefix matched by the pattern deleted.
+.It ${parameter##word}
+Remove Largest Prefix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the largest
+portion of the prefix matched by the pattern deleted.
+.El
+.Ss Command Substitution
+Command substitution allows the output of a command to be substituted in
+place of the command name itself.
+Command substitution occurs when the command is enclosed as follows:
+.Pp
+.Dl $(command)
+.Pp
+or
+.Po
+.Dq backquoted
+version
+.Pc :
+.Pp
+.Dl `command`
+.Pp
+The shell expands the command substitution by executing command in a
+subshell environment and replacing the command substitution with the
+standard output of the command, removing sequences of one or more
+.Ao newline Ac Ns s
+at the end of the substitution.
+(Embedded
+.Ao newline Ac Ns s
+before
+the end of the output are not removed; however, during field splitting,
+they may be translated into
+.Ao space Ac Ns s ,
+depending on the value of
+.Ev IFS
+and quoting that is in effect.)
+.Ss Arithmetic Expansion
+Arithmetic expansion provides a mechanism for evaluating an arithmetic
+expression and substituting its value.
+The format for arithmetic expansion is as follows:
+.Pp
+.Dl $((expression))
+.Pp
+The expression is treated as if it were in double-quotes, except
+that a double-quote inside the expression is not treated specially.
+The shell expands all tokens in the expression for parameter expansion,
+command substitution, and quote removal.
+.Pp
+Next, the shell treats this as an arithmetic expression and
+substitutes the value of the expression.
+.Ss White Space Splitting (Field Splitting)
+After parameter expansion, command substitution, and
+arithmetic expansion the shell scans the results of
+expansions and substitutions that did not occur in double-quotes for
+field splitting and multiple fields can result.
+.Pp
+The shell treats each character of the
+.Ev IFS
+as a delimiter and uses the delimiters to split the results of parameter
+expansion and command substitution into fields.
+.Ss Pathname Expansion (File Name Generation)
+Unless the
+.Fl f
+flag is set, file name generation is performed after word splitting is
+complete.
+Each word is viewed as a series of patterns, separated by slashes.
+The process of expansion replaces the word with the names of all
+existing files whose names can be formed by replacing each pattern with a
+string that matches the specified pattern.
+There are two restrictions on
+this: first, a pattern cannot match a string containing a slash, and
+second, a pattern cannot match a string starting with a period unless the
+first character of the pattern is a period.
+The next section describes the
+patterns used for both Pathname Expansion and the
+.Ic case
+command.
+.Ss Shell Patterns
+A pattern consists of normal characters, which match themselves,
+and meta-characters.
+The meta-characters are
+.Dq \&! ,
+.Dq * ,
+.Dq \&? ,
+and
+.Dq \&[ .
+These characters lose their special meanings if they are quoted.
+When command or variable substitution is performed
+and the dollar sign or back quotes are not double quoted,
+the value of the variable or the output of
+the command is scanned for these characters and they are turned into
+meta-characters.
+.Pp
+An asterisk
+.Pq Dq *
+matches any string of characters.
+A question mark matches any single character.
+A left bracket
+.Pq Dq \&[
+introduces a character class.
+The end of the character class is indicated by a
+.Pq Dq \&] ;
+if the
+.Dq \&]
+is missing then the
+.Dq \&[
+matches a
+.Dq \&[
+rather than introducing a character class.
+A character class matches any of the characters between the square brackets.
+A range of characters may be specified using a minus sign.
+The character class may be complemented
+by making an exclamation point the first character of the character class.
+.Pp
+To include a
+.Dq \&]
+in a character class, make it the first character listed (after the
+.Dq \&! ,
+if any).
+To include a minus sign, make it the first or last character listed.
+.Ss Builtins
+This section lists the builtin commands which are builtin because they
+need to perform some operation that can't be performed by a separate
+process.
+In addition to these, there are several other commands that may
+be builtin for efficiency (e.g.
+.Xr printf 1 ,
+.Xr echo 1 ,
+.Xr test 1 ,
+etc).
+.Bl -tag -width 5n
+.It :
+.It true
+A null command that returns a 0 (true) exit value.
+.It \&. file
+The commands in the specified file are read and executed by the shell.
+.It alias Op Ar name Ns Op Ar "=string ..."
+If
+.Ar name=string
+is specified, the shell defines the alias
+.Ar name
+with value
+.Ar string .
+If just
+.Ar name
+is specified, the value of the alias
+.Ar name
+is printed.
+With no arguments, the
+.Ic alias
+builtin prints the
+names and values of all defined aliases (see
+.Ic unalias ) .
+.It bg [ Ar job ] ...
+Continue the specified jobs (or the current job if no
+jobs are given) in the background.
+.It Xo command
+.Op Fl p
+.Op Fl v
+.Op Fl V
+.Ar command
+.Op Ar arg ...
+.Xc
+Execute the specified command but ignore shell functions when searching
+for it.
+(This is useful when you
+have a shell function with the same name as a builtin command.)
+.Bl -tag -width 5n
+.It Fl p
+search for command using a
+.Ev PATH
+that guarantees to find all the standard utilities.
+.It Fl V
+Do not execute the command but
+search for the command and print the resolution of the
+command search.
+This is the same as the type builtin.
+.It Fl v
+Do not execute the command but
+search for the command and print the absolute pathname
+of utilities, the name for builtins or the expansion of aliases.
+.El
+.It cd Ar -
+.It Xo cd Op Fl LP
+.Op Ar directory
+.Xc
+Switch to the specified directory (default
+.Ev HOME ) .
+If an entry for
+.Ev CDPATH
+appears in the environment of the
+.Ic cd
+command or the shell variable
+.Ev CDPATH
+is set and the directory name does not begin with a slash, then the
+directories listed in
+.Ev CDPATH
+will be searched for the specified directory.
+The format of
+.Ev CDPATH
+is the same as that of
+.Ev PATH .
+If a single dash is specified as the argument, it will be replaced by the
+value of
+.Ev OLDPWD .
+The
+.Ic cd
+command will print out the name of the
+directory that it actually switched to if this is different from the name
+that the user gave.
+These may be different either because the
+.Ev CDPATH
+mechanism was used or because the argument is a single dash.
+The
+.Fl P
+option causes the physical directory structure to be used, that is, all
+symbolic links are resolved to their respective values.  The
+.Fl L
+option turns off the effect of any preceding
+.Fl P
+options.
+.It Xo echo Op Fl n
+.Ar args... 
+.Xc
+Print the arguments on the standard output, separated by spaces.
+Unless the
+.Fl n
+option is present, a newline is output following the arguments.
+.Pp
+If any of the following sequences of characters is encountered during
+output, the sequence is not output.  Instead, the specified action is
+performed:
+.Bl -tag -width indent
+.It Li \eb
+A backspace character is output.
+.It Li \ec
+Subsequent output is suppressed.  This is normally used at the end of the
+last argument to suppress the trailing newline that
+.Ic echo
+would otherwise output.
+.It Li \ef
+Output a form feed.
+.It Li \en
+Output a newline character.
+.It Li \er
+Output a carriage return.
+.It Li \et
+Output a (horizontal) tab character.
+.It Li \ev
+Output a vertical tab.
+.It Li \e0 Ns Ar digits
+Output the character whose value is given by zero to three octal digits.
+If there are zero digits, a nul character is output.
+.It Li \e\e
+Output a backslash.
+.El
+.Pp
+All other backslash sequences elicit undefined behaviour.
+.It eval Ar string ...
+Concatenate all the arguments with spaces.
+Then re-parse and execute the command.
+.It exec Op Ar command arg ...
+Unless command is omitted, the shell process is replaced with the
+specified program (which must be a real program, not a shell builtin or
+function).
+Any redirections on the
+.Ic exec
+command are marked as permanent, so that they are not undone when the
+.Ic exec
+command finishes.
+.It exit Op Ar exitstatus
+Terminate the shell process.
+If
+.Ar exitstatus
+is given it is used as the exit status of the shell; otherwise the
+exit status of the preceding command is used.
+.It export Ar name ...
+.It export Fl p
+The specified names are exported so that they will appear in the
+environment of subsequent commands.
+The only way to un-export a variable is to unset it.
+The shell allows the value of a variable to be set at the
+same time it is exported by writing
+.Pp
+.Dl export name=value
+.Pp
+With no arguments the export command lists the names of all exported variables.
+With the
+.Fl p
+option specified the output will be formatted suitably for non-interactive use.
+.It Xo fc Op Fl e Ar editor
+.Op Ar first Op Ar last
+.Xc
+.It Xo fc Fl l
+.Op Fl nr
+.Op Ar first Op Ar last
+.Xc
+.It Xo fc Fl s Op Ar old=new
+.Op Ar first
+.Xc
+The
+.Ic fc
+builtin lists, or edits and re-executes, commands previously entered
+to an interactive shell.
+.Bl -tag -width 5n
+.It Fl e No editor
+Use the editor named by editor to edit the commands.
+The editor string is a command name, subject to search via the
+.Ev PATH
+variable.
+The value in the
+.Ev FCEDIT
+variable is used as a default when
+.Fl e
+is not specified.
+If
+.Ev FCEDIT
+is null or unset, the value of the
+.Ev EDITOR
+variable is used.
+If
+.Ev EDITOR
+is null or unset,
+.Xr ed 1
+is used as the editor.
+.It Fl l No (ell)
+List the commands rather than invoking an editor on them.
+The commands are written in the sequence indicated by
+the first and last operands, as affected by
+.Fl r ,
+with each command preceded by the command number.
+.It Fl n
+Suppress command numbers when listing with -l.
+.It Fl r
+Reverse the order of the commands listed (with
+.Fl l )
+or edited (with neither
+.Fl l
+nor
+.Fl s ) .
+.It Fl s
+Re-execute the command without invoking an editor.
+.It first
+.It last
+Select the commands to list or edit.
+The number of previous commands that
+can be accessed are determined by the value of the
+.Ev HISTSIZE
+variable.
+The value of first or last or both are one of the following:
+.Bl -tag -width 5n
+.It [+]number
+A positive number representing a command number; command numbers can be
+displayed with the
+.Fl l
+option.
+.It Fl number
+A negative decimal number representing the command that was executed
+number of commands previously.
+For example, \-1 is the immediately previous command.
+.El
+.It string
+A string indicating the most recently entered command that begins with
+that string.
+If the old=new operand is not also specified with
+.Fl s ,
+the string form of the first operand cannot contain an embedded equal sign.
+.El
+.Pp
+The following environment variables affect the execution of fc:
+.Bl -tag -width HISTSIZE
+.It Ev FCEDIT
+Name of the editor to use.
+.It Ev HISTSIZE
+The number of previous commands that are accessible.
+.El
+.It fg Op Ar job
+Move the specified job or the current job to the foreground.
+.It getopts Ar optstring var
+The
+.Tn POSIX
+.Ic getopts
+command, not to be confused with the
+.Em Bell Labs
+-derived
+.Xr getopt 1 .
+.Pp
+The first argument should be a series of letters, each of which may be
+optionally followed by a colon to indicate that the option requires an
+argument.
+The variable specified is set to the parsed option.
+.Pp
+The
+.Ic getopts
+command deprecates the older
+.Xr getopt 1
+utility due to its handling of arguments containing whitespace.
+.Pp
+The
+.Ic getopts
+builtin may be used to obtain options and their arguments
+from a list of parameters.
+When invoked,
+.Ic getopts
+places the value of the next option from the option string in the list in
+the shell variable specified by
+.Va var
+and its index in the shell variable
+.Ev OPTIND .
+When the shell is invoked,
+.Ev OPTIND
+is initialized to 1.
+For each option that requires an argument, the
+.Ic getopts
+builtin will place it in the shell variable
+.Ev OPTARG .
+If an option is not allowed for in the
+.Va optstring ,
+then
+.Ev OPTARG
+will be unset.
+.Pp
+.Va optstring
+is a string of recognized option letters (see
+.Xr getopt 3 ) .
+If a letter is followed by a colon, the option is expected to have an
+argument which may or may not be separated from it by white space.
+If an option character is not found where expected,
+.Ic getopts
+will set the variable
+.Va var
+to a
+.Dq \&? ;
+.Ic getopts
+will then unset
+.Ev OPTARG
+and write output to standard error.
+By specifying a colon as the first character of
+.Va optstring
+all errors will be ignored.
+.Pp
+A nonzero value is returned when the last option is reached.
+If there are no remaining arguments,
+.Ic getopts
+will set
+.Va var
+to the special option,
+.Dq -- ,
+otherwise, it will set
+.Va var
+to
+.Dq \&? .
+.Pp
+The following code fragment shows how one might process the arguments
+for a command that can take the options
+.Op a
+and
+.Op b ,
+and the option
+.Op c ,
+which requires an argument.
+.Pp
+.Bd -literal -offset indent
+while getopts abc: f
+do
+       case $f in
+       a | b)  flag=$f;;
+       c)      carg=$OPTARG;;
+       \\?)    echo $USAGE; exit 1;;
+       esac
+done
+shift `expr $OPTIND - 1`
+.Ed
+.Pp
+This code will accept any of the following as equivalent:
+.Pp
+.Bd -literal -offset indent
+cmd \-acarg file file
+cmd \-a \-c arg file file
+cmd \-carg -a file file
+cmd \-a \-carg \-\- file file
+.Ed
+.It hash Fl rv Ar command ...
+The shell maintains a hash table which remembers the
+locations of commands.
+With no arguments whatsoever,
+the
+.Ic hash
+command prints out the contents of this table.
+Entries which have not been looked at since the last
+.Ic cd
+command are marked with an asterisk; it is possible for these entries
+to be invalid.
+.Pp
+With arguments, the
+.Ic hash
+command removes the specified commands from the hash table (unless
+they are functions) and then locates them.
+With the
+.Fl v
+option, hash prints the locations of the commands as it finds them.
+The
+.Fl r
+option causes the hash command to delete all the entries in the hash table
+except for functions.
+.It pwd Op Fl LP
+builtin command remembers what the current directory
+is rather than recomputing it each time.
+This makes it faster.
+However, if the current directory is renamed, the builtin version of
+.Ic pwd
+will continue to print the old name for the directory.
+The
+.Fl P
+option causes the physical value of the current working directory to be shown,
+that is, all symbolic links are resolved to their respective values.  The
+.Fl L
+option turns off the effect of any preceding
+.Fl P
+options.
+.It Xo read Op Fl p Ar prompt
+.Op Fl r
+.Ar variable
+.Op Ar ...
+.Xc
+The prompt is printed if the
+.Fl p
+option is specified and the standard input is a terminal.
+Then a line is read from the standard input.
+The trailing newline is deleted from the
+line and the line is split as described in the section on word splitting
+above, and the pieces are assigned to the variables in order.
+At least one variable must be specified.
+If there are more pieces than variables, the remaining pieces
+(along with the characters in
+.Ev IFS
+that separated them) are assigned to the last variable.
+If there are more variables than pieces,
+the remaining variables are assigned the null string.
+The
+.Ic read
+builtin will indicate success unless EOF is encountered on input, in
+which case failure is returned.
+.Pp
+By default, unless the
+.Fl r
+option is specified, the backslash
+.Dq \e
+acts as an escape character, causing the following character to be treated
+literally.
+If a backslash is followed by a newline, the backslash and the
+newline will be deleted.
+.It readonly Ar name ...
+.It readonly Fl p
+The specified names are marked as read only, so that they cannot be
+subsequently modified or unset.
+The shell allows the value of a variable
+to be set at the same time it is marked read only by writing
+.Pp
+.Dl readonly name=value
+.Pp
+With no arguments the readonly command lists the names of all read only
+variables.
+With the
+.Fl p
+option specified the output will be formatted suitably for non-interactive use.
+.Pp
+.It Xo printf Ar format
+.Op Ar arguments  ...
+.Xc
+.Ic printf
+formats and prints its arguments, after the first, under control
+of the
+.Ar format  .
+The
+.Ar format
+is a character string which contains three types of objects: plain characters,
+which are simply copied to standard output, character escape sequences which
+are converted and copied to the standard output, and format specifications,
+each of which causes printing of the next successive
+.Ar argument  .
+.Pp
+The
+.Ar arguments
+after the first are treated as strings if the corresponding format is
+either
+.Cm b ,
+.Cm c
+or
+.Cm s ;
+otherwise it is evaluated as a C constant, with the following extensions:
+.Pp
+.Bl -bullet -offset indent -compact
+.It
+A leading plus or minus sign is allowed.
+.It
+If the leading character is a single or double quote, the value is the
+.Tn ASCII
+code of the next character.
+.El
+.Pp
+The format string is reused as often as necessary to satisfy the
+.Ar arguments  .
+Any extra format specifications are evaluated with zero or the null
+string.
+.Pp
+Character escape sequences are in backslash notation as defined in
+.St -ansiC .
+The characters and their meanings are as follows:
+.Bl -tag -width Ds -offset indent
+.It Cm \ea
+Write a \*[Lt]bell\*[Gt] character.
+.It Cm \eb
+Write a \*[Lt]backspace\*[Gt] character.
+.It Cm \ef
+Write a \*[Lt]form-feed\*[Gt] character.
+.It Cm \en
+Write a \*[Lt]new-line\*[Gt] character.
+.It Cm \er
+Write a \*[Lt]carriage return\*[Gt] character.
+.It Cm \et
+Write a \*[Lt]tab\*[Gt] character.
+.It Cm \ev
+Write a \*[Lt]vertical tab\*[Gt] character.
+.It Cm \e\e
+Write a backslash character.
+.It Cm \e Ns Ar num
+Write an 8\-bit character whose
+.Tn ASCII
+value is the 1\-, 2\-, or 3\-digit
+octal number
+.Ar num .
+.El
+.Pp
+Each format specification is introduced by the percent character
+(``%'').
+The remainder of the format specification includes,
+in the following order:
+.Bl -tag -width Ds
+.It "Zero or more of the following flags:"
+.Bl -tag -width Ds
+.It Cm #
+A `#' character
+specifying that the value should be printed in an ``alternative form''.
+For
+.Cm b ,
+.Cm c ,
+.Cm d ,
+and
+.Cm s
+formats, this option has no effect.
+For the
+.Cm o
+format the precision of the number is increased to force the first
+character of the output string to a zero.
+For the
+.Cm x
+.Pq Cm X
+format, a non-zero result has the string
+.Li 0x
+.Pq Li 0X
+prepended to it.
+For
+.Cm e  ,
+.Cm E ,
+.Cm f  ,
+.Cm g ,
+and
+.Cm G
+formats, the result will always contain a decimal point, even if no
+digits follow the point (normally, a decimal point only appears in the
+results of those formats if a digit follows the decimal point).
+For
+.Cm g
+and
+.Cm G
+formats, trailing zeros are not removed from the result as they
+would otherwise be.
+.It Cm \&\-
+A minus sign `\-' which specifies
+.Em left adjustment
+of the output in the indicated field;
+.It Cm \&+
+A `+' character specifying that there should always be
+a sign placed before the number when using signed formats.
+.It Sq \&\ \&
+A space specifying that a blank should be left before a positive number
+for a signed format.
+A `+' overrides a space if both are used;
+.It Cm \&0
+A zero `0' character indicating that zero-padding should be used
+rather than blank-padding.
+A `\-' overrides a `0' if both are used;
+.El
+.It "Field Width:"
+An optional digit string specifying a
+.Em field width ;
+if the output string has fewer characters than the field width it will
+be blank-padded on the left (or right, if the left-adjustment indicator
+has been given) to make up the field width (note that a leading zero
+is a flag, but an embedded zero is part of a field width);
+.It Precision :
+An optional period,
+.Sq Cm \&.\& ,
+followed by an optional digit string giving a
+.Em precision
+which specifies the number of digits to appear after the decimal point,
+for
+.Cm e
+and
+.Cm f
+formats, or the maximum number of characters to be printed
+from a string
+.Sm off
+.Pf ( Cm b
+.Sm on
+and
+.Cm s
+formats); if the digit string is missing, the precision is treated
+as zero;
+.It Format :
+A character which indicates the type of format to use (one of
+.Cm diouxXfwEgGbcs ) .
+.El
+.Pp
+A field width or precision may be
+.Sq Cm \&*
+instead of a digit string.
+In this case an
+.Ar argument
+supplies the field width or precision.
+.Pp
+The format characters and their meanings are:
+.Bl -tag -width Fl
+.It Cm diouXx
+The
+.Ar argument
+is printed as a signed decimal (d or i), unsigned octal, unsigned decimal,
+or unsigned hexadecimal (X or x), respectively.
+.It Cm f
+The
+.Ar argument
+is printed in the style
+.Sm off
+.Pf [\-]ddd Cm \&. No ddd
+.Sm on
+where the number of d's
+after the decimal point is equal to the precision specification for
+the argument.
+If the precision is missing, 6 digits are given; if the precision
+is explicitly 0, no digits and no decimal point are printed.
+.It Cm eE
+The
+.Ar argument
+is printed in the style
+.Sm off
+.Pf [\-]d Cm \&. No ddd Cm e No \\*(Pmdd
+.Sm on
+where there
+is one digit before the decimal point and the number after is equal to
+the precision specification for the argument; when the precision is
+missing, 6 digits are produced.
+An upper-case E is used for an `E' format.
+.It Cm gG
+The
+.Ar argument
+is printed in style
+.Cm f
+or in style
+.Cm e
+.Pq Cm E
+whichever gives full precision in minimum space.
+.It Cm b
+Characters from the string
+.Ar argument
+are printed with backslash-escape sequences expanded.
+.br
+The following additional backslash-escape sequences are supported:
+.Bl -tag -width Ds
+.It Cm \ec
+Causes
+.Nm
+to ignore any remaining characters in the string operand containing it,
+any remaining string operands, and any additional characters in
+the format operand.
+.It Cm \e0 Ns Ar num
+Write an 8\-bit character whose
+.Tn ASCII
+value is the 1\-, 2\-, or 3\-digit
+octal number
+.Ar num .
+.El
+.It Cm c
+The first character of
+.Ar argument
+is printed.
+.It Cm s
+Characters from the string
+.Ar argument
+are printed until the end is reached or until the number of characters
+indicated by the precision specification is reached; if the
+precision is omitted, all characters in the string are printed.
+.It Cm \&%
+Print a `%'; no argument is used.
+.El
+.Pp
+In no case does a non-existent or small field width cause truncation of
+a field; padding takes place only if the specified field width exceeds
+the actual width.
+.It Xo set
+.Oo {
+.Fl options | Cm +options | Cm -- }
+.Oc Ar arg ...
+.Xc
+The
+.Ic set
+command performs three different functions.
+.Pp
+With no arguments, it lists the values of all shell variables.
+.Pp
+If options are given, it sets the specified option
+flags, or clears them as described in the section called
+.Sx Argument List Processing .
+As a special case, if the option is -o or +o and no argument is
+supplied, the shell prints the settings of all its options.  If the
+option is -o, the settings are printed in a human-readable format; if
+the option is +o, the settings are printed in a format suitable for
+reinput to the shell to affect the same option settings.
+.Pp
+The third use of the set command is to set the values of the shell's
+positional parameters to the specified args.
+To change the positional
+parameters without changing any options, use
+.Dq --
+as the first argument to set.
+If no args are present, the set command
+will clear all the positional parameters (equivalent to executing
+.Dq shift $# . )
+.It shift Op Ar n
+Shift the positional parameters n times.
+A
+.Ic shift
+sets the value of
+.Va $1
+to the value of
+.Va $2 ,
+the value of
+.Va $2
+to the value of
+.Va $3 ,
+and so on, decreasing
+the value of
+.Va $#
+by one.
+If n is greater than the number of positional parameters,
+.Ic shift
+will issue an error message, and exit with return status 2.
+.It test Ar expression
+.It \&[ Ar expression Cm ]
+The
+.Ic test
+utility evaluates the expression and, if it evaluates
+to true, returns a zero (true) exit status; otherwise
+it returns 1 (false).
+If there is no expression, test also
+returns 1 (false).
+.Pp
+All operators and flags are separate arguments to the
+.Ic test
+utility.
+.Pp
+The following primaries are used to construct expression:
+.Bl -tag -width Ar
+.It Fl b Ar file
+True if
+.Ar file
+exists and is a block special
+file.
+.It Fl c Ar file
+True if
+.Ar file
+exists and is a character
+special file.
+.It Fl d Ar file
+True if
+.Ar file
+exists and is a directory.
+.It Fl e Ar file
+True if
+.Ar file
+exists (regardless of type).
+.It Fl f Ar file
+True if
+.Ar file
+exists and is a regular file.
+.It Fl g Ar file
+True if
+.Ar file
+exists and its set group ID flag
+is set.
+.It Fl h Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+.It Fl k Ar file
+True if
+.Ar file
+exists and its sticky bit is set.
+.It Fl n Ar string
+True if the length of
+.Ar string
+is nonzero.
+.It Fl p Ar file
+True if
+.Ar file
+is a named pipe
+.Po Tn FIFO Pc .
+.It Fl r Ar file
+True if
+.Ar file
+exists and is readable.
+.It Fl s Ar file
+True if
+.Ar file
+exists and has a size greater
+than zero.
+.It Fl t Ar file_descriptor
+True if the file whose file descriptor number
+is
+.Ar file_descriptor
+is open and is associated with a terminal.
+.It Fl u Ar file
+True if
+.Ar file
+exists and its set user ID flag
+is set.
+.It Fl w Ar file
+True if
+.Ar file
+exists and is writable.
+True
+indicates only that the write flag is on.
+The file is not writable on a read-only file
+system even if this test indicates true.
+.It Fl x Ar file
+True if
+.Ar file
+exists and is executable.
+True
+indicates only that the execute flag is on.
+If
+.Ar file
+is a directory, true indicates that
+.Ar file
+can be searched.
+.It Fl z Ar string
+True if the length of
+.Ar string
+is zero.
+.It Fl L Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+This operator is retained for compatibility with previous versions of
+this program.
+Do not rely on its existence; use
+.Fl h
+instead.
+.It Fl O Ar file
+True if
+.Ar file
+exists and its owner matches the effective user id of this process.
+.It Fl G Ar file
+True if
+.Ar file
+exists and its group matches the effective group id of this process.
+.It Fl S Ar file
+True if
+.Ar file
+exists and is a socket.
+.It Ar file1 Fl nt Ar file2
+True if
+.Ar file1
+and
+.Ar file2
+exist and
+.Ar file1
+is newer than
+.Ar file2 .
+.It Ar file1 Fl ot Ar file2
+True if
+.Ar file1
+and
+.Ar file2
+exist and
+.Ar file1
+is older than
+.Ar file2 .
+.It Ar file1 Fl ef Ar file2
+True if
+.Ar file1
+and
+.Ar file2
+exist and refer to the same file.
+.It Ar string
+True if
+.Ar string
+is not the null
+string.
+.It Ar \&s\&1 Cm \&= Ar \&s\&2
+True if the strings
+.Ar \&s\&1
+and
+.Ar \&s\&2
+are identical.
+.It Ar \&s\&1 Cm \&!= Ar \&s\&2
+True if the strings
+.Ar \&s\&1
+and
+.Ar \&s\&2
+are not identical.
+.It Ar \&s\&1 Cm \&\*[Lt] Ar \&s\&2
+True if string
+.Ar \&s\&1
+comes before
+.Ar \&s\&2
+based on the ASCII value of their characters.
+.It Ar \&s\&1 Cm \&\*[Gt] Ar \&s\&2
+True if string
+.Ar \&s\&1
+comes after
+.Ar \&s\&2
+based on the ASCII value of their characters.
+.It Ar \&n\&1 Fl \&eq Ar \&n\&2
+True if the integers
+.Ar \&n\&1
+and
+.Ar \&n\&2
+are algebraically
+equal.
+.It Ar \&n\&1 Fl \&ne Ar \&n\&2
+True if the integers
+.Ar \&n\&1
+and
+.Ar \&n\&2
+are not
+algebraically equal.
+.It Ar \&n\&1 Fl \&gt Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically
+greater than the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&ge Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically
+greater than or equal to the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&lt Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically less
+than the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&le Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically less
+than or equal to the integer
+.Ar \&n\&2 .
+.El
+.Pp
+These primaries can be combined with the following operators:
+.Bl -tag -width Ar
+.It Cm \&! Ar expression
+True if
+.Ar expression
+is false.
+.It Ar expression1 Fl a Ar expression2
+True if both
+.Ar expression1
+and
+.Ar expression2
+are true.
+.It Ar expression1 Fl o Ar expression2
+True if either
+.Ar expression1
+or
+.Ar expression2
+are true.
+.It Cm \&( Ns Ar expression Ns Cm \&)
+True if expression is true.
+.El
+.Pp
+The
+.Fl a
+operator has higher precedence than the
+.Fl o
+operator.
+.It times
+Print the accumulated user and system times for the shell and for processes
+run from the shell.  The return status is 0.
+.It Xo trap
+.Op Ar action Ar signal ...
+.Xc
+Cause the shell to parse and execute action when any of the specified
+signals are received.
+The signals are specified by signal number or as the name of the signal.
+If
+.Ar signal
+is
+.Li 0 ,
+the action is executed when the shell exits.
+.Ar action
+may be null, which cause the specified signals to be ignored.
+With
+.Ar action
+omitted or set to `-' the specified signals are set to their default action.
+When the shell forks off a subshell, it resets trapped (but not ignored)
+signals to the default action.
+The
+.Ic trap
+command has no effect on signals that were
+ignored on entry to the shell.
+.Ic trap
+without any arguments cause it to write a list of signals and their
+associated action to the standard output in a format that is suitable
+as an input to the shell that achieves the same trapping results.
+.Pp
+Examples:
+.Pp
+.Dl trap
+.Pp
+List trapped signals and their corresponding action
+.Pp
+.Dl trap '' INT QUIT tstp 30
+.Pp
+Ignore signals INT QUIT TSTP USR1
+.Pp
+.Dl trap date INT
+.Pp
+Print date upon receiving signal INT
+.It type Op Ar name ...
+Interpret each name as a command and print the resolution of the command
+search.
+Possible resolutions are:
+shell keyword, alias, shell builtin,
+command, tracked alias and not found.
+For aliases the alias expansion is
+printed; for commands and tracked aliases the complete pathname of the
+command is printed.
+.It ulimit Xo
+.Op Fl H \*(Ba Fl S
+.Op Fl a \*(Ba Fl tfdscmlpn Op Ar value
+.Xc
+Inquire about or set the hard or soft limits on processes or set new
+limits.
+The choice between hard limit (which no process is allowed to
+violate, and which may not be raised once it has been lowered) and soft
+limit (which causes processes to be signaled but not necessarily killed,
+and which may be raised) is made with these flags:
+.Bl -tag -width Fl
+.It Fl H
+set or inquire about hard limits
+.It Fl S
+set or inquire about soft limits.
+If neither
+.Fl H
+nor
+.Fl S
+is specified, the soft limit is displayed or both limits are set.
+If both are specified, the last one wins.
+.El
+.Pp
+.Bl -tag -width Fl
+The limit to be interrogated or set, then, is chosen by specifying
+any one of these flags:
+.It Fl a
+show all the current limits
+.It Fl t
+show or set the limit on CPU time (in seconds)
+.It Fl f
+show or set the limit on the largest file that can be created
+(in 512-byte blocks)
+.It Fl d
+show or set the limit on the data segment size of a process (in kilobytes)
+.It Fl s
+show or set the limit on the stack size of a process (in kilobytes)
+.It Fl c
+show or set the limit on the largest core dump size that can be produced
+(in 512-byte blocks)
+.It Fl m
+show or set the limit on the total physical memory that can be
+in use by a process (in kilobytes)
+.It Fl l
+show or set the limit on how much memory a process can lock with
+.Xr mlock 2
+(in kilobytes)
+.It Fl p
+show or set the limit on the number of processes this user can
+have at one time
+.It Fl n
+show or set the limit on the number files a process can have open at once
+.El
+.Pp
+If none of these is specified, it is the limit on file size that is shown
+or set.
+If value is specified, the limit is set to that number; otherwise
+the current limit is displayed.
+.Pp
+Limits of an arbitrary process can be displayed or set using the
+.Xr sysctl 8
+utility.
+.Pp
+.It umask Op Ar mask
+Set the value of umask (see
+.Xr umask 2 )
+to the specified octal value.
+If the argument is omitted, the umask value is printed.
+.It unalias Xo
+.Op Fl a
+.Op Ar name
+.Xc
+If
+.Ar name
+is specified, the shell removes that alias.
+If
+.Fl a
+is specified, all aliases are removed.
+.It unset Xo
+.Op Fl fv
+.Ar name ...
+.Xc
+The specified variables and functions are unset and unexported.
+If
+.Fl f
+or
+.Fl v
+is specified, the corresponding function or variable is unset, respectively.
+If a given name corresponds to both a variable and a function, and no
+options are given, only the variable is unset.
+.It wait Op Ar job
+Wait for the specified job to complete and return the exit status of the
+last process in the job.
+If the argument is omitted, wait for all jobs to
+complete and the return an exit status of zero.
+.El
+.Ss Command Line Editing
+When
+.Nm
+is being used interactively from a terminal, the current command
+and the command history (see
+.Ic fc
+in
+.Sx Builtins )
+can be edited using vi-mode command-line editing.
+This mode uses commands, described below,
+similar to a subset of those described in the vi man page.
+The command
+.Ql set -o vi
+enables vi-mode editing and place sh into vi insert mode.
+With vi-mode
+enabled, sh can be switched between insert mode and command mode.
+The editor is not described in full here, but will be in a later document.
+It's similar to vi: typing
+.Aq ESC
+will throw you into command VI command mode.
+Hitting
+.Aq return
+while in command mode will pass the line to the shell.
+.Sh EXIT STATUS
+Errors that are detected by the shell, such as a syntax error, will cause the
+shell to exit with a non-zero exit status.
+If the shell is not an
+interactive shell, the execution of the shell file will be aborted.
+Otherwise
+the shell will return the exit status of the last command executed, or
+if the exit builtin is used with a numeric argument, it will return the
+argument.
+.Sh ENVIRONMENT
+.Bl -tag -width MAILCHECK
+.It Ev HOME
+Set automatically by
+.Xr login 1
+from the user's login directory in the password file
+.Pq Xr passwd 4 .
+This environment variable also functions as the default argument for the
+cd builtin.
+.It Ev PATH
+The default search path for executables.
+See the above section
+.Sx Path Search .
+.It Ev CDPATH
+The search path used with the cd builtin.
+.It Ev MAIL
+The name of a mail file, that will be checked for the arrival of new mail.
+Overridden by
+.Ev MAILPATH .
+.It Ev MAILCHECK
+The frequency in seconds that the shell checks for the arrival of mail
+in the files specified by the
+.Ev MAILPATH
+or the
+.Ev MAIL
+file.
+If set to 0, the check will occur at each prompt.
+.It Ev MAILPATH
+A colon
+.Dq \&:
+separated list of file names, for the shell to check for incoming mail.
+This environment setting overrides the
+.Ev MAIL
+setting.
+There is a maximum of 10 mailboxes that can be monitored at once.
+.It Ev PS1
+The primary prompt string, which defaults to
+.Dq $\  ,
+unless you are the superuser, in which case it defaults to
+.Dq #\  .
+.It Ev PS2
+The secondary prompt string, which defaults to
+.Dq \*[Gt]\  .
+.It Ev PS4
+Output before each line when execution trace (set -x) is enabled,
+defaults to
+.Dq +\  .
+.It Ev IFS
+Input Field Separators.
+This is normally set to
+.Aq space ,
+.Aq tab ,
+and
+.Aq newline .
+See the
+.Sx White Space Splitting
+section for more details.
+.It Ev TERM
+The default terminal setting for the shell.
+This is inherited by
+children of the shell, and is used in the history editing modes.
+.It Ev HISTSIZE
+The number of lines in the history buffer for the shell.
+.It Ev PWD
+The logical value of the current working directory.  This is set by the
+.Ic cd
+command.
+.It Ev OLDPWD
+The previous logical value of the current working directory.  This is set by
+the
+.Ic cd
+command.
+.It Ev PPID
+The process ID of the parent process of the shell.
+.El
+.Sh FILES
+.Bl -item -width HOMEprofilexxxx
+.It
+.Pa $HOME/.profile
+.It
+.Pa /etc/profile
+.El
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr echo 1 ,
+.Xr getopt 1 ,
+.Xr ksh 1 ,
+.Xr login 1 ,
+.Xr printf 1 ,
+.Xr test 1 ,
+.Xr getopt 3 ,
+.Xr passwd 5 ,
+.\" .Xr profile 4 ,
+.Xr environ 7 ,
+.Xr sysctl 8
+.Sh HISTORY
+.Nm
+is a POSIX-compliant implementation of /bin/sh that aims to be as small as
+possible.
+.Nm
+is a direct descendant of the NetBSD version of ash (the Almquist SHell),
+ported to Linux in early 1997.
+It was renamed to
+.Nm
+in 2002.
+.Sh BUGS
+Setuid shell scripts should be avoided at all costs, as they are a
+significant security risk.
+.Pp
+PS1, PS2, and PS4 should be subject to parameter expansion before
+being displayed.
diff --git a/src/error.c b/src/error.c
new file mode 100644 (file)
index 0000000..9d31989
--- /dev/null
@@ -0,0 +1,232 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Errors and exceptions.
+ */
+
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "shell.h"
+#include "main.h"
+#include "options.h"
+#include "output.h"
+#include "error.h"
+#include "show.h"
+#include "eval.h"
+#include "parser.h"
+#include "system.h"
+
+
+/*
+ * Code to handle exceptions in C.
+ */
+
+struct jmploc *handler;
+int exception;
+int suppressint;
+volatile sig_atomic_t intpending;
+int errlinno;
+
+
+static void exverror(int, const char *, va_list)
+    __attribute__((__noreturn__));
+
+/*
+ * Called to raise an exception.  Since C doesn't include exceptions, we
+ * just do a longjmp to the exception handler.  The type of exception is
+ * stored in the global variable "exception".
+ */
+
+void
+exraise(int e)
+{
+#ifdef DEBUG
+       if (handler == NULL)
+               abort();
+#endif
+       INTOFF;
+
+       exception = e;
+       longjmp(handler->loc, 1);
+}
+
+
+/*
+ * Called from trap.c when a SIGINT is received.  (If the user specifies
+ * that SIGINT is to be trapped or ignored using the trap builtin, then
+ * this routine is not called.)  Suppressint is nonzero when interrupts
+ * are held using the INTOFF macro.  (The test for iflag is just
+ * defensive programming.)
+ */
+
+void
+onint(void) {
+
+       intpending = 0;
+       sigclearmask();
+       if (!(rootshell && iflag)) {
+               signal(SIGINT, SIG_DFL);
+               raise(SIGINT);
+       }
+       exraise(EXINT);
+       /* NOTREACHED */
+}
+
+static void
+exvwarning2(const char *msg, va_list ap)
+{
+       struct output *errs;
+       const char *name;
+       const char *fmt;
+
+       errs = out2;
+       name = arg0 ? arg0 : "sh";
+       if (!commandname)
+               fmt = "%s: %d: ";
+       else
+               fmt = "%s: %d: %s: ";
+       outfmt(errs, fmt, name, errlinno, commandname);
+       doformat(errs, msg, ap);
+#if FLUSHERR
+       outc('\n', errs);
+#else
+       outcslow('\n', errs);
+#endif
+}
+
+#define exvwarning(a, b, c) exvwarning2(b, c)
+
+/*
+ * Exverror is called to raise the error exception.  If the second argument
+ * is not NULL then error prints an error message using printf style
+ * formatting.  It then raises the error exception.
+ */
+static void
+exverror(int cond, const char *msg, va_list ap)
+{
+#ifdef DEBUG
+       if (msg) {
+               va_list aq;
+               TRACE(("exverror(%d, \"", cond));
+               va_copy(aq, ap);
+               TRACEV((msg, aq));
+               va_end(aq);
+               TRACE(("\") pid=%d\n", getpid()));
+       } else
+               TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
+       if (msg)
+#endif
+               exvwarning(-1, msg, ap);
+
+       flushall();
+       exraise(cond);
+       /* NOTREACHED */
+}
+
+
+void
+sh_error(const char *msg, ...)
+{
+       va_list ap;
+
+       exitstatus = 2;
+
+       va_start(ap, msg);
+       exverror(EXERROR, msg, ap);
+       /* NOTREACHED */
+       va_end(ap);
+}
+
+
+void
+exerror(int cond, const char *msg, ...)
+{
+       va_list ap;
+
+       va_start(ap, msg);
+       exverror(cond, msg, ap);
+       /* NOTREACHED */
+       va_end(ap);
+}
+
+/*
+ * error/warning routines for external builtins
+ */
+
+void
+sh_warnx(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       exvwarning(-1, fmt, ap);
+       va_end(ap);
+}
+
+
+/*
+ * Return a string describing an error.  The returned string may be a
+ * pointer to a static buffer that will be overwritten on the next call.
+ * Action describes the operation that got the error.
+ */
+
+const char *
+errmsg(int e, int action)
+{
+       if (e != ENOENT && e != ENOTDIR)
+               return strerror(e);
+
+       if (action & E_OPEN)
+               return "No such file";
+       else if (action & E_CREAT)
+               return "Directory nonexistent";
+       else
+               return "not found";
+}
+
+
+#ifdef REALLY_SMALL
+void
+__inton() {
+       if (--suppressint == 0 && intpending) {
+               onint();
+       }
+}
+#endif
diff --git a/src/error.h b/src/error.h
new file mode 100644 (file)
index 0000000..9630b56
--- /dev/null
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)error.h     8.2 (Berkeley) 5/4/95
+ */
+
+#include <setjmp.h>
+#include <signal.h>
+
+/*
+ * Types of operations (passed to the errmsg routine).
+ */
+
+#define E_OPEN 01      /* opening a file */
+#define E_CREAT 02     /* creating a file */
+#define E_EXEC 04      /* executing a program */
+
+
+/*
+ * We enclose jmp_buf in a structure so that we can declare pointers to
+ * jump locations.  The global variable handler contains the location to
+ * jump to when an exception occurs, and the global variable exception
+ * contains a code identifying the exeception.  To implement nested
+ * exception handlers, the user should save the value of handler on entry
+ * to an inner scope, set handler to point to a jmploc structure for the
+ * inner scope, and restore handler on exit from the scope.
+ */
+
+struct jmploc {
+       jmp_buf loc;
+};
+
+extern struct jmploc *handler;
+extern int exception;
+
+/* exceptions */
+#define EXINT 0                /* SIGINT received */
+#define EXERROR 1      /* a generic error */
+#define EXEXIT 4       /* exit the shell */
+
+
+/*
+ * These macros allow the user to suspend the handling of interrupt signals
+ * over a period of time.  This is similar to SIGHOLD to or sigblock, but
+ * much more efficient and portable.  (But hacking the kernel is so much
+ * more fun than worrying about efficiency and portability. :-))
+ */
+
+extern int suppressint;
+extern volatile sig_atomic_t intpending;
+
+#define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
+#define INTOFF \
+       ({ \
+               suppressint++; \
+               barrier(); \
+               0; \
+       })
+#ifdef REALLY_SMALL
+void __inton(void);
+#define INTON __inton()
+#else
+#define INTON \
+       ({ \
+               barrier(); \
+               if (--suppressint == 0 && intpending) onint(); \
+               0; \
+       })
+#endif
+#define FORCEINTON \
+       ({ \
+               barrier(); \
+               suppressint = 0; \
+               if (intpending) onint(); \
+               0; \
+       })
+#define SAVEINT(v) ((v) = suppressint)
+#define RESTOREINT(v) \
+       ({ \
+               barrier(); \
+               if ((suppressint = (v)) == 0 && intpending) onint(); \
+               0; \
+       })
+#define CLEAR_PENDING_INT intpending = 0
+#define int_pending() intpending
+
+void exraise(int) __attribute__((__noreturn__));
+#ifdef USE_NORETURN
+void onint(void) __attribute__((__noreturn__));
+#else
+void onint(void);
+#endif
+extern int errlinno;
+void sh_error(const char *, ...) __attribute__((__noreturn__));
+void exerror(int, const char *, ...) __attribute__((__noreturn__));
+const char *errmsg(int, int);
+
+void sh_warnx(const char *, ...);
diff --git a/src/eval.c b/src/eval.c
new file mode 100644 (file)
index 0000000..95d30f4
--- /dev/null
@@ -0,0 +1,1087 @@
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+/*
+ * Evaluate a command.
+ */
+
+#include "shell.h"
+#include "nodes.h"
+#include "syntax.h"
+#include "expand.h"
+#include "parser.h"
+#include "jobs.h"
+#include "eval.h"
+#include "builtins.h"
+#include "options.h"
+#include "exec.h"
+#include "redir.h"
+#include "input.h"
+#include "output.h"
+#include "trap.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "show.h"
+#include "mystring.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+
+
+int evalskip;                  /* set if we are skipping commands */
+STATIC int skipcount;          /* number of levels to skip */
+MKINIT int loopnest;           /* current loop nesting level */
+static int funcline;           /* starting line number of current function, or 0 if not in a function */
+
+
+char *commandname;
+int exitstatus;                        /* exit status of last command */
+int back_exitstatus;           /* exit status of backquoted command */
+
+
+#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
+STATIC
+#endif
+void evaltreenr(union node *, int) __attribute__ ((__noreturn__));
+STATIC void evalloop(union node *, int);
+STATIC void evalfor(union node *, int);
+STATIC void evalcase(union node *, int);
+STATIC void evalsubshell(union node *, int);
+STATIC void expredir(union node *);
+STATIC void evalpipe(union node *, int);
+#ifdef notyet
+STATIC void evalcommand(union node *, int, struct backcmd *);
+#else
+STATIC void evalcommand(union node *, int);
+#endif
+STATIC int evalbltin(const struct builtincmd *, int, char **, int);
+STATIC int evalfun(struct funcnode *, int, char **, int);
+STATIC void prehash(union node *);
+STATIC int eprintlist(struct output *, struct strlist *, int);
+STATIC int bltincmd(int, char **);
+
+
+STATIC const struct builtincmd bltin = {
+       name: nullstr,
+       builtin: bltincmd
+};
+
+
+/*
+ * Called to reset things after an exception.
+ */
+
+#ifdef mkinit
+INCLUDE "eval.h"
+
+RESET {
+       evalskip = 0;
+       loopnest = 0;
+}
+#endif
+
+
+
+/*
+ * The eval commmand.
+ */
+
+static int evalcmd(int argc, char **argv, int flags)
+{
+        char *p;
+        char *concat;
+        char **ap;
+
+        if (argc > 1) {
+                p = argv[1];
+                if (argc > 2) {
+                        STARTSTACKSTR(concat);
+                        ap = argv + 2;
+                        for (;;) {
+                               concat = stputs(p, concat);
+                                if ((p = *ap++) == NULL)
+                                        break;
+                                STPUTC(' ', concat);
+                        }
+                        STPUTC('\0', concat);
+                        p = grabstackstr(concat);
+                }
+                return evalstring(p, flags & EV_TESTED);
+        }
+        return 0;
+}
+
+
+/*
+ * Execute a command or commands contained in a string.
+ */
+
+int
+evalstring(char *s, int flags)
+{
+       union node *n;
+       struct stackmark smark;
+       int status;
+
+       setinputstring(s);
+       setstackmark(&smark);
+
+       status = 0;
+       while ((n = parsecmd(0)) != NEOF) {
+               evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
+               status = exitstatus;
+               popstackmark(&smark);
+               if (evalskip)
+                       break;
+       }
+       popfile();
+
+       return status;
+}
+
+
+
+/*
+ * Evaluate a parse tree.  The value is left in the global variable
+ * exitstatus.
+ */
+
+void
+evaltree(union node *n, int flags)
+{
+       int checkexit = 0;
+       void (*evalfn)(union node *, int);
+       unsigned isor;
+       int status;
+       if (n == NULL) {
+               TRACE(("evaltree(NULL) called\n"));
+               goto out;
+       }
+#ifndef SMALL
+       displayhist = 1;        /* show history substitutions done with fc */
+#endif
+       TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
+           getpid(), n, n->type, flags));
+       switch (n->type) {
+       default:
+#ifdef DEBUG
+               out1fmt("Node type = %d\n", n->type);
+#ifndef USE_GLIBC_STDIO
+               flushout(out1);
+#endif
+               break;
+#endif
+       case NNOT:
+               evaltree(n->nnot.com, EV_TESTED);
+               status = !exitstatus;
+               goto setstatus;
+       case NREDIR:
+               errlinno = lineno = n->nredir.linno;
+               if (funcline)
+                       lineno -= funcline - 1;
+               expredir(n->nredir.redirect);
+               pushredir(n->nredir.redirect);
+               status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
+               if (!status) {
+                       evaltree(n->nredir.n, flags & EV_TESTED);
+                       status = exitstatus;
+               }
+               if (n->nredir.redirect)
+                       popredir(0);
+               goto setstatus;
+       case NCMD:
+#ifdef notyet
+               if (eflag && !(flags & EV_TESTED))
+                       checkexit = ~0;
+               evalcommand(n, flags, (struct backcmd *)NULL);
+               break;
+#else
+               evalfn = evalcommand;
+checkexit:
+               if (eflag && !(flags & EV_TESTED))
+                       checkexit = ~0;
+               goto calleval;
+#endif
+       case NFOR:
+               evalfn = evalfor;
+               goto calleval;
+       case NWHILE:
+       case NUNTIL:
+               evalfn = evalloop;
+               goto calleval;
+       case NSUBSHELL:
+       case NBACKGND:
+               evalfn = evalsubshell;
+               goto checkexit;
+       case NPIPE:
+               evalfn = evalpipe;
+               goto checkexit;
+       case NCASE:
+               evalfn = evalcase;
+               goto calleval;
+       case NAND:
+       case NOR:
+       case NSEMI:
+#if NAND + 1 != NOR
+#error NAND + 1 != NOR
+#endif
+#if NOR + 1 != NSEMI
+#error NOR + 1 != NSEMI
+#endif
+               isor = n->type - NAND;
+               evaltree(
+                       n->nbinary.ch1,
+                       (flags | ((isor >> 1) - 1)) & EV_TESTED
+               );
+               if (!exitstatus == isor)
+                       break;
+               if (!evalskip) {
+                       n = n->nbinary.ch2;
+evaln:
+                       evalfn = evaltree;
+calleval:
+                       evalfn(n, flags);
+                       break;
+               }
+               break;
+       case NIF:
+               evaltree(n->nif.test, EV_TESTED);
+               if (evalskip)
+                       break;
+               if (exitstatus == 0) {
+                       n = n->nif.ifpart;
+                       goto evaln;
+               } else if (n->nif.elsepart) {
+                       n = n->nif.elsepart;
+                       goto evaln;
+               }
+               goto success;
+       case NDEFUN:
+               defun(n);
+success:
+               status = 0;
+setstatus:
+               exitstatus = status;
+               break;
+       }
+out:
+       if (checkexit & exitstatus)
+               goto exexit;
+
+       if (pendingsigs)
+               dotrap();
+
+       if (flags & EV_EXIT) {
+exexit:
+               exraise(EXEXIT);
+       }
+}
+
+
+#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
+STATIC
+#endif
+void evaltreenr(union node *n, int flags)
+#ifdef HAVE_ATTRIBUTE_ALIAS
+       __attribute__ ((alias("evaltree")));
+#else
+{
+       evaltree(n, flags);
+       abort();
+}
+#endif
+
+
+STATIC void
+evalloop(union node *n, int flags)
+{
+       int status;
+
+       loopnest++;
+       status = 0;
+       flags &= EV_TESTED;
+       for (;;) {
+               int i;
+
+               evaltree(n->nbinary.ch1, EV_TESTED);
+               if (evalskip) {
+skipping:        if (evalskip == SKIPCONT && --skipcount <= 0) {
+                               evalskip = 0;
+                               continue;
+                       }
+                       if (evalskip == SKIPBREAK && --skipcount <= 0)
+                               evalskip = 0;
+                       break;
+               }
+               i = exitstatus;
+               if (n->type != NWHILE)
+                       i = !i;
+               if (i != 0)
+                       break;
+               evaltree(n->nbinary.ch2, flags);
+               status = exitstatus;
+               if (evalskip)
+                       goto skipping;
+       }
+       loopnest--;
+       exitstatus = status;
+}
+
+
+
+STATIC void
+evalfor(union node *n, int flags)
+{
+       struct arglist arglist;
+       union node *argp;
+       struct strlist *sp;
+       struct stackmark smark;
+
+       errlinno = lineno = n->nfor.linno;
+       if (funcline)
+               lineno -= funcline - 1;
+
+       setstackmark(&smark);
+       arglist.lastp = &arglist.list;
+       for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
+               expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+               /* XXX */
+               if (evalskip)
+                       goto out;
+       }
+       *arglist.lastp = NULL;
+
+       exitstatus = 0;
+       loopnest++;
+       flags &= EV_TESTED;
+       for (sp = arglist.list ; sp ; sp = sp->next) {
+               setvar(n->nfor.var, sp->text, 0);
+               evaltree(n->nfor.body, flags);
+               if (evalskip) {
+                       if (evalskip == SKIPCONT && --skipcount <= 0) {
+                               evalskip = 0;
+                               continue;
+                       }
+                       if (evalskip == SKIPBREAK && --skipcount <= 0)
+                               evalskip = 0;
+                       break;
+               }
+       }
+       loopnest--;
+out:
+       popstackmark(&smark);
+}
+
+
+
+STATIC void
+evalcase(union node *n, int flags)
+{
+       union node *cp;
+       union node *patp;
+       struct arglist arglist;
+       struct stackmark smark;
+
+       errlinno = lineno = n->ncase.linno;
+       if (funcline)
+               lineno -= funcline - 1;
+
+       setstackmark(&smark);
+       arglist.lastp = &arglist.list;
+       expandarg(n->ncase.expr, &arglist, EXP_TILDE);
+       exitstatus = 0;
+       for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
+               for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
+                       if (casematch(patp, arglist.list->text)) {
+                               if (evalskip == 0) {
+                                       evaltree(cp->nclist.body, flags);
+                               }
+                               goto out;
+                       }
+               }
+       }
+out:
+       popstackmark(&smark);
+}
+
+
+
+/*
+ * Kick off a subshell to evaluate a tree.
+ */
+
+STATIC void
+evalsubshell(union node *n, int flags)
+{
+       struct job *jp;
+       int backgnd = (n->type == NBACKGND);
+       int status;
+
+       errlinno = lineno = n->nredir.linno;
+       if (funcline)
+               lineno -= funcline - 1;
+
+       expredir(n->nredir.redirect);
+       if (!backgnd && flags & EV_EXIT && !have_traps())
+               goto nofork;
+       INTOFF;
+       jp = makejob(n, 1);
+       if (forkshell(jp, n, backgnd) == 0) {
+               INTON;
+               flags |= EV_EXIT;
+               if (backgnd)
+                       flags &=~ EV_TESTED;
+nofork:
+               redirect(n->nredir.redirect, 0);
+               evaltreenr(n->nredir.n, flags);
+               /* never returns */
+       }
+       status = 0;
+       if (! backgnd)
+               status = waitforjob(jp);
+       exitstatus = status;
+       INTON;
+}
+
+
+
+/*
+ * Compute the names of the files in a redirection list.
+ */
+
+STATIC void
+expredir(union node *n)
+{
+       union node *redir;
+
+       for (redir = n ; redir ; redir = redir->nfile.next) {
+               struct arglist fn;
+               fn.lastp = &fn.list;
+               switch (redir->type) {
+               case NFROMTO:
+               case NFROM:
+               case NTO:
+               case NCLOBBER:
+               case NAPPEND:
+                       expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
+                       redir->nfile.expfname = fn.list->text;
+                       break;
+               case NFROMFD:
+               case NTOFD:
+                       if (redir->ndup.vname) {
+                               expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
+                               fixredir(redir, fn.list->text, 1);
+                       }
+                       break;
+               }
+       }
+}
+
+
+
+/*
+ * Evaluate a pipeline.  All the processes in the pipeline are children
+ * of the process creating the pipeline.  (This differs from some versions
+ * of the shell, which make the last process in a pipeline the parent
+ * of all the rest.)
+ */
+
+STATIC void
+evalpipe(union node *n, int flags)
+{
+       struct job *jp;
+       struct nodelist *lp;
+       int pipelen;
+       int prevfd;
+       int pip[2];
+
+       TRACE(("evalpipe(0x%lx) called\n", (long)n));
+       pipelen = 0;
+       for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
+               pipelen++;
+       flags |= EV_EXIT;
+       INTOFF;
+       jp = makejob(n, pipelen);
+       prevfd = -1;
+       for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+               prehash(lp->n);
+               pip[1] = -1;
+               if (lp->next) {
+                       if (pipe(pip) < 0) {
+                               close(prevfd);
+                               sh_error("Pipe call failed");
+                       }
+               }
+               if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
+                       INTON;
+                       if (pip[1] >= 0) {
+                               close(pip[0]);
+                       }
+                       if (prevfd > 0) {
+                               dup2(prevfd, 0);
+                               close(prevfd);
+                       }
+                       if (pip[1] > 1) {
+                               dup2(pip[1], 1);
+                               close(pip[1]);
+                       }
+                       evaltreenr(lp->n, flags);
+                       /* never returns */
+               }
+               if (prevfd >= 0)
+                       close(prevfd);
+               prevfd = pip[0];
+               close(pip[1]);
+       }
+       if (n->npipe.backgnd == 0) {
+               exitstatus = waitforjob(jp);
+               TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
+       }
+       INTON;
+}
+
+
+
+/*
+ * Execute a command inside back quotes.  If it's a builtin command, we
+ * want to save its output in a block obtained from malloc.  Otherwise
+ * we fork off a subprocess and get the output of the command via a pipe.
+ * Should be called with interrupts off.
+ */
+
+void
+evalbackcmd(union node *n, struct backcmd *result)
+{
+       int pip[2];
+       struct job *jp;
+
+       result->fd = -1;
+       result->buf = NULL;
+       result->nleft = 0;
+       result->jp = NULL;
+       if (n == NULL) {
+               goto out;
+       }
+
+       if (pipe(pip) < 0)
+               sh_error("Pipe call failed");
+       jp = makejob(n, 1);
+       if (forkshell(jp, n, FORK_NOJOB) == 0) {
+               FORCEINTON;
+               close(pip[0]);
+               if (pip[1] != 1) {
+                       dup2(pip[1], 1);
+                       close(pip[1]);
+               }
+               ifsfree();
+               evaltreenr(n, EV_EXIT);
+               /* NOTREACHED */
+       }
+       close(pip[1]);
+       result->fd = pip[0];
+       result->jp = jp;
+
+out:
+       TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
+               result->fd, result->buf, result->nleft, result->jp));
+}
+
+static char **
+parse_command_args(char **argv, const char **path)
+{
+       char *cp, c;
+
+       for (;;) {
+               cp = *++argv;
+               if (!cp)
+                       return 0;
+               if (*cp++ != '-')
+                       break;
+               if (!(c = *cp++))
+                       break;
+               if (c == '-' && !*cp) {
+                       if (!*++argv)
+                               return 0;
+                       break;
+               }
+               do {
+                       switch (c) {
+                       case 'p':
+                               *path = defpath;
+                               break;
+                       default:
+                               /* run 'typecmd' for other options */
+                               return 0;
+                       }
+               } while ((c = *cp++));
+       }
+       return argv;
+}
+
+
+
+/*
+ * Execute a simple command.
+ */
+
+STATIC void
+#ifdef notyet
+evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
+#else
+evalcommand(union node *cmd, int flags)
+#endif
+{
+       struct localvar_list *localvar_stop;
+       struct redirtab *redir_stop;
+       struct stackmark smark;
+       union node *argp;
+       struct arglist arglist;
+       struct arglist varlist;
+       char **argv;
+       int argc;
+       struct strlist *sp;
+#ifdef notyet
+       int pip[2];
+#endif
+       struct cmdentry cmdentry;
+       struct job *jp;
+       char *lastarg;
+       const char *path;
+       int spclbltin;
+       int execcmd;
+       int status;
+       char **nargv;
+
+       errlinno = lineno = cmd->ncmd.linno;
+       if (funcline)
+               lineno -= funcline - 1;
+
+       /* First expand the arguments. */
+       TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
+       setstackmark(&smark);
+       localvar_stop = pushlocalvars();
+       back_exitstatus = 0;
+
+       cmdentry.cmdtype = CMDBUILTIN;
+       cmdentry.u.cmd = &bltin;
+       varlist.lastp = &varlist.list;
+       *varlist.lastp = NULL;
+       arglist.lastp = &arglist.list;
+       *arglist.lastp = NULL;
+
+       argc = 0;
+       for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
+               struct strlist **spp;
+
+               spp = arglist.lastp;
+               expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+               for (sp = *spp; sp; sp = sp->next)
+                       argc++;
+       }
+
+       /* Reserve one extra spot at the front for shellexec. */
+       nargv = stalloc(sizeof (char *) * (argc + 2));
+       argv = ++nargv;
+       for (sp = arglist.list ; sp ; sp = sp->next) {
+               TRACE(("evalcommand arg: %s\n", sp->text));
+               *nargv++ = sp->text;
+       }
+       *nargv = NULL;
+
+       lastarg = NULL;
+       if (iflag && funcline == 0 && argc > 0)
+               lastarg = nargv[-1];
+
+       preverrout.fd = 2;
+       expredir(cmd->ncmd.redirect);
+       redir_stop = pushredir(cmd->ncmd.redirect);
+       status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
+
+       path = vpath.text;
+       for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
+               struct strlist **spp;
+               char *p;
+
+               spp = varlist.lastp;
+               expandarg(argp, &varlist, EXP_VARTILDE);
+
+               mklocal((*spp)->text);
+
+               /*
+                * Modify the command lookup path, if a PATH= assignment
+                * is present
+                */
+               p = (*spp)->text;
+               if (varequal(p, path))
+                       path = p;
+       }
+
+       /* Print the command if xflag is set. */
+       if (xflag) {
+               struct output *out;
+               int sep;
+
+               out = &preverrout;
+               outstr(expandstr(ps4val()), out);
+               sep = 0;
+               sep = eprintlist(out, varlist.list, sep);
+               eprintlist(out, arglist.list, sep);
+               outcslow('\n', out);
+#ifdef FLUSHERR
+               flushout(out);
+#endif
+       }
+
+       execcmd = 0;
+       spclbltin = -1;
+
+       /* Now locate the command. */
+       if (argc) {
+               const char *oldpath;
+               int cmd_flag = DO_ERR;
+
+               path += 5;
+               oldpath = path;
+               for (;;) {
+                       find_command(argv[0], &cmdentry, cmd_flag, path);
+                       if (cmdentry.cmdtype == CMDUNKNOWN) {
+                               status = 127;
+#ifdef FLUSHERR
+                               flushout(&errout);
+#endif
+                               goto bail;
+                       }
+
+                       /* implement bltin and command here */
+                       if (cmdentry.cmdtype != CMDBUILTIN)
+                               break;
+                       if (spclbltin < 0)
+                               spclbltin = 
+                                       cmdentry.u.cmd->flags &
+                                       BUILTIN_SPECIAL
+                               ;
+                       if (cmdentry.u.cmd == EXECCMD)
+                               execcmd++;
+                       if (cmdentry.u.cmd != COMMANDCMD)
+                               break;
+
+                       path = oldpath;
+                       nargv = parse_command_args(argv, &path);
+                       if (!nargv)
+                               break;
+                       argc -= nargv - argv;
+                       argv = nargv;
+                       cmd_flag |= DO_NOFUNC;
+               }
+       }
+
+       if (status) {
+bail:
+               exitstatus = status;
+
+               /* We have a redirection error. */
+               if (spclbltin > 0)
+                       exraise(EXERROR);
+
+               goto out;
+       }
+
+       /* Execute the command. */
+       switch (cmdentry.cmdtype) {
+       default:
+               /* Fork off a child process if necessary. */
+               if (!(flags & EV_EXIT) || have_traps()) {
+                       INTOFF;
+                       jp = makejob(cmd, 1);
+                       if (forkshell(jp, cmd, FORK_FG) != 0) {
+                               exitstatus = waitforjob(jp);
+                               INTON;
+                               break;
+                       }
+                       FORCEINTON;
+               }
+               listsetvar(varlist.list, VEXPORT|VSTACK);
+               shellexec(argv, path, cmdentry.u.index);
+               /* NOTREACHED */
+
+       case CMDBUILTIN:
+               if (spclbltin > 0 || argc == 0) {
+                       poplocalvars(1);
+                       if (execcmd && argc > 1)
+                               listsetvar(varlist.list, VEXPORT);
+               }
+               if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
+                       int status;
+                       int i;
+
+                       i = exception;
+                       if (i == EXEXIT)
+                               goto raise;
+
+                       status = (i == EXINT) ? SIGINT + 128 : 2;
+                       exitstatus = status;
+
+                       if (i == EXINT || spclbltin > 0) {
+raise:
+                               longjmp(handler->loc, 1);
+                       }
+                       FORCEINTON;
+               }
+               break;
+
+       case CMDFUNCTION:
+               poplocalvars(1);
+               if (evalfun(cmdentry.u.func, argc, argv, flags))
+                       goto raise;
+               break;
+       }
+
+out:
+       if (cmd->ncmd.redirect)
+               popredir(execcmd);
+       unwindredir(redir_stop);
+       unwindlocalvars(localvar_stop);
+       if (lastarg)
+               /* dsl: I think this is intended to be used to support
+                * '_' in 'vi' command mode during line editing...
+                * However I implemented that within libedit itself.
+                */
+               setvar("_", lastarg, 0);
+       popstackmark(&smark);
+}
+
+STATIC int
+evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
+{
+       char *volatile savecmdname;
+       struct jmploc *volatile savehandler;
+       struct jmploc jmploc;
+       int status;
+       int i;
+
+       savecmdname = commandname;
+       savehandler = handler;
+       if ((i = setjmp(jmploc.loc)))
+               goto cmddone;
+       handler = &jmploc;
+       commandname = argv[0];
+       argptr = argv + 1;
+       optptr = NULL;                  /* initialize nextopt */
+       if (cmd == EVALCMD)
+               status = evalcmd(argc, argv, flags);
+       else
+               status = (*cmd->builtin)(argc, argv);
+       flushall();
+       status |= outerr(out1);
+       exitstatus = status;
+cmddone:
+       freestdout();
+       commandname = savecmdname;
+       handler = savehandler;
+
+       return i;
+}
+
+STATIC int
+evalfun(struct funcnode *func, int argc, char **argv, int flags)
+{
+       volatile struct shparam saveparam;
+       struct jmploc *volatile savehandler;
+       struct jmploc jmploc;
+       int e;
+       int savefuncline;
+
+       saveparam = shellparam;
+       savefuncline = funcline;
+       savehandler = handler;
+       if ((e = setjmp(jmploc.loc))) {
+               goto funcdone;
+       }
+       INTOFF;
+       handler = &jmploc;
+       shellparam.malloc = 0;
+       func->count++;
+       funcline = func->n.ndefun.linno;
+       INTON;
+       shellparam.nparam = argc - 1;
+       shellparam.p = argv + 1;
+       shellparam.optind = 1;
+       shellparam.optoff = -1;
+       pushlocalvars();
+       evaltree(func->n.ndefun.body, flags & EV_TESTED);
+       poplocalvars(0);
+funcdone:
+       INTOFF;
+       funcline = savefuncline;
+       freefunc(func);
+       freeparam(&shellparam);
+       shellparam = saveparam;
+       handler = savehandler;
+       INTON;
+       evalskip &= ~SKIPFUNC;
+       return e;
+}
+
+
+/*
+ * Search for a command.  This is called before we fork so that the
+ * location of the command will be available in the parent as well as
+ * the child.  The check for "goodname" is an overly conservative
+ * check that the name will not be subject to expansion.
+ */
+
+STATIC void
+prehash(union node *n)
+{
+       struct cmdentry entry;
+
+       if (n->type == NCMD && n->ncmd.args)
+               if (goodname(n->ncmd.args->narg.text))
+                       find_command(n->ncmd.args->narg.text, &entry, 0,
+                                    pathval());
+}
+
+
+
+/*
+ * Builtin commands.  Builtin commands whose functions are closely
+ * tied to evaluation are implemented here.
+ */
+
+/*
+ * No command given.
+ */
+
+STATIC int
+bltincmd(int argc, char **argv)
+{
+       /*
+        * Preserve exitstatus of a previous possible redirection
+        * as POSIX mandates
+        */
+       return back_exitstatus;
+}
+
+
+/*
+ * Handle break and continue commands.  Break, continue, and return are
+ * all handled by setting the evalskip flag.  The evaluation routines
+ * above all check this flag, and if it is set they start skipping
+ * commands rather than executing them.  The variable skipcount is
+ * the number of loops to break/continue, or the number of function
+ * levels to return.  (The latter is always 1.)  It should probably
+ * be an error to break out of more loops than exist, but it isn't
+ * in the standard shell so we don't make it one here.
+ */
+
+int
+breakcmd(int argc, char **argv)
+{
+       int n = argc > 1 ? number(argv[1]) : 1;
+
+       if (n <= 0)
+               badnum(argv[1]);
+       if (n > loopnest)
+               n = loopnest;
+       if (n > 0) {
+               evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
+               skipcount = n;
+       }
+       return 0;
+}
+
+
+/*
+ * The return command.
+ */
+
+int
+returncmd(int argc, char **argv)
+{
+       /*
+        * If called outside a function, do what ksh does;
+        * skip the rest of the file.
+        */
+       evalskip = funcline ? SKIPFUNC : SKIPFILE;
+       return argv[1] ? number(argv[1]) : exitstatus;
+}
+
+
+int
+falsecmd(int argc, char **argv)
+{
+       return 1;
+}
+
+
+int
+truecmd(int argc, char **argv)
+{
+       return 0;
+}
+
+
+int
+execcmd(int argc, char **argv)
+{
+       if (argc > 1) {
+               iflag = 0;              /* exit on error */
+               mflag = 0;
+               optschanged();
+               shellexec(argv + 1, pathval(), 0);
+       }
+       return 0;
+}
+
+
+STATIC int
+eprintlist(struct output *out, struct strlist *sp, int sep)
+{
+       while (sp) {
+               const char *p;
+
+               p = " %s" + (1 - sep);
+               sep |= 1;
+               outfmt(out, p, sp->text);
+               sp = sp->next;
+       }
+
+       return sep;
+}
diff --git a/src/eval.h b/src/eval.h
new file mode 100644 (file)
index 0000000..4e4de30
--- /dev/null
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)eval.h      8.2 (Berkeley) 5/4/95
+ */
+
+extern char *commandname;      /* currently executing command */
+extern int exitstatus;         /* exit status of last command */
+extern int back_exitstatus;    /* exit status of backquoted command */
+
+
+struct backcmd {               /* result of evalbackcmd */
+       int fd;                 /* file descriptor to read from */
+       char *buf;              /* buffer */
+       int nleft;              /* number of chars in buffer */
+       struct job *jp;         /* job structure for command */
+};
+
+/* flags in argument to evaltree */
+#define EV_EXIT 01             /* exit after evaluating tree */
+#define EV_TESTED 02           /* exit status is checked; ignore -e flag */
+
+int evalstring(char *, int);
+union node;    /* BLETCH for ansi C */
+void evaltree(union node *, int);
+void evalbackcmd(union node *, struct backcmd *);
+
+extern int evalskip;
+
+/* reasons for skipping commands (see comment on breakcmd routine) */
+#define SKIPBREAK      (1 << 0)
+#define SKIPCONT       (1 << 1)
+#define SKIPFUNC       (1 << 2)
+#define SKIPFILE       (1 << 3)
diff --git a/src/exec.c b/src/exec.c
new file mode 100644 (file)
index 0000000..79e2007
--- /dev/null
@@ -0,0 +1,859 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+/*
+ * When commands are first encountered, they are entered in a hash table.
+ * This ensures that a full path search will not have to be done for them
+ * on each invocation.
+ *
+ * We should investigate converting to a linear search, even though that
+ * would make the command name "hash" a misnomer.
+ */
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h"
+#include "parser.h"
+#include "redir.h"
+#include "eval.h"
+#include "exec.h"
+#include "builtins.h"
+#include "var.h"
+#include "options.h"
+#include "output.h"
+#include "syntax.h"
+#include "memalloc.h"
+#include "error.h"
+#include "init.h"
+#include "mystring.h"
+#include "show.h"
+#include "jobs.h"
+#include "alias.h"
+#include "system.h"
+
+
+#define CMDTABLESIZE 31                /* should be prime */
+#define ARB 1                  /* actual size determined at run time */
+
+
+
+struct tblentry {
+       struct tblentry *next;  /* next entry in hash chain */
+       union param param;      /* definition of builtin function */
+       short cmdtype;          /* index identifying command */
+       char rehash;            /* if set, cd done since entry created */
+       char cmdname[ARB];      /* name of command */
+};
+
+
+STATIC struct tblentry *cmdtable[CMDTABLESIZE];
+STATIC int builtinloc = -1;            /* index in path of %builtin, or -1 */
+
+
+STATIC void tryexec(char *, char **, char **);
+STATIC void printentry(struct tblentry *);
+STATIC void clearcmdentry(int);
+STATIC struct tblentry *cmdlookup(const char *, int);
+STATIC void delete_cmd_entry(void);
+STATIC void addcmdentry(char *, struct cmdentry *);
+STATIC int describe_command(struct output *, char *, int);
+
+
+/*
+ * Exec a program.  Never returns.  If you change this routine, you may
+ * have to change the find_command routine as well.
+ */
+
+void
+shellexec(char **argv, const char *path, int idx)
+{
+       char *cmdname;
+       int e;
+       char **envp;
+       int exerrno;
+
+       envp = environment();
+       if (strchr(argv[0], '/') != NULL) {
+               tryexec(argv[0], argv, envp);
+               e = errno;
+       } else {
+               e = ENOENT;
+               while ((cmdname = padvance(&path, argv[0])) != NULL) {
+                       if (--idx < 0 && pathopt == NULL) {
+                               tryexec(cmdname, argv, envp);
+                               if (errno != ENOENT && errno != ENOTDIR)
+                                       e = errno;
+                       }
+                       stunalloc(cmdname);
+               }
+       }
+
+       /* Map to POSIX errors */
+       switch (e) {
+       case EACCES:
+               exerrno = 126;
+               break;
+       case ENOENT:
+               exerrno = 127;
+               break;
+       default:
+               exerrno = 2;
+               break;
+       }
+       exitstatus = exerrno;
+       TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
+               argv[0], e, suppressint ));
+       exerror(EXEXIT, "%s: %s", argv[0], errmsg(e, E_EXEC));
+       /* NOTREACHED */
+}
+
+
+STATIC void
+tryexec(char *cmd, char **argv, char **envp)
+{
+       char *const path_bshell = _PATH_BSHELL;
+
+repeat:
+#ifdef SYSV
+       do {
+               execve(cmd, argv, envp);
+       } while (errno == EINTR);
+#else
+       execve(cmd, argv, envp);
+#endif
+       if (cmd != path_bshell && errno == ENOEXEC) {
+               *argv-- = cmd;
+               *argv = cmd = path_bshell;
+               goto repeat;
+       }
+}
+
+
+
+/*
+ * Do a path search.  The variable path (passed by reference) should be
+ * set to the start of the path before the first call; padvance will update
+ * this value as it proceeds.  Successive calls to padvance will return
+ * the possible path expansions in sequence.  If an option (indicated by
+ * a percent sign) appears in the path entry then the global variable
+ * pathopt will be set to point to it; otherwise pathopt will be set to
+ * NULL.
+ */
+
+const char *pathopt;
+
+char *
+padvance(const char **path, const char *name)
+{
+       const char *p;
+       char *q;
+       const char *start;
+       size_t len;
+
+       if (*path == NULL)
+               return NULL;
+       start = *path;
+       for (p = start ; *p && *p != ':' && *p != '%' ; p++);
+       len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
+       while (stackblocksize() < len)
+               growstackblock();
+       q = stackblock();
+       if (p != start) {
+               memcpy(q, start, p - start);
+               q += p - start;
+               *q++ = '/';
+       }
+       strcpy(q, name);
+       pathopt = NULL;
+       if (*p == '%') {
+               pathopt = ++p;
+               while (*p && *p != ':')  p++;
+       }
+       if (*p == ':')
+               *path = p + 1;
+       else
+               *path = NULL;
+       return stalloc(len);
+}
+
+
+
+/*** Command hashing code ***/
+
+
+int
+hashcmd(int argc, char **argv)
+{
+       struct tblentry **pp;
+       struct tblentry *cmdp;
+       int c;
+       struct cmdentry entry;
+       char *name;
+
+       while ((c = nextopt("r")) != '\0') {
+               clearcmdentry(0);
+               return 0;
+       }
+       if (*argptr == NULL) {
+               for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
+                       for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+                               if (cmdp->cmdtype == CMDNORMAL)
+                                       printentry(cmdp);
+                       }
+               }
+               return 0;
+       }
+       c = 0;
+       while ((name = *argptr) != NULL) {
+               if ((cmdp = cmdlookup(name, 0)) != NULL
+                && (cmdp->cmdtype == CMDNORMAL
+                    || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
+                       delete_cmd_entry();
+               find_command(name, &entry, DO_ERR, pathval());
+               if (entry.cmdtype == CMDUNKNOWN)
+                       c = 1;
+               argptr++;
+       }
+       return c;
+}
+
+
+STATIC void
+printentry(struct tblentry *cmdp)
+{
+       int idx;
+       const char *path;
+       char *name;
+
+       idx = cmdp->param.index;
+       path = pathval();
+       do {
+               name = padvance(&path, cmdp->cmdname);
+               stunalloc(name);
+       } while (--idx >= 0);
+       out1str(name);
+       out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
+}
+
+
+
+/*
+ * Resolve a command name.  If you change this routine, you may have to
+ * change the shellexec routine as well.
+ */
+
+void
+find_command(char *name, struct cmdentry *entry, int act, const char *path)
+{
+       struct tblentry *cmdp;
+       int idx;
+       int prev;
+       char *fullname;
+       struct stat64 statb;
+       int e;
+       int updatetbl;
+       struct builtincmd *bcmd;
+
+       /* If name contains a slash, don't use PATH or hash table */
+       if (strchr(name, '/') != NULL) {
+               entry->u.index = -1;
+               if (act & DO_ABS) {
+                       while (stat64(name, &statb) < 0) {
+#ifdef SYSV
+                               if (errno == EINTR)
+                                       continue;
+#endif
+                               entry->cmdtype = CMDUNKNOWN;
+                               return;
+                       }
+               }
+               entry->cmdtype = CMDNORMAL;
+               return;
+       }
+
+       updatetbl = (path == pathval());
+       if (!updatetbl) {
+               act |= DO_ALTPATH;
+               if (strstr(path, "%builtin") != NULL)
+                       act |= DO_ALTBLTIN;
+       }
+
+       /* If name is in the table, check answer will be ok */
+       if ((cmdp = cmdlookup(name, 0)) != NULL) {
+               int bit;
+
+               switch (cmdp->cmdtype) {
+               default:
+#if DEBUG
+                       abort();
+#endif
+               case CMDNORMAL:
+                       bit = DO_ALTPATH;
+                       break;
+               case CMDFUNCTION:
+                       bit = DO_NOFUNC;
+                       break;
+               case CMDBUILTIN:
+                       bit = DO_ALTBLTIN;
+                       break;
+               }
+               if (act & bit) {
+                       updatetbl = 0;
+                       cmdp = NULL;
+               } else if (cmdp->rehash == 0)
+                       /* if not invalidated by cd, we're done */
+                       goto success;
+       }
+
+       /* If %builtin not in path, check for builtin next */
+       bcmd = find_builtin(name);
+       if (bcmd && (bcmd->flags & BUILTIN_REGULAR || (
+               act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
+       )))
+               goto builtin_success;
+
+       /* We have to search path. */
+       prev = -1;              /* where to start */
+       if (cmdp && cmdp->rehash) {     /* doing a rehash */
+               if (cmdp->cmdtype == CMDBUILTIN)
+                       prev = builtinloc;
+               else
+                       prev = cmdp->param.index;
+       }
+
+       e = ENOENT;
+       idx = -1;
+loop:
+       while ((fullname = padvance(&path, name)) != NULL) {
+               stunalloc(fullname);
+               idx++;
+               if (pathopt) {
+                       if (prefix(pathopt, "builtin")) {
+                               if (bcmd)
+                                       goto builtin_success;
+                               continue;
+                       } else if (!(act & DO_NOFUNC) &&
+                                  prefix(pathopt, "func")) {
+                               /* handled below */
+                       } else {
+                               /* ignore unimplemented options */
+                               continue;
+                       }
+               }
+               /* if rehash, don't redo absolute path names */
+               if (fullname[0] == '/' && idx <= prev) {
+                       if (idx < prev)
+                               continue;
+                       TRACE(("searchexec \"%s\": no change\n", name));
+                       goto success;
+               }
+               while (stat64(fullname, &statb) < 0) {
+#ifdef SYSV
+                       if (errno == EINTR)
+                               continue;
+#endif
+                       if (errno != ENOENT && errno != ENOTDIR)
+                               e = errno;
+                       goto loop;
+               }
+               e = EACCES;     /* if we fail, this will be the error */
+               if (!S_ISREG(statb.st_mode))
+                       continue;
+               if (pathopt) {          /* this is a %func directory */
+                       stalloc(strlen(fullname) + 1);
+                       readcmdfile(fullname);
+                       if ((cmdp = cmdlookup(name, 0)) == NULL ||
+                           cmdp->cmdtype != CMDFUNCTION)
+                               sh_error("%s not defined in %s", name,
+                                        fullname);
+                       stunalloc(fullname);
+                       goto success;
+               }
+#ifdef notdef
+               /* XXX this code stops root executing stuff, and is buggy
+                  if you need a group from the group list. */
+               if (statb.st_uid == geteuid()) {
+                       if ((statb.st_mode & 0100) == 0)
+                               goto loop;
+               } else if (statb.st_gid == getegid()) {
+                       if ((statb.st_mode & 010) == 0)
+                               goto loop;
+               } else {
+                       if ((statb.st_mode & 01) == 0)
+                               goto loop;
+               }
+#endif
+               TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
+               if (!updatetbl) {
+                       entry->cmdtype = CMDNORMAL;
+                       entry->u.index = idx;
+                       return;
+               }
+               INTOFF;
+               cmdp = cmdlookup(name, 1);
+               cmdp->cmdtype = CMDNORMAL;
+               cmdp->param.index = idx;
+               INTON;
+               goto success;
+       }
+
+       /* We failed.  If there was an entry for this command, delete it */
+       if (cmdp && updatetbl)
+               delete_cmd_entry();
+       if (act & DO_ERR)
+               sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
+       entry->cmdtype = CMDUNKNOWN;
+       return;
+
+builtin_success:
+       if (!updatetbl) {
+               entry->cmdtype = CMDBUILTIN;
+               entry->u.cmd = bcmd;
+               return;
+       }
+       INTOFF;
+       cmdp = cmdlookup(name, 1);
+       cmdp->cmdtype = CMDBUILTIN;
+       cmdp->param.cmd = bcmd;
+       INTON;
+success:
+       cmdp->rehash = 0;
+       entry->cmdtype = cmdp->cmdtype;
+       entry->u = cmdp->param;
+}
+
+
+
+/*
+ * Search the table of builtin commands.
+ */
+
+struct builtincmd *
+find_builtin(const char *name)
+{
+       struct builtincmd *bp;
+
+       bp = bsearch(
+               &name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
+               pstrcmp
+       );
+       return bp;
+}
+
+
+
+/*
+ * Called when a cd is done.  Marks all commands so the next time they
+ * are executed they will be rehashed.
+ */
+
+void
+hashcd(void)
+{
+       struct tblentry **pp;
+       struct tblentry *cmdp;
+
+       for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
+               for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+                       if (cmdp->cmdtype == CMDNORMAL || (
+                               cmdp->cmdtype == CMDBUILTIN &&
+                               !(cmdp->param.cmd->flags & BUILTIN_REGULAR) &&
+                               builtinloc > 0
+                       ))
+                               cmdp->rehash = 1;
+               }
+       }
+}
+
+
+
+/*
+ * Fix command hash table when PATH changed.
+ * Called before PATH is changed.  The argument is the new value of PATH;
+ * pathval() still returns the old value at this point.
+ * Called with interrupts off.
+ */
+
+void
+changepath(const char *newval)
+{
+       const char *old, *new;
+       int idx;
+       int firstchange;
+       int bltin;
+
+       old = pathval();
+       new = newval;
+       firstchange = 9999;     /* assume no change */
+       idx = 0;
+       bltin = -1;
+       for (;;) {
+               if (*old != *new) {
+                       firstchange = idx;
+                       if ((*old == '\0' && *new == ':')
+                        || (*old == ':' && *new == '\0'))
+                               firstchange++;
+                       old = new;      /* ignore subsequent differences */
+               }
+               if (*new == '\0')
+                       break;
+               if (*new == '%' && bltin < 0 && prefix(new + 1, "builtin"))
+                       bltin = idx;
+               if (*new == ':') {
+                       idx++;
+               }
+               new++, old++;
+       }
+       if (builtinloc < 0 && bltin >= 0)
+               builtinloc = bltin;             /* zap builtins */
+       if (builtinloc >= 0 && bltin < 0)
+               firstchange = 0;
+       clearcmdentry(firstchange);
+       builtinloc = bltin;
+}
+
+
+/*
+ * Clear out command entries.  The argument specifies the first entry in
+ * PATH which has changed.
+ */
+
+STATIC void
+clearcmdentry(int firstchange)
+{
+       struct tblentry **tblp;
+       struct tblentry **pp;
+       struct tblentry *cmdp;
+
+       INTOFF;
+       for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
+               pp = tblp;
+               while ((cmdp = *pp) != NULL) {
+                       if ((cmdp->cmdtype == CMDNORMAL &&
+                            cmdp->param.index >= firstchange)
+                        || (cmdp->cmdtype == CMDBUILTIN &&
+                            builtinloc >= firstchange)) {
+                               *pp = cmdp->next;
+                               ckfree(cmdp);
+                       } else {
+                               pp = &cmdp->next;
+                       }
+               }
+       }
+       INTON;
+}
+
+
+
+/*
+ * Locate a command in the command hash table.  If "add" is nonzero,
+ * add the command to the table if it is not already present.  The
+ * variable "lastcmdentry" is set to point to the address of the link
+ * pointing to the entry, so that delete_cmd_entry can delete the
+ * entry.
+ *
+ * Interrupts must be off if called with add != 0.
+ */
+
+struct tblentry **lastcmdentry;
+
+
+STATIC struct tblentry *
+cmdlookup(const char *name, int add)
+{
+       unsigned int hashval;
+       const char *p;
+       struct tblentry *cmdp;
+       struct tblentry **pp;
+
+       p = name;
+       hashval = (unsigned char)*p << 4;
+       while (*p)
+               hashval += (unsigned char)*p++;
+       hashval &= 0x7FFF;
+       pp = &cmdtable[hashval % CMDTABLESIZE];
+       for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+               if (equal(cmdp->cmdname, name))
+                       break;
+               pp = &cmdp->next;
+       }
+       if (add && cmdp == NULL) {
+               cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
+                                       + strlen(name) + 1);
+               cmdp->next = NULL;
+               cmdp->cmdtype = CMDUNKNOWN;
+               strcpy(cmdp->cmdname, name);
+       }
+       lastcmdentry = pp;
+       return cmdp;
+}
+
+/*
+ * Delete the command entry returned on the last lookup.
+ */
+
+STATIC void
+delete_cmd_entry(void)
+{
+       struct tblentry *cmdp;
+
+       INTOFF;
+       cmdp = *lastcmdentry;
+       *lastcmdentry = cmdp->next;
+       if (cmdp->cmdtype == CMDFUNCTION)
+               freefunc(cmdp->param.func);
+       ckfree(cmdp);
+       INTON;
+}
+
+
+
+#ifdef notdef
+void
+getcmdentry(char *name, struct cmdentry *entry)
+{
+       struct tblentry *cmdp = cmdlookup(name, 0);
+
+       if (cmdp) {
+               entry->u = cmdp->param;
+               entry->cmdtype = cmdp->cmdtype;
+       } else {
+               entry->cmdtype = CMDUNKNOWN;
+               entry->u.index = 0;
+       }
+}
+#endif
+
+
+/*
+ * Add a new command entry, replacing any existing command entry for
+ * the same name - except special builtins.
+ */
+
+STATIC void
+addcmdentry(char *name, struct cmdentry *entry)
+{
+       struct tblentry *cmdp;
+
+       cmdp = cmdlookup(name, 1);
+       if (cmdp->cmdtype == CMDFUNCTION) {
+               freefunc(cmdp->param.func);
+       }
+       cmdp->cmdtype = entry->cmdtype;
+       cmdp->param = entry->u;
+       cmdp->rehash = 0;
+}
+
+
+/*
+ * Define a shell function.
+ */
+
+void
+defun(union node *func)
+{
+       struct cmdentry entry;
+
+       INTOFF;
+       entry.cmdtype = CMDFUNCTION;
+       entry.u.func = copyfunc(func);
+       addcmdentry(func->ndefun.text, &entry);
+       INTON;
+}
+
+
+/*
+ * Delete a function if it exists.
+ */
+
+void
+unsetfunc(const char *name)
+{
+       struct tblentry *cmdp;
+
+       if ((cmdp = cmdlookup(name, 0)) != NULL &&
+           cmdp->cmdtype == CMDFUNCTION)
+               delete_cmd_entry();
+}
+
+/*
+ * Locate and print what a word is...
+ */
+
+int
+typecmd(int argc, char **argv)
+{
+       int i;
+       int err = 0;
+
+       for (i = 1; i < argc; i++) {
+               err |= describe_command(out1, argv[i], 1);
+       }
+       return err;
+}
+
+STATIC int
+describe_command(out, command, verbose)
+       struct output *out;
+       char *command;
+       int verbose;
+{
+       struct cmdentry entry;
+       struct tblentry *cmdp;
+       const struct alias *ap;
+       const char *path = pathval();
+
+       if (verbose) {
+               outstr(command, out);
+       }
+
+       /* First look at the keywords */
+       if (findkwd(command)) {
+               outstr(verbose ? " is a shell keyword" : command, out);
+               goto out;
+       }
+
+       /* Then look at the aliases */
+       if ((ap = lookupalias(command, 0)) != NULL) {
+               if (verbose) {
+                       outfmt(out, " is an alias for %s", ap->val);
+               } else {
+                       outstr("alias ", out);
+                       printalias(ap);
+                       return 0;
+               }
+               goto out;
+       }
+
+       /* Then check if it is a tracked alias */
+       if ((cmdp = cmdlookup(command, 0)) != NULL) {
+               entry.cmdtype = cmdp->cmdtype;
+               entry.u = cmdp->param;
+       } else {
+               /* Finally use brute force */
+               find_command(command, &entry, DO_ABS, path);
+       }
+
+       switch (entry.cmdtype) {
+       case CMDNORMAL: {
+               int j = entry.u.index;
+               char *p;
+               if (j == -1) {
+                       p = command;
+               } else {
+                       do {
+                               p = padvance(&path, command);
+                               stunalloc(p);
+                       } while (--j >= 0);
+               }
+               if (verbose) {
+                       outfmt(
+                               out, " is%s %s",
+                               cmdp ? " a tracked alias for" : nullstr, p
+                       );
+               } else {
+                       outstr(p, out);
+               }
+               break;
+       }
+
+       case CMDFUNCTION:
+               if (verbose) {
+                       outstr(" is a shell function", out);
+               } else {
+                       outstr(command, out);
+               }
+               break;
+
+       case CMDBUILTIN:
+               if (verbose) {
+                       outfmt(
+                               out, " is a %sshell builtin",
+                               entry.u.cmd->flags & BUILTIN_SPECIAL ?
+                                       "special " : nullstr
+                       );
+               } else {
+                       outstr(command, out);
+               }
+               break;
+
+       default:
+               if (verbose) {
+                       outstr(": not found\n", out);
+               }
+               return 127;
+       }
+
+out:
+       outc('\n', out);
+       return 0;
+}
+
+int
+commandcmd(argc, argv)
+       int argc;
+       char **argv;
+{
+       char *cmd;
+       int c;
+       enum {
+               VERIFY_BRIEF = 1,
+               VERIFY_VERBOSE = 2,
+       } verify = 0;
+
+       while ((c = nextopt("pvV")) != '\0')
+               if (c == 'V')
+                       verify |= VERIFY_VERBOSE;
+               else if (c == 'v')
+                       verify |= VERIFY_BRIEF;
+#ifdef DEBUG
+               else if (c != 'p')
+                       abort();
+#endif
+
+       cmd = *argptr;
+       if (verify && cmd)
+               return describe_command(out1, cmd, verify - VERIFY_BRIEF);
+
+       return 0;
+}
diff --git a/src/exec.h b/src/exec.h
new file mode 100644 (file)
index 0000000..9ccb305
--- /dev/null
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)exec.h      8.3 (Berkeley) 6/8/95
+ */
+
+/* values of cmdtype */
+#define CMDUNKNOWN     -1      /* no entry in table for command */
+#define CMDNORMAL      0       /* command is an executable program */
+#define CMDFUNCTION    1       /* command is a shell function */
+#define CMDBUILTIN     2       /* command is a shell builtin */
+
+
+struct cmdentry {
+       int cmdtype;
+       union param {
+               int index;
+               const struct builtincmd *cmd;
+               struct funcnode *func;
+       } u;
+};
+
+
+/* action to find_command() */
+#define DO_ERR         0x01    /* prints errors */
+#define DO_ABS         0x02    /* checks absolute paths */
+#define DO_NOFUNC      0x04    /* don't return shell functions, for command */
+#define DO_ALTPATH     0x08    /* using alternate path */
+#define DO_ALTBLTIN    0x20    /* %builtin in alt. path */
+
+extern const char *pathopt;    /* set by padvance */
+
+void shellexec(char **, const char *, int)
+    __attribute__((__noreturn__));
+char *padvance(const char **, const char *);
+int hashcmd(int, char **);
+void find_command(char *, struct cmdentry *, int, const char *);
+struct builtincmd *find_builtin(const char *);
+void hashcd(void);
+void changepath(const char *);
+#ifdef notdef
+void getcmdentry(char *, struct cmdentry *);
+#endif
+void defun(union node *);
+void unsetfunc(const char *);
+int typecmd(int, char **);
+int commandcmd(int, char **);
diff --git a/src/expand.c b/src/expand.c
new file mode 100644 (file)
index 0000000..ce60fe9
--- /dev/null
@@ -0,0 +1,1728 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#ifdef HAVE_GETPWNAM
+#include <pwd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <string.h>
+#include <fnmatch.h>
+#ifdef HAVE_GLOB
+#include <glob.h>
+#endif
+#include <ctype.h>
+
+/*
+ * Routines to expand arguments to commands.  We have to deal with
+ * backquotes, shell variables, and file metacharacters.
+ */
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h"
+#include "eval.h"
+#include "expand.h"
+#include "syntax.h"
+#include "parser.h"
+#include "jobs.h"
+#include "options.h"
+#include "var.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "show.h"
+#include "system.h"
+
+/*
+ * _rmescape() flags
+ */
+#define RMESCAPE_ALLOC 0x1     /* Allocate a new string */
+#define RMESCAPE_GLOB  0x2     /* Add backslashes for glob */
+#define RMESCAPE_GROW  0x8     /* Grow strings instead of stalloc */
+#define RMESCAPE_HEAP  0x10    /* Malloc strings instead of stalloc */
+
+/* Add CTLESC when necessary. */
+#define QUOTES_ESC     (EXP_FULL | EXP_CASE | EXP_QPAT)
+/* Do not skip NUL characters. */
+#define QUOTES_KEEPNUL EXP_TILDE
+
+/*
+ * Structure specifying which parts of the string should be searched
+ * for IFS characters.
+ */
+
+struct ifsregion {
+       struct ifsregion *next; /* next region in list */
+       int begoff;             /* offset of start of region */
+       int endoff;             /* offset of end of region */
+       int nulonly;            /* search for nul bytes only */
+};
+
+/* output of current string */
+static char *expdest;
+/* list of back quote expressions */
+static struct nodelist *argbackq;
+/* first struct in list of ifs regions */
+static struct ifsregion ifsfirst;
+/* last struct in list */
+static struct ifsregion *ifslastp;
+/* holds expanded arg list */
+static struct arglist exparg;
+
+STATIC void argstr(char *, int);
+STATIC char *exptilde(char *, char *, int);
+STATIC void expbackq(union node *, int);
+STATIC const char *subevalvar(char *, char *, int, int, int, int, int);
+STATIC char *evalvar(char *, int);
+STATIC size_t strtodest(const char *, const char *, int);
+STATIC void memtodest(const char *, size_t, const char *, int);
+STATIC ssize_t varvalue(char *, int, int);
+STATIC void expandmeta(struct strlist *, int);
+#ifdef HAVE_GLOB
+STATIC void addglob(const glob_t *);
+#else
+STATIC void expmeta(char *, char *);
+STATIC struct strlist *expsort(struct strlist *);
+STATIC struct strlist *msort(struct strlist *, int);
+#endif
+STATIC void addfname(char *);
+STATIC int patmatch(char *, const char *);
+#ifndef HAVE_FNMATCH
+STATIC int pmatch(const char *, const char *);
+#else
+#define pmatch(a, b) !fnmatch((a), (b), 0)
+#endif
+STATIC int cvtnum(intmax_t);
+STATIC size_t esclen(const char *, const char *);
+STATIC char *scanleft(char *, char *, char *, char *, int, int);
+STATIC char *scanright(char *, char *, char *, char *, int, int);
+STATIC void varunset(const char *, const char *, const char *, int)
+       __attribute__((__noreturn__));
+
+
+/*
+ * Prepare a pattern for a glob(3) call.
+ *
+ * Returns an stalloced string.
+ */
+
+STATIC inline char *
+preglob(const char *pattern, int flag) {
+       flag |= RMESCAPE_GLOB;
+       return _rmescapes((char *)pattern, flag);
+}
+
+
+STATIC size_t
+esclen(const char *start, const char *p) {
+       size_t esc = 0;
+
+       while (p > start && *--p == (char)CTLESC) {
+               esc++;
+       }
+       return esc;
+}
+
+
+static inline const char *getpwhome(const char *name)
+{
+#ifdef HAVE_GETPWNAM
+       struct passwd *pw = getpwnam(name);
+       return pw ? pw->pw_dir : 0;
+#else
+       return 0;
+#endif
+}
+
+
+/*
+ * Perform variable substitution and command substitution on an argument,
+ * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
+ * perform splitting and file name expansion.  When arglist is NULL, perform
+ * here document expansion.
+ */
+
+void
+expandarg(union node *arg, struct arglist *arglist, int flag)
+{
+       struct strlist *sp;
+       char *p;
+
+       argbackq = arg->narg.backquote;
+       STARTSTACKSTR(expdest);
+       argstr(arg->narg.text, flag);
+       p = _STPUTC('\0', expdest);
+       expdest = p - 1;
+       if (arglist == NULL) {
+               /* here document expanded */
+               goto out;
+       }
+       p = grabstackstr(p);
+       exparg.lastp = &exparg.list;
+       /*
+        * TODO - EXP_REDIR
+        */
+       if (flag & EXP_FULL) {
+               ifsbreakup(p, &exparg);
+               *exparg.lastp = NULL;
+               exparg.lastp = &exparg.list;
+               expandmeta(exparg.list, flag);
+       } else {
+               sp = (struct strlist *)stalloc(sizeof (struct strlist));
+               sp->text = p;
+               *exparg.lastp = sp;
+               exparg.lastp = &sp->next;
+       }
+       *exparg.lastp = NULL;
+       if (exparg.list) {
+               *arglist->lastp = exparg.list;
+               arglist->lastp = exparg.lastp;
+       }
+
+out:
+       ifsfree();
+}
+
+
+
+/*
+ * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
+ * characters to allow for further processing.  Otherwise treat
+ * $@ like $* since no splitting will be performed.
+ */
+
+STATIC void
+argstr(char *p, int flag)
+{
+       static const char spclchars[] = {
+               '=',
+               ':',
+               CTLQUOTEMARK,
+               CTLENDVAR,
+               CTLESC,
+               CTLVAR,
+               CTLBACKQ,
+               CTLENDARI,
+               0
+       };
+       const char *reject = spclchars;
+       int c;
+       int breakall = (flag & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
+       int inquotes;
+       size_t length;
+       int startloc;
+
+       if (!(flag & EXP_VARTILDE)) {
+               reject += 2;
+       } else if (flag & EXP_VARTILDE2) {
+               reject++;
+       }
+       inquotes = 0;
+       length = 0;
+       if (flag & EXP_TILDE) {
+               char *q;
+
+               flag &= ~EXP_TILDE;
+tilde:
+               q = p;
+               if (*q == '~')
+                       p = exptilde(p, q, flag);
+       }
+start:
+       startloc = expdest - (char *)stackblock();
+       for (;;) {
+               length += strcspn(p + length, reject);
+               c = (signed char)p[length];
+               if (c && (!(c & 0x80) || c == CTLENDARI)) {
+                       /* c == '=' || c == ':' || c == CTLENDARI */
+                       length++;
+               }
+               if (length > 0) {
+                       int newloc;
+                       expdest = stnputs(p, length, expdest);
+                       newloc = expdest - (char *)stackblock();
+                       if (breakall && !inquotes && newloc > startloc) {
+                               recordregion(startloc, newloc, 0);
+                       }
+                       startloc = newloc;
+               }
+               p += length + 1;
+               length = 0;
+
+               switch (c) {
+               case '\0':
+                       goto breakloop;
+               case '=':
+                       if (flag & EXP_VARTILDE2) {
+                               p--;
+                               continue;
+                       }
+                       flag |= EXP_VARTILDE2;
+                       reject++;
+                       /* fall through */
+               case ':':
+                       /*
+                        * sort of a hack - expand tildes in variable
+                        * assignments (after the first '=' and after ':'s).
+                        */
+                       if (*--p == '~') {
+                               goto tilde;
+                       }
+                       continue;
+               }
+
+               switch (c) {
+               case CTLENDVAR: /* ??? */
+                       goto breakloop;
+               case CTLQUOTEMARK:
+                       inquotes ^= EXP_QUOTED;
+                       /* "$@" syntax adherence hack */
+                       if (inquotes && !memcmp(p, dolatstr + 1,
+                                               DOLATSTRLEN - 1)) {
+                               p = evalvar(p + 1, flag | inquotes) + 1;
+                               goto start;
+                       }
+addquote:
+                       if (flag & QUOTES_ESC) {
+                               p--;
+                               length++;
+                               startloc++;
+                       }
+                       break;
+               case CTLESC:
+                       startloc++;
+                       length++;
+
+                       /*
+                        * Quoted parameter expansion pattern: remove quote
+                        * unless inside inner quotes or we have a literal
+                        * backslash.
+                        */
+                       if (((flag | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
+                           EXP_QPAT && *p != '\\')
+                               break;
+
+                       goto addquote;
+               case CTLVAR:
+                       p = evalvar(p, flag | inquotes);
+                       goto start;
+               case CTLBACKQ:
+                       expbackq(argbackq->n, flag | inquotes);
+                       argbackq = argbackq->next;
+                       goto start;
+               case CTLENDARI:
+                       p--;
+                       expari(flag | inquotes);
+                       goto start;
+               }
+       }
+breakloop:
+       ;
+}
+
+STATIC char *
+exptilde(char *startp, char *p, int flag)
+{
+       signed char c;
+       char *name;
+       const char *home;
+       int quotes = flag & QUOTES_ESC;
+
+       name = p + 1;
+
+       while ((c = *++p) != '\0') {
+               switch(c) {
+               case CTLESC:
+                       return (startp);
+               case CTLQUOTEMARK:
+                       return (startp);
+               case ':':
+                       if (flag & EXP_VARTILDE)
+                               goto done;
+                       break;
+               case '/':
+               case CTLENDVAR:
+                       goto done;
+               }
+       }
+done:
+       *p = '\0';
+       if (*name == '\0') {
+               home = lookupvar(homestr);
+       } else {
+               home = getpwhome(name);
+       }
+       if (!home || !*home)
+               goto lose;
+       *p = c;
+       strtodest(home, SQSYNTAX, quotes);
+       return (p);
+lose:
+       *p = c;
+       return (startp);
+}
+
+
+void 
+removerecordregions(int endoff)
+{
+       if (ifslastp == NULL)
+               return;
+
+       if (ifsfirst.endoff > endoff) {
+               while (ifsfirst.next != NULL) {
+                       struct ifsregion *ifsp;
+                       INTOFF;
+                       ifsp = ifsfirst.next->next;
+                       ckfree(ifsfirst.next);
+                       ifsfirst.next = ifsp;
+                       INTON;
+               }
+               if (ifsfirst.begoff > endoff)
+                       ifslastp = NULL;
+               else {
+                       ifslastp = &ifsfirst;
+                       ifsfirst.endoff = endoff;
+               }
+               return;
+       }
+       
+       ifslastp = &ifsfirst;
+       while (ifslastp->next && ifslastp->next->begoff < endoff)
+               ifslastp=ifslastp->next;
+       while (ifslastp->next != NULL) {
+               struct ifsregion *ifsp;
+               INTOFF;
+               ifsp = ifslastp->next->next;
+               ckfree(ifslastp->next);
+               ifslastp->next = ifsp;
+               INTON;
+       }
+       if (ifslastp->endoff > endoff)
+               ifslastp->endoff = endoff;
+}
+
+
+/*
+ * Expand arithmetic expression.  Backup to start of expression,
+ * evaluate, place result in (backed up) result, adjust string position.
+ */
+void
+expari(int flag)
+{
+       struct stackmark sm;
+       char *p, *start;
+       int begoff;
+       int len;
+       intmax_t result;
+
+       /*      ifsfree(); */
+
+       /*
+        * This routine is slightly over-complicated for
+        * efficiency.  Next we scan backwards looking for the
+        * start of arithmetic.
+        */
+       start = stackblock();
+       p = expdest;
+       pushstackmark(&sm, p - start);
+       *--p = '\0';
+       p--;
+       do {
+               int esc;
+
+               while (*p != (char)CTLARI) {
+                       p--;
+#ifdef DEBUG
+                       if (p < start) {
+                               sh_error("missing CTLARI (shouldn't happen)");
+                       }
+#endif
+               }
+
+               esc = esclen(start, p);
+               if (!(esc % 2)) {
+                       break;
+               }
+
+               p -= esc + 1;
+       } while (1);
+
+       begoff = p - start;
+
+       removerecordregions(begoff);
+
+       expdest = p;
+
+       if (likely(flag & QUOTES_ESC))
+               rmescapes(p + 1);
+
+       result = arith(p + 1);
+       popstackmark(&sm);
+
+       len = cvtnum(result);
+
+       if (likely(!(flag & EXP_QUOTED)))
+               recordregion(begoff, begoff + len, 0);
+}
+
+
+/*
+ * Expand stuff in backwards quotes.
+ */
+
+STATIC void
+expbackq(union node *cmd, int flag)
+{
+       struct backcmd in;
+       int i;
+       char buf[128];
+       char *p;
+       char *dest;
+       int startloc;
+       char const *syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
+       struct stackmark smark;
+
+       INTOFF;
+       startloc = expdest - (char *)stackblock();
+       pushstackmark(&smark, startloc);
+       evalbackcmd(cmd, (struct backcmd *) &in);
+       popstackmark(&smark);
+
+       p = in.buf;
+       i = in.nleft;
+       if (i == 0)
+               goto read;
+       for (;;) {
+               memtodest(p, i, syntax, flag & QUOTES_ESC);
+read:
+               if (in.fd < 0)
+                       break;
+               do {
+                       i = read(in.fd, buf, sizeof buf);
+               } while (i < 0 && errno == EINTR);
+               TRACE(("expbackq: read returns %d\n", i));
+               if (i <= 0)
+                       break;
+               p = buf;
+       }
+
+       if (in.buf)
+               ckfree(in.buf);
+       if (in.fd >= 0) {
+               close(in.fd);
+               back_exitstatus = waitforjob(in.jp);
+       }
+       INTON;
+
+       /* Eat all trailing newlines */
+       dest = expdest;
+       for (; dest > (char *)stackblock() && dest[-1] == '\n';)
+               STUNPUTC(dest);
+       expdest = dest;
+
+       if (!(flag & EXP_QUOTED))
+               recordregion(startloc, dest - (char *)stackblock(), 0);
+       TRACE(("evalbackq: size=%d: \"%.*s\"\n",
+               (dest - (char *)stackblock()) - startloc,
+               (dest - (char *)stackblock()) - startloc,
+               stackblock() + startloc));
+}
+
+
+STATIC char *
+scanleft(
+       char *startp, char *rmesc, char *rmescend, char *str, int quotes,
+       int zero
+) {
+       char *loc;
+       char *loc2;
+       char c;
+
+       loc = startp;
+       loc2 = rmesc;
+       do {
+               int match;
+               const char *s = loc2;
+               c = *loc2;
+               if (zero) {
+                       *loc2 = '\0';
+                       s = rmesc;
+               }
+               match = pmatch(str, s);
+               *loc2 = c;
+               if (match)
+                       return loc;
+               if (quotes && *loc == (char)CTLESC)
+                       loc++;
+               loc++;
+               loc2++;
+       } while (c);
+       return 0;
+}
+
+
+STATIC char *
+scanright(
+       char *startp, char *rmesc, char *rmescend, char *str, int quotes,
+       int zero
+) {
+       int esc = 0;
+       char *loc;
+       char *loc2;
+
+       for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
+               int match;
+               char c = *loc2;
+               const char *s = loc2;
+               if (zero) {
+                       *loc2 = '\0';
+                       s = rmesc;
+               }
+               match = pmatch(str, s);
+               *loc2 = c;
+               if (match)
+                       return loc;
+               loc--;
+               if (quotes) {
+                       if (--esc < 0) {
+                               esc = esclen(startp, loc);
+                       }
+                       if (esc % 2) {
+                               esc--;
+                               loc--;
+                       }
+               }
+       }
+       return 0;
+}
+
+STATIC const char *
+subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int flag)
+{
+       int quotes = flag & QUOTES_ESC;
+       char *startp;
+       char *loc;
+       struct nodelist *saveargbackq = argbackq;
+       int amount;
+       char *rmesc, *rmescend;
+       int zero;
+       char *(*scan)(char *, char *, char *, char *, int , int);
+
+       argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
+                              (flag & EXP_QUOTED ? EXP_QPAT : EXP_CASE) : 0));
+       STPUTC('\0', expdest);
+       argbackq = saveargbackq;
+       startp = stackblock() + startloc;
+
+       switch (subtype) {
+       case VSASSIGN:
+               setvar(str, startp, 0);
+               amount = startp - expdest;
+               STADJUST(amount, expdest);
+               return startp;
+
+       case VSQUESTION:
+               varunset(p, str, startp, varflags);
+               /* NOTREACHED */
+       }
+
+       subtype -= VSTRIMRIGHT;
+#ifdef DEBUG
+       if (subtype < 0 || subtype > 3)
+               abort();
+#endif
+
+       rmesc = startp;
+       rmescend = stackblock() + strloc;
+       if (quotes) {
+               rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
+               if (rmesc != startp) {
+                       rmescend = expdest;
+                       startp = stackblock() + startloc;
+               }
+       }
+       rmescend--;
+       str = stackblock() + strloc;
+       preglob(str, 0);
+
+       /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
+       zero = subtype >> 1;
+       /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
+       scan = (subtype & 1) ^ zero ? scanleft : scanright;
+
+       loc = scan(startp, rmesc, rmescend, str, quotes, zero);
+       if (loc) {
+               if (zero) {
+                       memmove(startp, loc, str - loc);
+                       loc = startp + (str - loc) - 1;
+               }
+               *loc = '\0';
+               amount = loc - expdest;
+               STADJUST(amount, expdest);
+       }
+       return loc;
+}
+
+
+/*
+ * Expand a variable, and return a pointer to the next character in the
+ * input string.
+ */
+STATIC char *
+evalvar(char *p, int flag)
+{
+       int subtype;
+       int varflags;
+       char *var;
+       int patloc;
+       int c;
+       int startloc;
+       ssize_t varlen;
+       int easy;
+       int quoted;
+
+       varflags = *p++;
+       subtype = varflags & VSTYPE;
+
+       if (!subtype)
+               sh_error("Bad substitution");
+
+       quoted = flag & EXP_QUOTED;
+       var = p;
+       easy = (!quoted || (*var == '@' && shellparam.nparam));
+       startloc = expdest - (char *)stackblock();
+       p = strchr(p, '=') + 1;
+
+again:
+       varlen = varvalue(var, varflags, flag);
+       if (varflags & VSNUL)
+               varlen--;
+
+       if (subtype == VSPLUS) {
+               varlen = -1 - varlen;
+               goto vsplus;
+       }
+
+       if (subtype == VSMINUS) {
+vsplus:
+               if (varlen < 0) {
+                       argstr(p, flag | EXP_TILDE | EXP_WORD);
+                       goto end;
+               }
+               if (easy)
+                       goto record;
+               goto end;
+       }
+
+       if (subtype == VSASSIGN || subtype == VSQUESTION) {
+               if (varlen < 0) {
+                       if (subevalvar(p, var, 0, subtype, startloc,
+                                      varflags, flag & ~QUOTES_ESC)) {
+                               varflags &= ~VSNUL;
+                               /* 
+                                * Remove any recorded regions beyond 
+                                * start of variable 
+                                */
+                               removerecordregions(startloc);
+                               goto again;
+                       }
+                       goto end;
+               }
+               if (easy)
+                       goto record;
+               goto end;
+       }
+
+       if (varlen < 0 && uflag)
+               varunset(p, var, 0, 0);
+
+       if (subtype == VSLENGTH) {
+               cvtnum(varlen > 0 ? varlen : 0);
+               goto record;
+       }
+
+       if (subtype == VSNORMAL) {
+               if (!easy)
+                       goto end;
+record:
+               recordregion(startloc, expdest - (char *)stackblock(), quoted);
+               goto end;
+       }
+
+#ifdef DEBUG
+       switch (subtype) {
+       case VSTRIMLEFT:
+       case VSTRIMLEFTMAX:
+       case VSTRIMRIGHT:
+       case VSTRIMRIGHTMAX:
+               break;
+       default:
+               abort();
+       }
+#endif
+
+       if (varlen >= 0) {
+               /*
+                * Terminate the string and start recording the pattern
+                * right after it
+                */
+               STPUTC('\0', expdest);
+               patloc = expdest - (char *)stackblock();
+               if (subevalvar(p, NULL, patloc, subtype,
+                              startloc, varflags, flag) == 0) {
+                       int amount = expdest - (
+                               (char *)stackblock() + patloc - 1
+                       );
+                       STADJUST(-amount, expdest);
+               }
+               /* Remove any recorded regions beyond start of variable */
+               removerecordregions(startloc);
+               goto record;
+       }
+
+end:
+       if (subtype != VSNORMAL) {      /* skip to end of alternative */
+               int nesting = 1;
+               for (;;) {
+                       if ((c = (signed char)*p++) == CTLESC)
+                               p++;
+                       else if (c == CTLBACKQ) {
+                               if (varlen >= 0)
+                                       argbackq = argbackq->next;
+                       } else if (c == CTLVAR) {
+                               if ((*p++ & VSTYPE) != VSNORMAL)
+                                       nesting++;
+                       } else if (c == CTLENDVAR) {
+                               if (--nesting == 0)
+                                       break;
+                       }
+               }
+       }
+       return p;
+}
+
+
+/*
+ * Put a string on the stack.
+ */
+
+STATIC void
+memtodest(const char *p, size_t len, const char *syntax, int quotes) {
+       char *q;
+
+       if (unlikely(!len))
+               return;
+
+       q = makestrspace(len * 2, expdest);
+
+       do {
+               int c = (signed char)*p++;
+               if (c) {
+                       if ((quotes & QUOTES_ESC) &&
+                           ((syntax[c] == CCTL) ||
+                            (((quotes & EXP_FULL) || syntax != BASESYNTAX) &&
+                             syntax[c] == CBACK)))
+                               USTPUTC(CTLESC, q);
+               } else if (!(quotes & QUOTES_KEEPNUL))
+                       continue;
+               USTPUTC(c, q);
+       } while (--len);
+
+       expdest = q;
+}
+
+
+STATIC size_t
+strtodest(p, syntax, quotes)
+       const char *p;
+       const char *syntax;
+       int quotes;
+{
+       size_t len = strlen(p);
+       memtodest(p, len, syntax, quotes);
+       return len;
+}
+
+
+
+/*
+ * Add the value of a specialized variable to the stack string.
+ */
+
+STATIC ssize_t
+varvalue(char *name, int varflags, int flags)
+{
+       int num;
+       char *p;
+       int i;
+       int sep;
+       char sepc;
+       char **ap;
+       char const *syntax;
+       int quoted = flags & EXP_QUOTED;
+       int subtype = varflags & VSTYPE;
+       int discard = subtype == VSPLUS || subtype == VSLENGTH;
+       int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
+       ssize_t len = 0;
+
+       sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
+       syntax = quoted ? DQSYNTAX : BASESYNTAX;
+
+       switch (*name) {
+       case '$':
+               num = rootpid;
+               goto numvar;
+       case '?':
+               num = exitstatus;
+               goto numvar;
+       case '#':
+               num = shellparam.nparam;
+               goto numvar;
+       case '!':
+               num = backgndpid;
+               if (num == 0)
+                       return -1;
+numvar:
+               len = cvtnum(num);
+               break;
+       case '-':
+               p = makestrspace(NOPTS, expdest);
+               for (i = NOPTS - 1; i >= 0; i--) {
+                       if (optlist[i]) {
+                               USTPUTC(optletters[i], p);
+                               len++;
+                       }
+               }
+               expdest = p;
+               break;
+       case '@':
+               if (sep)
+                       goto param;
+               /* fall through */
+       case '*':
+               sep = ifsset() ? ifsval()[0] : ' ';
+param:
+               if (!(ap = shellparam.p))
+                       return -1;
+               sepc = sep;
+               while ((p = *ap++)) {
+                       len += strtodest(p, syntax, quotes);
+
+                       if (*ap && sep) {
+                               len++;
+                               memtodest(&sepc, 1, syntax, quotes);
+                       }
+               }
+               break;
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+               num = atoi(name);
+               if (num < 0 || num > shellparam.nparam)
+                       return -1;
+               p = num ? shellparam.p[num - 1] : arg0;
+               goto value;
+       default:
+               p = lookupvar(name);
+value:
+               if (!p)
+                       return -1;
+
+               len = strtodest(p, syntax, quotes);
+               break;
+       }
+
+       if (discard)
+               STADJUST(-len, expdest);
+       return len;
+}
+
+
+
+/*
+ * Record the fact that we have to scan this region of the
+ * string for IFS characters.
+ */
+
+void
+recordregion(int start, int end, int nulonly)
+{
+       struct ifsregion *ifsp;
+
+       if (ifslastp == NULL) {
+               ifsp = &ifsfirst;
+       } else {
+               INTOFF;
+               ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
+               ifsp->next = NULL;
+               ifslastp->next = ifsp;
+               INTON;
+       }
+       ifslastp = ifsp;
+       ifslastp->begoff = start;
+       ifslastp->endoff = end;
+       ifslastp->nulonly = nulonly;
+}
+
+
+
+/*
+ * Break the argument string into pieces based upon IFS and add the
+ * strings to the argument list.  The regions of the string to be
+ * searched for IFS characters have been stored by recordregion.
+ */
+void
+ifsbreakup(char *string, struct arglist *arglist)
+{
+       struct ifsregion *ifsp;
+       struct strlist *sp;
+       char *start;
+       char *p;
+       char *q;
+       const char *ifs, *realifs;
+       int ifsspc;
+       int nulonly;
+
+
+       start = string;
+       if (ifslastp != NULL) {
+               ifsspc = 0;
+               nulonly = 0;
+               realifs = ifsset() ? ifsval() : defifs;
+               ifsp = &ifsfirst;
+               do {
+                       p = string + ifsp->begoff;
+                       nulonly = ifsp->nulonly;
+                       ifs = nulonly ? nullstr : realifs;
+                       ifsspc = 0;
+                       while (p < string + ifsp->endoff) {
+                               q = p;
+                               if (*p == (char)CTLESC)
+                                       p++;
+                               if (strchr(ifs, *p)) {
+                                       if (!nulonly)
+                                               ifsspc = (strchr(defifs, *p) != NULL);
+                                       /* Ignore IFS whitespace at start */
+                                       if (q == start && ifsspc) {
+                                               p++;
+                                               start = p;
+                                               continue;
+                                       }
+                                       *q = '\0';
+                                       sp = (struct strlist *)stalloc(sizeof *sp);
+                                       sp->text = start;
+                                       *arglist->lastp = sp;
+                                       arglist->lastp = &sp->next;
+                                       p++;
+                                       if (!nulonly) {
+                                               for (;;) {
+                                                       if (p >= string + ifsp->endoff) {
+                                                               break;
+                                                       }
+                                                       q = p;
+                                                       if (*p == (char)CTLESC)
+                                                               p++;
+                                                       if (strchr(ifs, *p) == NULL ) {
+                                                               p = q;
+                                                               break;
+                                                       } else if (strchr(defifs, *p) == NULL) {
+                                                               if (ifsspc) {
+                                                                       p++;
+                                                                       ifsspc = 0;
+                                                               } else {
+                                                                       p = q;
+                                                                       break;
+                                                               }
+                                                       } else
+                                                               p++;
+                                               }
+                                       }
+                                       start = p;
+                               } else
+                                       p++;
+                       }
+               } while ((ifsp = ifsp->next) != NULL);
+               if (nulonly)
+                       goto add;
+       }
+
+       if (!*start)
+               return;
+
+add:
+       sp = (struct strlist *)stalloc(sizeof *sp);
+       sp->text = start;
+       *arglist->lastp = sp;
+       arglist->lastp = &sp->next;
+}
+
+void ifsfree(void)
+{
+       struct ifsregion *p = ifsfirst.next;
+
+       if (!p)
+               goto out;
+
+       INTOFF;
+       do {
+               struct ifsregion *ifsp;
+               ifsp = p->next;
+               ckfree(p);
+               p = ifsp;
+       } while (p);
+       ifsfirst.next = NULL;
+       INTON;
+
+out:
+       ifslastp = NULL;
+}
+
+
+
+/*
+ * Expand shell metacharacters.  At this point, the only control characters
+ * should be escapes.  The results are stored in the list exparg.
+ */
+
+#ifdef HAVE_GLOB
+STATIC void
+expandmeta(str, flag)
+       struct strlist *str;
+       int flag;
+{
+       /* TODO - EXP_REDIR */
+
+       while (str) {
+               const char *p;
+               glob_t pglob;
+               int i;
+
+               if (fflag)
+                       goto nometa;
+               INTOFF;
+               p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
+               i = glob(p, GLOB_NOMAGIC, 0, &pglob);
+               if (p != str->text)
+                       ckfree(p);
+               switch (i) {
+               case 0:
+                       if (!(pglob.gl_flags & GLOB_MAGCHAR))
+                               goto nometa2;
+                       addglob(&pglob);
+                       globfree(&pglob);
+                       INTON;
+                       break;
+               case GLOB_NOMATCH:
+nometa2:
+                       globfree(&pglob);
+                       INTON;
+nometa:
+                       *exparg.lastp = str;
+                       rmescapes(str->text);
+                       exparg.lastp = &str->next;
+                       break;
+               default:        /* GLOB_NOSPACE */
+                       sh_error("Out of space");
+               }
+               str = str->next;
+       }
+}
+
+
+/*
+ * Add the result of glob(3) to the list.
+ */
+
+STATIC void
+addglob(pglob)
+       const glob_t *pglob;
+{
+       char **p = pglob->gl_pathv;
+
+       do {
+               addfname(*p);
+       } while (*++p);
+}
+
+
+#else  /* HAVE_GLOB */
+STATIC char *expdir;
+
+
+STATIC void
+expandmeta(struct strlist *str, int flag)
+{
+       static const char metachars[] = {
+               '*', '?', '[', 0
+       };
+       /* TODO - EXP_REDIR */
+
+       while (str) {
+               struct strlist **savelastp;
+               struct strlist *sp;
+               char *p;
+
+               if (fflag)
+                       goto nometa;
+               if (!strpbrk(str->text, metachars))
+                       goto nometa;
+               savelastp = exparg.lastp;
+
+               INTOFF;
+               p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
+               {
+                       int i = strlen(str->text);
+                       expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
+               }
+
+               expmeta(expdir, p);
+               ckfree(expdir);
+               if (p != str->text)
+                       ckfree(p);
+               INTON;
+               if (exparg.lastp == savelastp) {
+                       /*
+                        * no matches
+                        */
+nometa:
+                       *exparg.lastp = str;
+                       rmescapes(str->text);
+                       exparg.lastp = &str->next;
+               } else {
+                       *exparg.lastp = NULL;
+                       *savelastp = sp = expsort(*savelastp);
+                       while (sp->next != NULL)
+                               sp = sp->next;
+                       exparg.lastp = &sp->next;
+               }
+               str = str->next;
+       }
+}
+
+
+/*
+ * Do metacharacter (i.e. *, ?, [...]) expansion.
+ */
+
+STATIC void
+expmeta(char *enddir, char *name)
+{
+       char *p;
+       const char *cp;
+       char *start;
+       char *endname;
+       int metaflag;
+       struct stat64 statb;
+       DIR *dirp;
+       struct dirent *dp;
+       int atend;
+       int matchdot;
+       int esc;
+
+       metaflag = 0;
+       start = name;
+       for (p = name; esc = 0, *p; p += esc + 1) {
+               if (*p == '*' || *p == '?')
+                       metaflag = 1;
+               else if (*p == '[') {
+                       char *q = p + 1;
+                       if (*q == '!')
+                               q++;
+                       for (;;) {
+                               if (*q == '\\')
+                                       q++;
+                               if (*q == '/' || *q == '\0')
+                                       break;
+                               if (*++q == ']') {
+                                       metaflag = 1;
+                                       break;
+                               }
+                       }
+               } else {
+                       if (*p == '\\')
+                               esc++;
+                       if (p[esc] == '/') {
+                               if (metaflag)
+                                       break;
+                               start = p + esc + 1;
+                       }
+               }
+       }
+       if (metaflag == 0) {    /* we've reached the end of the file name */
+               if (enddir != expdir)
+                       metaflag++;
+               p = name;
+               do {
+                       if (*p == '\\')
+                               p++;
+                       *enddir++ = *p;
+               } while (*p++);
+               if (metaflag == 0 || lstat64(expdir, &statb) >= 0)
+                       addfname(expdir);
+               return;
+       }
+       endname = p;
+       if (name < start) {
+               p = name;
+               do {
+                       if (*p == '\\')
+                               p++;
+                       *enddir++ = *p++;
+               } while (p < start);
+       }
+       if (enddir == expdir) {
+               cp = ".";
+       } else if (enddir == expdir + 1 && *expdir == '/') {
+               cp = "/";
+       } else {
+               cp = expdir;
+               enddir[-1] = '\0';
+       }
+       if ((dirp = opendir(cp)) == NULL)
+               return;
+       if (enddir != expdir)
+               enddir[-1] = '/';
+       if (*endname == 0) {
+               atend = 1;
+       } else {
+               atend = 0;
+               *endname = '\0';
+               endname += esc + 1;
+       }
+       matchdot = 0;
+       p = start;
+       if (*p == '\\')
+               p++;
+       if (*p == '.')
+               matchdot++;
+       while (! int_pending() && (dp = readdir(dirp)) != NULL) {
+               if (dp->d_name[0] == '.' && ! matchdot)
+                       continue;
+               if (pmatch(start, dp->d_name)) {
+                       if (atend) {
+                               scopy(dp->d_name, enddir);
+                               addfname(expdir);
+                       } else {
+                               for (p = enddir, cp = dp->d_name;
+                                    (*p++ = *cp++) != '\0';)
+                                       continue;
+                               p[-1] = '/';
+                               expmeta(p, endname);
+                       }
+               }
+       }
+       closedir(dirp);
+       if (! atend)
+               endname[-esc - 1] = esc ? '\\' : '/';
+}
+#endif /* HAVE_GLOB */
+
+
+/*
+ * Add a file name to the list.
+ */
+
+STATIC void
+addfname(char *name)
+{
+       struct strlist *sp;
+
+       sp = (struct strlist *)stalloc(sizeof *sp);
+       sp->text = sstrdup(name);
+       *exparg.lastp = sp;
+       exparg.lastp = &sp->next;
+}
+
+
+#ifndef HAVE_GLOB
+/*
+ * Sort the results of file name expansion.  It calculates the number of
+ * strings to sort and then calls msort (short for merge sort) to do the
+ * work.
+ */
+
+STATIC struct strlist *
+expsort(struct strlist *str)
+{
+       int len;
+       struct strlist *sp;
+
+       len = 0;
+       for (sp = str ; sp ; sp = sp->next)
+               len++;
+       return msort(str, len);
+}
+
+
+STATIC struct strlist *
+msort(struct strlist *list, int len)
+{
+       struct strlist *p, *q = NULL;
+       struct strlist **lpp;
+       int half;
+       int n;
+
+       if (len <= 1)
+               return list;
+       half = len >> 1;
+       p = list;
+       for (n = half ; --n >= 0 ; ) {
+               q = p;
+               p = p->next;
+       }
+       q->next = NULL;                 /* terminate first half of list */
+       q = msort(list, half);          /* sort first half of list */
+       p = msort(p, len - half);               /* sort second half */
+       lpp = &list;
+       for (;;) {
+               if (strcmp(p->text, q->text) < 0) {
+                       *lpp = p;
+                       lpp = &p->next;
+                       if ((p = *lpp) == NULL) {
+                               *lpp = q;
+                               break;
+                       }
+               } else {
+                       *lpp = q;
+                       lpp = &q->next;
+                       if ((q = *lpp) == NULL) {
+                               *lpp = p;
+                               break;
+                       }
+               }
+       }
+       return list;
+}
+#endif
+
+
+/*
+ * Returns true if the pattern matches the string.
+ */
+
+STATIC inline int
+patmatch(char *pattern, const char *string)
+{
+       return pmatch(preglob(pattern, 0), string);
+}
+
+
+#ifndef HAVE_FNMATCH
+STATIC int ccmatch(const char *p, int chr, const char **r)
+{
+       static const struct class {
+               char name[10];
+               int (*fn)(int);
+       } classes[] = {
+               { .name = ":alnum:]", .fn = isalnum },
+               { .name = ":cntrl:]", .fn = iscntrl },
+               { .name = ":lower:]", .fn = islower },
+               { .name = ":space:]", .fn = isspace },
+               { .name = ":alpha:]", .fn = isalpha },
+               { .name = ":digit:]", .fn = isdigit },
+               { .name = ":print:]", .fn = isprint },
+               { .name = ":upper:]", .fn = isupper },
+               { .name = ":blank:]", .fn = isblank },
+               { .name = ":graph:]", .fn = isgraph },
+               { .name = ":punct:]", .fn = ispunct },
+               { .name = ":xdigit:]", .fn = isxdigit },
+       };
+       const struct class *class, *end;
+
+       end = classes + sizeof(classes) / sizeof(classes[0]);
+       for (class = classes; class < end; class++) {
+               const char *q;
+
+               q = prefix(p, class->name);
+               if (!q)
+                       continue;
+               *r = q;
+               return class->fn(chr);
+       }
+
+       *r = 0;
+       return 0;
+}
+
+STATIC int
+pmatch(const char *pattern, const char *string)
+{
+       const char *p, *q;
+       char c;
+
+       p = pattern;
+       q = string;
+       for (;;) {
+               switch (c = *p++) {
+               case '\0':
+                       goto breakloop;
+               case '\\':
+                       if (*p) {
+                               c = *p++;
+                       }
+                       goto dft;
+               case '?':
+                       if (*q++ == '\0')
+                               return 0;
+                       break;
+               case '*':
+                       c = *p;
+                       while (c == '*')
+                               c = *++p;
+                       if (c != '\\' && c != '?' && c != '*' && c != '[') {
+                               while (*q != c) {
+                                       if (*q == '\0')
+                                               return 0;
+                                       q++;
+                               }
+                       }
+                       do {
+                               if (pmatch(p, q))
+                                       return 1;
+                       } while (*q++ != '\0');
+                       return 0;
+               case '[': {
+                       const char *startp;
+                       int invert, found;
+                       char chr;
+
+                       startp = p;
+                       invert = 0;
+                       if (*p == '!') {
+                               invert++;
+                               p++;
+                       }
+                       found = 0;
+                       chr = *q++;
+                       if (chr == '\0')
+                               return 0;
+                       c = *p++;
+                       do {
+                               if (!c) {
+                                       p = startp;
+                                       c = *p;
+                                       goto dft;
+                               }
+                               if (c == '[') {
+                                       const char *r;
+
+                                       found |= !!ccmatch(p, chr, &r);
+                                       if (r) {
+                                               p = r;
+                                               continue;
+                                       }
+                               } else if (c == '\\')
+                                       c = *p++;
+                               if (*p == '-' && p[1] != ']') {
+                                       p++;
+                                       if (*p == '\\')
+                                               p++;
+                                       if (chr >= c && chr <= *p)
+                                               found = 1;
+                                       p++;
+                               } else {
+                                       if (chr == c)
+                                               found = 1;
+                               }
+                       } while ((c = *p++) != ']');
+                       if (found == invert)
+                               return 0;
+                       break;
+               }
+dft:           default:
+                       if (*q++ != c)
+                               return 0;
+                       break;
+               }
+       }
+breakloop:
+       if (*q != '\0')
+               return 0;
+       return 1;
+}
+#endif
+
+
+
+/*
+ * Remove any CTLESC characters from a string.
+ */
+
+char *
+_rmescapes(char *str, int flag)
+{
+       char *p, *q, *r;
+       unsigned inquotes;
+       int notescaped;
+       int globbing;
+
+       p = strpbrk(str, qchars);
+       if (!p) {
+               return str;
+       }
+       q = p;
+       r = str;
+       if (flag & RMESCAPE_ALLOC) {
+               size_t len = p - str;
+               size_t fulllen = len + strlen(p) + 1;
+
+               if (flag & RMESCAPE_GROW) {
+                       int strloc = str - (char *)stackblock();
+
+                       r = makestrspace(fulllen, expdest);
+                       str = (char *)stackblock() + strloc;
+                       p = str + len;
+               } else if (flag & RMESCAPE_HEAP) {
+                       r = ckmalloc(fulllen);
+               } else {
+                       r = stalloc(fulllen);
+               }
+               q = r;
+               if (len > 0) {
+                       q = mempcpy(q, str, len);
+               }
+       }
+       inquotes = 0;
+       globbing = flag & RMESCAPE_GLOB;
+       notescaped = globbing;
+       while (*p) {
+               if (*p == (char)CTLQUOTEMARK) {
+                       inquotes = ~inquotes;
+                       p++;
+                       notescaped = globbing;
+                       continue;
+               }
+               if (*p == (char)CTLESC) {
+                       p++;
+                       if (notescaped)
+                               *q++ = '\\';
+               } else if (*p == '\\' && !inquotes) {
+                       /* naked back slash */
+                       notescaped = 0;
+                       goto copy;
+               }
+               notescaped = globbing;
+copy:
+               *q++ = *p++;
+       }
+       *q = '\0';
+       if (flag & RMESCAPE_GROW) {
+               expdest = r;
+               STADJUST(q - r + 1, expdest);
+       }
+       return r;
+}
+
+
+
+/*
+ * See if a pattern matches in a case statement.
+ */
+
+int
+casematch(union node *pattern, char *val)
+{
+       struct stackmark smark;
+       int result;
+
+       setstackmark(&smark);
+       argbackq = pattern->narg.backquote;
+       STARTSTACKSTR(expdest);
+       argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
+       STACKSTRNUL(expdest);
+       ifsfree();
+       result = patmatch(stackblock(), val);
+       popstackmark(&smark);
+       return result;
+}
+
+/*
+ * Our own itoa().
+ */
+
+STATIC int
+cvtnum(intmax_t num)
+{
+       int len = max_int_length(sizeof(num));
+
+       expdest = makestrspace(len, expdest);
+       len = fmtstr(expdest, len, "%" PRIdMAX, num);
+       STADJUST(len, expdest);
+       return len;
+}
+
+STATIC void
+varunset(const char *end, const char *var, const char *umsg, int varflags)
+{
+       const char *msg;
+       const char *tail;
+
+       tail = nullstr;
+       msg = "parameter not set";
+       if (umsg) {
+               if (*end == (char)CTLENDVAR) {
+                       if (varflags & VSNUL)
+                               tail = " or null";
+               } else
+                       msg = umsg;
+       }
+       sh_error("%.*s: %s%s", end - var - 1, var, msg, tail);
+}
+
+#ifdef mkinit
+
+INCLUDE "expand.h"
+
+RESET {
+       ifsfree();
+}
+
+#endif
diff --git a/src/expand.h b/src/expand.h
new file mode 100644 (file)
index 0000000..6a90f67
--- /dev/null
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)expand.h    8.2 (Berkeley) 5/4/95
+ */
+
+#include <inttypes.h>
+
+struct strlist {
+       struct strlist *next;
+       char *text;
+};
+
+
+struct arglist {
+       struct strlist *list;
+       struct strlist **lastp;
+};
+
+/*
+ * expandarg() flags
+ */
+#define EXP_FULL       0x1     /* perform word splitting & file globbing */
+#define EXP_TILDE      0x2     /* do normal tilde expansion */
+#define        EXP_VARTILDE    0x4     /* expand tildes in an assignment */
+#define        EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
+#define EXP_CASE       0x10    /* keeps quotes around for CASE pattern */
+#define EXP_QPAT       0x20    /* pattern in quoted parameter expansion */
+#define EXP_VARTILDE2  0x40    /* expand tildes after colons only */
+#define EXP_WORD       0x80    /* expand word in parameter expansion */
+#define EXP_QUOTED     0x100   /* expand word in double quotes */
+
+
+union node;
+void expandarg(union node *, struct arglist *, int);
+void expari(int);
+#define rmescapes(p) _rmescapes((p), 0)
+char *_rmescapes(char *, int);
+int casematch(union node *, char *);
+void recordregion(int, int, int);
+void removerecordregions(int); 
+void ifsbreakup(char *, struct arglist *);
+void ifsfree(void);
+
+/* From arith.y */
+intmax_t arith(const char *);
+int expcmd(int , char **);
+#ifdef USE_LEX
+void arith_lex_reset(void);
+#else
+#define arith_lex_reset()
+#endif
+int yylex(void);
diff --git a/src/hetio.h b/src/hetio.h
new file mode 100644 (file)
index 0000000..c3e915c
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Termios command line History and Editting for NetBSD sh (ash)
+ * Copyright (c) 1999
+ *     Main code:      Adam Rogoyski <rogoyski@cs.utexas.edu> 
+ *     Etc:            Dave Cinege <dcinege@psychosis.com>
+ *
+ * You may use this code as you wish, so long as the original author(s)
+ * are attributed in any redistributions of the source code.
+ * This code is 'as is' with no warranty.
+ * This code may safely be consumed by a BSD or GPL license.
+ *
+ * v 0.5  19990328     Initial release 
+ *
+ * Future plans: Simple file and path name completion. (like BASH)
+ *
+ */
+
+void hetio_init(void);
+int hetio_read_input(int fd);
+void hetio_reset_term(void);
+
+extern int hetio_inter;
diff --git a/src/histedit.c b/src/histedit.c
new file mode 100644 (file)
index 0000000..b27d629
--- /dev/null
@@ -0,0 +1,494 @@
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+/*
+ * Editline and history functions (and glue).
+ */
+#include "shell.h"
+#include "parser.h"
+#include "var.h"
+#include "options.h"
+#include "main.h"
+#include "output.h"
+#include "mystring.h"
+#include "error.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#include "eval.h"
+#include "memalloc.h"
+
+#define MAXHISTLOOPS   4       /* max recursions through fc */
+#define DEFEDITOR      "ed"    /* default editor *should* be $EDITOR */
+
+History *hist; /* history cookie */
+EditLine *el;  /* editline cookie */
+int displayhist;
+static FILE *el_in, *el_out;
+
+STATIC const char *fc_replace(const char *, char *, char *);
+
+#ifdef DEBUG
+extern FILE *tracefile;
+#endif
+
+/*
+ * Set history and editing status.  Called whenever the status may
+ * have changed (figures out what to do).
+ */
+void
+histedit(void)
+{
+       FILE *el_err;
+
+#define editing (Eflag || Vflag)
+
+       if (iflag) {
+               if (!hist) {
+                       /*
+                        * turn history on
+                        */
+                       INTOFF;
+                       hist = history_init();
+                       INTON;
+
+                       if (hist != NULL)
+                               sethistsize(histsizeval());
+                       else
+                               out2str("sh: can't initialize history\n");
+               }
+               if (editing && !el && isatty(0)) { /* && isatty(2) ??? */
+                       /*
+                        * turn editing on
+                        */
+                       INTOFF;
+                       if (el_in == NULL)
+                               el_in = fdopen(0, "r");
+                       if (el_out == NULL)
+                               el_out = fdopen(2, "w");
+                       if (el_in == NULL || el_out == NULL)
+                               goto bad;
+                       el_err = el_out;
+#if DEBUG
+                       if (tracefile)
+                               el_err = tracefile;
+#endif
+                       el = el_init(arg0, el_in, el_out, el_err);
+                       if (el != NULL) {
+                               if (hist)
+                                       el_set(el, EL_HIST, history, hist);
+                               el_set(el, EL_PROMPT, getprompt);
+                       } else {
+bad:
+                               out2str("sh: can't initialize editing\n");
+                       }
+                       INTON;
+               } else if (!editing && el) {
+                       INTOFF;
+                       el_end(el);
+                       el = NULL;
+                       INTON;
+               }
+               if (el) {
+                       if (Vflag)
+                               el_set(el, EL_EDITOR, "vi");
+                       else if (Eflag)
+                               el_set(el, EL_EDITOR, "emacs");
+                       el_source(el, NULL);
+               }
+       } else {
+               INTOFF;
+               if (el) {       /* no editing if not interactive */
+                       el_end(el);
+                       el = NULL;
+               }
+               if (hist) {
+                       history_end(hist);
+                       hist = NULL;
+               }
+               INTON;
+       }
+}
+
+
+void
+sethistsize(const char *hs)
+{
+       int histsize;
+       HistEvent he;
+
+       if (hist != NULL) {
+               if (hs == NULL || *hs == '\0' ||
+                  (histsize = atoi(hs)) < 0)
+                       histsize = 100;
+               history(hist, &he, H_SETSIZE, histsize);
+       }
+}
+
+void
+setterm(const char *term)
+{
+       if (el != NULL && term != NULL)
+               if (el_set(el, EL_TERMINAL, term) != 0) {
+                       outfmt(out2, "sh: Can't set terminal type %s\n", term);
+                       outfmt(out2, "sh: Using dumb terminal settings.\n");
+               }
+}
+
+/*
+ *  This command is provided since POSIX decided to standardize
+ *  the Korn shell fc command.  Oh well...
+ */
+int
+histcmd(int argc, char **argv)
+{
+       int ch;
+       const char *editor = NULL;
+       HistEvent he;
+       int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
+       int i, retval;
+       const char *firststr, *laststr;
+       int first, last, direction;
+       char *pat = NULL, *repl;        /* ksh "fc old=new" crap */
+       static int active = 0;
+       struct jmploc jmploc;
+       struct jmploc *volatile savehandler;
+       char editfile[MAXPATHLEN + 1];
+       FILE *efp;
+#ifdef __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &editor;
+       (void) &lflg;
+       (void) &nflg;
+       (void) &rflg;
+       (void) &sflg;
+       (void) &firststr;
+       (void) &laststr;
+       (void) &pat;
+       (void) &repl;
+       (void) &efp;
+       (void) &argc;
+       (void) &argv;
+#endif
+
+       if (hist == NULL)
+               sh_error("history not active");
+
+       if (argc == 1)
+               sh_error("missing history argument");
+
+#ifdef __GLIBC__
+       optind = 0;
+#else
+       optreset = 1; optind = 1; /* initialize getopt */
+#endif
+       while (not_fcnumber(argv[optind]) &&
+             (ch = getopt(argc, argv, ":e:lnrs")) != -1)
+               switch ((char)ch) {
+               case 'e':
+                       editor = optionarg;
+                       break;
+               case 'l':
+                       lflg = 1;
+                       break;
+               case 'n':
+                       nflg = 1;
+                       break;
+               case 'r':
+                       rflg = 1;
+                       break;
+               case 's':
+                       sflg = 1;
+                       break;
+               case ':':
+                       sh_error("option -%c expects argument", optopt);
+                       /* NOTREACHED */
+               case '?':
+               default:
+                       sh_error("unknown option: -%c", optopt);
+                       /* NOTREACHED */
+               }
+       argc -= optind, argv += optind;
+
+       /*
+        * If executing...
+        */
+       if (lflg == 0 || editor || sflg) {
+               lflg = 0;       /* ignore */
+               editfile[0] = '\0';
+               /*
+                * Catch interrupts to reset active counter and
+                * cleanup temp files.
+                */
+               if (setjmp(jmploc.loc)) {
+                       active = 0;
+                       if (*editfile)
+                               unlink(editfile);
+                       handler = savehandler;
+                       longjmp(handler->loc, 1);
+               }
+               savehandler = handler;
+               handler = &jmploc;
+               if (++active > MAXHISTLOOPS) {
+                       active = 0;
+                       displayhist = 0;
+                       sh_error("called recursively too many times");
+               }
+               /*
+                * Set editor.
+                */
+               if (sflg == 0) {
+                       if (editor == NULL &&
+                           (editor = bltinlookup("FCEDIT")) == NULL &&
+                           (editor = bltinlookup("EDITOR")) == NULL)
+                               editor = DEFEDITOR;
+                       if (editor[0] == '-' && editor[1] == '\0') {
+                               sflg = 1;       /* no edit */
+                               editor = NULL;
+                       }
+               }
+       }
+
+       /*
+        * If executing, parse [old=new] now
+        */
+       if (lflg == 0 && argc > 0 &&
+            ((repl = strchr(argv[0], '=')) != NULL)) {
+               pat = argv[0];
+               *repl++ = '\0';
+               argc--, argv++;
+       }
+       /*
+        * determine [first] and [last]
+        */
+       switch (argc) {
+       case 0:
+               firststr = lflg ? "-16" : "-1";
+               laststr = "-1";
+               break;
+       case 1:
+               firststr = argv[0];
+               laststr = lflg ? "-1" : argv[0];
+               break;
+       case 2:
+               firststr = argv[0];
+               laststr = argv[1];
+               break;
+       default:
+               sh_error("too many args");
+               /* NOTREACHED */
+       }
+       /*
+        * Turn into event numbers.
+        */
+       first = str_to_event(firststr, 0);
+       last = str_to_event(laststr, 1);
+
+       if (rflg) {
+               i = last;
+               last = first;
+               first = i;
+       }
+       /*
+        * XXX - this should not depend on the event numbers
+        * always increasing.  Add sequence numbers or offset
+        * to the history element in next (diskbased) release.
+        */
+       direction = first < last ? H_PREV : H_NEXT;
+
+       /*
+        * If editing, grab a temp file.
+        */
+       if (editor) {
+               int fd;
+               INTOFF;         /* easier */
+               sprintf(editfile, "%s_shXXXXXX", _PATH_TMP);
+               if ((fd = mkstemp(editfile)) < 0)
+                       sh_error("can't create temporary file %s", editfile);
+               if ((efp = fdopen(fd, "w")) == NULL) {
+                       close(fd);
+                       sh_error("can't allocate stdio buffer for temp");
+               }
+       }
+
+       /*
+        * Loop through selected history events.  If listing or executing,
+        * do it now.  Otherwise, put into temp file and call the editor
+        * after.
+        *
+        * The history interface needs rethinking, as the following
+        * convolutions will demonstrate.
+        */
+       history(hist, &he, H_FIRST);
+       retval = history(hist, &he, H_NEXT_EVENT, first);
+       for (;retval != -1; retval = history(hist, &he, direction)) {
+               if (lflg) {
+                       if (!nflg)
+                               out1fmt("%5d ", he.num);
+                       out1str(he.str);
+               } else {
+                       const char *s = pat ?
+                          fc_replace(he.str, pat, repl) : he.str;
+
+                       if (sflg) {
+                               if (displayhist) {
+                                       out2str(s);
+                               }
+
+                               evalstring(strcpy(stalloc(strlen(s) + 1), s),
+                                          0);
+                               if (displayhist && hist) {
+                                       /*
+                                        *  XXX what about recursive and
+                                        *  relative histnums.
+                                        */
+                                       history(hist, &he, H_ENTER, s);
+                               }
+                       } else
+                               fputs(s, efp);
+               }
+               /*
+                * At end?  (if we were to lose last, we'd sure be
+                * messed up).
+                */
+               if (he.num == last)
+                       break;
+       }
+       if (editor) {
+               char *editcmd;
+
+               fclose(efp);
+               editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
+               sprintf(editcmd, "%s %s", editor, editfile);
+               /* XXX - should use no JC command */
+               evalstring(editcmd, 0);
+               INTON;
+               readcmdfile(editfile);  /* XXX - should read back - quick tst */
+               unlink(editfile);
+       }
+
+       if (lflg == 0 && active > 0)
+               --active;
+       if (displayhist)
+               displayhist = 0;
+       return 0;
+}
+
+STATIC const char *
+fc_replace(const char *s, char *p, char *r)
+{
+       char *dest;
+       int plen = strlen(p);
+
+       STARTSTACKSTR(dest);
+       while (*s) {
+               if (*s == *p && strncmp(s, p, plen) == 0) {
+                       while (*r)
+                               STPUTC(*r++, dest);
+                       s += plen;
+                       *p = '\0';      /* so no more matches */
+               } else
+                       STPUTC(*s++, dest);
+       }
+       STACKSTRNUL(dest);
+       dest = grabstackstr(dest);
+
+       return (dest);
+}
+
+int
+not_fcnumber(char *s)
+{
+       if (s == NULL)
+               return 0;
+        if (*s == '-')
+                s++;
+       return (!is_number(s));
+}
+
+int
+str_to_event(const char *str, int last)
+{
+       HistEvent he;
+       const char *s = str;
+       int relative = 0;
+       int i, retval;
+
+       retval = history(hist, &he, H_FIRST);
+       switch (*s) {
+       case '-':
+               relative = 1;
+               /*FALLTHROUGH*/
+       case '+':
+               s++;
+       }
+       if (is_number(s)) {
+               i = atoi(s);
+               if (relative) {
+                       while (retval != -1 && i--) {
+                               retval = history(hist, &he, H_NEXT);
+                       }
+                       if (retval == -1)
+                               retval = history(hist, &he, H_LAST);
+               } else {
+                       retval = history(hist, &he, H_NEXT_EVENT, i);
+                       if (retval == -1) {
+                               /*
+                                * the notion of first and last is
+                                * backwards to that of the history package
+                                */
+                               retval = history(hist, &he,
+                                               last ? H_FIRST : H_LAST);
+                       }
+               }
+               if (retval == -1)
+                       sh_error("history number %s not found (internal error)",
+                                str);
+       } else {
+               /*
+                * pattern
+                */
+               retval = history(hist, &he, H_PREV_STR, str);
+               if (retval == -1)
+                       sh_error("history pattern not found: %s", str);
+       }
+       return (he.num);
+}
+#endif
diff --git a/src/init.h b/src/init.h
new file mode 100644 (file)
index 0000000..e026e86
--- /dev/null
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)init.h      8.2 (Berkeley) 5/4/95
+ */
+
+void init(void);
+void reset(void);
+void initshellproc(void);
diff --git a/src/input.c b/src/input.c
new file mode 100644 (file)
index 0000000..d31c45b
--- /dev/null
@@ -0,0 +1,532 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>     /* defines BUFSIZ */
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * This file implements the input routines used by the parser.
+ */
+
+#include "eval.h"
+#include "shell.h"
+#include "redir.h"
+#include "syntax.h"
+#include "input.h"
+#include "output.h"
+#include "options.h"
+#include "memalloc.h"
+#include "error.h"
+#include "alias.h"
+#include "parser.h"
+#include "main.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+
+#ifdef HETIO
+#include "hetio.h"
+#endif
+
+#define EOF_NLEFT -99          /* value of parsenleft when EOF pushed back */
+#define IBUFSIZ (BUFSIZ + 1)
+
+MKINIT
+struct strpush {
+       struct strpush *prev;   /* preceding string on stack */
+       char *prevstring;
+       int prevnleft;
+       struct alias *ap;       /* if push was associated with an alias */
+       char *string;           /* remember the string since it may change */
+};
+
+/*
+ * The parsefile structure pointed to by the global variable parsefile
+ * contains information about the current file being read.
+ */
+
+MKINIT
+struct parsefile {
+       struct parsefile *prev; /* preceding file on stack */
+       int linno;              /* current line */
+       int fd;                 /* file descriptor (or -1 if string) */
+       int nleft;              /* number of chars left in this line */
+       int lleft;              /* number of chars left in this buffer */
+       char *nextc;            /* next char in buffer */
+       char *buf;              /* input buffer */
+       struct strpush *strpush; /* for pushing strings at this level */
+       struct strpush basestrpush; /* so pushing one is fast */
+};
+
+
+int plinno = 1;                        /* input line number */
+int parsenleft;                        /* copy of parsefile->nleft */
+MKINIT int parselleft;         /* copy of parsefile->lleft */
+char *parsenextc;              /* copy of parsefile->nextc */
+MKINIT struct parsefile basepf;        /* top level input file */
+MKINIT char basebuf[IBUFSIZ];  /* buffer for top level input file */
+struct parsefile *parsefile = &basepf; /* current input file */
+int whichprompt;               /* 1 == PS1, 2 == PS2 */
+
+#ifndef SMALL
+EditLine *el;                  /* cookie for editline package */
+#endif
+
+STATIC void pushfile(void);
+static int preadfd(void);
+static void setinputfd(int fd, int push);
+
+#ifdef mkinit
+INCLUDE <stdio.h>
+INCLUDE "input.h"
+INCLUDE "error.h"
+
+INIT {
+       basepf.nextc = basepf.buf = basebuf;
+}
+
+RESET {
+       parselleft = parsenleft = 0;    /* clear input buffer */
+       popallfiles();
+}
+#endif
+
+
+/*
+ * Read a character from the script, returning PEOF on end of file.
+ * Nul characters in the input are silently discarded.
+ */
+
+int
+pgetc(void)
+{
+       return pgetc_macro();
+}
+
+
+/*
+ * Same as pgetc(), but ignores PEOA.
+ */
+
+int
+pgetc2()
+{
+       int c;
+       do {
+               c = pgetc_macro();
+       } while (c == PEOA);
+       return c;
+}
+
+
+static int
+preadfd(void)
+{
+       int nr;
+       char *buf =  parsefile->buf;
+       parsenextc = buf;
+
+retry:
+#ifndef SMALL
+       if (parsefile->fd == 0 && el) {
+               static const char *rl_cp;
+               static int el_len;
+
+               if (rl_cp == NULL)
+                       rl_cp = el_gets(el, &el_len);
+               if (rl_cp == NULL)
+                       nr = 0;
+               else {
+                       nr = el_len;
+                       if (nr > IBUFSIZ - 1)
+                               nr = IBUFSIZ - 1;
+                       memcpy(buf, rl_cp, nr);
+                       if (nr != el_len) {
+                               el_len -= nr;
+                               rl_cp += nr;
+                       } else
+                               rl_cp = 0;
+               }
+
+       } else
+#endif
+
+#ifdef HETIO
+               nr = hetio_read_input(parsefile->fd);
+               if (nr == -255)
+#endif
+               nr = read(parsefile->fd, buf, IBUFSIZ - 1);
+
+
+       if (nr < 0) {
+               if (errno == EINTR)
+                       goto retry;
+               if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
+                       int flags = fcntl(0, F_GETFL, 0);
+                       if (flags >= 0 && flags & O_NONBLOCK) {
+                               flags &=~ O_NONBLOCK;
+                               if (fcntl(0, F_SETFL, flags) >= 0) {
+                                       out2str("sh: turning off NDELAY mode\n");
+                                       goto retry;
+                               }
+                       }
+               }
+       }
+       return nr;
+}
+
+/*
+ * Refill the input buffer and return the next input character:
+ *
+ * 1) If a string was pushed back on the input, pop it;
+ * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
+ *    from a string so we can't refill the buffer, return EOF.
+ * 3) If the is more stuff in this buffer, use it else call read to fill it.
+ * 4) Process input up to the next newline, deleting nul characters.
+ */
+
+int
+preadbuffer(void)
+{
+       char *q;
+       int more;
+#ifndef SMALL
+       int something;
+#endif
+       char savec;
+
+       while (unlikely(parsefile->strpush)) {
+               if (
+                       parsenleft == -1 && parsefile->strpush->ap &&
+                       parsenextc[-1] != ' ' && parsenextc[-1] != '\t'
+               ) {
+                       return PEOA;
+               }
+               popstring();
+               if (--parsenleft >= 0)
+                       return (signed char)*parsenextc++;
+       }
+       if (unlikely(parsenleft == EOF_NLEFT || parsefile->buf == NULL))
+               return PEOF;
+       flushout(&output);
+#ifdef FLUSHERR
+       flushout(&errout);
+#endif
+
+       more = parselleft;
+       if (more <= 0) {
+again:
+               if ((more = preadfd()) <= 0) {
+                       parselleft = parsenleft = EOF_NLEFT;
+                       return PEOF;
+               }
+       }
+
+       q = parsenextc;
+
+       /* delete nul characters */
+#ifndef SMALL
+       something = 0;
+#endif
+       for (;;) {
+               int c;
+
+               more--;
+               c = *q;
+
+               if (!c)
+                       memmove(q, q + 1, more);
+               else {
+                       q++;
+
+                       if (c == '\n') {
+                               parsenleft = q - parsenextc - 1;
+                               break;
+                       }
+
+#ifndef SMALL
+                       switch (c) {
+                       default:
+                               something = 1;
+                               /* fall through */
+                       case '\t':
+                       case ' ':
+                               break;
+                       }
+#endif
+               }
+
+               if (more <= 0) {
+                       parsenleft = q - parsenextc - 1;
+                       if (parsenleft < 0)
+                               goto again;
+                       break;
+               }
+       }
+       parselleft = more;
+
+       savec = *q;
+       *q = '\0';
+
+#ifndef SMALL
+       if (parsefile->fd == 0 && hist && something) {
+               HistEvent he;
+               INTOFF;
+               history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
+                   parsenextc);
+               INTON;
+       }
+#endif
+
+       if (vflag) {
+               out2str(parsenextc);
+#ifdef FLUSHERR
+               flushout(out2);
+#endif
+       }
+
+       *q = savec;
+
+       return (signed char)*parsenextc++;
+}
+
+/*
+ * Undo the last call to pgetc.  Only one character may be pushed back.
+ * PEOF may be pushed back.
+ */
+
+void
+pungetc(void)
+{
+       parsenleft++;
+       parsenextc--;
+}
+
+/*
+ * Push a string back onto the input at this current parsefile level.
+ * We handle aliases this way.
+ */
+void
+pushstring(char *s, void *ap)
+{
+       struct strpush *sp;
+       size_t len;
+
+       len = strlen(s);
+       INTOFF;
+/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
+       if (parsefile->strpush) {
+               sp = ckmalloc(sizeof (struct strpush));
+               sp->prev = parsefile->strpush;
+               parsefile->strpush = sp;
+       } else
+               sp = parsefile->strpush = &(parsefile->basestrpush);
+       sp->prevstring = parsenextc;
+       sp->prevnleft = parsenleft;
+       sp->ap = (struct alias *)ap;
+       if (ap) {
+               ((struct alias *)ap)->flag |= ALIASINUSE;
+               sp->string = s;
+       }
+       parsenextc = s;
+       parsenleft = len;
+       INTON;
+}
+
+void
+popstring(void)
+{
+       struct strpush *sp = parsefile->strpush;
+
+       INTOFF;
+       if (sp->ap) {
+               if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
+                       checkkwd |= CHKALIAS;
+               }
+               if (sp->string != sp->ap->val) {
+                       ckfree(sp->string);
+               }
+               sp->ap->flag &= ~ALIASINUSE;
+               if (sp->ap->flag & ALIASDEAD) {
+                       unalias(sp->ap->name);
+               }
+       }
+       parsenextc = sp->prevstring;
+       parsenleft = sp->prevnleft;
+/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
+       parsefile->strpush = sp->prev;
+       if (sp != &(parsefile->basestrpush))
+               ckfree(sp);
+       INTON;
+}
+
+/*
+ * Set the input to take input from a file.  If push is set, push the
+ * old input onto the stack first.
+ */
+
+int
+setinputfile(const char *fname, int flags)
+{
+       int fd;
+
+       INTOFF;
+       if ((fd = open(fname, O_RDONLY)) < 0) {
+               if (flags & INPUT_NOFILE_OK)
+                       goto out;
+               exitstatus = 127;
+               exerror(EXERROR, "Can't open %s", fname);
+       }
+       if (fd < 10)
+               fd = savefd(fd, fd);
+       setinputfd(fd, flags & INPUT_PUSH_FILE);
+out:
+       INTON;
+       return fd;
+}
+
+
+/*
+ * Like setinputfile, but takes an open file descriptor.  Call this with
+ * interrupts off.
+ */
+
+static void
+setinputfd(int fd, int push)
+{
+       if (push) {
+               pushfile();
+               parsefile->buf = 0;
+       }
+       parsefile->fd = fd;
+       if (parsefile->buf == NULL)
+               parsefile->buf = ckmalloc(IBUFSIZ);
+       parselleft = parsenleft = 0;
+       plinno = 1;
+}
+
+
+/*
+ * Like setinputfile, but takes input from a string.
+ */
+
+void
+setinputstring(char *string)
+{
+       INTOFF;
+       pushfile();
+       parsenextc = string;
+       parsenleft = strlen(string);
+       parsefile->buf = NULL;
+       plinno = 1;
+       INTON;
+}
+
+
+
+/*
+ * To handle the "." command, a stack of input files is used.  Pushfile
+ * adds a new entry to the stack and popfile restores the previous level.
+ */
+
+STATIC void
+pushfile(void)
+{
+       struct parsefile *pf;
+
+       parsefile->nleft = parsenleft;
+       parsefile->lleft = parselleft;
+       parsefile->nextc = parsenextc;
+       parsefile->linno = plinno;
+       pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
+       pf->prev = parsefile;
+       pf->fd = -1;
+       pf->strpush = NULL;
+       pf->basestrpush.prev = NULL;
+       parsefile = pf;
+}
+
+
+void
+popfile(void)
+{
+       struct parsefile *pf = parsefile;
+
+       INTOFF;
+       if (pf->fd >= 0)
+               close(pf->fd);
+       if (pf->buf)
+               ckfree(pf->buf);
+       while (pf->strpush)
+               popstring();
+       parsefile = pf->prev;
+       ckfree(pf);
+       parsenleft = parsefile->nleft;
+       parselleft = parsefile->lleft;
+       parsenextc = parsefile->nextc;
+       plinno = parsefile->linno;
+       INTON;
+}
+
+
+/*
+ * Return to top level.
+ */
+
+void
+popallfiles(void)
+{
+       while (parsefile != &basepf)
+               popfile();
+}
+
+
+
+/*
+ * Close the file(s) that the shell is reading commands from.  Called
+ * after a fork is done.
+ */
+
+void
+closescript(void)
+{
+       popallfiles();
+       if (parsefile->fd > 0) {
+               close(parsefile->fd);
+               parsefile->fd = 0;
+       }
+}
diff --git a/src/input.h b/src/input.h
new file mode 100644 (file)
index 0000000..50a7797
--- /dev/null
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)input.h     8.2 (Berkeley) 5/4/95
+ */
+
+/* PEOF (the end of file marker) is defined in syntax.h */
+
+enum {
+       INPUT_PUSH_FILE = 1,
+       INPUT_NOFILE_OK = 2,
+};
+
+/*
+ * The input line number.  Input.c just defines this variable, and saves
+ * and restores it when files are pushed and popped.  The user of this
+ * package must set its value.
+ */
+extern int plinno;
+extern int parsenleft;         /* number of characters left in input buffer */
+extern char *parsenextc;       /* next character in input buffer */
+
+int pgetc(void);
+int pgetc2(void);
+int preadbuffer(void);
+void pungetc(void);
+void pushstring(char *, void *);
+void popstring(void);
+int setinputfile(const char *, int);
+void setinputstring(char *);
+void popfile(void);
+void popallfiles(void);
+void closescript(void);
+
+#define pgetc_macro() \
+       (--parsenleft >= 0 ? (signed char)*parsenextc++ : preadbuffer())
diff --git a/src/jobs.c b/src/jobs.c
new file mode 100644 (file)
index 0000000..bf40204
--- /dev/null
@@ -0,0 +1,1504 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef BSD
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#include <sys/ioctl.h>
+
+#include "shell.h"
+#if JOBS
+#include <termios.h>
+#undef CEOF                    /* syntax.h redefines this */
+#endif
+#include "redir.h"
+#include "show.h"
+#include "main.h"
+#include "parser.h"
+#include "nodes.h"
+#include "jobs.h"
+#include "options.h"
+#include "trap.h"
+#include "syntax.h"
+#include "input.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "system.h"
+
+/* mode flags for set_curjob */
+#define CUR_DELETE 2
+#define CUR_RUNNING 1
+#define CUR_STOPPED 0
+
+/* mode flags for dowait */
+#define DOWAIT_NORMAL 0
+#define DOWAIT_BLOCK 1
+#define DOWAIT_WAITCMD 2
+
+/* array of jobs */
+static struct job *jobtab;
+/* size of array */
+static unsigned njobs;
+/* pid of last background process */
+pid_t backgndpid;
+
+#if JOBS
+/* pgrp of shell on invocation */
+static int initialpgrp;
+/* control terminal */
+static int ttyfd = -1;
+#endif
+
+/* current job */
+static struct job *curjob;
+/* number of presumed living untracked jobs */
+static int jobless;
+
+STATIC void set_curjob(struct job *, unsigned);
+STATIC int jobno(const struct job *);
+STATIC int sprint_status(char *, int, int);
+STATIC void freejob(struct job *);
+STATIC struct job *getjob(const char *, int);
+STATIC struct job *growjobtab(void);
+STATIC void forkchild(struct job *, union node *, int);
+STATIC void forkparent(struct job *, union node *, int, pid_t);
+STATIC int dowait(int, struct job *);
+#ifdef SYSV
+STATIC int onsigchild(void);
+#endif
+STATIC int waitproc(int, int *);
+STATIC char *commandtext(union node *);
+STATIC void cmdtxt(union node *);
+STATIC void cmdlist(union node *, int);
+STATIC void cmdputs(const char *);
+STATIC void showpipe(struct job *, struct output *);
+STATIC int getstatus(struct job *);
+
+#if JOBS
+static int restartjob(struct job *, int);
+static void xtcsetpgrp(int, pid_t);
+#endif
+
+STATIC void
+set_curjob(struct job *jp, unsigned mode)
+{
+       struct job *jp1;
+       struct job **jpp, **curp;
+
+       /* first remove from list */
+       jpp = curp = &curjob;
+       do {
+               jp1 = *jpp;
+               if (jp1 == jp)
+                       break;
+               jpp = &jp1->prev_job;
+       } while (1);
+       *jpp = jp1->prev_job;
+
+       /* Then re-insert in correct position */
+       jpp = curp;
+       switch (mode) {
+       default:
+#ifdef DEBUG
+               abort();
+#endif
+       case CUR_DELETE:
+               /* job being deleted */
+               break;
+       case CUR_RUNNING:
+               /* newly created job or backgrounded job,
+                  put after all stopped jobs. */
+               do {
+                       jp1 = *jpp;
+                       if (!JOBS || !jp1 || jp1->state != JOBSTOPPED)
+                               break;
+                       jpp = &jp1->prev_job;
+               } while (1);
+               /* FALLTHROUGH */
+#if JOBS
+       case CUR_STOPPED:
+#endif
+               /* newly stopped job - becomes curjob */
+               jp->prev_job = *jpp;
+               *jpp = jp;
+               break;
+       }
+}
+
+#if JOBS
+/*
+ * Turn job control on and off.
+ *
+ * Note:  This code assumes that the third arg to ioctl is a character
+ * pointer, which is true on Berkeley systems but not System V.  Since
+ * System V doesn't have job control yet, this isn't a problem now.
+ *
+ * Called with interrupts off.
+ */
+
+int jobctl;
+
+void
+setjobctl(int on)
+{
+       int fd;
+       int pgrp;
+
+       if (on == jobctl || rootshell == 0)
+               return;
+       if (on) {
+               int ofd;
+               ofd = fd = open(_PATH_TTY, O_RDWR);
+               if (fd < 0) {
+                       fd += 3;
+                       while (!isatty(fd))
+                               if (--fd < 0)
+                                       goto out;
+               }
+               fd = savefd(fd, ofd);
+               do { /* while we are in the background */
+                       if ((pgrp = tcgetpgrp(fd)) < 0) {
+out:
+                               sh_warnx("can't access tty; job control turned off");
+                               mflag = on = 0;
+                               goto close;
+                       }
+                       if (pgrp == getpgrp())
+                               break;
+                       killpg(0, SIGTTIN);
+               } while (1);
+               initialpgrp = pgrp;
+
+               setsignal(SIGTSTP);
+               setsignal(SIGTTOU);
+               setsignal(SIGTTIN);
+               pgrp = rootpid;
+               setpgid(0, pgrp);
+               xtcsetpgrp(fd, pgrp);
+       } else {
+               /* turning job control off */
+               fd = ttyfd;
+               pgrp = initialpgrp;
+               xtcsetpgrp(fd, pgrp);
+               setpgid(0, pgrp);
+               setsignal(SIGTSTP);
+               setsignal(SIGTTOU);
+               setsignal(SIGTTIN);
+close:
+               close(fd);
+               fd = -1;
+       }
+       ttyfd = fd;
+       jobctl = on;
+}
+#endif
+
+
+int
+killcmd(argc, argv)
+       int argc;
+       char **argv;
+{
+       extern char *signal_names[];
+       int signo = -1;
+       int list = 0;
+       int i;
+       pid_t pid;
+       struct job *jp;
+
+       if (argc <= 1) {
+usage:
+               sh_error(
+"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
+"kill -l [exitstatus]"
+               );
+       }
+
+       if (**++argv == '-') {
+               signo = decode_signal(*argv + 1, 1);
+               if (signo < 0) {
+                       int c;
+
+                       while ((c = nextopt("ls:")) != '\0')
+                               switch (c) {
+                               default:
+#ifdef DEBUG
+                                       abort();
+#endif
+                               case 'l':
+                                       list = 1;
+                                       break;
+                               case 's':
+                                       signo = decode_signal(optionarg, 1);
+                                       if (signo < 0) {
+                                               sh_error(
+                                                       "invalid signal number or name: %s",
+                                                       optionarg
+                                               );
+                                       }
+                                       break;
+                               }
+                       argv = argptr;
+               } else
+                       argv++;
+       }
+
+       if (!list && signo < 0)
+               signo = SIGTERM;
+
+       if ((signo < 0 || !*argv) ^ list) {
+               goto usage;
+       }
+
+       if (list) {
+               struct output *out;
+
+               out = out1;
+               if (!*argv) {
+                       outstr("0\n", out);
+                       for (i = 1; i < NSIG; i++) {
+                               outfmt(out, snlfmt, signal_names[i]);
+                       }
+                       return 0;
+               }
+               signo = number(*argv);
+               if (signo > 128)
+                       signo -= 128;
+               if (0 < signo && signo < NSIG)
+                       outfmt(out, snlfmt, signal_names[signo]);
+               else
+                       sh_error("invalid signal number or exit status: %s",
+                                *argv);
+               return 0;
+       }
+
+       i = 0;
+       do {
+               if (**argv == '%') {
+                       jp = getjob(*argv, 0);
+                       pid = -jp->ps[0].pid;
+               } else
+                       pid = **argv == '-' ?
+                               -number(*argv + 1) : number(*argv);
+               if (kill(pid, signo) != 0) {
+                       sh_warnx("%s\n", strerror(errno));
+                       i = 1;
+               }
+       } while (*++argv);
+
+       return i;
+}
+
+STATIC int
+jobno(const struct job *jp)
+{
+       return jp - jobtab + 1;
+}
+
+#if JOBS
+int
+fgcmd(int argc, char **argv)
+{
+       struct job *jp;
+       struct output *out;
+       int mode;
+       int retval;
+
+       mode = (**argv == 'f') ? FORK_FG : FORK_BG;
+       nextopt(nullstr);
+       argv = argptr;
+       out = out1;
+       do {
+               jp = getjob(*argv, 1);
+               if (mode == FORK_BG) {
+                       set_curjob(jp, CUR_RUNNING);
+                       outfmt(out, "[%d] ", jobno(jp));
+               }
+               outstr(jp->ps->cmd, out);
+               showpipe(jp, out);
+               retval = restartjob(jp, mode);
+       } while (*argv && *++argv);
+       return retval;
+}
+
+int bgcmd(int argc, char **argv)
+#ifdef HAVE_ALIAS_ATTRIBUTE
+       __attribute__((__alias__("fgcmd")));
+#else
+{
+       return fgcmd(argc, argv);
+}
+#endif
+
+
+STATIC int
+restartjob(struct job *jp, int mode)
+{
+       struct procstat *ps;
+       int i;
+       int status;
+       pid_t pgid;
+
+       INTOFF;
+       if (jp->state == JOBDONE)
+               goto out;
+       jp->state = JOBRUNNING;
+       pgid = jp->ps->pid;
+       if (mode == FORK_FG)
+               xtcsetpgrp(ttyfd, pgid);
+       killpg(pgid, SIGCONT);
+       ps = jp->ps;
+       i = jp->nprocs;
+       do {
+               if (WIFSTOPPED(ps->status)) {
+                       ps->status = -1;
+               }
+       } while (ps++, --i);
+out:
+       status = (mode == FORK_FG) ? waitforjob(jp) : 0;
+       INTON;
+       return status;
+}
+#endif
+
+STATIC int
+sprint_status(char *s, int status, int sigonly)
+{
+       int col;
+       int st;
+
+       col = 0;
+       st = WEXITSTATUS(status);
+       if (!WIFEXITED(status)) {
+#if JOBS
+               st = WSTOPSIG(status);
+               if (!WIFSTOPPED(status))
+#endif
+                       st = WTERMSIG(status);
+               if (sigonly) {
+                       if (st == SIGINT || st == SIGPIPE)
+                               goto out;
+#if JOBS
+                       if (WIFSTOPPED(status))
+                               goto out;
+#endif
+               }
+               col = fmtstr(s, 32, strsignal(st));
+#ifdef WCOREDUMP
+               if (WCOREDUMP(status)) {
+                       col += fmtstr(s + col, 16, " (core dumped)");
+               }
+#endif
+       } else if (!sigonly) {
+               if (st)
+                       col = fmtstr(s, 16, "Done(%d)", st);
+               else
+                       col = fmtstr(s, 16, "Done");
+       }
+
+out:
+       return col;
+}
+
+static void
+showjob(struct output *out, struct job *jp, int mode)
+{
+       struct procstat *ps;
+       struct procstat *psend;
+       int col;
+       int indent;
+       char s[80];
+
+       ps = jp->ps;
+
+       if (mode & SHOW_PGID) {
+               /* just output process (group) id of pipeline */
+               outfmt(out, "%d\n", ps->pid);
+               return;
+       }
+
+       col = fmtstr(s, 16, "[%d]   ", jobno(jp));
+       indent = col;
+
+       if (jp == curjob)
+               s[col - 2] = '+';
+       else if (curjob && jp == curjob->prev_job)
+               s[col - 2] = '-';
+
+       if (mode & SHOW_PID)
+               col += fmtstr(s + col, 16, "%d ", ps->pid);
+
+       psend = ps + jp->nprocs;
+
+       if (jp->state == JOBRUNNING) {
+               scopy("Running", s + col);
+               col += strlen("Running");
+       } else {
+               int status = psend[-1].status;
+#if JOBS
+               if (jp->state == JOBSTOPPED)
+                       status = jp->stopstatus;
+#endif
+               col += sprint_status(s + col, status, 0);
+       }
+
+       goto start;
+
+       do {
+               /* for each process */
+               col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
+
+start:
+               outfmt(
+                       out, "%s%*c%s",
+                       s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
+               );
+               if (!(mode & SHOW_PID)) {
+                       showpipe(jp, out);
+                       break;
+               }
+               if (++ps == psend) {
+                       outcslow('\n', out);
+                       break;
+               }
+       } while (1);
+
+       jp->changed = 0;
+
+       if (jp->state == JOBDONE) {
+               TRACE(("showjob: freeing job %d\n", jobno(jp)));
+               freejob(jp);
+       }
+}
+
+
+int
+jobscmd(int argc, char **argv)
+{
+       int mode, m;
+       struct output *out;
+
+       mode = 0;
+       while ((m = nextopt("lp")))
+               if (m == 'l')
+                       mode = SHOW_PID;
+               else
+                       mode = SHOW_PGID;
+
+       out = out1;
+       argv = argptr;
+       if (*argv)
+               do
+                       showjob(out, getjob(*argv,0), mode);
+               while (*++argv);
+       else
+               showjobs(out, mode);
+
+       return 0;
+}
+
+
+/*
+ * Print a list of jobs.  If "change" is nonzero, only print jobs whose
+ * statuses have changed since the last call to showjobs.
+ */
+
+void
+showjobs(struct output *out, int mode)
+{
+       struct job *jp;
+
+       TRACE(("showjobs(%x) called\n", mode));
+
+       /* If not even one one job changed, there is nothing to do */
+       while (dowait(DOWAIT_NORMAL, NULL) > 0)
+               continue;
+
+       for (jp = curjob; jp; jp = jp->prev_job) {
+               if (!(mode & SHOW_CHANGED) || jp->changed)
+                       showjob(out, jp, mode);
+       }
+}
+
+/*
+ * Mark a job structure as unused.
+ */
+
+STATIC void
+freejob(struct job *jp)
+{
+       struct procstat *ps;
+       int i;
+
+       INTOFF;
+       for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
+               if (ps->cmd != nullstr)
+                       ckfree(ps->cmd);
+       }
+       if (jp->ps != &jp->ps0)
+               ckfree(jp->ps);
+       jp->used = 0;
+       set_curjob(jp, CUR_DELETE);
+       INTON;
+}
+
+
+
+int
+waitcmd(int argc, char **argv)
+{
+       struct job *job;
+       int retval;
+       struct job *jp;
+
+       nextopt(nullstr);
+       retval = 0;
+
+       argv = argptr;
+       if (!*argv) {
+               /* wait for all jobs */
+               for (;;) {
+                       jp = curjob;
+                       while (1) {
+                               if (!jp) {
+                                       /* no running procs */
+                                       goto out;
+                               }
+                               if (jp->state == JOBRUNNING)
+                                       break;
+                               jp->waited = 1;
+                               jp = jp->prev_job;
+                       }
+                       if (dowait(DOWAIT_WAITCMD, 0) <= 0)
+                               goto sigout;
+               }
+       }
+
+       retval = 127;
+       do {
+               if (**argv != '%') {
+                       pid_t pid = number(*argv);
+                       job = curjob;
+                       goto start;
+                       do {
+                               if (job->ps[job->nprocs - 1].pid == pid)
+                                       break;
+                               job = job->prev_job;
+start:
+                               if (!job)
+                                       goto repeat;
+                       } while (1);
+               } else
+                       job = getjob(*argv, 0);
+               /* loop until process terminated or stopped */
+               while (job->state == JOBRUNNING)
+                       if (dowait(DOWAIT_WAITCMD, 0) <= 0)
+                               goto sigout;
+               job->waited = 1;
+               retval = getstatus(job);
+repeat:
+               ;
+       } while (*++argv);
+
+out:
+       return retval;
+
+sigout:
+       retval = 128 + pendingsigs;
+       goto out;
+}
+
+
+
+/*
+ * Convert a job name to a job structure.
+ */
+
+STATIC struct job *
+getjob(const char *name, int getctl)
+{
+       struct job *jp;
+       struct job *found;
+       const char *err_msg = "No such job: %s";
+       unsigned num;
+       int c;
+       const char *p;
+       char *(*match)(const char *, const char *);
+
+       jp = curjob;
+       p = name;
+       if (!p)
+               goto currentjob;
+
+       if (*p != '%')
+               goto err;
+
+       c = *++p;
+       if (!c)
+               goto currentjob;
+
+       if (!p[1]) {
+               if (c == '+' || c == '%') {
+currentjob:
+                       err_msg = "No current job";
+                       goto check;
+               } else if (c == '-') {
+                       if (jp)
+                               jp = jp->prev_job;
+                       err_msg = "No previous job";
+check:
+                       if (!jp)
+                               goto err;
+                       goto gotit;
+               }
+       }
+
+       if (is_number(p)) {
+               num = atoi(p);
+               if (num < njobs) {
+                       jp = jobtab + num - 1;
+                       if (jp->used)
+                               goto gotit;
+                       goto err;
+               }
+       }
+
+       match = prefix;
+       if (*p == '?') {
+               match = strstr;
+               p++;
+       }
+
+       found = 0;
+       while (1) {
+               if (!jp)
+                       goto err;
+               if (match(jp->ps[0].cmd, p)) {
+                       if (found)
+                               goto err;
+                       found = jp;
+                       err_msg = "%s: ambiguous";
+               }
+               jp = jp->prev_job;
+       }
+
+gotit:
+#if JOBS
+       err_msg = "job %s not created under job control";
+       if (getctl && jp->jobctl == 0)
+               goto err;
+#endif
+       return jp;
+err:
+       sh_error(err_msg, name);
+}
+
+
+
+/*
+ * Return a new job structure.
+ * Called with interrupts off.
+ */
+
+struct job *
+makejob(union node *node, int nprocs)
+{
+       int i;
+       struct job *jp;
+
+       for (i = njobs, jp = jobtab ; ; jp++) {
+               if (--i < 0) {
+                       jp = growjobtab();
+                       break;
+               }
+               if (jp->used == 0)
+                       break;
+               if (jp->state != JOBDONE || !jp->waited)
+                       continue;
+               if (jobctl)
+                       continue;
+               freejob(jp);
+               break;
+       }
+       memset(jp, 0, sizeof(*jp));
+#if JOBS
+       if (jobctl)
+               jp->jobctl = 1;
+#endif
+       jp->prev_job = curjob;
+       curjob = jp;
+       jp->used = 1;
+       jp->ps = &jp->ps0;
+       if (nprocs > 1) {
+               jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
+       }
+       TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
+           jobno(jp)));
+       return jp;
+}
+
+STATIC struct job *
+growjobtab(void)
+{
+       size_t len;
+       ptrdiff_t offset;
+       struct job *jp, *jq;
+
+       len = njobs * sizeof(*jp);
+       jq = jobtab;
+       jp = ckrealloc(jq, len + 4 * sizeof(*jp));
+
+       offset = (char *)jp - (char *)jq;
+       if (offset) {
+               /* Relocate pointers */
+               size_t l = len;
+
+               jq = (struct job *)((char *)jq + l);
+               while (l) {
+                       l -= sizeof(*jp);
+                       jq--;
+#define joff(p) ((struct job *)((char *)(p) + l))
+#define jmove(p) (p) = (void *)((char *)(p) + offset)
+                       if (likely(joff(jp)->ps == &jq->ps0))
+                               jmove(joff(jp)->ps);
+                       if (joff(jp)->prev_job)
+                               jmove(joff(jp)->prev_job);
+               }
+               if (curjob)
+                       jmove(curjob);
+#undef joff
+#undef jmove
+       }
+
+       njobs += 4;
+       jobtab = jp;
+       jp = (struct job *)((char *)jp + len);
+       jq = jp + 3;
+       do {
+               jq->used = 0;
+       } while (--jq >= jp);
+       return jp;
+}
+
+
+/*
+ * Fork off a subshell.  If we are doing job control, give the subshell its
+ * own process group.  Jp is a job structure that the job is to be added to.
+ * N is the command that will be evaluated by the child.  Both jp and n may
+ * be NULL.  The mode parameter can be one of the following:
+ *     FORK_FG - Fork off a foreground process.
+ *     FORK_BG - Fork off a background process.
+ *     FORK_NOJOB - Like FORK_FG, but don't give the process its own
+ *                  process group even if job control is on.
+ *
+ * When job control is turned off, background processes have their standard
+ * input redirected to /dev/null (except for the second and later processes
+ * in a pipeline).
+ *
+ * Called with interrupts off.
+ */
+
+STATIC inline void
+forkchild(struct job *jp, union node *n, int mode)
+{
+       int oldlvl;
+
+       TRACE(("Child shell %d\n", getpid()));
+       oldlvl = shlvl;
+       shlvl++;
+
+       closescript();
+       clear_traps();
+#if JOBS
+       /* do job control only in root shell */
+       jobctl = 0;
+       if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
+               pid_t pgrp;
+
+               if (jp->nprocs == 0)
+                       pgrp = getpid();
+               else
+                       pgrp = jp->ps[0].pid;
+               /* This can fail because we are doing it in the parent also */
+               (void)setpgid(0, pgrp);
+               if (mode == FORK_FG)
+                       xtcsetpgrp(ttyfd, pgrp);
+               setsignal(SIGTSTP);
+               setsignal(SIGTTOU);
+       } else
+#endif
+       if (mode == FORK_BG) {
+               ignoresig(SIGINT);
+               ignoresig(SIGQUIT);
+               if (jp->nprocs == 0) {
+                       close(0);
+                       if (open(_PATH_DEVNULL, O_RDONLY) != 0)
+                               sh_error("Can't open %s", _PATH_DEVNULL);
+               }
+       }
+       if (!oldlvl && iflag) {
+               setsignal(SIGINT);
+               setsignal(SIGQUIT);
+               setsignal(SIGTERM);
+       }
+       for (jp = curjob; jp; jp = jp->prev_job)
+               freejob(jp);
+       jobless = 0;
+}
+
+STATIC inline void
+forkparent(struct job *jp, union node *n, int mode, pid_t pid)
+{
+       TRACE(("In parent shell:  child = %d\n", pid));
+       if (!jp) {
+               while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
+               jobless++;
+               return;
+       }
+#if JOBS
+       if (mode != FORK_NOJOB && jp->jobctl) {
+               int pgrp;
+
+               if (jp->nprocs == 0)
+                       pgrp = pid;
+               else
+                       pgrp = jp->ps[0].pid;
+               /* This can fail because we are doing it in the child also */
+               (void)setpgid(pid, pgrp);
+       }
+#endif
+       if (mode == FORK_BG) {
+               backgndpid = pid;               /* set $! */
+               set_curjob(jp, CUR_RUNNING);
+       }
+       if (jp) {
+               struct procstat *ps = &jp->ps[jp->nprocs++];
+               ps->pid = pid;
+               ps->status = -1;
+               ps->cmd = nullstr;
+               if (jobctl && n)
+                       ps->cmd = commandtext(n);
+       }
+}
+
+int
+forkshell(struct job *jp, union node *n, int mode)
+{
+       int pid;
+
+       TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
+       pid = fork();
+       if (pid < 0) {
+               TRACE(("Fork failed, errno=%d", errno));
+               if (jp)
+                       freejob(jp);
+               sh_error("Cannot fork");
+       }
+       if (pid == 0)
+               forkchild(jp, n, mode);
+       else
+               forkparent(jp, n, mode, pid);
+       return pid;
+}
+
+/*
+ * Wait for job to finish.
+ *
+ * Under job control we have the problem that while a child process is
+ * running interrupts generated by the user are sent to the child but not
+ * to the shell.  This means that an infinite loop started by an inter-
+ * active user may be hard to kill.  With job control turned off, an
+ * interactive user may place an interactive program inside a loop.  If
+ * the interactive program catches interrupts, the user doesn't want
+ * these interrupts to also abort the loop.  The approach we take here
+ * is to have the shell ignore interrupt signals while waiting for a
+ * forground process to terminate, and then send itself an interrupt
+ * signal if the child process was terminated by an interrupt signal.
+ * Unfortunately, some programs want to do a bit of cleanup and then
+ * exit on interrupt; unless these processes terminate themselves by
+ * sending a signal to themselves (instead of calling exit) they will
+ * confuse this approach.
+ *
+ * Called with interrupts off.
+ */
+
+int
+waitforjob(struct job *jp)
+{
+       int st;
+
+       TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
+       while (jp->state == JOBRUNNING) {
+               dowait(DOWAIT_BLOCK, jp);
+       }
+       st = getstatus(jp);
+#if JOBS
+       if (jp->jobctl) {
+               xtcsetpgrp(ttyfd, rootpid);
+               /*
+                * This is truly gross.
+                * If we're doing job control, then we did a TIOCSPGRP which
+                * caused us (the shell) to no longer be in the controlling
+                * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
+                * intuit from the subprocess exit status whether a SIGINT
+                * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
+                */
+               if (jp->sigint)
+                       raise(SIGINT);
+       }
+#endif
+       if (! JOBS || jp->state == JOBDONE)
+               freejob(jp);
+       return st;
+}
+
+
+
+/*
+ * Wait for a process to terminate.
+ */
+
+STATIC int
+dowait(int block, struct job *job)
+{
+       int pid;
+       int status;
+       struct job *jp;
+       struct job *thisjob = NULL;
+       int state;
+
+       INTOFF;
+       TRACE(("dowait(%d) called\n", block));
+       pid = waitproc(block, &status);
+       TRACE(("wait returns pid %d, status=%d\n", pid, status));
+       if (pid <= 0)
+               goto out;
+
+       for (jp = curjob; jp; jp = jp->prev_job) {
+               struct procstat *sp;
+               struct procstat *spend;
+               if (jp->state == JOBDONE)
+                       continue;
+               state = JOBDONE;
+               spend = jp->ps + jp->nprocs;
+               sp = jp->ps;
+               do {
+                       if (sp->pid == pid) {
+                               TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
+                               sp->status = status;
+                               thisjob = jp;
+                       }
+                       if (sp->status == -1)
+                               state = JOBRUNNING;
+#if JOBS
+                       if (state == JOBRUNNING)
+                               continue;
+                       if (WIFSTOPPED(sp->status)) {
+                               jp->stopstatus = sp->status;
+                               state = JOBSTOPPED;
+                       }
+#endif
+               } while (++sp < spend);
+               if (thisjob)
+                       goto gotjob;
+       }
+       if (!JOBS || !WIFSTOPPED(status))
+               jobless--;
+       goto out;
+
+gotjob:
+       if (state != JOBRUNNING) {
+               thisjob->changed = 1;
+
+               if (thisjob->state != state) {
+                       TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
+                       thisjob->state = state;
+#if JOBS
+                       if (state == JOBSTOPPED) {
+                               set_curjob(thisjob, CUR_STOPPED);
+                       }
+#endif
+               }
+       }
+
+out:
+       INTON;
+
+       if (thisjob && thisjob == job) {
+               char s[48 + 1];
+               int len;
+
+               len = sprint_status(s, status, 1);
+               if (len) {
+                       s[len] = '\n';
+                       s[len + 1] = 0;
+                       outstr(s, out2);
+               }
+       }
+       return pid;
+}
+
+
+
+/*
+ * Do a wait system call.  If job control is compiled in, we accept
+ * stopped processes.  If block is zero, we return a value of zero
+ * rather than blocking.
+ *
+ * System V doesn't have a non-blocking wait system call.  It does
+ * have a SIGCLD signal that is sent to a process when one of it's
+ * children dies.  The obvious way to use SIGCLD would be to install
+ * a handler for SIGCLD which simply bumped a counter when a SIGCLD
+ * was received, and have waitproc bump another counter when it got
+ * the status of a process.  Waitproc would then know that a wait
+ * system call would not block if the two counters were different.
+ * This approach doesn't work because if a process has children that
+ * have not been waited for, System V will send it a SIGCLD when it
+ * installs a signal handler for SIGCLD.  What this means is that when
+ * a child exits, the shell will be sent SIGCLD signals continuously
+ * until is runs out of stack space, unless it does a wait call before
+ * restoring the signal handler.  The code below takes advantage of
+ * this (mis)feature by installing a signal handler for SIGCLD and
+ * then checking to see whether it was called.  If there are any
+ * children to be waited for, it will be.
+ *
+ * If neither SYSV nor BSD is defined, we don't implement nonblocking
+ * waits at all.  In this case, the user will not be informed when
+ * a background process until the next time she runs a real program
+ * (as opposed to running a builtin command or just typing return),
+ * and the jobs command may give out of date information.
+ */
+
+#ifdef SYSV
+STATIC int gotsigchild;
+
+STATIC int onsigchild() {
+       gotsigchild = 1;
+}
+#endif
+
+
+STATIC int
+waitproc(int block, int *status)
+{
+       sigset_t mask, oldmask;
+       int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG;
+       int err;
+
+#if JOBS
+       if (jobctl)
+               flags |= WUNTRACED;
+#endif
+
+       do {
+               gotsigchld = 0;
+               err = wait3(status, flags, NULL);
+               if (err || !block)
+                       break;
+
+               block = 0;
+
+               sigfillset(&mask);
+               sigprocmask(SIG_SETMASK, &mask, &oldmask);
+
+               while (!gotsigchld && !pendingsigs)
+                       sigsuspend(&oldmask);
+
+               sigclearmask();
+       } while (gotsigchld);
+
+       return err;
+}
+
+/*
+ * return 1 if there are stopped jobs, otherwise 0
+ */
+int job_warning;
+int
+stoppedjobs(void)
+{
+       struct job *jp;
+       int retval;
+
+       retval = 0;
+       if (job_warning)
+               goto out;
+       jp = curjob;
+       if (jp && jp->state == JOBSTOPPED) {
+               out2str("You have stopped jobs.\n");
+               job_warning = 2;
+               retval++;
+       }
+
+out:
+       return retval;
+}
+
+/*
+ * Return a string identifying a command (to be printed by the
+ * jobs command).
+ */
+
+STATIC char *cmdnextc;
+
+STATIC char *
+commandtext(union node *n)
+{
+       char *name;
+
+       STARTSTACKSTR(cmdnextc);
+       cmdtxt(n);
+       name = stackblock();
+       TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
+       return savestr(name);
+}
+
+
+STATIC void
+cmdtxt(union node *n)
+{
+       union node *np;
+       struct nodelist *lp;
+       const char *p;
+       char s[2];
+
+       if (!n)
+               return;
+       switch (n->type) {
+       default:
+#if DEBUG
+               abort();
+#endif
+       case NPIPE:
+               lp = n->npipe.cmdlist;
+               for (;;) {
+                       cmdtxt(lp->n);
+                       lp = lp->next;
+                       if (!lp)
+                               break;
+                       cmdputs(" | ");
+               }
+               break;
+       case NSEMI:
+               p = "; ";
+               goto binop;
+       case NAND:
+               p = " && ";
+               goto binop;
+       case NOR:
+               p = " || ";
+binop:
+               cmdtxt(n->nbinary.ch1);
+               cmdputs(p);
+               n = n->nbinary.ch2;
+               goto donode;
+       case NREDIR:
+       case NBACKGND:
+               n = n->nredir.n;
+               goto donode;
+       case NNOT:
+               cmdputs("!");
+               n = n->nnot.com;
+donode:
+               cmdtxt(n);
+               break;
+       case NIF:
+               cmdputs("if ");
+               cmdtxt(n->nif.test);
+               cmdputs("; then ");
+               if (n->nif.elsepart) {
+                       cmdtxt(n->nif.ifpart);
+                       cmdputs("; else ");
+                       n = n->nif.elsepart;
+               } else {
+                       n = n->nif.ifpart;
+               }
+               p = "; fi";
+               goto dotail;
+       case NSUBSHELL:
+               cmdputs("(");
+               n = n->nredir.n;
+               p = ")";
+               goto dotail;
+       case NWHILE:
+               p = "while ";
+               goto until;
+       case NUNTIL:
+               p = "until ";
+until:
+               cmdputs(p);
+               cmdtxt(n->nbinary.ch1);
+               n = n->nbinary.ch2;
+               p = "; done";
+dodo:
+               cmdputs("; do ");
+dotail:
+               cmdtxt(n);
+               goto dotail2;
+       case NFOR:
+               cmdputs("for ");
+               cmdputs(n->nfor.var);
+               cmdputs(" in ");
+               cmdlist(n->nfor.args, 1);
+               n = n->nfor.body;
+               p = "; done";
+               goto dodo;
+       case NDEFUN:
+               cmdputs(n->ndefun.text);
+               p = "() { ... }";
+               goto dotail2;
+       case NCMD:
+               cmdlist(n->ncmd.args, 1);
+               cmdlist(n->ncmd.redirect, 0);
+               break;
+       case NARG:
+               p = n->narg.text;
+dotail2:
+               cmdputs(p);
+               break;
+       case NHERE:
+       case NXHERE:
+               p = "<<...";
+               goto dotail2;
+       case NCASE:
+               cmdputs("case ");
+               cmdputs(n->ncase.expr->narg.text);
+               cmdputs(" in ");
+               for (np = n->ncase.cases; np; np = np->nclist.next) {
+                       cmdtxt(np->nclist.pattern);
+                       cmdputs(") ");
+                       cmdtxt(np->nclist.body);
+                       cmdputs(";; ");
+               }
+               p = "esac";
+               goto dotail2;
+       case NTO:
+               p = ">";
+               goto redir;
+       case NCLOBBER:
+               p = ">|";
+               goto redir;
+       case NAPPEND:
+               p = ">>";
+               goto redir;
+       case NTOFD:
+               p = ">&";
+               goto redir;
+       case NFROM:
+               p = "<";
+               goto redir;
+       case NFROMFD:
+               p = "<&";
+               goto redir;
+       case NFROMTO:
+               p = "<>";
+redir:
+               s[0] = n->nfile.fd + '0';
+               s[1] = '\0';
+               cmdputs(s);
+               cmdputs(p);
+               if (n->type == NTOFD || n->type == NFROMFD) {
+                       s[0] = n->ndup.dupfd + '0';
+                       p = s;
+                       goto dotail2;
+               } else {
+                       n = n->nfile.fname;
+                       goto donode;
+               }
+       }
+}
+
+STATIC void
+cmdlist(union node *np, int sep)
+{
+       for (; np; np = np->narg.next) {
+               if (!sep)
+                       cmdputs(spcstr);
+               cmdtxt(np);
+               if (sep && np->narg.next)
+                       cmdputs(spcstr);
+       }
+}
+
+
+STATIC void
+cmdputs(const char *s)
+{
+       const char *p, *str;
+       char cc[2] = " ";
+       char *nextc;
+       signed char c;
+       int subtype = 0;
+       int quoted = 0;
+       static const char vstype[VSTYPE + 1][4] = {
+               "", "}", "-", "+", "?", "=",
+               "%", "%%", "#", "##",
+       };
+
+       nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
+       p = s;
+       while ((c = *p++) != 0) {
+               str = 0;
+               switch (c) {
+               case CTLESC:
+                       c = *p++;
+                       break;
+               case CTLVAR:
+                       subtype = *p++;
+                       if ((subtype & VSTYPE) == VSLENGTH)
+                               str = "${#";
+                       else
+                               str = "${";
+                       goto dostr;
+               case CTLENDVAR:
+                       str = "\"}" + !(quoted & 1);
+                       quoted >>= 1;
+                       subtype = 0;
+                       goto dostr;
+               case CTLBACKQ:
+                       str = "$(...)";
+                       goto dostr;
+               case CTLARI:
+                       str = "$((";
+                       goto dostr;
+               case CTLENDARI:
+                       str = "))";
+                       goto dostr;
+               case CTLQUOTEMARK:
+                       quoted ^= 1;
+                       c = '"';
+                       break;
+               case '=':
+                       if (subtype == 0)
+                               break;
+                       if ((subtype & VSTYPE) != VSNORMAL)
+                               quoted <<= 1;
+                       str = vstype[subtype & VSTYPE];
+                       if (subtype & VSNUL)
+                               c = ':';
+                       else
+                               goto checkstr;
+                       break;
+               case '\'':
+               case '\\':
+               case '"':
+               case '$':
+                       /* These can only happen inside quotes */
+                       cc[0] = c;
+                       str = cc;
+                       c = '\\';
+                       break;
+               default:
+                       break;
+               }
+               USTPUTC(c, nextc);
+checkstr:
+               if (!str)
+                       continue;
+dostr:
+               while ((c = *str++)) {
+                       USTPUTC(c, nextc);
+               }
+       }
+       if (quoted & 1) {
+               USTPUTC('"', nextc);
+       }
+       *nextc = 0;
+       cmdnextc = nextc;
+}
+
+
+STATIC void
+showpipe(struct job *jp, struct output *out)
+{
+       struct procstat *sp;
+       struct procstat *spend;
+
+       spend = jp->ps + jp->nprocs;
+       for (sp = jp->ps + 1; sp < spend; sp++)
+               outfmt(out, " | %s", sp->cmd);
+       outcslow('\n', out);
+       flushall();
+}
+
+
+#if JOBS
+STATIC void
+xtcsetpgrp(int fd, pid_t pgrp)
+{
+       if (tcsetpgrp(fd, pgrp))
+               sh_error("Cannot set tty process group (%s)", strerror(errno));
+}
+#endif
+
+
+STATIC int
+getstatus(struct job *job) {
+       int status;
+       int retval;
+
+       status = job->ps[job->nprocs - 1].status;
+       retval = WEXITSTATUS(status);
+       if (!WIFEXITED(status)) {
+#if JOBS
+               retval = WSTOPSIG(status);
+               if (!WIFSTOPPED(status))
+#endif
+               {
+                       /* XXX: limits number of signals */
+                       retval = WTERMSIG(status);
+#if JOBS
+                       if (retval == SIGINT)
+                               job->sigint = 1;
+#endif
+               }
+               retval += 128;
+       }
+       TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
+               jobno(job), job->nprocs, status, retval));
+       return retval;
+}
diff --git a/src/jobs.h b/src/jobs.h
new file mode 100644 (file)
index 0000000..953ee87
--- /dev/null
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)jobs.h      8.2 (Berkeley) 5/4/95
+ */
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+/* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
+#define FORK_FG 0
+#define FORK_BG 1
+#define FORK_NOJOB 2
+
+/* mode flags for showjob(s) */
+#define        SHOW_PGID       0x01    /* only show pgid - for jobs -p */
+#define        SHOW_PID        0x04    /* include process pid */
+#define        SHOW_CHANGED    0x08    /* only jobs whose state has changed */
+
+
+/*
+ * A job structure contains information about a job.  A job is either a
+ * single process or a set of processes contained in a pipeline.  In the
+ * latter case, pidlist will be non-NULL, and will point to a -1 terminated
+ * array of pids.
+ */
+
+struct procstat {
+       pid_t   pid;            /* process id */
+       int     status;         /* last process status from wait() */
+       char    *cmd;           /* text of command being run */
+};
+
+struct job {
+       struct procstat ps0;    /* status of process */
+       struct procstat *ps;    /* status or processes when more than one */
+#if JOBS
+       int stopstatus;         /* status of a stopped job */
+#endif
+       uint32_t
+               nprocs: 16,     /* number of processes */
+               state: 8,
+#define        JOBRUNNING      0       /* at least one proc running */
+#define        JOBSTOPPED      1       /* all procs are stopped */
+#define        JOBDONE         2       /* all procs are completed */
+#if JOBS
+               sigint: 1,      /* job was killed by SIGINT */
+               jobctl: 1,      /* job running under job control */
+#endif
+               waited: 1,      /* true if this entry has been waited for */
+               used: 1,        /* true if this entry is in used */
+               changed: 1;     /* true if status has changed */
+       struct job *prev_job;   /* previous job */
+};
+
+extern pid_t backgndpid;       /* pid of last background process */
+extern int job_warning;                /* user was warned about stopped jobs */
+#if JOBS
+extern int jobctl;             /* true if doing job control */
+#else
+#define jobctl 0
+#endif
+
+void setjobctl(int);
+int killcmd(int, char **);
+int fgcmd(int, char **);
+int bgcmd(int, char **);
+int jobscmd(int, char **);
+struct output;
+void showjobs(struct output *, int);
+int waitcmd(int, char **);
+struct job *makejob(union node *, int);
+int forkshell(struct job *, union node *, int);
+int waitforjob(struct job *);
+int stoppedjobs(void);
+
+#if ! JOBS
+#define setjobctl(on) ((void)(on))     /* do nothing */
+#endif
diff --git a/src/machdep.h b/src/machdep.h
new file mode 100644 (file)
index 0000000..f2ff0ad
--- /dev/null
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)machdep.h   8.2 (Berkeley) 5/4/95
+ */
+
+/*
+ * Most machines require the value returned from malloc to be aligned
+ * in some way.  The following macro will get this right on many machines.
+ */
+
+#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
+/*
+ * It appears that grabstackstr() will barf with such alignments
+ * because stalloc() will return a string allocated in a new stackblock.
+ */
+#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
diff --git a/src/mail.c b/src/mail.c
new file mode 100644 (file)
index 0000000..02e07f7
--- /dev/null
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Routines to check for mail.  (Perhaps make part of main.c?)
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#include "nodes.h"
+#include "exec.h"      /* defines padvance() */
+#include "var.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mail.h"
+#include "mystring.h"
+
+
+#define MAXMBOXES 10
+
+/* times of mailboxes */
+static time_t mailtime[MAXMBOXES];
+/* Set if MAIL or MAILPATH is changed. */
+static int changed;
+
+
+
+/*
+ * Print appropriate message(s) if mail has arrived.  If changed is set,
+ * then the value of MAIL has changed, so we just update the values.
+ */
+
+void
+chkmail(void)
+{
+       const char *mpath;
+       char *p;
+       char *q;
+       time_t *mtp;
+       struct stackmark smark;
+       struct stat64 statb;
+
+       setstackmark(&smark);
+       mpath = mpathset() ? mpathval() : mailval();
+       for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
+               p = padvance(&mpath, nullstr);
+               if (p == NULL)
+                       break;
+               if (*p == '\0')
+                       continue;
+               for (q = p ; *q ; q++);
+#ifdef DEBUG
+               if (q[-1] != '/')
+                       abort();
+#endif
+               q[-1] = '\0';                   /* delete trailing '/' */
+               if (stat64(p, &statb) < 0) {
+                       *mtp = 0;
+                       continue;
+               }
+               if (!changed && statb.st_mtime != *mtp) {
+                       outfmt(
+                               &errout, snlfmt,
+                               pathopt ? pathopt : "you have mail"
+                       );
+               }
+               *mtp = statb.st_mtime;
+       }
+       changed = 0;
+       popstackmark(&smark);
+}
+
+
+void
+changemail(const char *val)
+{
+       changed++;
+}
diff --git a/src/mail.h b/src/mail.h
new file mode 100644 (file)
index 0000000..3c6b21d
--- /dev/null
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)mail.h      8.2 (Berkeley) 5/4/95
+ */
+
+void chkmail(void);
+void changemail(const char *);
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..af987c6
--- /dev/null
@@ -0,0 +1,346 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+#include "shell.h"
+#include "main.h"
+#include "mail.h"
+#include "options.h"
+#include "output.h"
+#include "parser.h"
+#include "nodes.h"
+#include "expand.h"
+#include "eval.h"
+#include "jobs.h"
+#include "input.h"
+#include "trap.h"
+#include "var.h"
+#include "show.h"
+#include "memalloc.h"
+#include "error.h"
+#include "init.h"
+#include "mystring.h"
+#include "exec.h"
+#include "cd.h"
+
+#ifdef HETIO
+#include "hetio.h"
+#endif
+
+#define PROFILE 0
+
+int rootpid;
+int shlvl;
+#ifdef __GLIBC__
+int *dash_errno;
+#endif
+#if PROFILE
+short profile_buf[16384];
+extern int etext();
+#endif
+
+STATIC void read_profile(const char *);
+STATIC char *find_dot_file(char *);
+static int cmdloop(int);
+int main(int, char **);
+
+/*
+ * Main routine.  We initialize things, parse the arguments, execute
+ * profiles if we're a login shell, and then call cmdloop to execute
+ * commands.  The setjmp call sets up the location to jump to when an
+ * exception occurs.  When an exception occurs the variable "state"
+ * is used to figure out how far we had gotten.
+ */
+
+int
+main(int argc, char **argv)
+{
+       char *shinit;
+       volatile int state;
+       struct jmploc jmploc;
+       struct stackmark smark;
+       int login;
+
+#ifdef __GLIBC__
+       dash_errno = __errno_location();
+#endif
+
+#if PROFILE
+       monitor(4, etext, profile_buf, sizeof profile_buf, 50);
+#endif
+       state = 0;
+       if (unlikely(setjmp(jmploc.loc))) {
+               int e;
+               int s;
+
+               reset();
+
+               e = exception;
+
+               s = state;
+               if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
+                       exitshell();
+
+               if (e == EXINT
+#if ATTY
+                && (! attyset() || equal(termval(), "emacs"))
+#endif
+                ) {
+                       out2c('\n');
+#ifdef FLUSHERR
+                       flushout(out2);
+#endif
+               }
+               popstackmark(&smark);
+               FORCEINTON;                             /* enable interrupts */
+               if (s == 1)
+                       goto state1;
+               else if (s == 2)
+                       goto state2;
+               else if (s == 3)
+                       goto state3;
+               else
+                       goto state4;
+       }
+       handler = &jmploc;
+#ifdef DEBUG
+       opentrace();
+       trputs("Shell args:  ");  trargs(argv);
+#endif
+       rootpid = getpid();
+       init();
+       setstackmark(&smark);
+       login = procargs(argc, argv);
+       if (login) {
+               state = 1;
+               read_profile("/etc/profile");
+state1:
+               state = 2;
+               read_profile("$HOME/.profile");
+       }
+state2:
+       state = 3;
+       if (
+#ifndef linux
+               getuid() == geteuid() && getgid() == getegid() &&
+#endif
+               iflag
+       ) {
+               if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
+                       read_profile(shinit);
+               }
+       }
+       popstackmark(&smark);
+state3:
+       state = 4;
+       if (minusc)
+               evalstring(minusc, sflag ? 0 : EV_EXIT);
+
+       if (sflag || minusc == NULL) {
+state4:        /* XXX ??? - why isn't this before the "if" statement */
+               cmdloop(1);
+       }
+#if PROFILE
+       monitor(0);
+#endif
+#if GPROF
+       {
+               extern void _mcleanup(void);
+               _mcleanup();
+       }
+#endif
+       exitshell();
+       /* NOTREACHED */
+}
+
+
+/*
+ * Read and execute commands.  "Top" is nonzero for the top level command
+ * loop; it turns on prompting if the shell is interactive.
+ */
+
+static int
+cmdloop(int top)
+{
+       union node *n;
+       struct stackmark smark;
+       int inter;
+       int status = 0;
+       int numeof = 0;
+
+       TRACE(("cmdloop(%d) called\n", top));
+#ifdef HETIO
+       if(iflag && top)
+               hetio_init();
+#endif
+       for (;;) {
+               int skip;
+
+               setstackmark(&smark);
+               if (jobctl)
+                       showjobs(out2, SHOW_CHANGED);
+               inter = 0;
+               if (iflag && top) {
+                       inter++;
+                       chkmail();
+               }
+               n = parsecmd(inter);
+               /* showtree(n); DEBUG */
+               if (n == NEOF) {
+                       if (!top || numeof >= 50)
+                               break;
+                       if (!stoppedjobs()) {
+                               if (!Iflag)
+                                       break;
+                               out2str("\nUse \"exit\" to leave shell.\n");
+                       }
+                       numeof++;
+               } else if (nflag == 0) {
+                       job_warning = (job_warning == 2) ? 1 : 0;
+                       numeof = 0;
+                       evaltree(n, 0);
+                       status = exitstatus;
+               }
+               popstackmark(&smark);
+
+               skip = evalskip;
+               if (skip) {
+                       evalskip = 0;
+                       break;
+               }
+       }
+
+       return status;
+}
+
+
+
+/*
+ * Read /etc/profile or .profile.  Return on error.
+ */
+
+STATIC void
+read_profile(const char *name)
+{
+       name = expandstr(name);
+       if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
+               return;
+
+       cmdloop(0);
+       popfile();
+}
+
+
+
+/*
+ * Read a file containing shell functions.
+ */
+
+void
+readcmdfile(char *name)
+{
+       setinputfile(name, INPUT_PUSH_FILE);
+       cmdloop(0);
+       popfile();
+}
+
+
+
+/*
+ * Take commands from a file.  To be compatible we should do a path
+ * search for the file, which is necessary to find sub-commands.
+ */
+
+
+STATIC char *
+find_dot_file(char *basename)
+{
+       char *fullname;
+       const char *path = pathval();
+       struct stat statb;
+
+       /* don't try this for absolute or relative paths */
+       if (strchr(basename, '/'))
+               return basename;
+
+       while ((fullname = padvance(&path, basename)) != NULL) {
+               if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
+                       /*
+                        * Don't bother freeing here, since it will
+                        * be freed by the caller.
+                        */
+                       return fullname;
+               }
+               stunalloc(fullname);
+       }
+
+       /* not found in the PATH */
+       sh_error("%s: not found", basename);
+       /* NOTREACHED */
+}
+
+int
+dotcmd(int argc, char **argv)
+{
+       int status = 0;
+
+       if (argc >= 2) {                /* That's what SVR2 does */
+               char *fullname;
+
+               fullname = find_dot_file(argv[1]);
+               setinputfile(fullname, INPUT_PUSH_FILE);
+               commandname = fullname;
+               status = cmdloop(0);
+               popfile();
+       }
+       return status;
+}
+
+
+int
+exitcmd(int argc, char **argv)
+{
+       if (stoppedjobs())
+               return 0;
+       if (argc > 1)
+               exitstatus = number(argv[1]);
+       exraise(EXEXIT);
+       /* NOTREACHED */
+}
diff --git a/src/main.h b/src/main.h
new file mode 100644 (file)
index 0000000..19e4983
--- /dev/null
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)main.h      8.2 (Berkeley) 5/4/95
+ */
+
+#include <errno.h>
+
+/* pid of main shell */
+extern int rootpid;
+/* shell level: 0 for the main shell, 1 for its children, and so on */
+extern int shlvl;
+#define rootshell (!shlvl)
+
+#ifdef __GLIBC__
+/* glibc sucks */
+extern int *dash_errno;
+#undef errno
+#define errno (*dash_errno)
+#endif
+
+void readcmdfile(char *);
+int dotcmd(int, char **);
+int exitcmd(int, char **);
diff --git a/src/memalloc.c b/src/memalloc.c
new file mode 100644 (file)
index 0000000..d8e4413
--- /dev/null
@@ -0,0 +1,302 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "shell.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "machdep.h"
+#include "mystring.h"
+#include "system.h"
+
+/*
+ * Like malloc, but returns an error when out of space.
+ */
+
+pointer
+ckmalloc(size_t nbytes)
+{
+       pointer p;
+
+       p = malloc(nbytes);
+       if (p == NULL)
+               sh_error("Out of space");
+       return p;
+}
+
+
+/*
+ * Same for realloc.
+ */
+
+pointer
+ckrealloc(pointer p, size_t nbytes)
+{
+       p = realloc(p, nbytes);
+       if (p == NULL)
+               sh_error("Out of space");
+       return p;
+}
+
+
+/*
+ * Make a copy of a string in safe storage.
+ */
+
+char *
+savestr(const char *s)
+{
+       char *p = strdup(s);
+       if (!p)
+               sh_error("Out of space");
+       return p;
+}
+
+
+/*
+ * Parse trees for commands are allocated in lifo order, so we use a stack
+ * to make this more efficient, and also to avoid all sorts of exception
+ * handling code to handle interrupts in the middle of a parse.
+ *
+ * The size 504 was chosen because the Ultrix malloc handles that size
+ * well.
+ */
+
+/* minimum size of a block */
+#define MINSIZE SHELL_ALIGN(504)
+
+struct stack_block {
+       struct stack_block *prev;
+       char space[MINSIZE];
+};
+
+struct stack_block stackbase;
+struct stack_block *stackp = &stackbase;
+char *stacknxt = stackbase.space;
+size_t stacknleft = MINSIZE;
+char *sstrend = stackbase.space + MINSIZE;
+
+pointer
+stalloc(size_t nbytes)
+{
+       char *p;
+       size_t aligned;
+
+       aligned = SHELL_ALIGN(nbytes);
+       if (aligned > stacknleft) {
+               size_t len;
+               size_t blocksize;
+               struct stack_block *sp;
+
+               blocksize = aligned;
+               if (blocksize < MINSIZE)
+                       blocksize = MINSIZE;
+               len = sizeof(struct stack_block) - MINSIZE + blocksize;
+               if (len < blocksize)
+                       sh_error("Out of space");
+               INTOFF;
+               sp = ckmalloc(len);
+               sp->prev = stackp;
+               stacknxt = sp->space;
+               stacknleft = blocksize;
+               sstrend = stacknxt + blocksize;
+               stackp = sp;
+               INTON;
+       }
+       p = stacknxt;
+       stacknxt += aligned;
+       stacknleft -= aligned;
+       return p;
+}
+
+
+void
+stunalloc(pointer p)
+{
+#ifdef DEBUG
+       if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
+               write(2, "stunalloc\n", 10);
+               abort();
+       }
+#endif
+       stacknleft += stacknxt - (char *)p;
+       stacknxt = p;
+}
+
+
+
+void pushstackmark(struct stackmark *mark, size_t len)
+{
+       mark->stackp = stackp;
+       mark->stacknxt = stacknxt;
+       mark->stacknleft = stacknleft;
+       grabstackblock(len);
+}
+
+void setstackmark(struct stackmark *mark)
+{
+       pushstackmark(mark, stacknxt == stackp->space && stackp != &stackbase);
+}
+
+
+void
+popstackmark(struct stackmark *mark)
+{
+       struct stack_block *sp;
+
+       INTOFF;
+       while (stackp != mark->stackp) {
+               sp = stackp;
+               stackp = sp->prev;
+               ckfree(sp);
+       }
+       stacknxt = mark->stacknxt;
+       stacknleft = mark->stacknleft;
+       sstrend = mark->stacknxt + mark->stacknleft;
+       INTON;
+}
+
+
+/*
+ * When the parser reads in a string, it wants to stick the string on the
+ * stack and only adjust the stack pointer when it knows how big the
+ * string is.  Stackblock (defined in stack.h) returns a pointer to a block
+ * of space on top of the stack and stackblocklen returns the length of
+ * this block.  Growstackblock will grow this space by at least one byte,
+ * possibly moving it (like realloc).  Grabstackblock actually allocates the
+ * part of the block that has been used.
+ */
+
+void
+growstackblock(void)
+{
+       size_t newlen;
+
+       newlen = stacknleft * 2;
+       if (newlen < stacknleft)
+               sh_error("Out of space");
+       if (newlen < 128)
+               newlen += 128;
+
+       if (stacknxt == stackp->space && stackp != &stackbase) {
+               struct stack_block *sp;
+               struct stack_block *prevstackp;
+               size_t grosslen;
+
+               INTOFF;
+               sp = stackp;
+               prevstackp = sp->prev;
+               grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
+               sp = ckrealloc((pointer)sp, grosslen);
+               sp->prev = prevstackp;
+               stackp = sp;
+               stacknxt = sp->space;
+               stacknleft = newlen;
+               sstrend = sp->space + newlen;
+               INTON;
+       } else {
+               char *oldspace = stacknxt;
+               int oldlen = stacknleft;
+               char *p = stalloc(newlen);
+
+               /* free the space we just allocated */
+               stacknxt = memcpy(p, oldspace, oldlen);
+               stacknleft += newlen;
+       }
+}
+
+/*
+ * The following routines are somewhat easier to use than the above.
+ * The user declares a variable of type STACKSTR, which may be declared
+ * to be a register.  The macro STARTSTACKSTR initializes things.  Then
+ * the user uses the macro STPUTC to add characters to the string.  In
+ * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
+ * grown as necessary.  When the user is done, she can just leave the
+ * string there and refer to it using stackblock().  Or she can allocate
+ * the space for it using grabstackstr().  If it is necessary to allow
+ * someone else to use the stack temporarily and then continue to grow
+ * the string, the user should use grabstack to allocate the space, and
+ * then call ungrabstr(p) to return to the previous mode of operation.
+ *
+ * USTPUTC is like STPUTC except that it doesn't check for overflow.
+ * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
+ * is space for at least one character.
+ */
+
+void *
+growstackstr(void)
+{
+       size_t len = stackblocksize();
+       growstackblock();
+       return stackblock() + len;
+}
+
+/*
+ * Called from CHECKSTRSPACE.
+ */
+
+char *
+makestrspace(size_t newlen, char *p)
+{
+       size_t len = p - stacknxt;
+       size_t size;
+
+       for (;;) {
+               size_t nleft;
+
+               size = stackblocksize();
+               nleft = size - len;
+               if (nleft >= newlen)
+                       break;
+               growstackblock();
+       }
+       return stackblock() + len;
+}
+
+char *
+stnputs(const char *s, size_t n, char *p)
+{
+       p = makestrspace(n, p);
+       p = mempcpy(p, s, n);
+       return p;
+}
+
+char *
+stputs(const char *s, char *p)
+{
+       return stnputs(s, strlen(s), p);
+}
diff --git a/src/memalloc.h b/src/memalloc.h
new file mode 100644 (file)
index 0000000..4b5be46
--- /dev/null
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)memalloc.h  8.2 (Berkeley) 5/4/95
+ */
+
+#include <stddef.h>
+
+struct stackmark {
+       struct stack_block *stackp;
+       char *stacknxt;
+       size_t stacknleft;
+};
+
+
+extern char *stacknxt;
+extern size_t stacknleft;
+extern char *sstrend;
+
+pointer ckmalloc(size_t);
+pointer ckrealloc(pointer, size_t);
+char *savestr(const char *);
+pointer stalloc(size_t);
+void stunalloc(pointer);
+void pushstackmark(struct stackmark *mark, size_t len);
+void setstackmark(struct stackmark *);
+void popstackmark(struct stackmark *);
+void growstackblock(void);
+void *growstackstr(void);
+char *makestrspace(size_t, char *);
+char *stnputs(const char *, size_t, char *);
+char *stputs(const char *, char *);
+
+
+static inline void grabstackblock(size_t len)
+{
+       stalloc(len);
+}
+
+static inline char *_STPUTC(int c, char *p) {
+       if (p == sstrend)
+               p = growstackstr();
+       *p++ = c;
+       return p;
+}
+
+#define stackblock() ((void *)stacknxt)
+#define stackblocksize() stacknleft
+#define STARTSTACKSTR(p) ((p) = stackblock())
+#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
+#define CHECKSTRSPACE(n, p) \
+       ({ \
+               char *q = (p); \
+               size_t l = (n); \
+               size_t m = sstrend - q; \
+               if (l > m) \
+                       (p) = makestrspace(l, q); \
+               0; \
+       })
+#define USTPUTC(c, p)  (*p++ = (c))
+#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
+#define STUNPUTC(p)    (--p)
+#define STTOPC(p)      p[-1]
+#define STADJUST(amount, p)    (p += (amount))
+
+#define grabstackstr(p)        stalloc((char *)(p) - (char *)stackblock())
+#define ungrabstackstr(s, p) stunalloc((s))
+#define stackstrend() ((void *)sstrend)
+
+#define ckfree(p)      free((pointer)(p))
diff --git a/src/miscbltin.c b/src/miscbltin.c
new file mode 100644 (file)
index 0000000..e354df4
--- /dev/null
@@ -0,0 +1,525 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Miscelaneous builtins.
+ */
+
+#include <sys/types.h>         /* quad_t */
+#include <sys/param.h>         /* BSD4_4 */
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <inttypes.h>
+
+#include "shell.h"
+#include "options.h"
+#include "var.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "miscbltin.h"
+#include "mystring.h"
+#include "main.h"
+#include "expand.h"
+#include "parser.h"
+#include "trap.h"
+
+#undef rflag
+
+
+/** handle one line of the read command.
+ *  more fields than variables -> remainder shall be part of last variable.
+ *  less fields than variables -> remaining variables unset.
+ *
+ *  @param line complete line of input
+ *  @param ap argument (variable) list
+ *  @param len length of line including trailing '\0'
+ */
+static void
+readcmd_handle_line(char *s, char **ap)
+{
+       struct arglist arglist;
+       struct strlist *sl;
+       char *backup;
+       char *line;
+
+       /* ifsbreakup will fiddle with stack region... */
+       line = stackblock();
+       s = grabstackstr(s);
+
+       /* need a copy, so that delimiters aren't lost
+        * in case there are more fields than variables */
+       backup = sstrdup(line);
+
+       arglist.lastp = &arglist.list;
+       
+       ifsbreakup(s, &arglist);
+       *arglist.lastp = NULL;
+       ifsfree();
+
+       sl = arglist.list;
+
+       do {
+               if (!sl) {
+                       /* nullify remaining arguments */
+                       do {
+                               setvar(*ap, nullstr, 0);
+                       } while (*++ap);
+
+                       return;
+               }
+
+               /* remaining fields present, but no variables left. */
+               if (!ap[1] && sl->next) {
+                       size_t offset;
+                       char *remainder;
+
+                       /* FIXME little bit hacky, assuming that ifsbreakup 
+                        * will not modify the length of the string */
+                       offset = sl->text - s;
+                       remainder = backup + offset;
+                       rmescapes(remainder);
+                       setvar(*ap, remainder, 0);
+
+                       return;
+               }
+               
+               /* set variable to field */
+               rmescapes(sl->text);
+               setvar(*ap, sl->text, 0);
+               sl = sl->next;
+       } while (*++ap);
+}
+
+/*
+ * The read builtin.  The -e option causes backslashes to escape the
+ * following character. The -p option followed by an argument prompts
+ * with the argument.
+ *
+ * This uses unbuffered input, which may be avoidable in some cases.
+ */
+
+int
+readcmd(int argc, char **argv)
+{
+       char **ap;
+       char c;
+       int rflag;
+       char *prompt;
+       char *p;
+       int startloc;
+       int newloc;
+       int status;
+       int i;
+
+       rflag = 0;
+       prompt = NULL;
+       while ((i = nextopt("p:r")) != '\0') {
+               if (i == 'p')
+                       prompt = optionarg;
+               else
+                       rflag = 1;
+       }
+       if (prompt && isatty(0)) {
+               out2str(prompt);
+#ifdef FLUSHERR
+               flushall();
+#endif
+       }
+       if (*(ap = argptr) == NULL)
+               sh_error("arg count");
+
+       status = 0;
+       STARTSTACKSTR(p);
+
+       goto start;
+
+       for (;;) {
+               switch (read(0, &c, 1)) {
+               case 1:
+                       break;
+               default:
+                       if (errno == EINTR && !pendingsigs)
+                               continue;
+                               /* fall through */
+               case 0:
+                       status = 1;
+                       goto out;
+               }
+               if (c == '\0')
+                       continue;
+               if (newloc >= startloc) {
+                       if (c == '\n')
+                               goto resetbs;
+                       goto put;
+               }
+               if (!rflag && c == '\\') {
+                       newloc = p - (char *)stackblock();
+                       continue;
+               }
+               if (c == '\n')
+                       break;
+put:
+               CHECKSTRSPACE(2, p);
+               if (strchr(qchars, c))
+                       USTPUTC(CTLESC, p);
+               USTPUTC(c, p);
+
+               if (newloc >= startloc) {
+resetbs:
+                       recordregion(startloc, newloc, 0);
+start:
+                       startloc = p - (char *)stackblock();
+                       newloc = startloc - 1;
+               }
+       }
+out:
+       recordregion(startloc, p - (char *)stackblock(), 0);
+       STACKSTRNUL(p);
+       readcmd_handle_line(p + 1, ap);
+       return status;
+}
+
+
+
+/*
+ * umask builtin
+ *
+ * This code was ripped from pdksh 5.2.14 and hacked for use with
+ * dash by Herbert Xu.
+ *
+ * Public domain.
+ */
+
+int
+umaskcmd(int argc, char **argv)
+{
+       char *ap;
+       int mask;
+       int i;
+       int symbolic_mode = 0;
+
+       while ((i = nextopt("S")) != '\0') {
+               symbolic_mode = 1;
+       }
+
+       INTOFF;
+       mask = umask(0);
+       umask(mask);
+       INTON;
+
+       if ((ap = *argptr) == NULL) {
+               if (symbolic_mode) {
+                       char buf[18];
+                       int j;
+
+                       mask = ~mask;
+                       ap = buf;
+                       for (i = 0; i < 3; i++) {
+                               *ap++ = "ugo"[i];
+                               *ap++ = '=';
+                               for (j = 0; j < 3; j++)
+                                       if (mask & (1 << (8 - (3*i + j))))
+                                               *ap++ = "rwx"[j];
+                               *ap++ = ',';
+                       }
+                       ap[-1] = '\0';
+                       out1fmt("%s\n", buf);
+               } else {
+                       out1fmt("%.4o\n", mask);
+               }
+       } else {
+               int new_mask;
+
+               if (isdigit((unsigned char) *ap)) {
+                       new_mask = 0;
+                       do {
+                               if (*ap >= '8' || *ap < '0')
+                                       sh_error(illnum, *argptr);
+                               new_mask = (new_mask << 3) + (*ap - '0');
+                       } while (*++ap != '\0');
+               } else {
+                       int positions, new_val;
+                       char op;
+
+                       mask = ~mask;
+                       new_mask = mask;
+                       positions = 0;
+                       while (*ap) {
+                               while (*ap && strchr("augo", *ap))
+                                       switch (*ap++) {
+                                       case 'a': positions |= 0111; break;
+                                       case 'u': positions |= 0100; break;
+                                       case 'g': positions |= 0010; break;
+                                       case 'o': positions |= 0001; break;
+                                       }
+                               if (!positions)
+                                       positions = 0111; /* default is a */
+                               if (!strchr("=+-", op = *ap))
+                                       break;
+                               ap++;
+                               new_val = 0;
+                               while (*ap && strchr("rwxugoXs", *ap))
+                                       switch (*ap++) {
+                                       case 'r': new_val |= 04; break;
+                                       case 'w': new_val |= 02; break;
+                                       case 'x': new_val |= 01; break;
+                                       case 'u': new_val |= mask >> 6;
+                                                 break;
+                                       case 'g': new_val |= mask >> 3;
+                                                 break;
+                                       case 'o': new_val |= mask >> 0;
+                                                 break;
+                                       case 'X': if (mask & 0111)
+                                                       new_val |= 01;
+                                                 break;
+                                       case 's': /* ignored */
+                                                 break;
+                                       }
+                               new_val = (new_val & 07) * positions;
+                               switch (op) {
+                               case '-':
+                                       new_mask &= ~new_val;
+                                       break;
+                               case '=':
+                                       new_mask = new_val
+                                           | (new_mask & ~(positions * 07));
+                                       break;
+                               case '+':
+                                       new_mask |= new_val;
+                               }
+                               if (*ap == ',') {
+                                       positions = 0;
+                                       ap++;
+                               } else if (!strchr("=+-", *ap))
+                                       break;
+                       }
+                       if (*ap) {
+                               sh_error("Illegal mode: %s", *argptr);
+                               return 1;
+                       }
+                       new_mask = ~new_mask;
+               }
+               umask(new_mask);
+       }
+       return 0;
+}
+
+#ifdef HAVE_GETRLIMIT
+/*
+ * ulimit builtin
+ *
+ * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
+ * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
+ * ash by J.T. Conklin.
+ *
+ * Public domain.
+ */
+
+struct limits {
+       const char *name;
+       int     cmd;
+       int     factor; /* multiply by to get rlim_{cur,max} values */
+       char    option;
+};
+
+static const struct limits limits[] = {
+#ifdef RLIMIT_CPU
+       { "time(seconds)",              RLIMIT_CPU,        1, 't' },
+#endif
+#ifdef RLIMIT_FSIZE
+       { "file(blocks)",               RLIMIT_FSIZE,    512, 'f' },
+#endif
+#ifdef RLIMIT_DATA
+       { "data(kbytes)",               RLIMIT_DATA,    1024, 'd' },
+#endif
+#ifdef RLIMIT_STACK
+       { "stack(kbytes)",              RLIMIT_STACK,   1024, 's' },
+#endif
+#ifdef RLIMIT_CORE
+       { "coredump(blocks)",           RLIMIT_CORE,     512, 'c' },
+#endif
+#ifdef RLIMIT_RSS
+       { "memory(kbytes)",             RLIMIT_RSS,     1024, 'm' },
+#endif
+#ifdef RLIMIT_MEMLOCK
+       { "locked memory(kbytes)",      RLIMIT_MEMLOCK, 1024, 'l' },
+#endif
+#ifdef RLIMIT_NPROC
+       { "process",                    RLIMIT_NPROC,      1, 'p' },
+#endif
+#ifdef RLIMIT_NOFILE
+       { "nofiles",                    RLIMIT_NOFILE,     1, 'n' },
+#endif
+#ifdef RLIMIT_AS
+       { "vmemory(kbytes)",            RLIMIT_AS,      1024, 'v' },
+#endif
+#ifdef RLIMIT_LOCKS
+       { "locks",                      RLIMIT_LOCKS,      1, 'w' },
+#endif
+       { (char *) 0,                   0,                 0,  '\0' }
+};
+
+enum limtype { SOFT = 0x1, HARD = 0x2 };
+
+static void printlim(enum limtype how, const struct rlimit *limit,
+                    const struct limits *l)
+{
+       rlim_t val;
+
+       val = limit->rlim_max;
+       if (how & SOFT)
+               val = limit->rlim_cur;
+
+       if (val == RLIM_INFINITY)
+               out1fmt("unlimited\n");
+       else {
+               val /= l->factor;
+               out1fmt("%" PRIdMAX "\n", (intmax_t) val);
+       }
+}
+
+int
+ulimitcmd(int argc, char **argv)
+{
+       int     c;
+       rlim_t val = 0;
+       enum limtype how = SOFT | HARD;
+       const struct limits     *l;
+       int             set, all = 0;
+       int             optc, what;
+       struct rlimit   limit;
+
+       what = 'f';
+       while ((optc = nextopt("HSa"
+#ifdef RLIMIT_CPU
+                              "t"
+#endif
+#ifdef RLIMIT_FSIZE
+                              "f"
+#endif
+#ifdef RLIMIT_DATA
+                              "d"
+#endif
+#ifdef RLIMIT_STACK
+                              "s"
+#endif
+#ifdef RLIMIT_CORE
+                              "c"
+#endif
+#ifdef RLIMIT_RSS
+                              "m"
+#endif
+#ifdef RLIMIT_MEMLOCK
+                              "l"
+#endif
+#ifdef RLIMIT_NPROC
+                              "p"
+#endif
+#ifdef RLIMIT_NOFILE
+                              "n"
+#endif
+#ifdef RLIMIT_AS
+                              "v"
+#endif
+#ifdef RLIMIT_LOCKS
+                              "w"
+#endif
+       )) != '\0')
+               switch (optc) {
+               case 'H':
+                       how = HARD;
+                       break;
+               case 'S':
+                       how = SOFT;
+                       break;
+               case 'a':
+                       all = 1;
+                       break;
+               default:
+                       what = optc;
+               }
+
+       for (l = limits; l->option != what; l++)
+               ;
+
+       set = *argptr ? 1 : 0;
+       if (set) {
+               char *p = *argptr;
+
+               if (all || argptr[1])
+                       sh_error("too many arguments");
+               if (strcmp(p, "unlimited") == 0)
+                       val = RLIM_INFINITY;
+               else {
+                       val = (rlim_t) 0;
+
+                       while ((c = *p++) >= '0' && c <= '9')
+                       {
+                               val = (val * 10) + (long)(c - '0');
+                               if (val < (rlim_t) 0)
+                                       break;
+                       }
+                       if (c)
+                               sh_error("bad number");
+                       val *= l->factor;
+               }
+       }
+       if (all) {
+               for (l = limits; l->name; l++) {
+                       getrlimit(l->cmd, &limit);
+                       out1fmt("%-20s ", l->name);
+                       printlim(how, &limit, l);
+               }
+               return 0;
+       }
+
+       getrlimit(l->cmd, &limit);
+       if (set) {
+               if (how & HARD)
+                       limit.rlim_max = val;
+               if (how & SOFT)
+                       limit.rlim_cur = val;
+               if (setrlimit(l->cmd, &limit) < 0)
+                       sh_error("error setting limit (%s)", strerror(errno));
+       } else {
+               printlim(how, &limit, l);
+       }
+       return 0;
+}
+#endif
diff --git a/src/miscbltin.h b/src/miscbltin.h
new file mode 100644 (file)
index 0000000..dd9a8d1
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 1997 Christos Zoulas.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+int readcmd(int, char **);
+int umaskcmd(int, char **);
+int ulimitcmd(int, char **);
diff --git a/src/mkbuiltins b/src/mkbuiltins
new file mode 100644 (file)
index 0000000..f562ae2
--- /dev/null
@@ -0,0 +1,115 @@
+#!/bin/sh -
+#      $NetBSD: mkbuiltins,v 1.17 2002/11/24 22:35:41 christos Exp $
+#
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#      Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#      @(#)mkbuiltins  8.2 (Berkeley) 5/4/95
+
+tempfile=tempfile
+if ! type tempfile > /dev/null 2>&1 && ! type mktemp > /dev/null 2>&1; then
+       _my_tempfile()
+       {
+               local index=0
+               while test -f "${TMPDIR:-/tmp}/builtin.$$.$index"; do
+                       index=`expr $index + 1`
+               done
+
+               touch "${TMPDIR:-/tmp}/builtin.$$.$index"
+               echo "${TMPDIR:-/tmp}/builtin.$$.$index"
+       }
+
+       tempfile="_my_tempfile"
+elif ! type tempfile > /dev/null 2>&1; then
+       tempfile="mktemp ${TMPDIR:-/tmp}/builtin.XXXXXX"
+fi
+
+trap 'rm -f $temp $temp2' EXIT
+temp=$($tempfile)
+temp2=$($tempfile)
+
+builtins=$1
+
+exec > builtins.c
+cat <<\!
+/*
+ * This file was generated by the mkbuiltins program.
+ */
+
+#include "shell.h"
+#include "builtins.h"
+
+!
+< $builtins sed '/^#/d; /^$/d' > $temp
+awk '{ printf "int %s(int, char **);\n", $1}' $temp
+echo '
+const struct builtincmd builtincmd[] = {'
+awk '{ for (i = 2 ; i <= NF ; i++) {
+               line = $i "\t" $1
+               if ($i ~ /^-/)
+                       line = $(++i) "\t" line
+               print line
+       }}' $temp | LC_COLLATE=C sort -k 1,1 | tee $temp2 | awk '{
+               opt = ""
+               if (NF > 2) {
+                       opt = substr($2, 2)
+                       $2 = $3
+               }
+               printf "\t{ \"%s\", %s, %d },\n", $1,
+                       (opt ~ /n/) ? "NULL" : $2,
+                       (opt ~ /s/) + (opt ~ /[su]/) * 2 + (opt ~ /a/) * 4
+       }'
+echo '};'
+
+exec > builtins.h
+cat <<\!
+/*
+ * This file was generated by the mkbuiltins program.
+ */
+
+!
+sed 's/        -[a-z]*//' $temp2 | nl -b a -v 0 | LC_COLLATE=C sort -u -k 3,3 |
+tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ |
+       awk '{  printf "#define %s (builtincmd + %d)\n", $3, $1}'
+printf '\n#define NUMBUILTINS %d\n' $(wc -l < $temp2)
+echo '
+#define BUILTIN_SPECIAL 0x1
+#define BUILTIN_REGULAR 0x2
+#define BUILTIN_ASSIGN 0x4
+
+struct builtincmd {
+       const char *name;
+       int (*builtin)(int, char **);
+       unsigned flags;
+};
+
+extern const struct builtincmd builtincmd[];'
diff --git a/src/mkinit.c b/src/mkinit.c
new file mode 100644 (file)
index 0000000..9714bee
--- /dev/null
@@ -0,0 +1,479 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This program scans all the source files for code to handle various
+ * special events and combines this code into one file.  This (allegedly)
+ * improves the structure of the program since there is no need for
+ * anyone outside of a module to know that that module performs special
+ * operations on particular events.
+ *
+ * Usage:  mkinit sourcefile...
+ */
+
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+/*
+ * OUTFILE is the name of the output file.  Output is initially written
+ * to the file OUTTEMP, which is then moved to OUTFILE.
+ */
+
+#define OUTFILE "init.c"
+#define OUTTEMP "init.c.new"
+
+
+/*
+ * A text structure is basicly just a string that grows as more characters
+ * are added onto the end of it.  It is implemented as a linked list of
+ * blocks of characters.  The routines addstr and addchar append a string
+ * or a single character, respectively, to a text structure.  Writetext
+ * writes the contents of a text structure to a file.
+ */
+
+#define BLOCKSIZE 512
+
+struct text {
+       char *nextc;
+       int nleft;
+       struct block *start;
+       struct block *last;
+};
+
+struct block {
+       struct block *next;
+       char text[BLOCKSIZE];
+};
+
+
+/*
+ * There is one event structure for each event that mkinit handles.
+ */
+
+struct event {
+       char *name;             /* name of event (e.g. INIT) */
+       char *routine;          /* name of routine called on event */
+       char *comment;          /* comment describing routine */
+       struct text code;       /* code for handling event */
+};
+
+
+char writer[] = "\
+/*\n\
+ * This file was generated by the mkinit program.\n\
+ */\n\
+\n";
+
+char init[] = "\
+/*\n\
+ * Initialization code.\n\
+ */\n";
+
+char reset[] = "\
+/*\n\
+ * This routine is called when an error or an interrupt occurs in an\n\
+ * interactive shell and control is returned to the main command loop.\n\
+ */\n";
+
+
+struct event event[] = {
+       {"INIT", "init", init},
+       {"RESET", "reset", reset},
+       {NULL, NULL}
+};
+
+
+char *curfile;                         /* current file */
+int linno;                             /* current line */
+char *header_files[200];               /* list of header files */
+struct text defines;                   /* #define statements */
+struct text decls;                     /* declarations */
+int amiddecls;                         /* for formatting */
+
+
+void readfile(char *);
+int match(char *, char *);
+int gooddefine(char *);
+void doevent(struct event *, FILE *, char *);
+void doinclude(char *);
+void dodecl(char *, FILE *);
+void output(void);
+void addstr(char *, struct text *);
+void addchar(int, struct text *);
+void writetext(struct text *, FILE *);
+FILE *ckfopen(char *, char *);
+void *ckmalloc(int);
+char *savestr(char *);
+static void error(char *);
+int main(int, char **);
+
+#define equal(s1, s2)  (strcmp(s1, s2) == 0)
+
+int
+main(int argc, char **argv)
+{
+       char **ap;
+
+       header_files[0] = "\"shell.h\"";
+       header_files[1] = "\"mystring.h\"";
+       header_files[2] = "\"init.h\"";
+       for (ap = argv + 1 ; *ap ; ap++)
+               readfile(*ap);
+       output();
+       rename(OUTTEMP, OUTFILE);
+       exit(0);
+       /* NOTREACHED */
+}
+
+
+/*
+ * Parse an input file.
+ */
+
+void
+readfile(char *fname)
+{
+       FILE *fp;
+       char line[1024];
+       struct event *ep;
+
+       fp = ckfopen(fname, "r");
+       curfile = fname;
+       linno = 0;
+       amiddecls = 0;
+       while (fgets(line, sizeof line, fp) != NULL) {
+               linno++;
+               for (ep = event ; ep->name ; ep++) {
+                       if (line[0] == ep->name[0] && match(ep->name, line)) {
+                               doevent(ep, fp, fname);
+                               break;
+                       }
+               }
+               if (line[0] == 'I' && match("INCLUDE", line))
+                       doinclude(line);
+               if (line[0] == 'M' && match("MKINIT", line))
+                       dodecl(line, fp);
+               if (line[0] == '#' && gooddefine(line)) {
+                       char *cp;
+                       char line2[1024];
+                       static const char undef[] = "#undef ";
+
+                       strcpy(line2, line);
+                       memcpy(line2, undef, sizeof(undef) - 1);
+                       cp = line2 + sizeof(undef) - 1;
+                       while(*cp && (*cp == ' ' || *cp == '\t'))
+                               cp++;
+                       while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
+                               cp++;
+                       *cp++ = '\n'; *cp = '\0';
+                       addstr(line2, &defines);
+                       addstr(line, &defines);
+               }
+       }
+       fclose(fp);
+}
+
+
+int
+match(char *name, char *line)
+{
+       char *p, *q;
+
+       p = name, q = line;
+       while (*p) {
+               if (*p++ != *q++)
+                       return 0;
+       }
+       if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
+               return 0;
+       return 1;
+}
+
+
+int
+gooddefine(char *line)
+{
+       char *p;
+
+       if (! match("#define", line))
+               return 0;                       /* not a define */
+       p = line + 7;
+       while (*p == ' ' || *p == '\t')
+               p++;
+       while (*p != ' ' && *p != '\t') {
+               if (*p == '(')
+                       return 0;               /* macro definition */
+               p++;
+       }
+       while (*p != '\n' && *p != '\0')
+               p++;
+       if (p[-1] == '\\')
+               return 0;                       /* multi-line definition */
+       return 1;
+}
+
+
+void
+doevent(struct event *ep, FILE *fp, char *fname)
+{
+       char line[1024];
+       int indent;
+       char *p;
+
+       sprintf(line, "\n      /* from %s: */\n", fname);
+       addstr(line, &ep->code);
+       addstr("      {\n", &ep->code);
+       for (;;) {
+               linno++;
+               if (fgets(line, sizeof line, fp) == NULL)
+                       error("Unexpected EOF");
+               if (equal(line, "}\n"))
+                       break;
+               indent = 6;
+               for (p = line ; *p == '\t' ; p++)
+                       indent += 8;
+               for ( ; *p == ' ' ; p++)
+                       indent++;
+               if (*p == '\n' || *p == '#')
+                       indent = 0;
+               while (indent >= 8) {
+                       addchar('\t', &ep->code);
+                       indent -= 8;
+               }
+               while (indent > 0) {
+                       addchar(' ', &ep->code);
+                       indent--;
+               }
+               addstr(p, &ep->code);
+       }
+       addstr("      }\n", &ep->code);
+}
+
+
+void
+doinclude(char *line)
+{
+       char *p;
+       char *name;
+       char **pp;
+
+       for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
+       if (*p == '\0')
+               error("Expecting '\"' or '<'");
+       name = p;
+       while (*p != ' ' && *p != '\t' && *p != '\n')
+               p++;
+       if (p[-1] != '"' && p[-1] != '>')
+               error("Missing terminator");
+       *p = '\0';
+
+       /* name now contains the name of the include file */
+       for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
+       if (*pp == NULL)
+               *pp = savestr(name);
+}
+
+
+void
+dodecl(char *line1, FILE *fp)
+{
+       char line[1024];
+       char *p, *q;
+
+       if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
+               addchar('\n', &decls);
+               do {
+                       linno++;
+                       if (fgets(line, sizeof line, fp) == NULL)
+                               error("Unterminated structure declaration");
+                       addstr(line, &decls);
+               } while (line[0] != '}');
+               amiddecls = 0;
+       } else {
+               if (! amiddecls)
+                       addchar('\n', &decls);
+               q = NULL;
+               for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++)
+                       continue;
+               if (*p == '=') {                /* eliminate initialization */
+                       for (q = p ; *q && *q != ';' ; q++);
+                       if (*q == '\0')
+                               q = NULL;
+                       else {
+                               while (p[-1] == ' ')
+                                       p--;
+                               *p = '\0';
+                       }
+               }
+               addstr("extern", &decls);
+               addstr(line1 + 6, &decls);
+               if (q != NULL)
+                       addstr(q, &decls);
+               amiddecls = 1;
+       }
+}
+
+
+
+/*
+ * Write the output to the file OUTTEMP.
+ */
+
+void
+output(void)
+{
+       FILE *fp;
+       char **pp;
+       struct event *ep;
+
+       fp = ckfopen(OUTTEMP, "w");
+       fputs(writer, fp);
+       for (pp = header_files ; *pp ; pp++)
+               fprintf(fp, "#include %s\n", *pp);
+       fputs("\n\n\n", fp);
+       writetext(&defines, fp);
+       fputs("\n\n", fp);
+       writetext(&decls, fp);
+       for (ep = event ; ep->name ; ep++) {
+               fputs("\n\n\n", fp);
+               fputs(ep->comment, fp);
+               fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
+               writetext(&ep->code, fp);
+               fprintf(fp, "}\n");
+       }
+       fclose(fp);
+}
+
+
+/*
+ * A text structure is simply a block of text that is kept in memory.
+ * Addstr appends a string to the text struct, and addchar appends a single
+ * character.
+ */
+
+void
+addstr(char *s, struct text *text)
+{
+       while (*s) {
+               if (--text->nleft < 0)
+                       addchar(*s++, text);
+               else
+                       *text->nextc++ = *s++;
+       }
+}
+
+
+void
+addchar(int c, struct text *text)
+{
+       struct block *bp;
+
+       if (--text->nleft < 0) {
+               bp = ckmalloc(sizeof *bp);
+               if (text->start == NULL)
+                       text->start = bp;
+               else
+                       text->last->next = bp;
+               text->last = bp;
+               text->nextc = bp->text;
+               text->nleft = BLOCKSIZE - 1;
+       }
+       *text->nextc++ = c;
+}
+
+/*
+ * Write the contents of a text structure to a file.
+ */
+void
+writetext(struct text *text, FILE *fp)
+{
+       struct block *bp;
+
+       if (text->start != NULL) {
+               for (bp = text->start ; bp != text->last ; bp = bp->next) {
+                       if ((fwrite(bp->text, sizeof (char), BLOCKSIZE, fp)) != BLOCKSIZE)
+                               error("Can't write data\n");
+               }
+               if ((fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp)) != (BLOCKSIZE - text->nleft))
+                       error("Can't write data\n");
+       }
+}
+
+FILE *
+ckfopen(char *file, char *mode)
+{
+       FILE *fp;
+
+       if ((fp = fopen(file, mode)) == NULL) {
+               fprintf(stderr, "Can't open %s\n", file);
+               exit(2);
+       }
+       return fp;
+}
+
+void *
+ckmalloc(int nbytes)
+{
+       char *p;
+
+       if ((p = malloc(nbytes)) == NULL)
+               error("Out of space");
+       return p;
+}
+
+char *
+savestr(char *s)
+{
+       char *p;
+
+       p = ckmalloc(strlen(s) + 1);
+       strcpy(p, s);
+       return p;
+}
+
+static void
+error(char *msg)
+{
+       if (curfile != NULL)
+               fprintf(stderr, "%s:%d: ", curfile, linno);
+       fprintf(stderr, "%s\n", msg);
+       exit(2);
+       /* NOTREACHED */
+}
diff --git a/src/mknodes.c b/src/mknodes.c
new file mode 100644 (file)
index 0000000..1903a60
--- /dev/null
@@ -0,0 +1,448 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This program reads the nodetypes file and nodes.c.pat file.  It generates
+ * the files nodes.h and nodes.c.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#define MAXTYPES 50            /* max number of node types */
+#define MAXFIELDS 20           /* max fields in a structure */
+#define BUFLEN 100             /* size of character buffers */
+
+/* field types */
+#define T_NODE 1               /* union node *field */
+#define T_NODELIST 2           /* struct nodelist *field */
+#define T_STRING 3
+#define T_INT 4                        /* int field */
+#define T_OTHER 5              /* other */
+#define T_TEMP 6               /* don't copy this field */
+
+
+struct field {                 /* a structure field */
+       char *name;             /* name of field */
+       int type;                       /* type of field */
+       char *decl;             /* declaration of field */
+};
+
+
+struct str {                   /* struct representing a node structure */
+       char *tag;              /* structure tag */
+       int nfields;            /* number of fields in the structure */
+       struct field field[MAXFIELDS];  /* the fields of the structure */
+       int done;                       /* set if fully parsed */
+};
+
+
+static int ntypes;                     /* number of node types */
+static char *nodename[MAXTYPES];       /* names of the nodes */
+static struct str *nodestr[MAXTYPES];  /* type of structure used by the node */
+static int nstr;                       /* number of structures */
+static struct str str[MAXTYPES];       /* the structures */
+static struct str *curstr;             /* current structure */
+static FILE *infp;
+static char line[1024];
+static int linno;
+static char *linep;
+
+static void parsenode(void);
+static void parsefield(void);
+static void output(char *);
+static void outsizes(FILE *);
+static void outfunc(FILE *, int);
+static void indent(int, FILE *);
+static int nextfield(char *);
+static void skipbl(void);
+static int readline(void);
+static void error(const char *, ...);
+static char *savestr(const char *);
+int main(int, char **);
+
+
+int
+main(int argc, char **argv)
+{
+
+       /*
+        * some versions of linux complain: initializer element is not
+        * constant if this is done at compile time.
+        */
+       infp = stdin;
+
+       if (argc != 3)
+               error("usage: mknodes file");
+       if ((infp = fopen(argv[1], "r")) == NULL)
+               error("Can't open %s", argv[1]);
+       while (readline()) {
+               if (line[0] == ' ' || line[0] == '\t')
+                       parsefield();
+               else if (line[0] != '\0')
+                       parsenode();
+       }
+       output(argv[2]);
+       exit(0);
+       /* NOTREACHED */
+}
+
+
+
+static void
+parsenode(void)
+{
+       char name[BUFLEN];
+       char tag[BUFLEN];
+       struct str *sp;
+
+       if (curstr && curstr->nfields > 0)
+               curstr->done = 1;
+       nextfield(name);
+       if (! nextfield(tag))
+               error("Tag expected");
+       if (*linep != '\0')
+               error("Garbage at end of line");
+       nodename[ntypes] = savestr(name);
+       for (sp = str ; sp < str + nstr ; sp++) {
+               if (strcmp(sp->tag, tag) == 0)
+                       break;
+       }
+       if (sp >= str + nstr) {
+               sp->tag = savestr(tag);
+               sp->nfields = 0;
+               curstr = sp;
+               nstr++;
+       }
+       nodestr[ntypes] = sp;
+       ntypes++;
+}
+
+
+static void
+parsefield(void)
+{
+       char name[BUFLEN];
+       char type[BUFLEN];
+       char decl[2 * BUFLEN];
+       struct field *fp;
+
+       if (curstr == NULL || curstr->done)
+               error("No current structure to add field to");
+       if (! nextfield(name))
+               error("No field name");
+       if (! nextfield(type))
+               error("No field type");
+       fp = &curstr->field[curstr->nfields];
+       fp->name = savestr(name);
+       if (strcmp(type, "nodeptr") == 0) {
+               fp->type = T_NODE;
+               sprintf(decl, "union node *%s", name);
+       } else if (strcmp(type, "nodelist") == 0) {
+               fp->type = T_NODELIST;
+               sprintf(decl, "struct nodelist *%s", name);
+       } else if (strcmp(type, "string") == 0) {
+               fp->type = T_STRING;
+               sprintf(decl, "char *%s", name);
+       } else if (strcmp(type, "int") == 0) {
+               fp->type = T_INT;
+               sprintf(decl, "int %s", name);
+       } else if (strcmp(type, "other") == 0) {
+               fp->type = T_OTHER;
+       } else if (strcmp(type, "temp") == 0) {
+               fp->type = T_TEMP;
+       } else {
+               error("Unknown type %s", type);
+       }
+       if (fp->type == T_OTHER || fp->type == T_TEMP) {
+               skipbl();
+               fp->decl = savestr(linep);
+       } else {
+               if (*linep)
+                       error("Garbage at end of line");
+               fp->decl = savestr(decl);
+       }
+       curstr->nfields++;
+}
+
+
+char writer[] = "\
+/*\n\
+ * This file was generated by the mknodes program.\n\
+ */\n\
+\n";
+
+static void
+output(char *file)
+{
+       FILE *hfile;
+       FILE *cfile;
+       FILE *patfile;
+       int i;
+       struct str *sp;
+       struct field *fp;
+       char *p;
+
+       if ((patfile = fopen(file, "r")) == NULL)
+               error("Can't open %s", file);
+       if ((hfile = fopen("nodes.h", "w")) == NULL)
+               error("Can't create nodes.h");
+       if ((cfile = fopen("nodes.c", "w")) == NULL)
+               error("Can't create nodes.c");
+       fputs(writer, hfile);
+       for (i = 0 ; i < ntypes ; i++)
+               fprintf(hfile, "#define %s %d\n", nodename[i], i);
+       fputs("\n\n\n", hfile);
+       for (sp = str ; sp < &str[nstr] ; sp++) {
+               fprintf(hfile, "struct %s {\n", sp->tag);
+               for (i = sp->nfields, fp = sp->field ; --i >= 0 ; fp++) {
+                       fprintf(hfile, "      %s;\n", fp->decl);
+               }
+               fputs("};\n\n\n", hfile);
+       }
+       fputs("union node {\n", hfile);
+       fprintf(hfile, "      int type;\n");
+       for (sp = str ; sp < &str[nstr] ; sp++) {
+               fprintf(hfile, "      struct %s %s;\n", sp->tag, sp->tag);
+       }
+       fputs("};\n\n\n", hfile);
+       fputs("struct nodelist {\n", hfile);
+       fputs("\tstruct nodelist *next;\n", hfile);
+       fputs("\tunion node *n;\n", hfile);
+       fputs("};\n\n\n", hfile);
+       fputs("struct funcnode {\n", hfile);
+       fputs("\tint count;\n", hfile);
+       fputs("\tunion node n;\n", hfile);
+       fputs("};\n\n\n", hfile);
+       fputs("struct funcnode *copyfunc(union node *);\n", hfile);
+       fputs("void freefunc(struct funcnode *);\n", hfile);
+
+       fputs(writer, cfile);
+       while (fgets(line, sizeof line, patfile) != NULL) {
+               for (p = line ; *p == ' ' || *p == '\t' ; p++);
+               if (strcmp(p, "%SIZES\n") == 0)
+                       outsizes(cfile);
+               else if (strcmp(p, "%CALCSIZE\n") == 0)
+                       outfunc(cfile, 1);
+               else if (strcmp(p, "%COPY\n") == 0)
+                       outfunc(cfile, 0);
+               else
+                       fputs(line, cfile);
+       }
+}
+
+
+
+static void
+outsizes(FILE *cfile)
+{
+       int i;
+
+       fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes);
+       for (i = 0 ; i < ntypes ; i++) {
+               fprintf(cfile, "      SHELL_ALIGN(sizeof (struct %s)),\n",
+                   nodestr[i]->tag);
+       }
+       fprintf(cfile, "};\n");
+}
+
+
+static void
+outfunc(FILE *cfile, int calcsize)
+{
+       struct str *sp;
+       struct field *fp;
+       int i;
+
+       fputs("      if (n == NULL)\n", cfile);
+       if (calcsize)
+               fputs("     return;\n", cfile);
+       else
+               fputs("     return NULL;\n", cfile);
+       if (calcsize)
+               fputs("      funcblocksize += nodesize[n->type];\n", cfile);
+       else {
+               fputs("      new = funcblock;\n", cfile);
+               fputs("      funcblock = (char *) funcblock + nodesize[n->type];\n", cfile);
+       }
+       fputs("      switch (n->type) {\n", cfile);
+       for (sp = str ; sp < &str[nstr] ; sp++) {
+               for (i = 0 ; i < ntypes ; i++) {
+                       if (nodestr[i] == sp)
+                               fprintf(cfile, "      case %s:\n", nodename[i]);
+               }
+               for (i = sp->nfields ; --i >= 1 ; ) {
+                       fp = &sp->field[i];
+                       switch (fp->type) {
+                       case T_NODE:
+                               if (calcsize) {
+                                       indent(12, cfile);
+                                       fprintf(cfile, "calcsize(n->%s.%s);\n",
+                                               sp->tag, fp->name);
+                               } else {
+                                       indent(12, cfile);
+                                       fprintf(cfile, "new->%s.%s = copynode(n->%s.%s);\n",
+                                               sp->tag, fp->name, sp->tag, fp->name);
+                               }
+                               break;
+                       case T_NODELIST:
+                               if (calcsize) {
+                                       indent(12, cfile);
+                                       fprintf(cfile, "sizenodelist(n->%s.%s);\n",
+                                               sp->tag, fp->name);
+                               } else {
+                                       indent(12, cfile);
+                                       fprintf(cfile, "new->%s.%s = copynodelist(n->%s.%s);\n",
+                                               sp->tag, fp->name, sp->tag, fp->name);
+                               }
+                               break;
+                       case T_STRING:
+                               if (calcsize) {
+                                       indent(12, cfile);
+                                       fprintf(cfile, "funcstringsize += strlen(n->%s.%s) + 1;\n",
+                                               sp->tag, fp->name);
+                               } else {
+                                       indent(12, cfile);
+                                       fprintf(cfile, "new->%s.%s = nodesavestr(n->%s.%s);\n",
+                                               sp->tag, fp->name, sp->tag, fp->name);
+                               }
+                               break;
+                       case T_INT:
+                       case T_OTHER:
+                               if (! calcsize) {
+                                       indent(12, cfile);
+                                       fprintf(cfile, "new->%s.%s = n->%s.%s;\n",
+                                               sp->tag, fp->name, sp->tag, fp->name);
+                               }
+                               break;
+                       }
+               }
+               indent(12, cfile);
+               fputs("break;\n", cfile);
+       }
+       fputs("      };\n", cfile);
+       if (! calcsize)
+               fputs("      new->type = n->type;\n", cfile);
+}
+
+
+static void
+indent(int amount, FILE *fp)
+{
+       while (amount >= 8) {
+               putc('\t', fp);
+               amount -= 8;
+       }
+       while (--amount >= 0) {
+               putc(' ', fp);
+       }
+}
+
+
+static int
+nextfield(char *buf)
+{
+       char *p, *q;
+
+       p = linep;
+       while (*p == ' ' || *p == '\t')
+               p++;
+       q = buf;
+       while (*p != ' ' && *p != '\t' && *p != '\0')
+               *q++ = *p++;
+       *q = '\0';
+       linep = p;
+       return (q > buf);
+}
+
+
+static void
+skipbl(void)
+{
+       while (*linep == ' ' || *linep == '\t')
+               linep++;
+}
+
+
+static int
+readline(void)
+{
+       char *p;
+
+       if (fgets(line, 1024, infp) == NULL)
+               return 0;
+       for (p = line ; *p != '#' && *p != '\n' && *p != '\0' ; p++);
+       while (p > line && (p[-1] == ' ' || p[-1] == '\t'))
+               p--;
+       *p = '\0';
+       linep = line;
+       linno++;
+       if (p - line > BUFLEN)
+               error("Line too long");
+       return 1;
+}
+
+
+
+static void
+error(const char *msg, ...)
+{
+       va_list va;
+
+       va_start(va, msg);
+
+       (void) fprintf(stderr, "line %d: ", linno);
+       (void) vfprintf(stderr, msg, va);
+       (void) fputc('\n', stderr);
+
+       va_end(va);
+
+       exit(2);
+       /* NOTREACHED */
+}
+
+
+
+static char *
+savestr(const char *s)
+{
+       char *p;
+
+       if ((p = malloc(strlen(s) + 1)) == NULL)
+               error("Out of space");
+       (void) strcpy(p, s);
+       return p;
+}
diff --git a/src/mksignames.c b/src/mksignames.c
new file mode 100644 (file)
index 0000000..a832eab
--- /dev/null
@@ -0,0 +1,417 @@
+/* signames.c -- Create and write `signames.c', which contains an array of
+   signal names. */
+
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Bash; see the file COPYING.  If not, write to the Free Software
+   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <stdlib.h>
+
+#if !defined (NSIG)
+#  define NSIG 64
+#endif
+
+/*
+ * Special traps:
+ *     EXIT == 0
+ */
+#define LASTSIG NSIG-1
+
+char *signal_names[2 * NSIG + 3];
+
+#define signal_names_size (sizeof(signal_names)/sizeof(signal_names[0]))
+
+char *progname;
+
+/* AIX 4.3 defines SIGRTMIN and SIGRTMAX as 888 and 999 respectively.
+   I don't want to allocate so much unused space for the intervening signal
+   numbers, so we just punt if SIGRTMAX is past the bounds of the
+   signal_names array (handled in configure). */
+#if defined (SIGRTMAX) && defined (UNUSABLE_RT_SIGNALS)
+#  undef SIGRTMAX
+#  undef SIGRTMIN
+#endif
+
+#if defined (SIGRTMAX) || defined (SIGRTMIN)
+#  define RTLEN 14
+#  define RTLIM 256
+#endif
+
+void
+initialize_signames ()
+{
+  register int i;
+#if defined (SIGRTMAX) || defined (SIGRTMIN)
+  int rtmin, rtmax, rtcnt;
+#endif
+
+  for (i = 1; i < signal_names_size; i++)
+    signal_names[i] = (char *)NULL;
+
+  /* `signal' 0 is what we do on exit. */
+  signal_names[0] = "EXIT";
+
+  /* Place signal names which can be aliases for more common signal
+     names first.  This allows (for example) SIGABRT to overwrite SIGLOST. */
+
+  /* POSIX 1003.1b-1993 real time signals, but take care of incomplete
+     implementations. Acoording to the standard, both, SIGRTMIN and
+     SIGRTMAX must be defined, SIGRTMIN must be stricly less than
+     SIGRTMAX, and the difference must be at least 7, that is, there
+     must be at least eight distinct real time signals. */
+
+  /* The generated signal names are SIGRTMIN, SIGRTMIN+1, ...,
+     SIGRTMIN+x, SIGRTMAX-x, ..., SIGRTMAX-1, SIGRTMAX. If the number
+     of RT signals is odd, there is an extra SIGRTMIN+(x+1).
+     These names are the ones used by ksh and /usr/xpg4/bin/sh on SunOS5. */
+
+#if defined (SIGRTMIN)
+  rtmin = SIGRTMIN;
+  signal_names[rtmin] = "RTMIN";
+#endif
+
+#if defined (SIGRTMAX)
+  rtmax = SIGRTMAX;
+  signal_names[rtmax] = "RTMAX";
+#endif
+
+#if defined (SIGRTMAX) && defined (SIGRTMIN)
+  if (rtmax > rtmin)
+    {
+      rtcnt = (rtmax - rtmin - 1) / 2;
+      /* croak if there are too many RT signals */
+      if (rtcnt >= RTLIM/2)
+       {
+         rtcnt = RTLIM/2-1;
+         fprintf(stderr, "%s: error: more than %i real time signals, fix `%s'\n",
+                 progname, RTLIM, progname);
+       }
+
+      for (i = 1; i <= rtcnt; i++)
+       {
+         signal_names[rtmin+i] = (char *)malloc(RTLEN);
+         if (signal_names[rtmin+i])
+           sprintf (signal_names[rtmin+i], "RTMIN+%d", i);
+         signal_names[rtmax-i] = (char *)malloc(RTLEN);
+         if (signal_names[rtmax-i])
+           sprintf (signal_names[rtmax-i], "RTMAX-%d", i);
+       }
+
+      if (rtcnt < RTLIM/2-1 && rtcnt != (rtmax-rtmin)/2)
+       {
+         /* Need an extra RTMIN signal */
+         signal_names[rtmin+rtcnt+1] = (char *)malloc(RTLEN);
+         if (signal_names[rtmin+rtcnt+1])
+           sprintf (signal_names[rtmin+rtcnt+1], "RTMIN+%d", rtcnt+1);
+       }
+    }
+#endif /* SIGRTMIN && SIGRTMAX */
+
+/* AIX */
+#if defined (SIGLOST)  /* resource lost (eg, record-lock lost) */
+  signal_names[SIGLOST] = "LOST";
+#endif
+
+#if defined (SIGMSG)   /* HFT input data pending */
+  signal_names[SIGMSG] = "MSG";
+#endif
+
+#if defined (SIGDANGER)        /* system crash imminent */
+  signal_names[SIGDANGER] = "DANGER";
+#endif
+
+#if defined (SIGMIGRATE) /* migrate process to another CPU */
+  signal_names[SIGMIGRATE] = "MIGRATE";
+#endif
+
+#if defined (SIGPRE)   /* programming error */
+  signal_names[SIGPRE] = "PRE";
+#endif
+
+#if defined (SIGVIRT)  /* AIX virtual time alarm */
+  signal_names[SIGVIRT] = "VIRT";
+#endif
+
+#if defined (SIGALRM1) /* m:n condition variables */
+  signal_names[SIGALRM1] = "ALRM1";
+#endif
+
+#if defined (SIGWAITING)       /* m:n scheduling */
+  signal_names[SIGWAITING] = "WAITING";
+#endif
+
+#if defined (SIGGRANT) /* HFT monitor mode granted */
+  signal_names[SIGGRANT] = "GRANT";
+#endif
+
+#if defined (SIGKAP)   /* keep alive poll from native keyboard */
+  signal_names[SIGKAP] = "KAP";
+#endif
+
+#if defined (SIGRETRACT) /* HFT monitor mode retracted */
+  signal_names[SIGRETRACT] = "RETRACT";
+#endif
+
+#if defined (SIGSOUND) /* HFT sound sequence has completed */
+  signal_names[SIGSOUND] = "SOUND";
+#endif
+
+#if defined (SIGSAK)   /* Secure Attention Key */
+  signal_names[SIGSAK] = "SAK";
+#endif
+
+/* SunOS5 */
+#if defined (SIGLWP)   /* special signal used by thread library */
+  signal_names[SIGLWP] = "LWP";
+#endif
+
+#if defined (SIGFREEZE)        /* special signal used by CPR */
+  signal_names[SIGFREEZE] = "FREEZE";
+#endif
+
+#if defined (SIGTHAW)  /* special signal used by CPR */
+  signal_names[SIGTHAW] = "THAW";
+#endif
+
+#if defined (SIGCANCEL)        /* thread cancellation signal used by libthread */
+  signal_names[SIGCANCEL] = "CANCEL";
+#endif
+
+/* HP-UX */
+#if defined (SIGDIL)   /* DIL signal (?) */
+  signal_names[SIGDIL] = "DIL";
+#endif
+
+/* System V */
+#if defined (SIGCLD)   /* Like SIGCHLD.  */
+  signal_names[SIGCLD] = "CLD";
+#endif
+
+#if defined (SIGPWR)   /* power state indication */
+  signal_names[SIGPWR] = "PWR";
+#endif
+
+#if defined (SIGPOLL)  /* Pollable event (for streams)  */
+  signal_names[SIGPOLL] = "POLL";
+#endif
+
+/* Unknown */
+#if defined (SIGWINDOW)
+  signal_names[SIGWINDOW] = "WINDOW";
+#endif
+
+/* Common */
+#if defined (SIGHUP)   /* hangup */
+  signal_names[SIGHUP] = "HUP";
+#endif
+
+#if defined (SIGINT)   /* interrupt */
+  signal_names[SIGINT] = "INT";
+#endif
+
+#if defined (SIGQUIT)  /* quit */
+  signal_names[SIGQUIT] = "QUIT";
+#endif
+
+#if defined (SIGILL)   /* illegal instruction (not reset when caught) */
+  signal_names[SIGILL] = "ILL";
+#endif
+
+#if defined (SIGTRAP)  /* trace trap (not reset when caught) */
+  signal_names[SIGTRAP] = "TRAP";
+#endif
+
+#if defined (SIGIOT)   /* IOT instruction */
+  signal_names[SIGIOT] = "IOT";
+#endif
+
+#if defined (SIGABRT)  /* Cause current process to dump core. */
+  signal_names[SIGABRT] = "ABRT";
+#endif
+
+#if defined (SIGEMT)   /* EMT instruction */
+  signal_names[SIGEMT] = "EMT";
+#endif
+
+#if defined (SIGFPE)   /* floating point exception */
+  signal_names[SIGFPE] = "FPE";
+#endif
+
+#if defined (SIGKILL)  /* kill (cannot be caught or ignored) */
+  signal_names[SIGKILL] = "KILL";
+#endif
+
+#if defined (SIGBUS)   /* bus error */
+  signal_names[SIGBUS] = "BUS";
+#endif
+
+#if defined (SIGSEGV)  /* segmentation violation */
+  signal_names[SIGSEGV] = "SEGV";
+#endif
+
+#if defined (SIGSYS)   /* bad argument to system call */
+  signal_names[SIGSYS] = "SYS";
+#endif
+
+#if defined (SIGPIPE)  /* write on a pipe with no one to read it */
+  signal_names[SIGPIPE] = "PIPE";
+#endif
+
+#if defined (SIGALRM)  /* alarm clock */
+  signal_names[SIGALRM] = "ALRM";
+#endif
+
+#if defined (SIGTERM)  /* software termination signal from kill */
+  signal_names[SIGTERM] = "TERM";
+#endif
+
+#if defined (SIGURG)   /* urgent condition on IO channel */
+  signal_names[SIGURG] = "URG";
+#endif
+
+#if defined (SIGSTOP)  /* sendable stop signal not from tty */
+  signal_names[SIGSTOP] = "STOP";
+#endif
+
+#if defined (SIGTSTP)  /* stop signal from tty */
+  signal_names[SIGTSTP] = "TSTP";
+#endif
+
+#if defined (SIGCONT)  /* continue a stopped process */
+  signal_names[SIGCONT] = "CONT";
+#endif
+
+#if defined (SIGCHLD)  /* to parent on child stop or exit */
+  signal_names[SIGCHLD] = "CHLD";
+#endif
+
+#if defined (SIGTTIN)  /* to readers pgrp upon background tty read */
+  signal_names[SIGTTIN] = "TTIN";
+#endif
+
+#if defined (SIGTTOU)  /* like TTIN for output if (tp->t_local&LTOSTOP) */
+  signal_names[SIGTTOU] = "TTOU";
+#endif
+
+#if defined (SIGIO)    /* input/output possible signal */
+  signal_names[SIGIO] = "IO";
+#endif
+
+#if defined (SIGXCPU)  /* exceeded CPU time limit */
+  signal_names[SIGXCPU] = "XCPU";
+#endif
+
+#if defined (SIGXFSZ)  /* exceeded file size limit */
+  signal_names[SIGXFSZ] = "XFSZ";
+#endif
+
+#if defined (SIGVTALRM)        /* virtual time alarm */
+  signal_names[SIGVTALRM] = "VTALRM";
+#endif
+
+#if defined (SIGPROF)  /* profiling time alarm */
+  signal_names[SIGPROF] = "PROF";
+#endif
+
+#if defined (SIGWINCH) /* window changed */
+  signal_names[SIGWINCH] = "WINCH";
+#endif
+
+/* 4.4 BSD */
+#if defined (SIGINFO) && !defined (_SEQUENT_)  /* information request */
+  signal_names[SIGINFO] = "INFO";
+#endif
+
+#if defined (SIGUSR1)  /* user defined signal 1 */
+  signal_names[SIGUSR1] = "USR1";
+#endif
+
+#if defined (SIGUSR2)  /* user defined signal 2 */
+  signal_names[SIGUSR2] = "USR2";
+#endif
+
+#if defined (SIGKILLTHR)       /* BeOS: Kill Thread */
+  signal_names[SIGKILLTHR] = "KILLTHR";
+#endif
+
+  for (i = 0; i < NSIG; i++)
+    if (signal_names[i] == (char *)NULL)
+      {
+       signal_names[i] = (char *)malloc (18);
+       if (signal_names[i])
+         sprintf (signal_names[i], "%d", i);
+      }
+}
+
+void
+write_signames (stream)
+     FILE *stream;
+{
+  register int i;
+
+  fprintf (stream, "/* This file was automatically created by %s.\n",
+          progname);
+  fprintf (stream, "   Do not edit.  Edit support/mksignames.c instead. */\n\n");
+  fprintf (stream, "#include <signal.h>\n\n");
+  fprintf (stream,
+          "/* A translation list so we can be polite to our users. */\n");
+  fprintf (stream, "const char *const signal_names[NSIG + 1] = {\n");
+
+  for (i = 0; i <= LASTSIG; i++)
+    fprintf (stream, "    \"%s\",\n", signal_names[i]);
+
+  fprintf (stream, "    (char *)0x0\n");
+  fprintf (stream, "};\n");
+}
+
+int
+main(int argc, char **argv)
+{
+  char *stream_name;
+  FILE *stream;
+
+  progname = argv[0];
+
+  if (argc == 1)
+    {
+      stream_name = "signames.c";
+    }
+  else if (argc == 2)
+    {
+      stream_name = argv[1];
+    }
+  else
+    {
+      fprintf (stderr, "Usage: %s [output-file]\n", progname);
+      exit (1);
+    }
+
+  stream = fopen (stream_name, "w");
+  if (!stream)
+    {
+      fprintf (stderr, "%s: %s: cannot open for writing\n",
+              progname, stream_name);
+      exit (2);
+    }
+
+  initialize_signames ();
+  write_signames (stream);
+  exit (0);
+}
diff --git a/src/mksyntax.c b/src/mksyntax.c
new file mode 100644 (file)
index 0000000..a23c18c
--- /dev/null
@@ -0,0 +1,315 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This program creates syntax.h and syntax.c.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "parser.h"
+
+
+struct synclass {
+       char *name;
+       char *comment;
+};
+
+/* Syntax classes */
+struct synclass synclass[] = {
+       { "CWORD",      "character is nothing special" },
+       { "CNL",        "newline character" },
+       { "CBACK",      "a backslash character" },
+       { "CSQUOTE",    "single quote" },
+       { "CDQUOTE",    "double quote" },
+       { "CENDQUOTE",  "a terminating quote" },
+       { "CBQUOTE",    "backwards single quote" },
+       { "CVAR",       "a dollar sign" },
+       { "CENDVAR",    "a '}' character" },
+       { "CLP",        "a left paren in arithmetic" },
+       { "CRP",        "a right paren in arithmetic" },
+       { "CEOF",       "end of file" },
+       { "CCTL",       "like CWORD, except it must be escaped" },
+       { "CSPCL",      "these terminate a word" },
+       { "CIGN",       "character should be ignored" },
+       { NULL,         NULL }
+};
+
+
+/*
+ * Syntax classes for is_ functions.  Warning:  if you add new classes
+ * you may have to change the definition of the is_in_name macro.
+ */
+struct synclass is_entry[] = {
+       { "ISDIGIT",    "a digit" },
+       { "ISUPPER",    "an upper case letter" },
+       { "ISLOWER",    "a lower case letter" },
+       { "ISUNDER",    "an underscore" },
+       { "ISSPECL",    "the name of a special parameter" },
+       { NULL,         NULL }
+};
+
+static char writer[] = "\
+/*\n\
+ * This file was generated by the mksyntax program.\n\
+ */\n\
+\n";
+
+
+static FILE *cfile;
+static FILE *hfile;
+static char *syntax[513];
+
+static void filltable(char *);
+static void init(void);
+static void add(char *, char *);
+static void print(char *);
+static void output_type_macros(void);
+int main(int, char **);
+
+int
+main(int argc, char **argv)
+{
+       int i;
+       char buf[80];
+       int pos;
+
+       /* Create output files */
+       if ((cfile = fopen("syntax.c", "w")) == NULL) {
+               perror("syntax.c");
+               exit(2);
+       }
+       if ((hfile = fopen("syntax.h", "w")) == NULL) {
+               perror("syntax.h");
+               exit(2);
+       }
+       fputs(writer, hfile);
+       fputs(writer, cfile);
+
+       fputs("#include <ctype.h>\n", hfile);
+       fputs("\n", hfile);
+       fputs("#ifdef CEOF\n", hfile);
+       fputs("#undef CEOF\n", hfile);
+       fputs("#endif\n", hfile);
+       fputs("\n", hfile);
+
+       /* Generate the #define statements in the header file */
+       fputs("/* Syntax classes */\n", hfile);
+       for (i = 0 ; synclass[i].name ; i++) {
+               sprintf(buf, "#define %s %d", synclass[i].name, i);
+               fputs(buf, hfile);
+               for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
+                       putc('\t', hfile);
+               fprintf(hfile, "/* %s */\n", synclass[i].comment);
+       }
+       putc('\n', hfile);
+       fputs("/* Syntax classes for is_ functions */\n", hfile);
+       for (i = 0 ; is_entry[i].name ; i++) {
+               sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i);
+               fputs(buf, hfile);
+               for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
+                       putc('\t', hfile);
+               fprintf(hfile, "/* %s */\n", is_entry[i].comment);
+       }
+       putc('\n', hfile);
+       fprintf(hfile, "#define SYNBASE %d\n", 130);
+       fprintf(hfile, "#define PEOF %d\n\n", -130);
+       fprintf(hfile, "#define PEOA %d\n\n", -129);
+       putc('\n', hfile);
+       fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile);
+       fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile);
+       fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile);
+       fputs("#define ARISYNTAX (arisyntax + SYNBASE)\n", hfile);
+       putc('\n', hfile);
+       output_type_macros();           /* is_digit, etc. */
+       putc('\n', hfile);
+
+       /* Generate the syntax tables. */
+       fputs("#include \"shell.h\"\n", cfile);
+       fputs("#include \"syntax.h\"\n\n", cfile);
+       init();
+       fputs("/* syntax table used when not in quotes */\n", cfile);
+       add("\n", "CNL");
+       add("\\", "CBACK");
+       add("'", "CSQUOTE");
+       add("\"", "CDQUOTE");
+       add("`", "CBQUOTE");
+       add("$", "CVAR");
+       add("}", "CENDVAR");
+       add("<>();&| \t", "CSPCL");
+       syntax[1] = "CSPCL";
+       print("basesyntax");
+       init();
+       fputs("\n/* syntax table used when in double quotes */\n", cfile);
+       add("\n", "CNL");
+       add("\\", "CBACK");
+       add("\"", "CENDQUOTE");
+       add("`", "CBQUOTE");
+       add("$", "CVAR");
+       add("}", "CENDVAR");
+       /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
+       add("!*?[=~:/-]", "CCTL");
+       print("dqsyntax");
+       init();
+       fputs("\n/* syntax table used when in single quotes */\n", cfile);
+       add("\n", "CNL");
+       add("'", "CENDQUOTE");
+       /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
+       add("!*?[=~:/-]\\", "CCTL");
+       print("sqsyntax");
+       init();
+       fputs("\n/* syntax table used when in arithmetic */\n", cfile);
+       add("\n", "CNL");
+       add("\\", "CBACK");
+       add("`", "CBQUOTE");
+       add("$", "CVAR");
+       add("}", "CENDVAR");
+       add("(", "CLP");
+       add(")", "CRP");
+       print("arisyntax");
+       filltable("0");
+       fputs("\n/* character classification table */\n", cfile);
+       add("0123456789", "ISDIGIT");
+       add("abcdefghijklmnopqrstucvwxyz", "ISLOWER");
+       add("ABCDEFGHIJKLMNOPQRSTUCVWXYZ", "ISUPPER");
+       add("_", "ISUNDER");
+       add("#?$!-*@", "ISSPECL");
+       print("is_type");
+       exit(0);
+       /* NOTREACHED */
+}
+
+
+
+/*
+ * Clear the syntax table.
+ */
+
+static void
+filltable(char *dftval)
+{
+       int i;
+
+       for (i = 0 ; i < 258; i++)
+               syntax[i] = dftval;
+}
+
+
+/*
+ * Initialize the syntax table with default values.
+ */
+
+static void
+init(void)
+{
+       int ctl;
+
+       filltable("CWORD");
+       syntax[0] = "CEOF";
+       syntax[1] = "CIGN";
+       for (ctl = CTL_FIRST; ctl <= CTL_LAST; ctl++ )
+               syntax[130 + ctl] = "CCTL";
+}
+
+
+/*
+ * Add entries to the syntax table.
+ */
+
+static void
+add(char *p, char *type)
+{
+       while (*p)
+               syntax[(signed char)*p++ + 130] = type;
+}
+
+
+
+/*
+ * Output the syntax table.
+ */
+
+static void
+print(char *name)
+{
+       int i;
+       int col;
+
+       fprintf(hfile, "extern const char %s[];\n", name);
+       fprintf(cfile, "const char %s[] = {\n", name);
+       col = 0;
+       for (i = 0 ; i < 258; i++) {
+               if (i == 0) {
+                       fputs("      ", cfile);
+               } else if ((i & 03) == 0) {
+                       fputs(",\n      ", cfile);
+                       col = 0;
+               } else {
+                       putc(',', cfile);
+                       while (++col < 9 * (i & 03))
+                               putc(' ', cfile);
+               }
+               fputs(syntax[i], cfile);
+               col += strlen(syntax[i]);
+       }
+       fputs("\n};\n", cfile);
+}
+
+
+
+/*
+ * Output character classification macros (e.g. is_digit).  If digits are
+ * contiguous, we can test for them quickly.
+ */
+
+static char *macro[] = {
+       "#define is_digit(c)\t((unsigned)((c) - '0') <= 9)\n",
+       "#define is_alpha(c)\tisalpha((unsigned char)(c))\n",
+       "#define is_name(c)\t((c) == '_' || isalpha((unsigned char)(c)))\n",
+       "#define is_in_name(c)\t((c) == '_' || isalnum((unsigned char)(c)))\n",
+       "#define is_special(c)\t((is_type+SYNBASE)[(signed char)(c)] & (ISSPECL|ISDIGIT))\n",
+       NULL
+};
+
+static void
+output_type_macros(void)
+{
+       char **pp;
+
+       for (pp = macro ; *pp ; pp++)
+               fputs(*pp, hfile);
+       fputs("#define digit_val(c)\t((c) - '0')\n", hfile);
+}
diff --git a/src/mktokens b/src/mktokens
new file mode 100644 (file)
index 0000000..cd52241
--- /dev/null
@@ -0,0 +1,95 @@
+#!/bin/sh -
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#      Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#      @(#)mktokens    8.1 (Berkeley) 5/31/93
+
+# The following is a list of tokens.  The second column is nonzero if the
+# token marks the end of a list.  The third column is the name to print in
+# error messages.
+
+cat > /tmp/ka$$ <<\!
+TEOF   1       end of file
+TNL    0       newline
+TSEMI  0       ";"
+TBACKGND 0     "&"
+TAND   0       "&&"
+TOR    0       "||"
+TPIPE  0       "|"
+TLP    0       "("
+TRP    1       ")"
+TENDCASE 1     ";;"
+TENDBQUOTE 1   "`"
+TREDIR 0       redirection
+TWORD  0       word
+TNOT   0       "!"
+TCASE  0       "case"
+TDO    1       "do"
+TDONE  1       "done"
+TELIF  1       "elif"
+TELSE  1       "else"
+TESAC  1       "esac"
+TFI    1       "fi"
+TFOR   0       "for"
+TIF    0       "if"
+TIN    0       "in"
+TTHEN  1       "then"
+TUNTIL 0       "until"
+TWHILE 0       "while"
+TBEGIN 0       "{"
+TEND   1       "}"
+!
+nl=`wc -l /tmp/ka$$`
+exec > token.h
+awk '{print "#define " $1 " " NR-1}' /tmp/ka$$
+
+exec > token_vars.h
+
+echo '
+/* Array indicating which tokens mark the end of a list */
+static const char tokendlist[] = {'
+awk '{print "\t" $2 ","}' /tmp/ka$$
+echo '};
+
+static const char *const tokname[] = {'
+sed -e 's/"/\\"/g' \
+    -e 's/[^    ]*[     ][      ]*[^    ]*[     ][      ]*\(.*\)/      "\1",/' \
+    /tmp/ka$$
+echo '};
+'
+sed 's/"//g' /tmp/ka$$ | awk '
+/TNOT/{print "#define KWDOFFSET " NR-1; print ""; 
+      print "static const char *const parsekwd[] = {"}
+/TNOT/,/neverfound/{if (last) print "  \"" last "\","; last = $3}
+END{print "    \"" last "\"\n};"}'
+
+rm /tmp/ka$$
diff --git a/src/myhistedit.h b/src/myhistedit.h
new file mode 100644 (file)
index 0000000..22e5c43
--- /dev/null
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)myhistedit.h        8.2 (Berkeley) 5/4/95
+ */
+
+#include <histedit.h>
+
+extern History *hist;
+extern EditLine *el;
+extern int displayhist;
+
+void histedit(void);
+void sethistsize(const char *);
+void setterm(const char *);
+int histcmd(int, char **);
+int not_fcnumber(char *);
+int str_to_event(const char *, int);
+
diff --git a/src/mystring.c b/src/mystring.c
new file mode 100644 (file)
index 0000000..0106bd2
--- /dev/null
@@ -0,0 +1,257 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * String functions.
+ *
+ *     equal(s1, s2)           Return true if strings are equal.
+ *     scopy(from, to)         Copy a string.
+ *     scopyn(from, to, n)     Like scopy, but checks for overflow.
+ *     number(s)               Convert a string of digits to an integer.
+ *     is_number(s)            Return true if s is a string of digits.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include "shell.h"
+#include "syntax.h"
+#include "error.h"
+#include "mystring.h"
+#include "memalloc.h"
+#include "parser.h"
+#include "system.h"
+
+
+char nullstr[1];               /* zero length string */
+const char spcstr[] = " ";
+const char snlfmt[] = "%s\n";
+const char dolatstr[] = { CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=',
+                         CTLQUOTEMARK, '\0' };
+const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
+const char illnum[] = "Illegal number: %s";
+const char homestr[] = "HOME";
+
+/*
+ * equal - #defined in mystring.h
+ */
+
+/*
+ * scopy - #defined in mystring.h
+ */
+
+
+#if 0
+/*
+ * scopyn - copy a string from "from" to "to", truncating the string
+ *             if necessary.  "To" is always nul terminated, even if
+ *             truncation is performed.  "Size" is the size of "to".
+ */
+
+void
+scopyn(const char *from, char *to, int size)
+{
+
+       while (--size > 0) {
+               if ((*to++ = *from++) == '\0')
+                       return;
+       }
+       *to = '\0';
+}
+#endif
+
+
+/*
+ * prefix -- see if pfx is a prefix of string.
+ */
+
+char *
+prefix(const char *string, const char *pfx)
+{
+       while (*pfx) {
+               if (*pfx++ != *string++)
+                       return 0;
+       }
+       return (char *) string;
+}
+
+void badnum(const char *s)
+{
+       sh_error(illnum, s);
+}
+
+/*
+ * Convert a string into an integer of type intmax_t.  Alow trailing spaces.
+ */
+intmax_t atomax(const char *s, int base)
+{
+       char *p;
+       intmax_t r;
+
+       errno = 0;
+       r = strtoimax(s, &p, base);
+
+       if (errno != 0)
+               badnum(s);
+
+       /*
+        * Disallow completely blank strings in non-arithmetic (base != 0)
+        * contexts.
+        */
+       if (p == s && base)
+               badnum(s);
+
+       while (isspace((unsigned char)*p))
+             p++;
+
+       if (*p)
+               badnum(s);
+
+       return r;
+}
+
+intmax_t atomax10(const char *s)
+{
+       return atomax(s, 10);
+}
+
+/*
+ * Convert a string of digits to an integer, printing an error message on
+ * failure.
+ */
+
+int
+number(const char *s)
+{
+       intmax_t n = atomax10(s);
+
+       if (n < 0 || n > INT_MAX)
+               badnum(s);
+
+       return n;
+}
+
+
+
+/*
+ * Check for a valid number.  This should be elsewhere.
+ */
+
+int
+is_number(const char *p)
+{
+       do {
+               if (! is_digit(*p))
+                       return 0;
+       } while (*++p != '\0');
+       return 1;
+}
+
+
+/*
+ * Produce a possibly single quoted string suitable as input to the shell.
+ * The return string is allocated on the stack.
+ */
+
+char *
+single_quote(const char *s) {
+       char *p;
+
+       STARTSTACKSTR(p);
+
+       do {
+               char *q;
+               size_t len;
+
+               len = strchrnul(s, '\'') - s;
+
+               q = p = makestrspace(len + 3, p);
+
+               *q++ = '\'';
+               q = mempcpy(q, s, len);
+               *q++ = '\'';
+               s += len;
+
+               STADJUST(q - p, p);
+
+               len = strspn(s, "'");
+               if (!len)
+                       break;
+
+               q = p = makestrspace(len + 3, p);
+
+               *q++ = '"';
+               q = mempcpy(q, s, len);
+               *q++ = '"';
+               s += len;
+
+               STADJUST(q - p, p);
+       } while (*s);
+
+       USTPUTC(0, p);
+
+       return stackblock();
+}
+
+/*
+ * Like strdup but works with the ash stack.
+ */
+
+char *
+sstrdup(const char *p)
+{
+       size_t len = strlen(p) + 1;
+       return memcpy(stalloc(len), p, len);
+}
+
+/*
+ * Wrapper around strcmp for qsort/bsearch/...
+ */
+int
+pstrcmp(const void *a, const void *b)
+{
+       return strcmp(*(const char *const *) a, *(const char *const *) b);
+}
+
+/*
+ * Find a string is in a sorted array.
+ */
+const char *const *
+findstring(const char *s, const char *const *array, size_t nmemb)
+{
+       return bsearch(&s, array, nmemb, sizeof(const char *), pstrcmp);
+}
diff --git a/src/mystring.h b/src/mystring.h
new file mode 100644 (file)
index 0000000..083ea98
--- /dev/null
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)mystring.h  8.2 (Berkeley) 5/4/95
+ */
+
+#include <inttypes.h>
+#include <string.h>
+
+extern const char snlfmt[];
+extern const char spcstr[];
+extern const char dolatstr[];
+#define DOLATSTRLEN 6
+extern const char qchars[];
+extern const char illnum[];
+extern const char homestr[];
+
+#if 0
+void scopyn(const char *, char *, int);
+#endif
+char *prefix(const char *, const char *);
+void badnum(const char *s) __attribute__ ((noreturn));
+intmax_t atomax(const char *, int);
+intmax_t atomax10(const char *);
+int number(const char *);
+int is_number(const char *);
+char *single_quote(const char *);
+char *sstrdup(const char *);
+int pstrcmp(const void *, const void *);
+const char *const *findstring(const char *, const char *const *, size_t);
+
+#define equal(s1, s2)  (strcmp(s1, s2) == 0)
+#define scopy(s1, s2)  ((void)strcpy(s2, s1))
diff --git a/src/nodes.c.pat b/src/nodes.c.pat
new file mode 100644 (file)
index 0000000..9125bc7
--- /dev/null
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95
+ */
+
+#include <stdlib.h>
+/*
+ * Routine for dealing with parsed shell commands.
+ */
+
+#include "shell.h"
+#include "nodes.h"
+#include "memalloc.h"
+#include "machdep.h"
+#include "mystring.h"
+#include "system.h"
+
+
+int     funcblocksize;         /* size of structures in function */
+int     funcstringsize;                /* size of strings in node */
+pointer funcblock;             /* block to allocate function from */
+char   *funcstring;            /* block to allocate strings from */
+
+%SIZES
+
+
+STATIC void calcsize(union node *);
+STATIC void sizenodelist(struct nodelist *);
+STATIC union node *copynode(union node *);
+STATIC struct nodelist *copynodelist(struct nodelist *);
+STATIC char *nodesavestr(char *);
+
+
+
+/*
+ * Make a copy of a parse tree.
+ */
+
+struct funcnode *
+copyfunc(union node *n)
+{
+       struct funcnode *f;
+       size_t blocksize;
+
+       funcblocksize = offsetof(struct funcnode, n);
+       funcstringsize = 0;
+       calcsize(n);
+       blocksize = funcblocksize;
+       f = ckmalloc(blocksize + funcstringsize);
+       funcblock = (char *) f + offsetof(struct funcnode, n);
+       funcstring = (char *) f + blocksize;
+       copynode(n);
+       f->count = 0;
+       return f;
+}
+
+
+
+STATIC void
+calcsize(n)
+       union node *n;
+{
+       %CALCSIZE
+}
+
+
+
+STATIC void
+sizenodelist(lp)
+       struct nodelist *lp;
+{
+       while (lp) {
+               funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
+               calcsize(lp->n);
+               lp = lp->next;
+       }
+}
+
+
+
+STATIC union node *
+copynode(n)
+       union node *n;
+{
+       union node *new;
+
+       %COPY
+       return new;
+}
+
+
+STATIC struct nodelist *
+copynodelist(lp)
+       struct nodelist *lp;
+{
+       struct nodelist *start;
+       struct nodelist **lpp;
+
+       lpp = &start;
+       while (lp) {
+               *lpp = funcblock;
+               funcblock = (char *) funcblock +
+                   SHELL_ALIGN(sizeof(struct nodelist));
+               (*lpp)->n = copynode(lp->n);
+               lp = lp->next;
+               lpp = &(*lpp)->next;
+       }
+       *lpp = NULL;
+       return start;
+}
+
+
+
+STATIC char *
+nodesavestr(s)
+       char   *s;
+{
+       char   *rtn = funcstring;
+
+       funcstring = stpcpy(funcstring, s) + 1;
+       return rtn;
+}
+
+
+
+/*
+ * Free a parse tree.
+ */
+
+void
+freefunc(struct funcnode *f)
+{
+       if (f && --f->count < 0)
+               ckfree(f);
+}
diff --git a/src/nodetypes b/src/nodetypes
new file mode 100644 (file)
index 0000000..ceaf478
--- /dev/null
@@ -0,0 +1,151 @@
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#      Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#      @(#)nodetypes   8.2 (Berkeley) 5/4/95
+
+# This file describes the nodes used in parse trees.  Unindented lines
+# contain a node type followed by a structure tag.  Subsequent indented
+# lines specify the fields of the structure.  Several node types can share
+# the same structure, in which case the fields of the structure should be
+# specified only once.
+#
+# A field of a structure is described by the name of the field followed
+# by a type.  The currently implemented types are:
+#      nodeptr - a pointer to a node
+#      nodelist - a pointer to a list of nodes
+#      string - a pointer to a nul terminated string
+#      int - an integer
+#      other - any type that can be copied by assignment
+#      temp - a field that doesn't have to be copied when the node is copied
+# The last two types should be followed by the text of a C declaration for
+# the field.
+
+NCMD ncmd                      # a simple command
+       type      int
+       linno     int
+       assign    nodeptr               # variable assignments
+       args      nodeptr               # the arguments
+       redirect  nodeptr               # list of file redirections
+
+NPIPE npipe                    # a pipeline
+       type      int
+       backgnd   int                   # set to run pipeline in background
+       cmdlist   nodelist              # the commands in the pipeline
+
+NREDIR nredir                  # redirection (of a complex command)
+       type      int
+       linno     int
+       n         nodeptr               # the command
+       redirect  nodeptr               # list of file redirections
+
+NBACKGND nredir                        # run command in background
+NSUBSHELL nredir               # run command in a subshell
+
+NAND nbinary                   # the && operator
+NOR nbinary                    # the || operator
+
+NSEMI nbinary                  # two commands separated by a semicolon
+       type      int
+       ch1       nodeptr               # the first child
+       ch2       nodeptr               # the second child
+
+NIF nif                                # the if statement.  Elif clauses are handled
+       type      int               # using multiple if nodes.
+       test      nodeptr               # if test
+       ifpart    nodeptr               # then ifpart
+       elsepart  nodeptr               # else elsepart
+
+NWHILE nbinary                 # the while statement.  First child is the test
+NUNTIL nbinary                 # the until statement
+
+NFOR nfor                      # the for statement
+       type      int
+       linno     int
+       args      nodeptr               # for var in args
+       body      nodeptr               # do body; done
+       var       string                # the for variable
+
+NCASE ncase                    # a case statement
+       type      int
+       linno     int
+       expr      nodeptr               # the word to switch on
+       cases     nodeptr               # the list of cases (NCLIST nodes)
+
+NCLIST nclist                  # a case
+       type      int
+       next      nodeptr               # the next case in list
+       pattern   nodeptr               # list of patterns for this case
+       body      nodeptr               # code to execute for this case
+
+
+NDEFUN ndefun                  # a function
+       type      int
+       linno     int
+       text      string
+       body      nodeptr
+
+NARG narg                      # represents a word
+       type      int
+       next      nodeptr               # next word in list
+       text      string                # the text of the word
+       backquote nodelist              # list of commands in back quotes
+
+NTO nfile                      # fd> fname
+NCLOBBER nfile                 # fd>| fname
+NFROM nfile                    # fd< fname
+NFROMTO nfile                  # fd<> fname
+NAPPEND nfile                  # fd>> fname
+       type      int
+       next      nodeptr               # next redirection in list
+       fd        int                   # file descriptor being redirected
+       fname     nodeptr               # file name, in a NARG node
+       expfname  temp  char *expfname  # actual file name
+
+NTOFD ndup                     # fd<&dupfd
+NFROMFD ndup                   # fd>&dupfd
+       type      int
+       next      nodeptr               # next redirection in list
+       fd        int                   # file descriptor being redirected
+       dupfd     int                   # file descriptor to duplicate
+       vname     nodeptr               # file name if fd>&$var
+
+
+NHERE nhere                    # fd<<\!
+NXHERE nhere                   # fd<<!
+       type      int
+       next      nodeptr               # next redirection in list
+       fd        int                   # file descriptor being redirected
+       doc       nodeptr               # input to command (NARG node)
+
+NNOT nnot                      # ! command  (actually pipeline)
+       type    int
+       com     nodeptr
diff --git a/src/options.c b/src/options.c
new file mode 100644 (file)
index 0000000..6f381e6
--- /dev/null
@@ -0,0 +1,559 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#define DEFINE_OPTIONS
+#include "options.h"
+#undef DEFINE_OPTIONS
+#include "nodes.h"     /* for other header files */
+#include "eval.h"
+#include "jobs.h"
+#include "input.h"
+#include "output.h"
+#include "trap.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+#include "show.h"
+
+char *arg0;                    /* value of $0 */
+struct shparam shellparam;     /* current positional parameters */
+char **argptr;                 /* argument list for builtin commands */
+char *optionarg;               /* set by nextopt (like getopt) */
+char *optptr;                  /* used by nextopt */
+
+char *minusc;                  /* argument to -c option */
+
+static const char *const optnames[NOPTS] = {
+       "errexit",
+       "noglob",
+       "ignoreeof",
+       "interactive",
+       "monitor",
+       "noexec",
+       "stdin",
+       "xtrace",
+       "verbose",
+       "vi",
+       "emacs",
+       "noclobber",
+       "allexport",
+       "notify",
+       "nounset",
+       "nolog",
+       "debug",
+};
+
+const char optletters[NOPTS] = {
+       'e',
+       'f',
+       'I',
+       'i',
+       'm',
+       'n',
+       's',
+       'x',
+       'v',
+       'V',
+       'E',
+       'C',
+       'a',
+       'b',
+       'u',
+       0,
+       0,
+};
+
+char optlist[NOPTS];
+
+
+static int options(int);
+STATIC void minus_o(char *, int);
+STATIC void setoption(int, int);
+STATIC int getopts(char *, char *, char **);
+
+
+/*
+ * Process the shell command line arguments.
+ */
+
+int
+procargs(int argc, char **argv)
+{
+       int i;
+       const char *xminusc;
+       char **xargv;
+       int login;
+
+       xargv = argv;
+       login = xargv[0] && xargv[0][0] == '-';
+       arg0 = xargv[0];
+       if (argc > 0)
+               xargv++;
+       for (i = 0; i < NOPTS; i++)
+               optlist[i] = 2;
+       argptr = xargv;
+       login |= options(1);
+       xargv = argptr;
+       xminusc = minusc;
+       if (*xargv == NULL) {
+               if (xminusc)
+                       sh_error("-c requires an argument");
+               sflag = 1;
+       }
+       if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
+               iflag = 1;
+       if (mflag == 2)
+               mflag = iflag;
+       for (i = 0; i < NOPTS; i++)
+               if (optlist[i] == 2)
+                       optlist[i] = 0;
+#if DEBUG == 2
+       debug = 1;
+#endif
+       /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
+       if (xminusc) {
+               minusc = *xargv++;
+               if (*xargv)
+                       goto setarg0;
+       } else if (!sflag) {
+               setinputfile(*xargv, 0);
+setarg0:
+               arg0 = *xargv++;
+               commandname = arg0;
+       }
+
+       shellparam.p = xargv;
+       shellparam.optind = 1;
+       shellparam.optoff = -1;
+       /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
+       while (*xargv) {
+               shellparam.nparam++;
+               xargv++;
+       }
+       optschanged();
+
+       return login;
+}
+
+
+void
+optschanged(void)
+{
+#ifdef DEBUG
+       opentrace();
+#endif
+       setinteractive(iflag);
+#ifndef SMALL
+       histedit();
+#endif
+       setjobctl(mflag);
+}
+
+/*
+ * Process shell options.  The global variable argptr contains a pointer
+ * to the argument list; we advance it past the options.
+ */
+
+STATIC int
+options(int cmdline)
+{
+       char *p;
+       int val;
+       int c;
+       int login = 0;
+
+       if (cmdline)
+               minusc = NULL;
+       while ((p = *argptr) != NULL) {
+               argptr++;
+               if ((c = *p++) == '-') {
+                       val = 1;
+                        if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
+                                if (!cmdline) {
+                                        /* "-" means turn off -x and -v */
+                                        if (p[0] == '\0')
+                                                xflag = vflag = 0;
+                                        /* "--" means reset params */
+                                        else if (*argptr == NULL)
+                                               setparam(argptr);
+                                }
+                               break;    /* "-" or  "--" terminates options */
+                       }
+               } else if (c == '+') {
+                       val = 0;
+               } else {
+                       argptr--;
+                       break;
+               }
+               while ((c = *p++) != '\0') {
+                       if (c == 'c' && cmdline) {
+                               minusc = p;     /* command is after shell args*/
+                       } else if (c == 'l' && cmdline) {
+                               login = 1;
+                       } else if (c == 'o') {
+                               minus_o(*argptr, val);
+                               if (*argptr)
+                                       argptr++;
+                       } else {
+                               setoption(c, val);
+                       }
+               }
+       }
+
+       return login;
+}
+
+STATIC void
+minus_o(char *name, int val)
+{
+       int i;
+
+       if (name == NULL) {
+               if (val) {
+                       out1str("Current option settings\n");
+                       for (i = 0; i < NOPTS; i++)
+                               out1fmt("%-16s%s\n", optnames[i],
+                                       optlist[i] ? "on" : "off");
+               } else {
+                       for (i = 0; i < NOPTS; i++)
+                               out1fmt("set %s %s\n",
+                                       optlist[i] ? "-o" : "+o",
+                                       optnames[i]);
+
+               }
+       } else {
+               for (i = 0; i < NOPTS; i++)
+                       if (equal(name, optnames[i])) {
+                               optlist[i] = val;
+                               return;
+                       }
+               sh_error("Illegal option -o %s", name);
+       }
+}
+
+
+STATIC void
+setoption(int flag, int val)
+{
+       int i;
+
+       for (i = 0; i < NOPTS; i++)
+               if (optletters[i] == flag) {
+                       optlist[i] = val;
+                       if (val) {
+                               /* #%$ hack for ksh semantics */
+                               if (flag == 'V')
+                                       Eflag = 0;
+                               else if (flag == 'E')
+                                       Vflag = 0;
+                       }
+                       return;
+               }
+       sh_error("Illegal option -%c", flag);
+       /* NOTREACHED */
+}
+
+
+
+/*
+ * Set the shell parameters.
+ */
+
+void
+setparam(char **argv)
+{
+       char **newparam;
+       char **ap;
+       int nparam;
+
+       for (nparam = 0 ; argv[nparam] ; nparam++);
+       ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
+       while (*argv) {
+               *ap++ = savestr(*argv++);
+       }
+       *ap = NULL;
+       freeparam(&shellparam);
+       shellparam.malloc = 1;
+       shellparam.nparam = nparam;
+       shellparam.p = newparam;
+       shellparam.optind = 1;
+       shellparam.optoff = -1;
+}
+
+
+/*
+ * Free the list of positional parameters.
+ */
+
+void
+freeparam(volatile struct shparam *param)
+{
+       char **ap;
+
+       if (param->malloc) {
+               for (ap = param->p ; *ap ; ap++)
+                       ckfree(*ap);
+               ckfree(param->p);
+       }
+}
+
+
+
+/*
+ * The shift builtin command.
+ */
+
+int
+shiftcmd(int argc, char **argv)
+{
+       int n;
+       char **ap1, **ap2;
+
+       n = 1;
+       if (argc > 1)
+               n = number(argv[1]);
+       if (n > shellparam.nparam)
+               sh_error("can't shift that many");
+       INTOFF;
+       shellparam.nparam -= n;
+       for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
+               if (shellparam.malloc)
+                       ckfree(*ap1);
+       }
+       ap2 = shellparam.p;
+       while ((*ap2++ = *ap1++) != NULL);
+       shellparam.optind = 1;
+       shellparam.optoff = -1;
+       INTON;
+       return 0;
+}
+
+
+
+/*
+ * The set command builtin.
+ */
+
+int
+setcmd(int argc, char **argv)
+{
+       if (argc == 1)
+               return showvars(nullstr, 0, VUNSET);
+       INTOFF;
+       options(0);
+       optschanged();
+       if (*argptr != NULL) {
+               setparam(argptr);
+       }
+       INTON;
+       return 0;
+}
+
+
+void
+getoptsreset(value)
+       const char *value;
+{
+       shellparam.optind = number(value) ?: 1;
+       shellparam.optoff = -1;
+}
+
+/*
+ * The getopts builtin.  Shellparam.optnext points to the next argument
+ * to be processed.  Shellparam.optptr points to the next character to
+ * be processed in the current argument.  If shellparam.optnext is NULL,
+ * then it's the first time getopts has been called.
+ */
+
+int
+getoptscmd(int argc, char **argv)
+{
+       char **optbase;
+
+       if (argc < 3)
+               sh_error("Usage: getopts optstring var [arg]");
+       else if (argc == 3) {
+               optbase = shellparam.p;
+               if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
+                       shellparam.optind = 1;
+                       shellparam.optoff = -1;
+               }
+       }
+       else {
+               optbase = &argv[3];
+               if ((unsigned)shellparam.optind > argc - 2) {
+                       shellparam.optind = 1;
+                       shellparam.optoff = -1;
+               }
+       }
+
+       return getopts(argv[1], argv[2], optbase);
+}
+
+STATIC int
+getopts(char *optstr, char *optvar, char **optfirst)
+{
+       char *p, *q;
+       char c = '?';
+       int done = 0;
+       char s[2];
+       char **optnext;
+       int ind = shellparam.optind;
+       int off = shellparam.optoff;
+
+       shellparam.optind = -1;
+       optnext = optfirst + ind - 1;
+
+       if (ind <= 1 || off < 0 || strlen(optnext[-1]) < off)
+               p = NULL;
+       else
+               p = optnext[-1] + off;
+       if (p == NULL || *p == '\0') {
+               /* Current word is done, advance */
+               p = *optnext;
+               if (p == NULL || *p != '-' || *++p == '\0') {
+atend:
+                       p = NULL;
+                       done = 1;
+                       goto out;
+               }
+               optnext++;
+               if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
+                       goto atend;
+       }
+
+       c = *p++;
+       for (q = optstr; *q != c; ) {
+               if (*q == '\0') {
+                       if (optstr[0] == ':') {
+                               s[0] = c;
+                               s[1] = '\0';
+                               setvar("OPTARG", s, 0);
+                       } else {
+                               outfmt(&errout, "Illegal option -%c\n", c);
+                               (void) unsetvar("OPTARG");
+                       }
+                       c = '?';
+                       goto out;
+               }
+               if (*++q == ':')
+                       q++;
+       }
+
+       if (*++q == ':') {
+               if (*p == '\0' && (p = *optnext) == NULL) {
+                       if (optstr[0] == ':') {
+                               s[0] = c;
+                               s[1] = '\0';
+                               setvar("OPTARG", s, 0);
+                               c = ':';
+                       } else {
+                               outfmt(&errout, "No arg for -%c option\n", c);
+                               (void) unsetvar("OPTARG");
+                               c = '?';
+                       }
+                       goto out;
+               }
+
+               if (p == *optnext)
+                       optnext++;
+               setvar("OPTARG", p, 0);
+               p = NULL;
+       } else
+               setvar("OPTARG", nullstr, 0);
+
+out:
+       ind = optnext - optfirst + 1;
+       setvarint("OPTIND", ind, VNOFUNC);
+       s[0] = c;
+       s[1] = '\0';
+       setvar(optvar, s, 0);
+
+       shellparam.optoff = p ? p - *(optnext - 1) : -1;
+       shellparam.optind = ind;
+
+       return done;
+}
+
+/*
+ * XXX - should get rid of.  have all builtins use getopt(3).  the
+ * library getopt must have the BSD extension static variable "optreset"
+ * otherwise it can't be used within the shell safely.
+ *
+ * Standard option processing (a la getopt) for builtin routines.  The
+ * only argument that is passed to nextopt is the option string; the
+ * other arguments are unnecessary.  It return the character, or '\0' on
+ * end of input.
+ */
+
+int
+nextopt(const char *optstring)
+{
+       char *p;
+       const char *q;
+       char c;
+
+       if ((p = optptr) == NULL || *p == '\0') {
+               p = *argptr;
+               if (p == NULL || *p != '-' || *++p == '\0')
+                       return '\0';
+               argptr++;
+               if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
+                       return '\0';
+       }
+       c = *p++;
+       for (q = optstring ; *q != c ; ) {
+               if (*q == '\0')
+                       sh_error("Illegal option -%c", c);
+               if (*++q == ':')
+                       q++;
+       }
+       if (*++q == ':') {
+               if (*p == '\0' && (p = *argptr++) == NULL)
+                       sh_error("No arg for -%c option", c);
+               optionarg = p;
+               p = NULL;
+       }
+       optptr = p;
+       return c;
+}
diff --git a/src/options.h b/src/options.h
new file mode 100644 (file)
index 0000000..975fe33
--- /dev/null
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)options.h   8.2 (Berkeley) 5/4/95
+ */
+
+struct shparam {
+       int nparam;             /* # of positional parameters (without $0) */
+       unsigned char malloc;   /* if parameter list dynamically allocated */
+       char **p;               /* parameter list */
+       int optind;             /* next parameter to be processed by getopts */
+       int optoff;             /* used by getopts */
+};
+
+
+
+#define eflag optlist[0]
+#define fflag optlist[1]
+#define Iflag optlist[2]
+#define iflag optlist[3]
+#define mflag optlist[4]
+#define nflag optlist[5]
+#define sflag optlist[6]
+#define xflag optlist[7]
+#define vflag optlist[8]
+#define Vflag optlist[9]
+#define        Eflag optlist[10]
+#define        Cflag optlist[11]
+#define        aflag optlist[12]
+#define        bflag optlist[13]
+#define        uflag optlist[14]
+#define        nolog optlist[15]
+#define        debug optlist[16]
+
+#define NOPTS  17
+
+extern const char optletters[NOPTS];
+extern char optlist[NOPTS];
+
+
+extern char *minusc;           /* argument to -c option */
+extern char *arg0;             /* $0 */
+extern struct shparam shellparam;  /* $@ */
+extern char **argptr;          /* argument list for builtin commands */
+extern char *optionarg;                /* set by nextopt */
+extern char *optptr;           /* used by nextopt */
+
+int procargs(int, char **);
+void optschanged(void);
+void setparam(char **);
+void freeparam(volatile struct shparam *);
+int shiftcmd(int, char **);
+int setcmd(int, char **);
+int getoptscmd(int, char **);
+int nextopt(const char *);
+void getoptsreset(const char *);
diff --git a/src/output.c b/src/output.c
new file mode 100644 (file)
index 0000000..f62e7ea
--- /dev/null
@@ -0,0 +1,399 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Shell output routines.  We use our own output routines because:
+ *     When a builtin command is interrupted we have to discard
+ *             any pending output.
+ *     When a builtin command appears in back quotes, we want to
+ *             save the output of the command in a region obtained
+ *             via malloc, rather than doing a fork and reading the
+ *             output of the command via a pipe.
+ *     Our output routines may be smaller than the stdio routines.
+ */
+
+#include <sys/types.h>         /* quad_t */
+#include <sys/param.h>         /* BSD4_4 */
+#include <sys/ioctl.h>
+
+#include <stdio.h>     /* defines BUFSIZ */
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#ifdef USE_GLIBC_STDIO
+#include <fcntl.h>
+#endif
+#include <limits.h>
+
+#include "shell.h"
+#include "syntax.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "main.h"
+#include "system.h"
+
+
+#define OUTBUFSIZ BUFSIZ
+#define MEM_OUT -3             /* output to dynamically allocated memory */
+
+
+#ifdef USE_GLIBC_STDIO
+struct output output = {
+       stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 1, flags: 0
+};
+struct output errout = {
+       stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 2, flags: 0
+}
+#ifdef notyet
+struct output memout = {
+       stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: MEM_OUT, flags: 0
+};
+#endif
+#else
+struct output output = {
+       nextc: 0, end: 0, buf: 0, bufsize: OUTBUFSIZ, fd: 1, flags: 0
+};
+struct output errout = {
+       nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 2, flags: 0
+};
+struct output preverrout;
+#ifdef notyet
+struct output memout = {
+       nextc: 0, end: 0, buf: 0, bufsize: 0, fd: MEM_OUT, flags: 0
+};
+#endif
+#endif
+struct output *out1 = &output;
+struct output *out2 = &errout;
+
+
+#ifndef USE_GLIBC_STDIO
+static void __outstr(const char *, size_t, struct output *);
+#endif
+static int xvsnprintf(char *, size_t, const char *, va_list);
+
+
+#ifdef mkinit
+
+INCLUDE "output.h"
+INCLUDE "memalloc.h"
+
+INIT {
+#ifdef USE_GLIBC_STDIO
+       initstreams();
+#endif
+}
+
+RESET {
+#ifdef notyet
+       out1 = &output;
+       out2 = &errout;
+#ifdef USE_GLIBC_STDIO
+       if (memout.stream != NULL)
+               __closememout();
+#endif
+       if (memout.buf != NULL) {
+               ckfree(memout.buf);
+               memout.buf = NULL;
+       }
+#endif
+}
+
+#endif
+
+
+#ifndef USE_GLIBC_STDIO
+static void
+__outstr(const char *p, size_t len, struct output *dest)
+{
+       size_t bufsize;
+       size_t offset;
+       size_t nleft;
+
+       nleft = dest->end - dest->nextc;
+       if (nleft >= len) {
+buffered:
+               dest->nextc = mempcpy(dest->nextc, p, len);
+               return;
+       }
+
+       bufsize = dest->bufsize;
+       if (!bufsize) {
+               ;
+       } else if (dest->buf == NULL) {
+               if (dest->fd == MEM_OUT && len > bufsize) {
+                       bufsize = len;
+               }
+               offset = 0;
+               goto alloc;
+       } else if (dest->fd == MEM_OUT) {
+               offset = bufsize;
+               if (bufsize >= len) {
+                       bufsize <<= 1;
+               } else {
+                       bufsize += len;
+               }
+               if (bufsize < offset)
+                       goto err;
+alloc:
+               INTOFF;
+               dest->buf = ckrealloc(dest->buf, bufsize);
+               dest->bufsize = bufsize;
+               dest->end = dest->buf + bufsize;
+               dest->nextc = dest->buf + offset;
+               INTON;
+       } else {
+               flushout(dest);
+       }
+
+       nleft = dest->end - dest->nextc;
+       if (nleft > len)
+               goto buffered;
+
+       if ((xwrite(dest->fd, p, len))) {
+err:
+               dest->flags |= OUTPUT_ERR;
+       }
+}
+#endif
+
+
+void
+outstr(const char *p, struct output *file)
+{
+#ifdef USE_GLIBC_STDIO
+       INTOFF;
+       fputs(p, file->stream);
+       INTON;
+#else
+       size_t len;
+
+       len = strlen(p);
+       __outstr(p, len, file);
+#endif
+}
+
+
+#ifndef USE_GLIBC_STDIO
+
+
+void
+outcslow(int c, struct output *dest)
+{
+       char buf = c;
+       __outstr(&buf, 1, dest);
+}
+#endif
+
+
+void
+flushall(void)
+{
+       flushout(&output);
+#ifdef FLUSHERR
+       flushout(&errout);
+#endif
+}
+
+
+void
+flushout(struct output *dest)
+{
+#ifdef USE_GLIBC_STDIO
+       INTOFF;
+       fflush(dest->stream);
+       INTON;
+#else
+       size_t len;
+
+       len = dest->nextc - dest->buf;
+       if (!len || dest->fd < 0)
+               return;
+       dest->nextc = dest->buf;
+       if ((xwrite(dest->fd, dest->buf, len)))
+               dest->flags |= OUTPUT_ERR;
+#endif
+}
+
+
+void
+outfmt(struct output *file, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       doformat(file, fmt, ap);
+       va_end(ap);
+}
+
+
+void
+out1fmt(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       doformat(out1, fmt, ap);
+       va_end(ap);
+}
+
+
+int
+fmtstr(char *outbuf, size_t length, const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+
+       va_start(ap, fmt);
+       ret = xvsnprintf(outbuf, length, fmt, ap);
+       va_end(ap);
+       return ret;
+}
+
+
+#ifndef USE_GLIBC_STDIO
+void
+doformat(struct output *dest, const char *f, va_list ap)
+{
+       struct stackmark smark;
+       char *s;
+       int len, ret;
+       size_t size;
+       va_list ap2;
+
+       va_copy(ap2, ap);
+       size = dest->end - dest->nextc;
+       len = xvsnprintf(dest->nextc, size, f, ap2);
+       va_end(ap2);
+       if (len < 0) {
+               dest->flags |= OUTPUT_ERR;
+               return;
+       }
+       if (len < size) {
+               dest->nextc += len;
+               return;
+       }
+       setstackmark(&smark);
+       s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1);
+       ret = xvsnprintf(s, len + 1, f, ap);
+       if (ret == len)
+               __outstr(s, len, dest);
+       else
+               dest->flags |= OUTPUT_ERR;
+       popstackmark(&smark);
+}
+#endif
+
+
+
+/*
+ * Version of write which resumes after a signal is caught.
+ */
+
+int
+xwrite(int fd, const void *p, size_t n)
+{
+       const char *buf = p;
+
+       while (n) {
+               ssize_t i;
+               size_t m;
+
+               m = n;
+               if (m > SSIZE_MAX)
+                       m = SSIZE_MAX;
+               do {
+                       i = write(fd, buf, m);
+               } while (i < 0 && errno == EINTR);
+               if (i < 0)
+                       return -1;
+               buf += i;
+               n -= i;
+       }
+       return 0;
+}
+
+
+#ifdef notyet
+#ifdef USE_GLIBC_STDIO
+void initstreams() {
+       output.stream = stdout;
+       errout.stream = stderr;
+}
+
+
+void
+openmemout(void) {
+       INTOFF;
+       memout.stream = open_memstream(&memout.buf, &memout.bufsize);
+       INTON;
+}
+
+
+int
+__closememout(void) {
+       int error;
+       error = fclose(memout.stream);
+       memout.stream = NULL;
+       return error;
+}
+#endif
+#endif
+
+
+static int
+xvsnprintf(char *outbuf, size_t length, const char *fmt, va_list ap)
+{
+       int ret;
+
+#ifdef __sun
+       /*
+        * vsnprintf() on older versions of Solaris returns -1 when
+        * passed a length of 0.  To avoid this, use a dummy
+        * 1-character buffer instead.
+        */
+       char dummy[1];
+
+       if (length == 0) {
+               outbuf = dummy;
+               length = sizeof(dummy);
+       }
+#endif
+
+       INTOFF;
+       ret = vsnprintf(outbuf, length, fmt, ap);
+       INTON;
+       return ret;
+}
diff --git a/src/output.h b/src/output.h
new file mode 100644 (file)
index 0000000..f853e9d
--- /dev/null
@@ -0,0 +1,123 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)output.h    8.2 (Berkeley) 5/4/95
+ */
+
+#ifndef OUTPUT_INCL
+
+#include <stdarg.h>
+#ifdef USE_GLIBC_STDIO
+#include <stdio.h>
+#endif
+#include <sys/types.h>
+
+struct output {
+#ifdef USE_GLIBC_STDIO
+       FILE *stream;
+#endif
+       char *nextc;
+       char *end;
+       char *buf;
+       size_t bufsize;
+       int fd;
+       int flags;
+};
+
+extern struct output output;
+extern struct output errout;
+extern struct output preverrout;
+#ifdef notyet
+extern struct output memout;
+#endif
+extern struct output *out1;
+extern struct output *out2;
+
+void outstr(const char *, struct output *);
+#ifndef USE_GLIBC_STDIO
+void outcslow(int, struct output *);
+#endif
+void flushall(void);
+void flushout(struct output *);
+void outfmt(struct output *, const char *, ...)
+    __attribute__((__format__(__printf__,2,3)));
+void out1fmt(const char *, ...)
+    __attribute__((__format__(__printf__,1,2)));
+int fmtstr(char *, size_t, const char *, ...)
+    __attribute__((__format__(__printf__,3,4)));
+#ifndef USE_GLIBC_STDIO
+void doformat(struct output *, const char *, va_list);
+#endif
+int xwrite(int, const void *, size_t);
+#ifdef notyet
+#ifdef USE_GLIBC_STDIO
+void initstreams(void);
+void openmemout(void);
+int __closememout(void);
+#endif
+#endif
+
+static inline void
+freestdout()
+{
+       output.nextc = output.buf;
+       output.flags = 0;
+}
+
+#define OUTPUT_ERR 01          /* error occurred on output */
+
+#ifdef USE_GLIBC_STDIO
+static inline void outc(int ch, struct output *file)
+{
+       putc(ch, file->stream);
+}
+#define doformat(d, f, a)      vfprintf((d)->stream, (f), (a))
+#else
+static inline void outc(int ch, struct output *file)
+{
+       if (file->nextc == file->end)
+               outcslow(ch, file);
+       else {
+               *file->nextc = ch;
+               file->nextc++;
+       }
+}
+#endif
+#define out1c(c)       outc((c), out1)
+#define out2c(c)       outcslow((c), out2)
+#define out1str(s)     outstr((s), out1)
+#define out2str(s)     outstr((s), out2)
+#define outerr(f)      (f)->flags
+
+#define OUTPUT_INCL
+#endif
diff --git a/src/parser.c b/src/parser.c
new file mode 100644 (file)
index 0000000..6de2762
--- /dev/null
@@ -0,0 +1,1569 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include <stdlib.h>
+
+#include "shell.h"
+#include "parser.h"
+#include "nodes.h"
+#include "expand.h"    /* defines rmescapes() */
+#include "exec.h"      /* defines find_builtin() */
+#include "syntax.h"
+#include "options.h"
+#include "input.h"
+#include "output.h"
+#include "var.h"
+#include "error.h"
+#include "memalloc.h"
+#include "mystring.h"
+#include "alias.h"
+#include "show.h"
+#include "builtins.h"
+#include "system.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+
+/*
+ * Shell command parser.
+ */
+
+/* values returned by readtoken */
+#include "token_vars.h"
+
+
+
+/* Used by expandstr to get here-doc like behaviour. */
+#define FAKEEOFMARK (char *)1
+
+
+
+struct heredoc {
+       struct heredoc *next;   /* next here document in list */
+       union node *here;               /* redirection node */
+       char *eofmark;          /* string indicating end of input */
+       int striptabs;          /* if set, strip leading tabs */
+};
+
+
+
+struct heredoc *heredoclist;   /* list of here documents to read */
+int doprompt;                  /* if set, prompt the user */
+int needprompt;                        /* true if interactive and at start of line */
+int lasttoken;                 /* last token read */
+int tokpushback;               /* last token pushed back */
+char *wordtext;                        /* text of last word returned by readtoken */
+int checkkwd;
+struct nodelist *backquotelist;
+union node *redirnode;
+struct heredoc *heredoc;
+int quoteflag;                 /* set if (part of) last token was quoted */
+
+
+STATIC union node *list(int);
+STATIC union node *andor(void);
+STATIC union node *pipeline(void);
+STATIC union node *command(void);
+STATIC union node *simplecmd(void);
+STATIC union node *makename(void);
+STATIC void parsefname(void);
+STATIC void parseheredoc(void);
+STATIC int peektoken(void);
+STATIC int readtoken(void);
+STATIC int xxreadtoken(void);
+STATIC int readtoken1(int, char const *, char *, int);
+STATIC void synexpect(int) __attribute__((__noreturn__));
+STATIC void synerror(const char *) __attribute__((__noreturn__));
+STATIC void setprompt(int);
+
+
+static inline int
+isassignment(const char *p)
+{
+       const char *q = endofname(p);
+       if (p == q)
+               return 0;
+       return *q == '=';
+}
+
+static inline int realeofmark(const char *eofmark)
+{
+       return eofmark && eofmark != FAKEEOFMARK;
+}
+
+
+/*
+ * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
+ * valid parse tree indicating a blank line.)
+ */
+
+union node *
+parsecmd(int interact)
+{
+       int t;
+
+       tokpushback = 0;
+       doprompt = interact;
+       if (doprompt)
+               setprompt(doprompt);
+       needprompt = 0;
+       t = readtoken();
+       if (t == TEOF)
+               return NEOF;
+       if (t == TNL)
+               return NULL;
+       tokpushback++;
+       return list(1);
+}
+
+
+STATIC union node *
+list(int nlflag)
+{
+       union node *n1, *n2, *n3;
+       int tok;
+
+       checkkwd = CHKNL | CHKKWD | CHKALIAS;
+       if (nlflag == 2 && tokendlist[peektoken()])
+               return NULL;
+       n1 = NULL;
+       for (;;) {
+               n2 = andor();
+               tok = readtoken();
+               if (tok == TBACKGND) {
+                       if (n2->type == NPIPE) {
+                               n2->npipe.backgnd = 1;
+                       } else {
+                               if (n2->type != NREDIR) {
+                                       n3 = stalloc(sizeof(struct nredir));
+                                       n3->nredir.n = n2;
+                                       n3->nredir.redirect = NULL;
+                                       n2 = n3;
+                               }
+                               n2->type = NBACKGND;
+                       }
+               }
+               if (n1 == NULL) {
+                       n1 = n2;
+               }
+               else {
+                       n3 = (union node *)stalloc(sizeof (struct nbinary));
+                       n3->type = NSEMI;
+                       n3->nbinary.ch1 = n1;
+                       n3->nbinary.ch2 = n2;
+                       n1 = n3;
+               }
+               switch (tok) {
+               case TBACKGND:
+               case TSEMI:
+                       tok = readtoken();
+                       /* fall through */
+               case TNL:
+                       if (tok == TNL) {
+                               parseheredoc();
+                               if (nlflag == 1)
+                                       return n1;
+                       } else {
+                               tokpushback++;
+                       }
+                       checkkwd = CHKNL | CHKKWD | CHKALIAS;
+                       if (tokendlist[peektoken()])
+                               return n1;
+                       break;
+               case TEOF:
+                       if (heredoclist)
+                               parseheredoc();
+                       else
+                               pungetc();              /* push back EOF on input */
+                       tokpushback++;
+                       return n1;
+               default:
+                       if (nlflag == 1)
+                               synexpect(-1);
+                       tokpushback++;
+                       return n1;
+               }
+       }
+}
+
+
+
+STATIC union node *
+andor(void)
+{
+       union node *n1, *n2, *n3;
+       int t;
+
+       n1 = pipeline();
+       for (;;) {
+               if ((t = readtoken()) == TAND) {
+                       t = NAND;
+               } else if (t == TOR) {
+                       t = NOR;
+               } else {
+                       tokpushback++;
+                       return n1;
+               }
+               checkkwd = CHKNL | CHKKWD | CHKALIAS;
+               n2 = pipeline();
+               n3 = (union node *)stalloc(sizeof (struct nbinary));
+               n3->type = t;
+               n3->nbinary.ch1 = n1;
+               n3->nbinary.ch2 = n2;
+               n1 = n3;
+       }
+}
+
+
+
+STATIC union node *
+pipeline(void)
+{
+       union node *n1, *n2, *pipenode;
+       struct nodelist *lp, *prev;
+       int negate;
+
+       negate = 0;
+       TRACE(("pipeline: entered\n"));
+       if (readtoken() == TNOT) {
+               negate = !negate;
+               checkkwd = CHKKWD | CHKALIAS;
+       } else
+               tokpushback++;
+       n1 = command();
+       if (readtoken() == TPIPE) {
+               pipenode = (union node *)stalloc(sizeof (struct npipe));
+               pipenode->type = NPIPE;
+               pipenode->npipe.backgnd = 0;
+               lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+               pipenode->npipe.cmdlist = lp;
+               lp->n = n1;
+               do {
+                       prev = lp;
+                       lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+                       checkkwd = CHKNL | CHKKWD | CHKALIAS;
+                       lp->n = command();
+                       prev->next = lp;
+               } while (readtoken() == TPIPE);
+               lp->next = NULL;
+               n1 = pipenode;
+       }
+       tokpushback++;
+       if (negate) {
+               n2 = (union node *)stalloc(sizeof (struct nnot));
+               n2->type = NNOT;
+               n2->nnot.com = n1;
+               return n2;
+       } else
+               return n1;
+}
+
+
+
+STATIC union node *
+command(void)
+{
+       union node *n1, *n2;
+       union node *ap, **app;
+       union node *cp, **cpp;
+       union node *redir, **rpp;
+       union node **rpp2;
+       int t;
+       int savelinno;
+
+       redir = NULL;
+       rpp2 = &redir;
+
+       savelinno = plinno;
+
+       switch (readtoken()) {
+       default:
+               synexpect(-1);
+               /* NOTREACHED */
+       case TIF:
+               n1 = (union node *)stalloc(sizeof (struct nif));
+               n1->type = NIF;
+               n1->nif.test = list(0);
+               if (readtoken() != TTHEN)
+                       synexpect(TTHEN);
+               n1->nif.ifpart = list(0);
+               n2 = n1;
+               while (readtoken() == TELIF) {
+                       n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
+                       n2 = n2->nif.elsepart;
+                       n2->type = NIF;
+                       n2->nif.test = list(0);
+                       if (readtoken() != TTHEN)
+                               synexpect(TTHEN);
+                       n2->nif.ifpart = list(0);
+               }
+               if (lasttoken == TELSE)
+                       n2->nif.elsepart = list(0);
+               else {
+                       n2->nif.elsepart = NULL;
+                       tokpushback++;
+               }
+               t = TFI;
+               break;
+       case TWHILE:
+       case TUNTIL: {
+               int got;
+               n1 = (union node *)stalloc(sizeof (struct nbinary));
+               n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
+               n1->nbinary.ch1 = list(0);
+               if ((got=readtoken()) != TDO) {
+TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
+                       synexpect(TDO);
+               }
+               n1->nbinary.ch2 = list(0);
+               t = TDONE;
+               break;
+       }
+       case TFOR:
+               if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
+                       synerror("Bad for loop variable");
+               n1 = (union node *)stalloc(sizeof (struct nfor));
+               n1->type = NFOR;
+               n1->nfor.linno = savelinno;
+               n1->nfor.var = wordtext;
+               checkkwd = CHKNL | CHKKWD | CHKALIAS;
+               if (readtoken() == TIN) {
+                       app = &ap;
+                       while (readtoken() == TWORD) {
+                               n2 = (union node *)stalloc(sizeof (struct narg));
+                               n2->type = NARG;
+                               n2->narg.text = wordtext;
+                               n2->narg.backquote = backquotelist;
+                               *app = n2;
+                               app = &n2->narg.next;
+                       }
+                       *app = NULL;
+                       n1->nfor.args = ap;
+                       if (lasttoken != TNL && lasttoken != TSEMI)
+                               synexpect(-1);
+               } else {
+                       n2 = (union node *)stalloc(sizeof (struct narg));
+                       n2->type = NARG;
+                       n2->narg.text = (char *)dolatstr;
+                       n2->narg.backquote = NULL;
+                       n2->narg.next = NULL;
+                       n1->nfor.args = n2;
+                       /*
+                        * Newline or semicolon here is optional (but note
+                        * that the original Bourne shell only allowed NL).
+                        */
+                       if (lasttoken != TSEMI)
+                               tokpushback++;
+               }
+               checkkwd = CHKNL | CHKKWD | CHKALIAS;
+               if (readtoken() != TDO)
+                       synexpect(TDO);
+               n1->nfor.body = list(0);
+               t = TDONE;
+               break;
+       case TCASE:
+               n1 = (union node *)stalloc(sizeof (struct ncase));
+               n1->type = NCASE;
+               n1->ncase.linno = savelinno;
+               if (readtoken() != TWORD)
+                       synexpect(TWORD);
+               n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
+               n2->type = NARG;
+               n2->narg.text = wordtext;
+               n2->narg.backquote = backquotelist;
+               n2->narg.next = NULL;
+               checkkwd = CHKNL | CHKKWD | CHKALIAS;
+               if (readtoken() != TIN)
+                       synexpect(TIN);
+               cpp = &n1->ncase.cases;
+next_case:
+               checkkwd = CHKNL | CHKKWD;
+               t = readtoken();
+               while(t != TESAC) {
+                       if (lasttoken == TLP)
+                               readtoken();
+                       *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
+                       cp->type = NCLIST;
+                       app = &cp->nclist.pattern;
+                       for (;;) {
+                               *app = ap = (union node *)stalloc(sizeof (struct narg));
+                               ap->type = NARG;
+                               ap->narg.text = wordtext;
+                               ap->narg.backquote = backquotelist;
+                               if (readtoken() != TPIPE)
+                                       break;
+                               app = &ap->narg.next;
+                               readtoken();
+                       }
+                       ap->narg.next = NULL;
+                       if (lasttoken != TRP)
+                               synexpect(TRP);
+                       cp->nclist.body = list(2);
+
+                       cpp = &cp->nclist.next;
+
+                       checkkwd = CHKNL | CHKKWD;
+                       if ((t = readtoken()) != TESAC) {
+                               if (t != TENDCASE)
+                                       synexpect(TENDCASE);
+                               else
+                                       goto next_case;
+                       }
+               }
+               *cpp = NULL;
+               goto redir;
+       case TLP:
+               n1 = (union node *)stalloc(sizeof (struct nredir));
+               n1->type = NSUBSHELL;
+               n1->nredir.linno = savelinno;
+               n1->nredir.n = list(0);
+               n1->nredir.redirect = NULL;
+               t = TRP;
+               break;
+       case TBEGIN:
+               n1 = list(0);
+               t = TEND;
+               break;
+       case TWORD:
+       case TREDIR:
+               tokpushback++;
+               return simplecmd();
+       }
+
+       if (readtoken() != t)
+               synexpect(t);
+
+redir:
+       /* Now check for redirection which may follow command */
+       checkkwd = CHKKWD | CHKALIAS;
+       rpp = rpp2;
+       while (readtoken() == TREDIR) {
+               *rpp = n2 = redirnode;
+               rpp = &n2->nfile.next;
+               parsefname();
+       }
+       tokpushback++;
+       *rpp = NULL;
+       if (redir) {
+               if (n1->type != NSUBSHELL) {
+                       n2 = (union node *)stalloc(sizeof (struct nredir));
+                       n2->type = NREDIR;
+                       n2->nredir.linno = savelinno;
+                       n2->nredir.n = n1;
+                       n1 = n2;
+               }
+               n1->nredir.redirect = redir;
+       }
+
+       return n1;
+}
+
+
+STATIC union node *
+simplecmd(void) {
+       union node *args, **app;
+       union node *n = NULL;
+       union node *vars, **vpp;
+       union node **rpp, *redir;
+       int savecheckkwd;
+       int savelinno;
+
+       args = NULL;
+       app = &args;
+       vars = NULL;
+       vpp = &vars;
+       redir = NULL;
+       rpp = &redir;
+
+       savecheckkwd = CHKALIAS;
+       savelinno = plinno;
+       for (;;) {
+               checkkwd = savecheckkwd;
+               switch (readtoken()) {
+               case TWORD:
+                       n = (union node *)stalloc(sizeof (struct narg));
+                       n->type = NARG;
+                       n->narg.text = wordtext;
+                       n->narg.backquote = backquotelist;
+                       if (savecheckkwd && isassignment(wordtext)) {
+                               *vpp = n;
+                               vpp = &n->narg.next;
+                       } else {
+                               *app = n;
+                               app = &n->narg.next;
+                               savecheckkwd = 0;
+                       }
+                       break;
+               case TREDIR:
+                       *rpp = n = redirnode;
+                       rpp = &n->nfile.next;
+                       parsefname();   /* read name of redirection file */
+                       break;
+               case TLP:
+                       if (
+                               args && app == &args->narg.next &&
+                               !vars && !redir
+                       ) {
+                               struct builtincmd *bcmd;
+                               const char *name;
+
+                               /* We have a function */
+                               if (readtoken() != TRP)
+                                       synexpect(TRP);
+                               name = n->narg.text;
+                               if (
+                                       !goodname(name) || (
+                                               (bcmd = find_builtin(name)) &&
+                                               bcmd->flags & BUILTIN_SPECIAL
+                                       )
+                               )
+                                       synerror("Bad function name");
+                               n->type = NDEFUN;
+                               checkkwd = CHKNL | CHKKWD | CHKALIAS;
+                               n->ndefun.text = n->narg.text;
+                               n->ndefun.linno = plinno;
+                               n->ndefun.body = command();
+                               return n;
+                       }
+                       /* fall through */
+               default:
+                       tokpushback++;
+                       goto out;
+               }
+       }
+out:
+       *app = NULL;
+       *vpp = NULL;
+       *rpp = NULL;
+       n = (union node *)stalloc(sizeof (struct ncmd));
+       n->type = NCMD;
+       n->ncmd.linno = savelinno;
+       n->ncmd.args = args;
+       n->ncmd.assign = vars;
+       n->ncmd.redirect = redir;
+       return n;
+}
+
+STATIC union node *
+makename(void)
+{
+       union node *n;
+
+       n = (union node *)stalloc(sizeof (struct narg));
+       n->type = NARG;
+       n->narg.next = NULL;
+       n->narg.text = wordtext;
+       n->narg.backquote = backquotelist;
+       return n;
+}
+
+void fixredir(union node *n, const char *text, int err)
+       {
+       TRACE(("Fix redir %s %d\n", text, err));
+       if (!err)
+               n->ndup.vname = NULL;
+
+       if (is_digit(text[0]) && text[1] == '\0')
+               n->ndup.dupfd = digit_val(text[0]);
+       else if (text[0] == '-' && text[1] == '\0')
+               n->ndup.dupfd = -1;
+       else {
+
+               if (err)
+                       synerror("Bad fd number");
+               else
+                       n->ndup.vname = makename();
+       }
+}
+
+
+STATIC void
+parsefname(void)
+{
+       union node *n = redirnode;
+
+       if (n->type == NHERE)
+               checkkwd = CHKEOFMARK;
+       if (readtoken() != TWORD)
+               synexpect(-1);
+       if (n->type == NHERE) {
+               struct heredoc *here = heredoc;
+               struct heredoc *p;
+
+               if (quoteflag == 0)
+                       n->type = NXHERE;
+               TRACE(("Here document %d\n", n->type));
+               rmescapes(wordtext);
+               here->eofmark = wordtext;
+               here->next = NULL;
+               if (heredoclist == NULL)
+                       heredoclist = here;
+               else {
+                       for (p = heredoclist ; p->next ; p = p->next);
+                       p->next = here;
+               }
+       } else if (n->type == NTOFD || n->type == NFROMFD) {
+               fixredir(n, wordtext, 0);
+       } else {
+               n->nfile.fname = makename();
+       }
+}
+
+
+/*
+ * Input any here documents.
+ */
+
+STATIC void
+parseheredoc(void)
+{
+       struct heredoc *here;
+       union node *n;
+
+       here = heredoclist;
+       heredoclist = 0;
+
+       while (here) {
+               if (needprompt) {
+                       setprompt(2);
+               }
+               readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
+                               here->eofmark, here->striptabs);
+               n = (union node *)stalloc(sizeof (struct narg));
+               n->narg.type = NARG;
+               n->narg.next = NULL;
+               n->narg.text = wordtext;
+               n->narg.backquote = backquotelist;
+               here->here->nhere.doc = n;
+               here = here->next;
+       }
+}
+
+STATIC int
+peektoken(void)
+{
+       int t;
+
+       t = readtoken();
+       tokpushback++;
+       return (t);
+}
+
+STATIC int
+readtoken(void)
+{
+       int t;
+       int kwd = checkkwd;
+#ifdef DEBUG
+       int alreadyseen = tokpushback;
+#endif
+
+top:
+       t = xxreadtoken();
+
+       /*
+        * eat newlines
+        */
+       if (kwd & CHKNL) {
+               while (t == TNL) {
+                       parseheredoc();
+                       t = xxreadtoken();
+               }
+       }
+
+       if (t != TWORD || quoteflag) {
+               goto out;
+       }
+
+       /*
+        * check for keywords
+        */
+       if (kwd & CHKKWD) {
+               const char *const *pp;
+
+               if ((pp = findkwd(wordtext))) {
+                       lasttoken = t = pp - parsekwd + KWDOFFSET;
+                       TRACE(("keyword %s recognized\n", tokname[t]));
+                       goto out;
+               }
+       }
+
+       if (checkkwd & CHKALIAS) {
+               struct alias *ap;
+               if ((ap = lookupalias(wordtext, 1)) != NULL) {
+                       if (*ap->val) {
+                               pushstring(ap->val, ap);
+                       }
+                       goto top;
+               }
+       }
+out:
+       checkkwd = 0;
+#ifdef DEBUG
+       if (!alreadyseen)
+           TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
+       else
+           TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
+#endif
+       return (t);
+}
+
+
+/*
+ * Read the next input token.
+ * If the token is a word, we set backquotelist to the list of cmds in
+ *     backquotes.  We set quoteflag to true if any part of the word was
+ *     quoted.
+ * If the token is TREDIR, then we set redirnode to a structure containing
+ *     the redirection.
+ *
+ * [Change comment:  here documents and internal procedures]
+ * [Readtoken shouldn't have any arguments.  Perhaps we should make the
+ *  word parsing code into a separate routine.  In this case, readtoken
+ *  doesn't need to have any internal procedures, but parseword does.
+ *  We could also make parseoperator in essence the main routine, and
+ *  have parseword (readtoken1?) handle both words and redirection.]
+ */
+
+#define RETURN(token)  return lasttoken = token
+
+STATIC int
+xxreadtoken(void)
+{
+       int c;
+
+       if (tokpushback) {
+               tokpushback = 0;
+               return lasttoken;
+       }
+       if (needprompt) {
+               setprompt(2);
+       }
+       for (;;) {      /* until token or start of word found */
+               c = pgetc_macro();
+               switch (c) {
+               case ' ': case '\t':
+               case PEOA:
+                       continue;
+               case '#':
+                       while ((c = pgetc()) != '\n' && c != PEOF);
+                       pungetc();
+                       continue;
+               case '\\':
+                       if (pgetc() == '\n') {
+                               plinno++;
+                               if (doprompt)
+                                       setprompt(2);
+                               continue;
+                       }
+                       pungetc();
+                       goto breakloop;
+               case '\n':
+                       plinno++;
+                       needprompt = doprompt;
+                       RETURN(TNL);
+               case PEOF:
+                       RETURN(TEOF);
+               case '&':
+                       if (pgetc() == '&')
+                               RETURN(TAND);
+                       pungetc();
+                       RETURN(TBACKGND);
+               case '|':
+                       if (pgetc() == '|')
+                               RETURN(TOR);
+                       pungetc();
+                       RETURN(TPIPE);
+               case ';':
+                       if (pgetc() == ';')
+                               RETURN(TENDCASE);
+                       pungetc();
+                       RETURN(TSEMI);
+               case '(':
+                       RETURN(TLP);
+               case ')':
+                       RETURN(TRP);
+               default:
+                       goto breakloop;
+               }
+       }
+breakloop:
+       return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
+#undef RETURN
+}
+
+
+
+/*
+ * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
+ * is not NULL, read a here document.  In the latter case, eofmark is the
+ * word which marks the end of the document and striptabs is true if
+ * leading tabs should be stripped from the document.  The argument firstc
+ * is the first character of the input token or document.
+ *
+ * Because C does not have internal subroutines, I have simulated them
+ * using goto's to implement the subroutine linkage.  The following macros
+ * will run code that appears at the end of readtoken1.
+ */
+
+#define CHECKEND()     {goto checkend; checkend_return:;}
+#define PARSEREDIR()   {goto parseredir; parseredir_return:;}
+#define PARSESUB()     {goto parsesub; parsesub_return:;}
+#define PARSEBACKQOLD()        {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
+#define PARSEBACKQNEW()        {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
+#define        PARSEARITH()    {goto parsearith; parsearith_return:;}
+
+STATIC int
+readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
+{
+       int c = firstc;
+       char *out;
+       int len;
+       struct nodelist *bqlist;
+       int quotef;
+       int dblquote;
+       int varnest;    /* levels of variables expansion */
+       int arinest;    /* levels of arithmetic expansion */
+       int parenlevel; /* levels of parens in arithmetic */
+       int dqvarnest;  /* levels of variables expansion within double quotes */
+       int oldstyle;
+       /* syntax before arithmetic */
+       char const *uninitialized_var(prevsyntax);
+
+       dblquote = 0;
+       if (syntax == DQSYNTAX)
+               dblquote = 1;
+       quotef = 0;
+       bqlist = NULL;
+       varnest = 0;
+       arinest = 0;
+       parenlevel = 0;
+       dqvarnest = 0;
+
+       STARTSTACKSTR(out);
+       loop: { /* for each line, until end of word */
+#if ATTY
+               if (c == '\034' && doprompt
+                && attyset() && ! equal(termval(), "emacs")) {
+                       attyline();
+                       if (syntax == BASESYNTAX)
+                               return readtoken();
+                       c = pgetc();
+                       goto loop;
+               }
+#endif
+               CHECKEND();     /* set c to PEOF if at end of here document */
+               for (;;) {      /* until end of line or end of word */
+                       CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
+                       switch(syntax[c]) {
+                       case CNL:       /* '\n' */
+                               if (syntax == BASESYNTAX)
+                                       goto endword;   /* exit outer loop */
+                               USTPUTC(c, out);
+                               plinno++;
+                               if (doprompt)
+                                       setprompt(2);
+                               c = pgetc();
+                               goto loop;              /* continue outer loop */
+                       case CWORD:
+                               USTPUTC(c, out);
+                               break;
+                       case CCTL:
+                               if (eofmark == NULL || dblquote)
+                                       USTPUTC(CTLESC, out);
+                               USTPUTC(c, out);
+                               break;
+                       /* backslash */
+                       case CBACK:
+                               c = pgetc2();
+                               if (c == PEOF) {
+                                       USTPUTC(CTLESC, out);
+                                       USTPUTC('\\', out);
+                                       pungetc();
+                               } else if (c == '\n') {
+                                       plinno++;
+                                       if (doprompt)
+                                               setprompt(2);
+                               } else {
+                                       if (
+                                               dblquote &&
+                                               c != '\\' && c != '`' &&
+                                               c != '$' && (
+                                                       c != '"' ||
+                                                       eofmark != NULL
+                                               )
+                                       ) {
+                                               USTPUTC('\\', out);
+                                       }
+                                       USTPUTC(CTLESC, out);
+                                       USTPUTC(c, out);
+                                       quotef++;
+                               }
+                               break;
+                       case CSQUOTE:
+                               syntax = SQSYNTAX;
+quotemark:
+                               if (eofmark == NULL) {
+                                       USTPUTC(CTLQUOTEMARK, out);
+                               }
+                               break;
+                       case CDQUOTE:
+                               syntax = DQSYNTAX;
+                               dblquote = 1;
+                               goto quotemark;
+                       case CENDQUOTE:
+                               if (eofmark && !varnest)
+                                       USTPUTC(c, out);
+                               else {
+                                       if (dqvarnest == 0) {
+                                               syntax = BASESYNTAX;
+                                               dblquote = 0;
+                                       }
+                                       quotef++;
+                                       goto quotemark;
+                               }
+                               break;
+                       case CVAR:      /* '$' */
+                               PARSESUB();             /* parse substitution */
+                               break;
+                       case CENDVAR:   /* '}' */
+                               if (varnest > 0) {
+                                       varnest--;
+                                       if (dqvarnest > 0) {
+                                               dqvarnest--;
+                                       }
+                                       USTPUTC(CTLENDVAR, out);
+                               } else {
+                                       USTPUTC(c, out);
+                               }
+                               break;
+                       case CLP:       /* '(' in arithmetic */
+                               parenlevel++;
+                               USTPUTC(c, out);
+                               break;
+                       case CRP:       /* ')' in arithmetic */
+                               if (parenlevel > 0) {
+                                       USTPUTC(c, out);
+                                       --parenlevel;
+                               } else {
+                                       if (pgetc() == ')') {
+                                               USTPUTC(CTLENDARI, out);
+                                               if (!--arinest)
+                                                       syntax = prevsyntax;
+                                       } else {
+                                               /*
+                                                * unbalanced parens
+                                                *  (don't 2nd guess - no error)
+                                                */
+                                               pungetc();
+                                               USTPUTC(')', out);
+                                       }
+                               }
+                               break;
+                       case CBQUOTE:   /* '`' */
+                               PARSEBACKQOLD();
+                               break;
+                       case CEOF:
+                               goto endword;           /* exit outer loop */
+                       case CIGN:
+                               break;
+                       default:
+                               if (varnest == 0)
+                                       goto endword;   /* exit outer loop */
+                               if (c != PEOA) {
+                                       USTPUTC(c, out);
+                               }
+                       }
+                       c = pgetc_macro();
+               }
+       }
+endword:
+       if (syntax == ARISYNTAX)
+               synerror("Missing '))'");
+       if (syntax != BASESYNTAX && eofmark == NULL)
+               synerror("Unterminated quoted string");
+       if (varnest != 0) {
+               /* { */
+               synerror("Missing '}'");
+       }
+       USTPUTC('\0', out);
+       len = out - (char *)stackblock();
+       out = stackblock();
+       if (eofmark == NULL) {
+               if ((c == '>' || c == '<')
+                && quotef == 0
+                && len <= 2
+                && (*out == '\0' || is_digit(*out))) {
+                       PARSEREDIR();
+                       return lasttoken = TREDIR;
+               } else {
+                       pungetc();
+               }
+       }
+       quoteflag = quotef;
+       backquotelist = bqlist;
+       grabstackblock(len);
+       wordtext = out;
+       return lasttoken = TWORD;
+/* end of readtoken routine */
+
+
+
+/*
+ * Check to see whether we are at the end of the here document.  When this
+ * is called, c is set to the first character of the next input line.  If
+ * we are at the end of the here document, this routine sets the c to PEOF.
+ */
+
+checkend: {
+       if (realeofmark(eofmark)) {
+               int markloc;
+               char *p;
+
+               if (c == PEOA) {
+                       c = pgetc2();
+               }
+               if (striptabs) {
+                       while (c == '\t') {
+                               c = pgetc2();
+                       }
+               }
+
+               markloc = out - (char *)stackblock();
+               for (p = eofmark; STPUTC(c, out), *p; p++) {
+                       if (c != *p)
+                               goto more_heredoc;
+
+                       c = pgetc2();
+               }
+
+               if (c == '\n' || c == PEOF) {
+                       c = PEOF;
+                       plinno++;
+                       needprompt = doprompt;
+               } else {
+                       int len;
+
+more_heredoc:
+                       p = (char *)stackblock() + markloc + 1;
+                       len = out - p;
+
+                       if (len) {
+                               len -= c < 0;
+                               c = p[-1];
+
+                               if (len) {
+                                       char *str;
+
+                                       str = alloca(len + 1);
+                                       *(char *)mempcpy(str, p, len) = 0;
+
+                                       pushstring(str, NULL);
+                               }
+                       }
+               }
+
+               STADJUST((char *)stackblock() + markloc - out, out);
+       }
+       goto checkend_return;
+}
+
+
+/*
+ * Parse a redirection operator.  The variable "out" points to a string
+ * specifying the fd to be redirected.  The variable "c" contains the
+ * first character of the redirection operator.
+ */
+
+parseredir: {
+       char fd = *out;
+       union node *np;
+
+       np = (union node *)stalloc(sizeof (struct nfile));
+       if (c == '>') {
+               np->nfile.fd = 1;
+               c = pgetc();
+               if (c == '>')
+                       np->type = NAPPEND;
+               else if (c == '|')
+                       np->type = NCLOBBER;
+               else if (c == '&')
+                       np->type = NTOFD;
+               else {
+                       np->type = NTO;
+                       pungetc();
+               }
+       } else {        /* c == '<' */
+               np->nfile.fd = 0;
+               switch (c = pgetc()) {
+               case '<':
+                       if (sizeof (struct nfile) != sizeof (struct nhere)) {
+                               np = (union node *)stalloc(sizeof (struct nhere));
+                               np->nfile.fd = 0;
+                       }
+                       np->type = NHERE;
+                       heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
+                       heredoc->here = np;
+                       if ((c = pgetc()) == '-') {
+                               heredoc->striptabs = 1;
+                       } else {
+                               heredoc->striptabs = 0;
+                               pungetc();
+                       }
+                       break;
+
+               case '&':
+                       np->type = NFROMFD;
+                       break;
+
+               case '>':
+                       np->type = NFROMTO;
+                       break;
+
+               default:
+                       np->type = NFROM;
+                       pungetc();
+                       break;
+               }
+       }
+       if (fd != '\0')
+               np->nfile.fd = digit_val(fd);
+       redirnode = np;
+       goto parseredir_return;
+}
+
+
+/*
+ * Parse a substitution.  At this point, we have read the dollar sign
+ * and nothing else.
+ */
+
+parsesub: {
+       int subtype;
+       int typeloc;
+       char *p;
+       static const char types[] = "}-+?=";
+
+       c = pgetc();
+       if (
+               (checkkwd & CHKEOFMARK) ||
+               c <= PEOA  ||
+               (c != '(' && c != '{' && !is_name(c) && !is_special(c))
+       ) {
+               USTPUTC('$', out);
+               pungetc();
+       } else if (c == '(') {  /* $(command) or $((arith)) */
+               if (pgetc() == '(') {
+                       PARSEARITH();
+               } else {
+                       pungetc();
+                       PARSEBACKQNEW();
+               }
+       } else {
+               USTPUTC(CTLVAR, out);
+               typeloc = out - (char *)stackblock();
+               STADJUST(1, out);
+               subtype = VSNORMAL;
+               if (likely(c == '{')) {
+                       c = pgetc();
+                       subtype = 0;
+               }
+varname:
+               if (is_name(c)) {
+                       do {
+                               STPUTC(c, out);
+                               c = pgetc();
+                       } while (is_in_name(c));
+               } else if (is_digit(c)) {
+                       do {
+                               STPUTC(c, out);
+                               c = pgetc();
+                       } while (is_digit(c));
+               }
+               else if (is_special(c)) {
+                       int cc = c;
+
+                       c = pgetc();
+
+                       if (!subtype && cc == '#') {
+                               subtype = VSLENGTH;
+
+                               if (c == '_' || isalnum(c))
+                                       goto varname;
+
+                               cc = c;
+                               c = pgetc();
+                               if (cc == '}' || c != '}') {
+                                       pungetc();
+                                       subtype = 0;
+                                       c = cc;
+                                       cc = '#';
+                               }
+                       }
+
+                       USTPUTC(cc, out);
+               }
+               else
+                       goto badsub;
+
+               if (subtype == 0) {
+                       switch (c) {
+                       case ':':
+                               subtype = VSNUL;
+                               c = pgetc();
+                               /*FALLTHROUGH*/
+                       default:
+                               p = strchr(types, c);
+                               if (p == NULL)
+                                       break;
+                               subtype |= p - types + VSNORMAL;
+                               break;
+                       case '%':
+                       case '#':
+                               {
+                                       int cc = c;
+                                       subtype = c == '#' ? VSTRIMLEFT :
+                                                            VSTRIMRIGHT;
+                                       c = pgetc();
+                                       if (c == cc)
+                                               subtype++;
+                                       else
+                                               pungetc();
+                                       break;
+                               }
+                       }
+               } else {
+badsub:
+                       pungetc();
+               }
+               *((char *)stackblock() + typeloc) = subtype;
+               if (subtype != VSNORMAL) {
+                       varnest++;
+                       if (dblquote)
+                               dqvarnest++;
+               }
+               STPUTC('=', out);
+       }
+       goto parsesub_return;
+}
+
+
+/*
+ * Called to parse command substitutions.  Newstyle is set if the command
+ * is enclosed inside $(...); nlpp is a pointer to the head of the linked
+ * list of commands (passed by reference), and savelen is the number of
+ * characters on the top of the stack which must be preserved.
+ */
+
+parsebackq: {
+       struct nodelist **nlpp;
+       union node *n;
+       char *str;
+       size_t savelen;
+       int uninitialized_var(saveprompt);
+
+       str = NULL;
+       savelen = out - (char *)stackblock();
+       if (savelen > 0) {
+               str = alloca(savelen);
+               memcpy(str, stackblock(), savelen);
+       }
+        if (oldstyle) {
+                /* We must read until the closing backquote, giving special
+                   treatment to some slashes, and then push the string and
+                   reread it as input, interpreting it normally.  */
+                char *pout;
+                int pc;
+                size_t psavelen;
+                char *pstr;
+
+
+                STARTSTACKSTR(pout);
+               for (;;) {
+                       if (needprompt) {
+                               setprompt(2);
+                       }
+                       switch (pc = pgetc()) {
+                       case '`':
+                               goto done;
+
+                       case '\\':
+                                if ((pc = pgetc()) == '\n') {
+                                       plinno++;
+                                       if (doprompt)
+                                               setprompt(2);
+                                       /*
+                                        * If eating a newline, avoid putting
+                                        * the newline into the new character
+                                        * stream (via the STPUTC after the
+                                        * switch).
+                                        */
+                                       continue;
+                               }
+                                if (pc != '\\' && pc != '`' && pc != '$'
+                                    && (!dblquote || pc != '"'))
+                                        STPUTC('\\', pout);
+                               if (pc > PEOA) {
+                                       break;
+                               }
+                               /* fall through */
+
+                       case PEOF:
+                       case PEOA:
+                               synerror("EOF in backquote substitution");
+
+                       case '\n':
+                               plinno++;
+                               needprompt = doprompt;
+                               break;
+
+                       default:
+                               break;
+                       }
+                       STPUTC(pc, pout);
+                }
+done:
+                STPUTC('\0', pout);
+                psavelen = pout - (char *)stackblock();
+                if (psavelen > 0) {
+                       pstr = grabstackstr(pout);
+                       setinputstring(pstr);
+                }
+        }
+       nlpp = &bqlist;
+       while (*nlpp)
+               nlpp = &(*nlpp)->next;
+       *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+       (*nlpp)->next = NULL;
+
+       if (oldstyle) {
+               saveprompt = doprompt;
+               doprompt = 0;
+       }
+
+       n = list(2);
+
+       if (oldstyle)
+               doprompt = saveprompt;
+       else {
+               if (readtoken() != TRP)
+                       synexpect(TRP);
+       }
+
+       (*nlpp)->n = n;
+        if (oldstyle) {
+               /*
+                * Start reading from old file again, ignoring any pushed back
+                * tokens left from the backquote parsing
+                */
+                popfile();
+               tokpushback = 0;
+       }
+       while (stackblocksize() <= savelen)
+               growstackblock();
+       STARTSTACKSTR(out);
+       if (str) {
+               memcpy(out, str, savelen);
+               STADJUST(savelen, out);
+       }
+       USTPUTC(CTLBACKQ, out);
+       if (oldstyle)
+               goto parsebackq_oldreturn;
+       else
+               goto parsebackq_newreturn;
+}
+
+/*
+ * Parse an arithmetic expansion (indicate start of one and set state)
+ */
+parsearith: {
+
+       if (++arinest == 1) {
+               prevsyntax = syntax;
+               syntax = ARISYNTAX;
+       }
+       USTPUTC(CTLARI, out);
+       goto parsearith_return;
+}
+
+} /* end of readtoken */
+
+
+
+#ifdef mkinit
+INCLUDE "parser.h"
+RESET {
+       tokpushback = 0;
+       checkkwd = 0;
+}
+#endif
+
+
+/*
+ * Return of a legal variable name (a letter or underscore followed by zero or
+ * more letters, underscores, and digits).
+ */
+
+char *
+endofname(const char *name)
+       {
+       char *p;
+
+       p = (char *) name;
+       if (! is_name(*p))
+               return p;
+       while (*++p) {
+               if (! is_in_name(*p))
+                       break;
+       }
+       return p;
+}
+
+
+/*
+ * Called when an unexpected token is read during the parse.  The argument
+ * is the token that is expected, or -1 if more than one type of token can
+ * occur at this point.
+ */
+
+STATIC void
+synexpect(int token)
+{
+       char msg[64];
+
+       if (token >= 0) {
+               fmtstr(msg, 64, "%s unexpected (expecting %s)",
+                       tokname[lasttoken], tokname[token]);
+       } else {
+               fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
+       }
+       synerror(msg);
+       /* NOTREACHED */
+}
+
+
+STATIC void
+synerror(const char *msg)
+{
+       errlinno = plinno;
+       sh_error("Syntax error: %s", msg);
+       /* NOTREACHED */
+}
+
+STATIC void
+setprompt(int which)
+{
+       struct stackmark smark;
+       int show;
+
+       needprompt = 0;
+       whichprompt = which;
+
+#ifdef SMALL
+       show = 1;
+#else
+       show = !el;
+#endif
+       if (show) {
+               pushstackmark(&smark, stackblocksize());
+               out2str(getprompt(NULL));
+               popstackmark(&smark);
+       }
+}
+
+const char *
+expandstr(const char *ps)
+{
+       union node n;
+       int saveprompt;
+
+       /* XXX Fix (char *) cast. */
+       setinputstring((char *)ps);
+
+       saveprompt = doprompt;
+       doprompt = 0;
+
+       readtoken1(pgetc(), DQSYNTAX, FAKEEOFMARK, 0);
+
+       doprompt = saveprompt;
+
+       popfile();
+
+       n.narg.type = NARG;
+       n.narg.next = NULL;
+       n.narg.text = wordtext;
+       n.narg.backquote = backquotelist;
+
+       expandarg(&n, NULL, EXP_QUOTED);
+       return stackblock();
+}
+
+/*
+ * called by editline -- any expansions to the prompt
+ *    should be added here.
+ */
+const char *
+getprompt(void *unused)
+{
+       const char *prompt;
+
+       switch (whichprompt) {
+       default:
+#ifdef DEBUG
+               return "<internal prompt error>";
+#endif
+       case 0:
+               return nullstr;
+       case 1:
+               prompt = ps1val();
+               break;
+       case 2:
+               prompt = ps2val();
+               break;
+       }
+
+       return expandstr(prompt);
+}
+
+const char *const *
+findkwd(const char *s)
+{
+       return findstring(
+               s, parsekwd, sizeof(parsekwd) / sizeof(const char *)
+       );
+}
diff --git a/src/parser.h b/src/parser.h
new file mode 100644 (file)
index 0000000..2875cce
--- /dev/null
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)parser.h    8.3 (Berkeley) 5/4/95
+ */
+
+#include "token.h"
+
+/* control characters in argument strings */
+#define CTL_FIRST -127         /* first 'special' character */
+#define CTLESC -127            /* escape next character */
+#define CTLVAR -126            /* variable defn */
+#define CTLENDVAR -125
+#define CTLBACKQ -124
+#define        CTLARI -122             /* arithmetic expression */
+#define        CTLENDARI -121
+#define        CTLQUOTEMARK -120
+#define        CTL_LAST -120           /* last 'special' character */
+
+/* variable substitution byte (follows CTLVAR) */
+#define VSTYPE 0x0f            /* type of variable substitution */
+#define VSNUL  0x10            /* colon--treat the empty string as unset */
+
+/* values of VSTYPE field */
+#define VSNORMAL       0x1             /* normal variable:  $var or ${var} */
+#define VSMINUS                0x2             /* ${var-text} */
+#define VSPLUS         0x3             /* ${var+text} */
+#define VSQUESTION     0x4             /* ${var?message} */
+#define VSASSIGN       0x5             /* ${var=text} */
+#define VSTRIMRIGHT    0x6             /* ${var%pattern} */
+#define VSTRIMRIGHTMAX         0x7             /* ${var%%pattern} */
+#define VSTRIMLEFT     0x8             /* ${var#pattern} */
+#define VSTRIMLEFTMAX  0x9             /* ${var##pattern} */
+#define VSLENGTH       0xa             /* ${#var} */
+
+/* values of checkkwd variable */
+#define CHKALIAS       0x1
+#define CHKKWD         0x2
+#define CHKNL          0x4
+#define CHKEOFMARK     0x8
+
+
+/*
+ * NEOF is returned by parsecmd when it encounters an end of file.  It
+ * must be distinct from NULL, so we use the address of a variable that
+ * happens to be handy.
+ */
+extern int lasttoken;
+extern int tokpushback;
+#define NEOF ((union node *)&tokpushback)
+extern int whichprompt;                /* 1 == PS1, 2 == PS2 */
+extern int checkkwd;
+
+
+union node *parsecmd(int);
+void fixredir(union node *, const char *, int);
+const char *getprompt(void *);
+const char *const *findkwd(const char *);
+char *endofname(const char *);
+const char *expandstr(const char *);
+
+static inline int
+goodname(const char *p)
+{
+       return !*endofname(p);
+}
+
+static inline int parser_eof(void)
+{
+       return tokpushback && lasttoken == TEOF;
+}
diff --git a/src/redir.c b/src/redir.c
new file mode 100644 (file)
index 0000000..f96a76b
--- /dev/null
@@ -0,0 +1,459 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/param.h> /* PIPE_BUF */
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+/*
+ * Code for dealing with input/output redirection.
+ */
+
+#include "main.h"
+#include "shell.h"
+#include "nodes.h"
+#include "jobs.h"
+#include "options.h"
+#include "expand.h"
+#include "redir.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+
+
+#define REALLY_CLOSED -3       /* fd that was closed and still is */
+#define EMPTY -2               /* marks an unused slot in redirtab */
+#define CLOSED -1              /* fd opened for redir needs to be closed */
+
+#ifndef PIPE_BUF
+# define PIPESIZE 4096         /* amount of buffering in a pipe */
+#else
+# define PIPESIZE PIPE_BUF
+#endif
+
+
+MKINIT
+struct redirtab {
+       struct redirtab *next;
+       int renamed[10];
+};
+
+
+MKINIT struct redirtab *redirlist;
+
+STATIC int openredirect(union node *);
+#ifdef notyet
+STATIC void dupredirect(union node *, int, char[10]);
+#else
+STATIC void dupredirect(union node *, int);
+#endif
+STATIC int openhere(union node *);
+
+
+/*
+ * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
+ * old file descriptors are stashed away so that the redirection can be
+ * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
+ * standard output, and the standard error if it becomes a duplicate of
+ * stdout, is saved in memory.
+ */
+
+void
+redirect(union node *redir, int flags)
+{
+       union node *n;
+       struct redirtab *sv;
+       int i;
+       int fd;
+       int newfd;
+       int *p;
+#if notyet
+       char memory[10];        /* file descriptors to write to memory */
+
+       for (i = 10 ; --i >= 0 ; )
+               memory[i] = 0;
+       memory[1] = flags & REDIR_BACKQ;
+#endif
+       if (!redir)
+               return;
+       sv = NULL;
+       INTOFF;
+       if (likely(flags & REDIR_PUSH))
+               sv = redirlist;
+       n = redir;
+       do {
+               newfd = openredirect(n);
+               if (newfd < -1)
+                       continue;
+
+               fd = n->nfile.fd;
+
+               if (sv) {
+                       p = &sv->renamed[fd];
+                       i = *p;
+
+                       if (likely(i == EMPTY)) {
+                               i = CLOSED;
+                               if (fd != newfd) {
+                                       i = savefd(fd, fd);
+                                       fd = -1;
+                               }
+                       }
+
+                       if (i == newfd)
+                               /* Can only happen if i == newfd == CLOSED */
+                               i = REALLY_CLOSED;
+
+                       *p = i;
+               }
+
+               if (fd == newfd)
+                       continue;
+
+#ifdef notyet
+               dupredirect(n, newfd, memory);
+#else
+               dupredirect(n, newfd);
+#endif
+       } while ((n = n->nfile.next));
+       INTON;
+#ifdef notyet
+       if (memory[1])
+               out1 = &memout;
+       if (memory[2])
+               out2 = &memout;
+#endif
+       if (flags & REDIR_SAVEFD2 && sv->renamed[2] >= 0)
+               preverrout.fd = sv->renamed[2];
+}
+
+
+STATIC int
+openredirect(union node *redir)
+{
+       struct stat64 sb;
+       char *fname;
+       int f;
+
+       switch (redir->nfile.type) {
+       case NFROM:
+               fname = redir->nfile.expfname;
+               if ((f = open64(fname, O_RDONLY)) < 0)
+                       goto eopen;
+               break;
+       case NFROMTO:
+               fname = redir->nfile.expfname;
+               if ((f = open64(fname, O_RDWR|O_CREAT, 0666)) < 0)
+                       goto ecreate;
+               break;
+       case NTO:
+               /* Take care of noclobber mode. */
+               if (Cflag) {
+                       fname = redir->nfile.expfname;
+                       if (stat64(fname, &sb) < 0) {
+                               if ((f = open64(fname, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0)
+                                       goto ecreate;
+                       } else if (!S_ISREG(sb.st_mode)) {
+                               if ((f = open64(fname, O_WRONLY, 0666)) < 0)
+                                       goto ecreate;
+                               if (fstat64(f, &sb) < 0 && S_ISREG(sb.st_mode)) {
+                                       close(f);
+                                       errno = EEXIST;
+                                       goto ecreate;
+                               }
+                       } else {
+                               errno = EEXIST;
+                               goto ecreate;
+                       }
+                       break;
+               }
+               /* FALLTHROUGH */
+       case NCLOBBER:
+               fname = redir->nfile.expfname;
+               if ((f = open64(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
+                       goto ecreate;
+               break;
+       case NAPPEND:
+               fname = redir->nfile.expfname;
+               if ((f = open64(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
+                       goto ecreate;
+               break;
+       case NTOFD:
+       case NFROMFD:
+               f = redir->ndup.dupfd;
+               if (f == redir->nfile.fd)
+                       f = -2;
+               break;
+       default:
+#ifdef DEBUG
+               abort();
+#endif
+               /* Fall through to eliminate warning. */
+       case NHERE:
+       case NXHERE:
+               f = openhere(redir);
+               break;
+       }
+
+       return f;
+ecreate:
+       sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
+eopen:
+       sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
+}
+
+
+STATIC void
+#ifdef notyet
+dupredirect(redir, f, memory)
+#else
+dupredirect(redir, f)
+#endif
+       union node *redir;
+       int f;
+#ifdef notyet
+       char memory[10];
+#endif
+       {
+       int fd = redir->nfile.fd;
+       int err = 0;
+
+#ifdef notyet
+       memory[fd] = 0;
+#endif
+       if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
+               /* if not ">&-" */
+               if (f >= 0) {
+#ifdef notyet
+                       if (memory[f])
+                               memory[fd] = 1;
+                       else
+#endif
+                               if (dup2(f, fd) < 0) {
+                                       err = errno;
+                                       goto err;
+                               }
+                       return;
+               }
+               f = fd;
+       } else if (dup2(f, fd) < 0)
+               err = errno;
+
+       close(f);
+       if (err < 0)
+               goto err;
+
+       return;
+
+err:
+       sh_error("%d: %s", f, strerror(err));
+}
+
+
+/*
+ * Handle here documents.  Normally we fork off a process to write the
+ * data to a pipe.  If the document is short, we can stuff the data in
+ * the pipe without forking.
+ */
+
+STATIC int
+openhere(union node *redir)
+{
+       char *p;
+       int pip[2];
+       size_t len = 0;
+
+       if (pipe(pip) < 0)
+               sh_error("Pipe call failed");
+
+       p = redir->nhere.doc->narg.text;
+       if (redir->type == NXHERE) {
+               expandarg(redir->nhere.doc, NULL, EXP_QUOTED);
+               p = stackblock();
+       }
+
+       len = strlen(p);
+       if (len <= PIPESIZE) {
+               xwrite(pip[1], p, len);
+               goto out;
+       }
+
+       if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
+               close(pip[0]);
+               signal(SIGINT, SIG_IGN);
+               signal(SIGQUIT, SIG_IGN);
+               signal(SIGHUP, SIG_IGN);
+#ifdef SIGTSTP
+               signal(SIGTSTP, SIG_IGN);
+#endif
+               signal(SIGPIPE, SIG_DFL);
+               xwrite(pip[1], p, len);
+               _exit(0);
+       }
+out:
+       close(pip[1]);
+       return pip[0];
+}
+
+
+
+/*
+ * Undo the effects of the last redirection.
+ */
+
+void
+popredir(int drop)
+{
+       struct redirtab *rp;
+       int i;
+
+       INTOFF;
+       rp = redirlist;
+       for (i = 0 ; i < 10 ; i++) {
+               switch (rp->renamed[i]) {
+               case CLOSED:
+                       if (!drop)
+                               close(i);
+                       break;
+               case EMPTY:
+               case REALLY_CLOSED:
+                       break;
+               default:
+                       if (!drop)
+                               dup2(rp->renamed[i], i);
+                       close(rp->renamed[i]);
+                       break;
+               }
+       }
+       redirlist = rp->next;
+       ckfree(rp);
+       INTON;
+}
+
+/*
+ * Undo all redirections.  Called on error or interrupt.
+ */
+
+#ifdef mkinit
+
+INCLUDE "redir.h"
+
+RESET {
+       /*
+        * Discard all saved file descriptors.
+        */
+       unwindredir(0);
+}
+
+#endif
+
+
+
+/*
+ * Move a file descriptor to > 10.  Invokes sh_error on error unless
+ * the original file dscriptor is not open.
+ */
+
+int
+savefd(int from, int ofd)
+{
+       int newfd;
+       int err;
+
+       newfd = fcntl(from, F_DUPFD, 10);
+       err = newfd < 0 ? errno : 0;
+       if (err != EBADF) {
+               close(ofd);
+               if (err)
+                       sh_error("%d: %s", from, strerror(err));
+               else
+                       fcntl(newfd, F_SETFD, FD_CLOEXEC);
+       }
+
+       return newfd;
+}
+
+
+int
+redirectsafe(union node *redir, int flags)
+{
+       int err;
+       volatile int saveint;
+       struct jmploc *volatile savehandler = handler;
+       struct jmploc jmploc;
+
+       SAVEINT(saveint);
+       if (!(err = setjmp(jmploc.loc) * 2)) {
+               handler = &jmploc;
+               redirect(redir, flags);
+       }
+       handler = savehandler;
+       if (err && exception != EXERROR)
+               longjmp(handler->loc, 1);
+       RESTOREINT(saveint);
+       return err;
+}
+
+
+void unwindredir(struct redirtab *stop)
+{
+       while (redirlist != stop)
+               popredir(0);
+}
+
+
+struct redirtab *pushredir(union node *redir)
+{
+       struct redirtab *sv;
+       struct redirtab *q;
+       int i;
+
+       q = redirlist;
+       if (!redir)
+               goto out;
+
+       sv = ckmalloc(sizeof (struct redirtab));
+       sv->next = q;
+       redirlist = sv;
+       for (i = 0; i < 10; i++)
+               sv->renamed[i] = EMPTY;
+
+out:
+       return q;
+}
diff --git a/src/redir.h b/src/redir.h
new file mode 100644 (file)
index 0000000..8e56995
--- /dev/null
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)redir.h     8.2 (Berkeley) 5/4/95
+ */
+
+/* flags passed to redirect */
+#define REDIR_PUSH 01          /* save previous values of file descriptors */
+#ifdef notyet
+#define REDIR_BACKQ 02         /* save the command output in memory */
+#endif
+#define REDIR_SAVEFD2 03       /* set preverrout */
+
+struct redirtab;
+union node;
+void redirect(union node *, int);
+void popredir(int);
+void clearredir(void);
+int savefd(int, int);
+int redirectsafe(union node *, int);
+void unwindredir(struct redirtab *stop);
+struct redirtab *pushredir(union node *redir);
+
diff --git a/src/shell.h b/src/shell.h
new file mode 100644 (file)
index 0000000..98edc8b
--- /dev/null
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)shell.h     8.2 (Berkeley) 5/4/95
+ */
+
+/*
+ * The follow should be set to reflect the type of system you have:
+ *     JOBS -> 1 if you have Berkeley job control, 0 otherwise.
+ *     SHORTNAMES -> 1 if your linker cannot handle long names.
+ *     define BSD if you are running 4.2 BSD or later.
+ *     define SYSV if you are running under System V.
+ *     define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
+ *     define DEBUG=2 to compile in and turn on debugging.
+ *     define DO_SHAREDVFORK to indicate that vfork(2) shares its address
+ *            with its parent.
+ *
+ * When debugging is on, debugging info will be written to ./trace and
+ * a quit signal will generate a core dump.
+ */
+
+#include <sys/param.h>
+
+#ifndef JOBS
+#define JOBS 1
+#endif
+#ifndef BSD
+#define BSD 1
+#endif
+
+#ifndef DO_SHAREDVFORK
+#if __NetBSD_Version__ >= 104000000
+#define DO_SHAREDVFORK
+#endif
+#endif
+
+typedef void *pointer;
+#ifndef NULL
+#define NULL (void *)0
+#endif
+#define STATIC static
+#define MKINIT /* empty */
+
+extern char nullstr[1];                /* null string */
+
+
+#ifdef DEBUG
+#define TRACE(param)   trace param
+#define TRACEV(param)  tracev param
+#else
+#define TRACE(param)
+#define TRACEV(param)
+#endif
+
+#if defined(__GNUC__) && __GNUC__ < 3
+#define va_copy __va_copy
+#endif
+
+#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
+#define __builtin_expect(x, expected_value) (x)
+#endif
+
+#define likely(x)      __builtin_expect(!!(x),1)
+#define unlikely(x)    __builtin_expect(!!(x),0)
+
+/*
+ * Hack to calculate maximum length.
+ * (length * 8 - 1) * log10(2) + 1 + 1 + 12
+ * The second 1 is for the minus sign and the 12 is a safety margin.
+ */
+static inline int max_int_length(int bytes)
+{
+       return (bytes * 8 - 1) * 0.30102999566398119521 + 14;
+}
diff --git a/src/show.c b/src/show.c
new file mode 100644 (file)
index 0000000..14dbef3
--- /dev/null
@@ -0,0 +1,400 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "shell.h"
+#include "parser.h"
+#include "nodes.h"
+#include "mystring.h"
+#include "show.h"
+#include "options.h"
+
+
+#ifdef DEBUG
+static void shtree(union node *, int, char *, FILE*);
+static void shcmd(union node *, FILE *);
+static void sharg(union node *, FILE *);
+static void indent(int, char *, FILE *);
+static void trstring(char *);
+
+
+void
+showtree(union node *n)
+{
+       trputs("showtree called\n");
+       shtree(n, 1, NULL, stdout);
+}
+
+
+static void
+shtree(union node *n, int ind, char *pfx, FILE *fp)
+{
+       struct nodelist *lp;
+       const char *s;
+
+       if (n == NULL)
+               return;
+
+       indent(ind, pfx, fp);
+       switch(n->type) {
+       case NSEMI:
+               s = "; ";
+               goto binop;
+       case NAND:
+               s = " && ";
+               goto binop;
+       case NOR:
+               s = " || ";
+binop:
+               shtree(n->nbinary.ch1, ind, NULL, fp);
+          /*    if (ind < 0) */
+                       fputs(s, fp);
+               shtree(n->nbinary.ch2, ind, NULL, fp);
+               break;
+       case NCMD:
+               shcmd(n, fp);
+               if (ind >= 0)
+                       putc('\n', fp);
+               break;
+       case NPIPE:
+               for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+                       shcmd(lp->n, fp);
+                       if (lp->next)
+                               fputs(" | ", fp);
+               }
+               if (n->npipe.backgnd)
+                       fputs(" &", fp);
+               if (ind >= 0)
+                       putc('\n', fp);
+               break;
+       default:
+               fprintf(fp, "<node type %d>", n->type);
+               if (ind >= 0)
+                       putc('\n', fp);
+               break;
+       }
+}
+
+
+
+static void
+shcmd(union node *cmd, FILE *fp)
+{
+       union node *np;
+       int first;
+       const char *s;
+       int dftfd;
+
+       first = 1;
+       for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
+               if (! first)
+                       putchar(' ');
+               sharg(np, fp);
+               first = 0;
+       }
+       for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
+               if (! first)
+                       putchar(' ');
+               switch (np->nfile.type) {
+                       case NTO:       s = ">";  dftfd = 1; break;
+                       case NCLOBBER:  s = ">|"; dftfd = 1; break;
+                       case NAPPEND:   s = ">>"; dftfd = 1; break;
+                       case NTOFD:     s = ">&"; dftfd = 1; break;
+                       case NFROM:     s = "<";  dftfd = 0; break;
+                       case NFROMFD:   s = "<&"; dftfd = 0; break;
+                       case NFROMTO:   s = "<>"; dftfd = 0; break;
+                       default:        s = "*error*"; dftfd = 0; break;
+               }
+               if (np->nfile.fd != dftfd)
+                       fprintf(fp, "%d", np->nfile.fd);
+               fputs(s, fp);
+               if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
+                       fprintf(fp, "%d", np->ndup.dupfd);
+               } else {
+                       sharg(np->nfile.fname, fp);
+               }
+               first = 0;
+       }
+}
+
+
+
+static void
+sharg(union node *arg, FILE *fp)
+{
+       char *p;
+       struct nodelist *bqlist;
+       int subtype;
+
+       if (arg->type != NARG) {
+               printf("<node type %d>\n", arg->type);
+               abort();
+       }
+       bqlist = arg->narg.backquote;
+       for (p = arg->narg.text ; *p ; p++) {
+               switch ((signed char)*p) {
+               case CTLESC:
+                       putc(*++p, fp);
+                       break;
+               case CTLVAR:
+                       putc('$', fp);
+                       putc('{', fp);
+                       subtype = *++p;
+                       if (subtype == VSLENGTH)
+                               putc('#', fp);
+
+                       while (*p != '=')
+                               putc(*p++, fp);
+
+                       if (subtype & VSNUL)
+                               putc(':', fp);
+
+                       switch (subtype & VSTYPE) {
+                       case VSNORMAL:
+                               putc('}', fp);
+                               break;
+                       case VSMINUS:
+                               putc('-', fp);
+                               break;
+                       case VSPLUS:
+                               putc('+', fp);
+                               break;
+                       case VSQUESTION:
+                               putc('?', fp);
+                               break;
+                       case VSASSIGN:
+                               putc('=', fp);
+                               break;
+                       case VSTRIMLEFT:
+                               putc('#', fp);
+                               break;
+                       case VSTRIMLEFTMAX:
+                               putc('#', fp);
+                               putc('#', fp);
+                               break;
+                       case VSTRIMRIGHT:
+                               putc('%', fp);
+                               break;
+                       case VSTRIMRIGHTMAX:
+                               putc('%', fp);
+                               putc('%', fp);
+                               break;
+                       case VSLENGTH:
+                               break;
+                       default:
+                               printf("<subtype %d>", subtype);
+                       }
+                       break;
+               case CTLENDVAR:
+                    putc('}', fp);
+                    break;
+               case CTLBACKQ:
+                       putc('$', fp);
+                       putc('(', fp);
+                       shtree(bqlist->n, -1, NULL, fp);
+                       putc(')', fp);
+                       break;
+               default:
+                       putc(*p, fp);
+                       break;
+               }
+       }
+}
+
+
+static void
+indent(int amount, char *pfx, FILE *fp)
+{
+       int i;
+
+       for (i = 0 ; i < amount ; i++) {
+               if (pfx && i == amount - 1)
+                       fputs(pfx, fp);
+               putc('\t', fp);
+       }
+}
+
+
+
+/*
+ * Debugging stuff.
+ */
+
+
+FILE *tracefile;
+
+
+void
+trputc(int c)
+{
+       if (debug != 1)
+               return;
+       putc(c, tracefile);
+}
+
+void
+trace(const char *fmt, ...)
+{
+       va_list va;
+
+       if (debug != 1)
+               return;
+       va_start(va, fmt);
+       (void) vfprintf(tracefile, fmt, va);
+       va_end(va);
+}
+
+void
+tracev(const char *fmt, va_list va)
+{
+       if (debug != 1)
+               return;
+       (void) vfprintf(tracefile, fmt, va);
+}
+
+
+void
+trputs(const char *s)
+{
+       if (debug != 1)
+               return;
+       fputs(s, tracefile);
+}
+
+
+static void
+trstring(char *s)
+{
+       char *p;
+       char c;
+
+       if (debug != 1)
+               return;
+       putc('"', tracefile);
+       for (p = s ; *p ; p++) {
+               switch ((signed char)*p) {
+               case '\n':  c = 'n';  goto backslash;
+               case '\t':  c = 't';  goto backslash;
+               case '\r':  c = 'r';  goto backslash;
+               case '"':  c = '"';  goto backslash;
+               case '\\':  c = '\\';  goto backslash;
+               case CTLESC:  c = 'e';  goto backslash;
+               case CTLVAR:  c = 'v';  goto backslash;
+               case CTLBACKQ:  c = 'q';  goto backslash;
+backslash:       putc('\\', tracefile);
+                       putc(c, tracefile);
+                       break;
+               default:
+                       if (*p >= ' ' && *p <= '~')
+                               putc(*p, tracefile);
+                       else {
+                               putc('\\', tracefile);
+                               putc(*p >> 6 & 03, tracefile);
+                               putc(*p >> 3 & 07, tracefile);
+                               putc(*p & 07, tracefile);
+                       }
+                       break;
+               }
+       }
+       putc('"', tracefile);
+}
+
+
+void
+trargs(char **ap)
+{
+       if (debug != 1)
+               return;
+       while (*ap) {
+               trstring(*ap++);
+               if (*ap)
+                       putc(' ', tracefile);
+               else
+                       putc('\n', tracefile);
+       }
+}
+
+
+void
+opentrace(void)
+{
+       char s[100];
+#ifdef O_APPEND
+       int flags;
+#endif
+
+       if (debug != 1) {
+               if (tracefile)
+                       fflush(tracefile);
+               /* leave open because libedit might be using it */
+               return;
+       }
+#ifdef not_this_way
+       {
+               char *p;
+               if ((p = getenv(homestr)) == NULL) {
+                       if (geteuid() == 0)
+                               p = "/";
+                       else
+                               p = "/tmp";
+               }
+               scopy(p, s);
+               strcat(s, "/trace");
+       }
+#else
+       scopy("./trace", s);
+#endif /* not_this_way */
+       if (tracefile) {
+               if (!freopen(s, "a", tracefile)) {
+                       fprintf(stderr, "Can't re-open %s\n", s);
+                       debug = 0;
+                       return;
+               }
+       } else {
+               if ((tracefile = fopen(s, "a")) == NULL) {
+                       fprintf(stderr, "Can't open %s\n", s);
+                       debug = 0;
+                       return;
+               }
+       }
+#ifdef O_APPEND
+       if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
+               fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
+#endif
+       setlinebuf(tracefile);
+       fputs("\nTracing started.\n", tracefile);
+}
+#endif /* DEBUG */
diff --git a/src/show.h b/src/show.h
new file mode 100644 (file)
index 0000000..d0ccac7
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 1995
+ *      The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)show.h      1.1 (Berkeley) 5/4/95
+ */
+
+#include <stdarg.h>
+
+#ifdef DEBUG
+union node;
+void showtree(union node *);
+void trace(const char *, ...);
+void tracev(const char *, va_list);
+void trargs(char **);
+void trputc(int);
+void trputs(const char *);
+void opentrace(void);
+#endif
diff --git a/src/system.c b/src/system.c
new file mode 100644 (file)
index 0000000..844a641
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2004
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef HAVE_ISALPHA
+#define isalnum _isalnum
+#define iscntrl _iscntrl
+#define islower _islower
+#define isspace _isspace
+#define isalpha _isalpha
+#define isdigit _isdigit
+#define isprint _isprint
+#define isupper _isupper
+#define isblank _isblank
+#define isgraph _isgraph
+#define ispunct _ispunct
+#define isxdigit _isxdigit
+#include <ctype.h>
+#undef isalnum
+#undef iscntrl
+#undef islower
+#undef isspace
+#undef isalpha
+#undef isdigit
+#undef isprint
+#undef isupper
+#undef isblank
+#undef isgraph
+#undef ispunct
+#undef isxdigit
+#endif
+
+#include <signal.h>
+#include <string.h>
+
+#include "error.h"
+#include "output.h"
+#include "system.h"
+
+#ifndef HAVE_MEMPCPY
+void *mempcpy(void *dest, const void *src, size_t n)
+{
+       return memcpy(dest, src, n) + n;
+}
+#endif
+
+#ifndef HAVE_STPCPY
+char *stpcpy(char *dest, const char *src)
+{
+       size_t len = strlen(src);
+       dest[len] = 0;
+       return mempcpy(dest, src, len);
+}
+#endif
+
+#ifndef HAVE_STRCHRNUL
+char *strchrnul(const char *s, int c)
+{
+       char *p = strchr(s, c);
+       if (!p)
+               p = (char *)s + strlen(s);
+       return p;
+}
+#endif
+
+#ifndef HAVE_STRSIGNAL
+char *strsignal(int sig)
+{
+       static char buf[19];
+
+       if ((unsigned)sig < NSIG && sys_siglist[sig])
+               return (char *)sys_siglist[sig];
+       fmtstr(buf, sizeof(buf), "Signal %d", sig); 
+       return buf;
+}
+#endif
+
+#ifndef HAVE_BSEARCH
+void *bsearch(const void *key, const void *base, size_t nmemb,
+             size_t size, int (*cmp)(const void *, const void *))
+{
+       while (nmemb) {
+               size_t mididx = nmemb / 2;
+               const void *midobj = base + mididx * size;
+               int diff = cmp(key, midobj);
+
+               if (diff == 0)
+                       return (void *)midobj;
+
+               if (diff > 0) {
+                       base = midobj + size;
+                       nmemb -= mididx + 1;
+               } else
+                       nmemb = mididx;
+       }
+
+       return 0;
+}
+#endif
+
+#ifndef HAVE_SYSCONF
+long sysconf(int name)
+{
+       sh_error("no sysconf for: %d", name);
+}
+#endif
+
+#ifndef HAVE_ISALPHA
+int isalnum(int c) {
+       return _isalnum(c);
+}
+
+
+int iscntrl(int c) {
+       return _iscntrl(c);
+}
+
+
+int islower(int c) {
+       return _islower(c);
+}
+
+
+int isspace(int c) {
+       return _isspace(c);
+}
+
+
+int isalpha(int c) {
+       return _isalpha(c);
+}
+
+
+int isdigit(int c) {
+       return _isdigit(c);
+}
+
+
+int isprint(int c) {
+       return _isprint(c);
+}
+
+
+int isupper(int c) {
+       return _isupper(c);
+}
+
+
+#if HAVE_DECL_ISBLANK
+int isblank(int c) {
+       return _isblank(c);
+}
+#endif
+
+
+int isgraph(int c) {
+       return _isgraph(c);
+}
+
+
+int ispunct(int c) {
+       return _ispunct(c);
+}
+
+
+int isxdigit(int c) {
+       return _isxdigit(c);
+}
+#endif
+
+#if !HAVE_DECL_ISBLANK
+int isblank(int c) {
+       return c == ' ' || c == '\t';
+}
+#endif
diff --git a/src/system.h b/src/system.h
new file mode 100644 (file)
index 0000000..a8d09b3
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2004
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <limits.h>
+#include <signal.h>
+#include <sys/types.h>
+
+#ifndef SSIZE_MAX
+#define SSIZE_MAX ((ssize_t)((size_t)-1 >> 1))
+#endif
+
+static inline void sigclearmask(void)
+{
+#ifdef HAVE_SIGSETMASK
+       sigsetmask(0);
+#else
+       sigset_t set;
+       sigemptyset(&set);
+       sigprocmask(SIG_SETMASK, &set, 0);
+#endif
+}
+
+#ifndef HAVE_MEMPCPY
+void *mempcpy(void *, const void *, size_t);
+#endif
+
+#ifndef HAVE_STPCPY
+char *stpcpy(char *, const char *);
+#endif
+
+#ifndef HAVE_STRCHRNUL
+char *strchrnul(const char *, int);
+#endif
+
+#ifndef HAVE_STRSIGNAL
+char *strsignal(int);
+#endif
+
+#ifndef HAVE_STRTOD
+static inline double strtod(const char *nptr, char **endptr)
+{
+       *endptr = (char *)nptr;
+       return 0;
+}
+#endif
+
+#ifndef HAVE_STRTOIMAX
+#define strtoimax strtoll
+#endif
+
+#ifndef HAVE_STRTOUMAX
+#define strtoumax strtoull
+#endif
+
+#ifndef HAVE_BSEARCH
+void *bsearch(const void *, const void *, size_t, size_t,
+             int (*)(const void *, const void *));
+#endif
+
+#ifndef HAVE_KILLPG
+static inline int killpg(pid_t pid, int signal)
+{
+#ifdef DEBUG
+       if (pid < 0)
+               abort();
+#endif
+       return kill(-pid, signal);
+}
+#endif
+
+#ifndef HAVE_SYSCONF
+#define _SC_CLK_TCK 2
+long sysconf(int) __attribute__((__noreturn__));
+#endif
+
+#if !HAVE_DECL_ISBLANK
+int isblank(int c);
+#endif
+
+/*
+ * A trick to suppress uninitialized variable warning without generating any
+ * code
+ */
+#define uninitialized_var(x) x = x
diff --git a/src/trap.c b/src/trap.c
new file mode 100644 (file)
index 0000000..17316c9
--- /dev/null
@@ -0,0 +1,418 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h"     /* for other headers */
+#include "eval.h"
+#include "jobs.h"
+#include "show.h"
+#include "options.h"
+#include "syntax.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "trap.h"
+#include "mystring.h"
+
+#ifdef HETIO
+#include "hetio.h"
+#endif
+
+/*
+ * Sigmode records the current value of the signal handlers for the various
+ * modes.  A value of zero means that the current handler is not known.
+ * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
+ */
+
+#define S_DFL 1                        /* default signal handling (SIG_DFL) */
+#define S_CATCH 2              /* signal is caught */
+#define S_IGN 3                        /* signal is ignored (SIG_IGN) */
+#define S_HARD_IGN 4           /* signal is ignored permenantly */
+#define S_RESET 5              /* temporary - to reset a hard ignored sig */
+
+
+/* trap handler commands */
+static char *trap[NSIG];
+/* number of non-null traps */
+int trapcnt;
+/* current value of signal */
+char sigmode[NSIG - 1];
+/* indicates specified signal received */
+static char gotsig[NSIG - 1];
+/* last pending signal */
+volatile sig_atomic_t pendingsigs;
+/* received SIGCHLD */
+int gotsigchld;
+
+extern char *signal_names[];
+
+#ifdef mkinit
+INCLUDE "trap.h"
+INIT {
+       sigmode[SIGCHLD - 1] = S_DFL;
+       setsignal(SIGCHLD);
+}
+#endif
+
+/*
+ * The trap builtin.
+ */
+
+int
+trapcmd(int argc, char **argv)
+{
+       char *action;
+       char **ap;
+       int signo;
+
+       nextopt(nullstr);
+       ap = argptr;
+       if (!*ap) {
+               for (signo = 0 ; signo < NSIG ; signo++) {
+                       if (trap[signo] != NULL) {
+                               out1fmt(
+                                       "trap -- %s %s\n",
+                                       single_quote(trap[signo]),
+                                       signal_names[signo]
+                               );
+                       }
+               }
+               return 0;
+       }
+       if (!ap[1])
+               action = NULL;
+       else
+               action = *ap++;
+       while (*ap) {
+               if ((signo = decode_signal(*ap, 0)) < 0) {
+                       outfmt(out2, "trap: %s: bad trap\n", *ap);
+                       return 1;
+               }
+               INTOFF;
+               if (action) {
+                       if (action[0] == '-' && action[1] == '\0')
+                               action = NULL;
+                       else {
+                               if (*action)
+                                       trapcnt++;
+                               action = savestr(action);
+                       }
+               }
+               if (trap[signo]) {
+                       if (*trap[signo])
+                               trapcnt--;
+                       ckfree(trap[signo]);
+               }
+               trap[signo] = action;
+               if (signo != 0)
+                       setsignal(signo);
+               INTON;
+               ap++;
+       }
+       return 0;
+}
+
+
+
+/*
+ * Clear traps on a fork.
+ */
+
+void
+clear_traps(void)
+{
+       char **tp;
+
+       INTOFF;
+       for (tp = trap ; tp < &trap[NSIG] ; tp++) {
+               if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
+                       ckfree(*tp);
+                       *tp = NULL;
+                       if (tp != &trap[0])
+                               setsignal(tp - trap);
+               }
+       }
+       trapcnt = 0;
+       INTON;
+}
+
+
+
+/*
+ * Set the signal handler for the specified signal.  The routine figures
+ * out what it should be set to.
+ */
+
+void
+setsignal(int signo)
+{
+       int action;
+       char *t, tsig;
+       struct sigaction act;
+
+       if ((t = trap[signo]) == NULL)
+               action = S_DFL;
+       else if (*t != '\0')
+               action = S_CATCH;
+       else
+               action = S_IGN;
+       if (rootshell && action == S_DFL) {
+               switch (signo) {
+               case SIGINT:
+                       if (iflag || minusc || sflag == 0)
+                               action = S_CATCH;
+                       break;
+               case SIGQUIT:
+#ifdef DEBUG
+                       if (debug)
+                               break;
+#endif
+                       /* FALLTHROUGH */
+               case SIGTERM:
+                       if (iflag)
+                               action = S_IGN;
+                       break;
+#if JOBS
+               case SIGTSTP:
+               case SIGTTOU:
+                       if (mflag)
+                               action = S_IGN;
+                       break;
+#endif
+               }
+       }
+
+       if (signo == SIGCHLD)
+               action = S_CATCH;
+
+       t = &sigmode[signo - 1];
+       tsig = *t;
+       if (tsig == 0) {
+               /*
+                * current setting unknown
+                */
+               if (sigaction(signo, 0, &act) == -1) {
+                       /*
+                        * Pretend it worked; maybe we should give a warning
+                        * here, but other shells don't. We don't alter
+                        * sigmode, so that we retry every time.
+                        */
+                       return;
+               }
+               if (act.sa_handler == SIG_IGN) {
+                       if (mflag && (signo == SIGTSTP ||
+                            signo == SIGTTIN || signo == SIGTTOU)) {
+                               tsig = S_IGN;   /* don't hard ignore these */
+                       } else
+                               tsig = S_HARD_IGN;
+               } else {
+                       tsig = S_RESET; /* force to be set */
+               }
+       }
+       if (tsig == S_HARD_IGN || tsig == action)
+               return;
+       switch (action) {
+       case S_CATCH:
+               act.sa_handler = onsig;
+               break;
+       case S_IGN:
+               act.sa_handler = SIG_IGN;
+               break;
+       default:
+               act.sa_handler = SIG_DFL;
+       }
+       *t = action;
+       act.sa_flags = 0;
+       sigfillset(&act.sa_mask);
+       sigaction(signo, &act, 0);
+}
+
+/*
+ * Ignore a signal.
+ */
+
+void
+ignoresig(int signo)
+{
+       if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
+               signal(signo, SIG_IGN);
+       }
+       sigmode[signo - 1] = S_HARD_IGN;
+}
+
+
+
+/*
+ * Signal handler.
+ */
+
+void
+onsig(int signo)
+{
+       if (signo == SIGCHLD) {
+               gotsigchld = 1;
+               if (!trap[SIGCHLD])
+                       return;
+       }
+
+       gotsig[signo - 1] = 1;
+       pendingsigs = signo;
+
+       if (signo == SIGINT && !trap[SIGINT]) {
+               if (!suppressint)
+                       onint();
+               intpending = 1;
+       }
+}
+
+
+
+/*
+ * Called to execute a trap.  Perhaps we should avoid entering new trap
+ * handlers while we are executing a trap handler.
+ */
+
+void dotrap(void)
+{
+       char *p;
+       char *q;
+       int i;
+       int savestatus;
+
+       savestatus = exitstatus;
+       pendingsigs = 0;
+       barrier();
+
+       for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
+               if (!*q)
+                       continue;
+               *q = 0;
+
+               p = trap[i + 1];
+               if (!p)
+                       continue;
+               evalstring(p, 0);
+               exitstatus = savestatus;
+               if (evalskip)
+                       break;
+       }
+}
+
+
+
+/*
+ * Controls whether the shell is interactive or not.
+ */
+
+
+void
+setinteractive(int on)
+{
+       static int is_interactive;
+
+       if (++on == is_interactive)
+               return;
+       is_interactive = on;
+       setsignal(SIGINT);
+       setsignal(SIGQUIT);
+       setsignal(SIGTERM);
+}
+
+
+
+/*
+ * Called to exit the shell.
+ */
+
+void
+exitshell(void)
+{
+       struct jmploc loc;
+       char *p;
+       volatile int status;
+
+#ifdef HETIO
+       hetio_reset_term();
+#endif
+       status = exitstatus;
+       TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
+       if (setjmp(loc.loc)) {
+               if (exception == EXEXIT)
+                       status = exitstatus;
+               goto out;
+       }
+       handler = &loc;
+       if ((p = trap[0])) {
+               trap[0] = NULL;
+               evalskip = 0;
+               evalstring(p, 0);
+       }
+out:
+       /*
+        * Disable job control so that whoever had the foreground before we
+        * started can get it back.
+        */
+       if (likely(!setjmp(loc.loc)))
+               setjobctl(0);
+       flushall();
+       _exit(status);
+       /* NOTREACHED */
+}
+
+int decode_signal(const char *string, int minsig)
+{
+       int signo;
+
+       if (is_number(string)) {
+               signo = atoi(string);
+               if (signo >= NSIG) {
+                       return -1;
+               }
+               return signo;
+       }
+
+       for (signo = minsig; signo < NSIG; signo++) {
+               if (!strcasecmp(string, signal_names[signo])) {
+                       return signo;
+               }
+       }
+
+       return -1;
+}
diff --git a/src/trap.h b/src/trap.h
new file mode 100644 (file)
index 0000000..7573fd7
--- /dev/null
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)trap.h      8.3 (Berkeley) 6/5/95
+ */
+
+#include <signal.h>
+
+extern int trapcnt;
+extern char sigmode[];
+extern volatile sig_atomic_t pendingsigs;
+extern int gotsigchld;
+
+int trapcmd(int, char **);
+void clear_traps(void);
+void setsignal(int);
+void ignoresig(int);
+void onsig(int);
+void dotrap(void);
+void setinteractive(int);
+void exitshell(void) __attribute__((__noreturn__));
+int decode_signal(const char *, int);
+
+static inline int have_traps(void)
+{
+       return trapcnt;
+}
diff --git a/src/var.c b/src/var.c
new file mode 100644 (file)
index 0000000..ecc8c90
--- /dev/null
+++ b/src/var.c
@@ -0,0 +1,705 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+/*
+ * Shell variables.
+ */
+
+#include "shell.h"
+#include "output.h"
+#include "expand.h"
+#include "nodes.h"     /* for other headers */
+#include "exec.h"
+#include "syntax.h"
+#include "options.h"
+#include "mail.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "parser.h"
+#include "show.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+#include "system.h"
+
+
+#define VTABSIZE 39
+
+
+struct localvar_list {
+       struct localvar_list *next;
+       struct localvar *lv;
+};
+
+MKINIT struct localvar_list *localvar_stack;
+
+const char defpathvar[] =
+       "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
+#ifdef IFS_BROKEN
+const char defifsvar[] = "IFS= \t\n";
+#else
+const char defifs[] = " \t\n";
+#endif
+
+int lineno;
+char linenovar[sizeof("LINENO=")+sizeof(int)*CHAR_BIT/3+1] = "LINENO=";
+
+/* Some macros in var.h depend on the order, add new variables to the end. */
+struct var varinit[] = {
+#if ATTY
+       { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "ATTY\0",       0 },
+#endif
+#ifdef IFS_BROKEN
+       { 0,    VSTRFIXED|VTEXTFIXED,           defifsvar,      0 },
+#else
+       { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS\0",        0 },
+#endif
+       { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL\0",       changemail },
+       { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH\0",   changemail },
+       { 0,    VSTRFIXED|VTEXTFIXED,           defpathvar,     changepath },
+       { 0,    VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       0 },
+       { 0,    VSTRFIXED|VTEXTFIXED,           "PS2=> ",       0 },
+       { 0,    VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       0 },
+       { 0,    VSTRFIXED|VTEXTFIXED,           "OPTIND=1",     getoptsreset },
+       { 0,    VSTRFIXED|VTEXTFIXED,           linenovar,      0 },
+#ifndef SMALL
+       { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "TERM\0",       0 },
+       { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "HISTSIZE\0",   sethistsize },
+#endif
+};
+
+STATIC struct var *vartab[VTABSIZE];
+
+STATIC struct var **hashvar(const char *);
+STATIC int vpcmp(const void *, const void *);
+STATIC struct var **findvar(struct var **, const char *);
+
+/*
+ * Initialize the varable symbol tables and import the environment
+ */
+
+#ifdef mkinit
+INCLUDE <unistd.h>
+INCLUDE <sys/types.h>
+INCLUDE <sys/stat.h>
+INCLUDE "cd.h"
+INCLUDE "output.h"
+INCLUDE "var.h"
+MKINIT char **environ;
+INIT {
+       char **envp;
+       static char ppid[32] = "PPID=";
+       const char *p;
+       struct stat st1, st2;
+
+       initvar();
+       for (envp = environ ; *envp ; envp++) {
+               if (strchr(*envp, '=')) {
+                       setvareq(*envp, VEXPORT|VTEXTFIXED);
+               }
+       }
+
+       fmtstr(ppid + 5, sizeof(ppid) - 5, "%ld", (long) getppid());
+       setvareq(ppid, VTEXTFIXED);
+
+       p = lookupvar("PWD");
+       if (p)
+               if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
+                   st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
+                       p = 0;
+       setpwd(p, 0);
+}
+
+RESET {
+       unwindlocalvars(0);
+}
+#endif
+
+
+/*
+ * This routine initializes the builtin variables.  It is called when the
+ * shell is initialized.
+ */
+
+void
+initvar(void)
+{
+       struct var *vp;
+       struct var *end;
+       struct var **vpp;
+
+       vp = varinit;
+       end = vp + sizeof(varinit) / sizeof(varinit[0]);
+       do {
+               vpp = hashvar(vp->text);
+               vp->next = *vpp;
+               *vpp = vp;
+       } while (++vp < end);
+       /*
+        * PS1 depends on uid
+        */
+       if (!geteuid())
+               vps1.text = "PS1=# ";
+}
+
+/*
+ * Set the value of a variable.  The flags argument is ored with the
+ * flags of the variable.  If val is NULL, the variable is unset.
+ */
+
+struct var *setvar(const char *name, const char *val, int flags)
+{
+       char *p, *q;
+       size_t namelen;
+       char *nameeq;
+       size_t vallen;
+       struct var *vp;
+
+       q = endofname(name);
+       p = strchrnul(q, '=');
+       namelen = p - name;
+       if (!namelen || p != q)
+               sh_error("%.*s: bad variable name", namelen, name);
+       vallen = 0;
+       if (val == NULL) {
+               flags |= VUNSET;
+       } else {
+               vallen = strlen(val);
+       }
+       INTOFF;
+       p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
+       if (val) {
+               *p++ = '=';
+               p = mempcpy(p, val, vallen);
+       }
+       *p = '\0';
+       vp = setvareq(nameeq, flags | VNOSAVE);
+       INTON;
+
+       return vp;
+}
+
+/*
+ * Set the given integer as the value of a variable.  The flags argument is
+ * ored with the flags of the variable.
+ */
+
+intmax_t setvarint(const char *name, intmax_t val, int flags)
+{
+       int len = max_int_length(sizeof(val));
+       char buf[len];
+
+       fmtstr(buf, len, "%" PRIdMAX, val);
+       setvar(name, buf, flags);
+       return val;
+}
+
+
+
+/*
+ * Same as setvar except that the variable and value are passed in
+ * the first argument as name=value.  Since the first argument will
+ * be actually stored in the table, it should not be a string that
+ * will go away.
+ * Called with interrupts off.
+ */
+
+struct var *setvareq(char *s, int flags)
+{
+       struct var *vp, **vpp;
+
+       vpp = hashvar(s);
+       flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
+       vpp = findvar(vpp, s);
+       vp = *vpp;
+       if (vp) {
+               if (vp->flags & VREADONLY) {
+                       const char *n;
+
+                       if (flags & VNOSAVE)
+                               free(s);
+                       n = vp->text;
+                       sh_error("%.*s: is read only", strchrnul(n, '=') - n,
+                                n);
+               }
+
+               if (flags & VNOSET)
+                       goto out;
+
+               if (vp->func && (flags & VNOFUNC) == 0)
+                       (*vp->func)(strchrnul(s, '=') + 1);
+
+               if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
+                       ckfree(vp->text);
+
+               if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) |
+                    (vp->flags & VSTRFIXED)) == VUNSET) {
+                       *vpp = vp->next;
+                       ckfree(vp);
+out_free:
+                       if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
+                               ckfree(s);
+                       goto out;
+               }
+
+               flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
+       } else {
+               if (flags & VNOSET)
+                       goto out;
+               if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
+                       goto out_free;
+               /* not found */
+               vp = ckmalloc(sizeof (*vp));
+               vp->next = *vpp;
+               vp->func = NULL;
+               *vpp = vp;
+       }
+       if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
+               s = savestr(s);
+       vp->text = s;
+       vp->flags = flags;
+
+out:
+       return vp;
+}
+
+
+
+/*
+ * Process a linked list of variable assignments.
+ */
+
+void
+listsetvar(struct strlist *list, int flags)
+{
+       struct strlist *lp;
+
+       lp = list;
+       if (!lp)
+               return;
+       INTOFF;
+       do {
+               setvareq(lp->text, flags);
+       } while ((lp = lp->next));
+       INTON;
+}
+
+
+/*
+ * Find the value of a variable.  Returns NULL if not set.
+ */
+
+char *
+lookupvar(const char *name)
+{
+       struct var *v;
+
+       if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
+               if (v == &vlineno && v->text == linenovar) {
+                       fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
+               }
+               return strchrnul(v->text, '=') + 1;
+       }
+       return NULL;
+}
+
+intmax_t lookupvarint(const char *name)
+{
+       return atomax(lookupvar(name) ?: nullstr, 0);
+}
+
+
+
+/*
+ * Generate a list of variables satisfying the given conditions.
+ */
+
+char **
+listvars(int on, int off, char ***end)
+{
+       struct var **vpp;
+       struct var *vp;
+       char **ep;
+       int mask;
+
+       STARTSTACKSTR(ep);
+       vpp = vartab;
+       mask = on | off;
+       do {
+               for (vp = *vpp ; vp ; vp = vp->next)
+                       if ((vp->flags & mask) == on) {
+                               if (ep == stackstrend())
+                                       ep = growstackstr();
+                               *ep++ = (char *) vp->text;
+                       }
+       } while (++vpp < vartab + VTABSIZE);
+       if (ep == stackstrend())
+               ep = growstackstr();
+       if (end)
+               *end = ep;
+       *ep++ = NULL;
+       return grabstackstr(ep);
+}
+
+
+
+/*
+ * POSIX requires that 'set' (but not export or readonly) output the
+ * variables in lexicographic order - by the locale's collating order (sigh).
+ * Maybe we could keep them in an ordered balanced binary tree
+ * instead of hashed lists.
+ * For now just roll 'em through qsort for printing...
+ */
+
+int
+showvars(const char *prefix, int on, int off)
+{
+       const char *sep;
+       char **ep, **epend;
+
+       ep = listvars(on, off, &epend);
+       qsort(ep, epend - ep, sizeof(char *), vpcmp);
+
+       sep = *prefix ? spcstr : prefix;
+
+       for (; ep < epend; ep++) {
+               const char *p;
+               const char *q;
+
+               p = strchrnul(*ep, '=');
+               q = nullstr;
+               if (*p)
+                       q = single_quote(++p);
+
+               out1fmt("%s%s%.*s%s\n", prefix, sep, (int)(p - *ep), *ep, q);
+       }
+
+       return 0;
+}
+
+
+
+/*
+ * The export and readonly commands.
+ */
+
+int
+exportcmd(int argc, char **argv)
+{
+       struct var *vp;
+       char *name;
+       const char *p;
+       char **aptr;
+       int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
+       int notp;
+
+       notp = nextopt("p") - 'p';
+       if (notp && ((name = *(aptr = argptr)))) {
+               do {
+                       if ((p = strchr(name, '=')) != NULL) {
+                               p++;
+                       } else {
+                               if ((vp = *findvar(hashvar(name), name))) {
+                                       vp->flags |= flag;
+                                       continue;
+                               }
+                       }
+                       setvar(name, p, flag);
+               } while ((name = *++aptr) != NULL);
+       } else {
+               showvars(argv[0], flag, 0);
+       }
+       return 0;
+}
+
+
+/*
+ * The "local" command.
+ */
+
+int
+localcmd(int argc, char **argv)
+{
+       char *name;
+
+       if (!localvar_stack)
+               sh_error("not in a function");
+
+       argv = argptr;
+       while ((name = *argv++) != NULL) {
+               mklocal(name);
+       }
+       return 0;
+}
+
+
+/*
+ * Make a variable a local variable.  When a variable is made local, it's
+ * value and flags are saved in a localvar structure.  The saved values
+ * will be restored when the shell function returns.  We handle the name
+ * "-" as a special case.
+ */
+
+void mklocal(char *name)
+{
+       struct localvar *lvp;
+       struct var **vpp;
+       struct var *vp;
+
+       INTOFF;
+       lvp = ckmalloc(sizeof (struct localvar));
+       if (name[0] == '-' && name[1] == '\0') {
+               char *p;
+               p = ckmalloc(sizeof(optlist));
+               lvp->text = memcpy(p, optlist, sizeof(optlist));
+               vp = NULL;
+       } else {
+               char *eq;
+
+               vpp = hashvar(name);
+               vp = *findvar(vpp, name);
+               eq = strchr(name, '=');
+               if (vp == NULL) {
+                       if (eq)
+                               vp = setvareq(name, VSTRFIXED);
+                       else
+                               vp = setvar(name, NULL, VSTRFIXED);
+                       lvp->flags = VUNSET;
+               } else {
+                       lvp->text = vp->text;
+                       lvp->flags = vp->flags;
+                       vp->flags |= VSTRFIXED|VTEXTFIXED;
+                       if (eq)
+                               setvareq(name, 0);
+               }
+       }
+       lvp->vp = vp;
+       lvp->next = localvar_stack->lv;
+       localvar_stack->lv = lvp;
+       INTON;
+}
+
+
+/*
+ * Called after a function returns.
+ * Interrupts must be off.
+ */
+
+void
+poplocalvars(int keep)
+{
+       struct localvar_list *ll;
+       struct localvar *lvp, *next;
+       struct var *vp;
+
+       INTOFF;
+       ll = localvar_stack;
+       localvar_stack = ll->next;
+
+       next = ll->lv;
+       ckfree(ll);
+
+       while ((lvp = next) != NULL) {
+               next = lvp->next;
+               vp = lvp->vp;
+               TRACE(("poplocalvar %s", vp ? vp->text : "-"));
+               if (keep) {
+                       int bits = VSTRFIXED;
+
+                       if (lvp->flags != VUNSET) {
+                               if (vp->text == lvp->text)
+                                       bits |= VTEXTFIXED;
+                               else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
+                                       ckfree(lvp->text);
+                       }
+
+                       vp->flags &= ~bits;
+                       vp->flags |= (lvp->flags & bits);
+
+                       if ((vp->flags &
+                            (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
+                               unsetvar(vp->text);
+               } else if (vp == NULL) {        /* $- saved */
+                       memcpy(optlist, lvp->text, sizeof(optlist));
+                       ckfree(lvp->text);
+                       optschanged();
+               } else if (lvp->flags == VUNSET) {
+                       vp->flags &= ~(VSTRFIXED|VREADONLY);
+                       unsetvar(vp->text);
+               } else {
+                       if (vp->func)
+                               (*vp->func)(strchrnul(lvp->text, '=') + 1);
+                       if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
+                               ckfree(vp->text);
+                       vp->flags = lvp->flags;
+                       vp->text = lvp->text;
+               }
+               ckfree(lvp);
+       }
+       INTON;
+}
+
+
+/*
+ * Create a new localvar environment.
+ */
+struct localvar_list *pushlocalvars(void)
+{
+       struct localvar_list *ll;
+
+       INTOFF;
+       ll = ckmalloc(sizeof(*ll));
+       ll->lv = NULL;
+       ll->next = localvar_stack;
+       localvar_stack = ll;
+       INTON;
+
+       return ll->next;
+}
+
+
+void unwindlocalvars(struct localvar_list *stop)
+{
+       while (localvar_stack != stop)
+               poplocalvars(0);
+}
+
+
+/*
+ * The unset builtin command.  We unset the function before we unset the
+ * variable to allow a function to be unset when there is a readonly variable
+ * with the same name.
+ */
+
+int
+unsetcmd(int argc, char **argv)
+{
+       char **ap;
+       int i;
+       int flag = 0;
+
+       while ((i = nextopt("vf")) != '\0') {
+               flag = i;
+       }
+
+       for (ap = argptr; *ap ; ap++) {
+               if (flag != 'f') {
+                       unsetvar(*ap);
+                       continue;
+               }
+               if (flag != 'v')
+                       unsetfunc(*ap);
+       }
+       return 0;
+}
+
+
+/*
+ * Unset the specified variable.
+ */
+
+void unsetvar(const char *s)
+{
+       setvar(s, 0, 0);
+}
+
+
+
+/*
+ * Find the appropriate entry in the hash table from the name.
+ */
+
+STATIC struct var **
+hashvar(const char *p)
+{
+       unsigned int hashval;
+
+       hashval = ((unsigned char) *p) << 4;
+       while (*p && *p != '=')
+               hashval += (unsigned char) *p++;
+       return &vartab[hashval % VTABSIZE];
+}
+
+
+
+/*
+ * Compares two strings up to the first = or '\0'.  The first
+ * string must be terminated by '='; the second may be terminated by
+ * either '=' or '\0'.
+ */
+
+int
+varcmp(const char *p, const char *q)
+{
+       int c, d;
+
+       while ((c = *p) == (d = *q)) {
+               if (!c || c == '=')
+                       goto out;
+               p++;
+               q++;
+       }
+       if (c == '=')
+               c = 0;
+       if (d == '=')
+               d = 0;
+out:
+       return c - d;
+}
+
+STATIC int
+vpcmp(const void *a, const void *b)
+{
+       return varcmp(*(const char **)a, *(const char **)b);
+}
+
+STATIC struct var **
+findvar(struct var **vpp, const char *name)
+{
+       for (; *vpp; vpp = &(*vpp)->next) {
+               if (varequal((*vpp)->text, name)) {
+                       break;
+               }
+       }
+       return vpp;
+}
diff --git a/src/var.h b/src/var.h
new file mode 100644 (file)
index 0000000..54f7b2d
--- /dev/null
+++ b/src/var.h
@@ -0,0 +1,169 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *     Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)var.h       8.2 (Berkeley) 5/4/95
+ */
+
+#include <inttypes.h>
+
+/*
+ * Shell variables.
+ */
+
+/* flags */
+#define VEXPORT                0x01    /* variable is exported */
+#define VREADONLY      0x02    /* variable cannot be modified */
+#define VSTRFIXED      0x04    /* variable struct is statically allocated */
+#define VTEXTFIXED     0x08    /* text is statically allocated */
+#define VSTACK         0x10    /* text is allocated on the stack */
+#define VUNSET         0x20    /* the variable is not set */
+#define VNOFUNC                0x40    /* don't call the callback function */
+#define VNOSET         0x80    /* do not set variable - just readonly test */
+#define VNOSAVE                0x100   /* when text is on the heap before setvareq */
+
+
+struct var {
+       struct var *next;               /* next entry in hash list */
+       int flags;                      /* flags are defined above */
+       const char *text;               /* name=value */
+       void (*func)(const char *);
+                                       /* function to be called when  */
+                                       /* the variable gets set/unset */
+};
+
+
+struct localvar {
+       struct localvar *next;          /* next local variable in list */
+       struct var *vp;                 /* the variable that was made local */
+       int flags;                      /* saved flags */
+       const char *text;               /* saved text */
+};
+
+struct localvar_list;
+
+
+extern struct localvar *localvars;
+extern struct var varinit[];
+
+#if ATTY
+#define vatty varinit[0]
+#define vifs varinit[1]
+#else
+#define vifs varinit[0]
+#endif
+#define vmail (&vifs)[1]
+#define vmpath (&vmail)[1]
+#define vpath (&vmpath)[1]
+#define vps1 (&vpath)[1]
+#define vps2 (&vps1)[1]
+#define vps4 (&vps2)[1]
+#define voptind (&vps4)[1]
+#define vlineno (&voptind)[1]
+#ifndef SMALL
+#define vterm (&vlineno)[1]
+#define vhistsize (&vterm)[1]
+#endif
+
+#ifdef IFS_BROKEN
+extern const char defifsvar[];
+#define defifs (defifsvar + 4)
+#else
+extern const char defifs[];
+#endif
+extern const char defpathvar[];
+#define defpath (defpathvar + 5)
+
+extern int lineno;
+extern char linenovar[];
+
+/*
+ * The following macros access the values of the above variables.
+ * They have to skip over the name.  They return the null string
+ * for unset variables.
+ */
+
+#define ifsval()       (vifs.text + 4)
+#define ifsset()       ((vifs.flags & VUNSET) == 0)
+#define mailval()      (vmail.text + 5)
+#define mpathval()     (vmpath.text + 9)
+#define pathval()      (vpath.text + 5)
+#define ps1val()       (vps1.text + 4)
+#define ps2val()       (vps2.text + 4)
+#define ps4val()       (vps4.text + 4)
+#define optindval()    (voptind.text + 7)
+#define linenoval()    (vlineno.text + 7)
+#ifndef SMALL
+#define histsizeval()  (vhistsize.text + 9)
+#define termval()      (vterm.text + 5)
+#endif
+
+#if ATTY
+#define attyset()      ((vatty.flags & VUNSET) == 0)
+#endif
+#define mpathset()     ((vmpath.flags & VUNSET) == 0)
+
+void initvar(void);
+struct var *setvar(const char *name, const char *val, int flags);
+intmax_t setvarint(const char *, intmax_t, int);
+struct var *setvareq(char *s, int flags);
+struct strlist;
+void listsetvar(struct strlist *, int);
+char *lookupvar(const char *);
+intmax_t lookupvarint(const char *);
+char **listvars(int, int, char ***);
+#define environment() listvars(VEXPORT, VUNSET, 0)
+int showvars(const char *, int, int);
+int exportcmd(int, char **);
+int localcmd(int, char **);
+void mklocal(char *);
+struct localvar_list *pushlocalvars(void);
+void poplocalvars(int);
+void unwindlocalvars(struct localvar_list *stop);
+int unsetcmd(int, char **);
+void unsetvar(const char *);
+int varcmp(const char *, const char *);
+
+static inline int varequal(const char *a, const char *b) {
+       return !varcmp(a, b);
+}
+
+/*
+ * Search the environment of a builtin command.
+ */
+
+static inline char *bltinlookup(const char *name)
+{
+       return lookupvar(name);
+}
+
+