From 2870d964f8c849d00be20927085f45a30e4e8e53 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Mon, 2 Jul 2001 17:27:21 +0000 Subject: Some updates to ash from vodz. Makes ash smaller. I made a few changes, esp describing all the current ash configuration options. Now ash adds 66k in the default configuration. --- shell/ash.c | 6891 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 3504 insertions(+), 3387 deletions(-) (limited to 'shell/ash.c') diff --git a/shell/ash.c b/shell/ash.c index 7d394b617..489ccaa95 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -3,7 +3,7 @@ * ash shell port for busybox * * Copyright (c) 1989, 1991, 1993, 1994 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. @@ -22,20 +22,74 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * This version of ash is adapted from the source in Debian's ash 0.3.8-5 - * package. + * This version of ash is adapted from the source in Debian's ash 0.3.8-5 + * package. + * + * Modified by Erik Andersen and + * Vladimir Oleynik to be used in busybox * - * Modified by Erik Andersen to be used in busybox. * * Original copyright notice is retained at the end of this file. */ -#undef _GNU_SOURCE + +/* These defines allow you to adjust the feature set to be compiled + * into the ash shell. As a rule, enabling these options will make + * ash get bigger... With all of these options off, ash adds about + * 62k to busybox on an x86 system.*/ + + + +/* Enable job control. This allows you to run jobs in the background, + * which is great when ash is being used as an interactive shell, but + * it completely useless for is all you are doing is running scripts. + * This adds about 2.5k on an x86 system. */ +#define JOBS + +/* This enables alias support in ash. If you want to support things + * like "alias ls='ls -l'" with ash, enable this. This is only useful + * when ash is used as an intractive shell. This adds about 1.5k */ +#define ASH_ALIAS + +/* If you need ash to act as a full Posix shell, with full math + * support, enable this. This option needs some work, since it + * doesn't compile right now... */ +#undef ASH_MATH_SUPPORT + +/* This shell builtin is used to indicate how the shell would interpret + * what you give it. This command is only useful when debugging, and + * is obsolete anyways. Adds about 670 bytes... You probably want to + * leave this disabled. */ #undef ASH_TYPE + +/* Getopts is used by shell procedures to parse positional parameters. + * You probably want to leave this disabled, and use the busybox getopt + * applet if you want to do this sort of thing. There are some scripts + * out there that use it, so it you need it, enable. Most people will + * leave this disabled. This adds 1k on an x86 system. */ #undef ASH_GETOPTS -#undef ASH_MATH_SUPPORT + +/* This allows you to override shell builtins and use whatever is on + * the filesystem. This is most useful when ash is acting as a + * standalone shell. Adds about 320 bytes. */ +#undef ASH_CMDCMD + +/* This makes a few common apps that are usually part of busybox + * anyways to be used as builtins. This may cause these builtins to be + * a little bit faster, but leaving this disabled will save you 2k. */ +#undef ASH_BBAPPS_AS_BUILTINS + +/* Enable this to compile in extra debugging noise. When debugging is + * on, debugging info will be written to $HOME/trace and a quit signal + * will generate a core dump. */ +#undef DEBUG + + + +/* These are here to work with glibc -- Don't change these... */ #undef FNMATCH_BROKEN #undef GLOB_BROKEN +#undef _GNU_SOURCE #include #include @@ -72,1030 +126,2339 @@ #include #endif -#if JOBS +#ifdef JOBS #include -#undef CEOF /* syntax.h redefines this */ #endif -#include "cmdedit.h" #include "busybox.h" -#include "ash.h" +#include "cmdedit.h" + +/* if BB_PWD is defined, then disable ASH_PWD to save space */ +#ifdef BB_PWD +#undef ASH_PWD +#endif + + +/* + * This file was generated by the mksyntax program. + */ + +/* Syntax classes */ +#define CWORD 0 /* character is nothing special */ +#define CNL 1 /* newline character */ +#define CBACK 2 /* a backslash character */ +#define CSQUOTE 3 /* single quote */ +#define CDQUOTE 4 /* double quote */ +#define CENDQUOTE 5 /* a terminating quote */ +#define CBQUOTE 6 /* backwards single quote */ +#define CVAR 7 /* a dollar sign */ +#define CENDVAR 8 /* a '}' character */ +#define CLP 9 /* a left paren in arithmetic */ +#define CRP 10 /* a right paren in arithmetic */ +#define CENDFILE 11 /* end of file */ +#define CCTL 12 /* like CWORD, except it must be escaped */ +#define CSPCL 13 /* these terminate a word */ +#define CIGN 14 /* character should be ignored */ + +/* Syntax classes for is_ functions */ +#define ISDIGIT 01 /* a digit */ +#define ISUPPER 02 /* an upper case letter */ +#define ISLOWER 04 /* a lower case letter */ +#define ISUNDER 010 /* an underscore */ +#define ISSPECL 020 /* the name of a special parameter */ + +#define SYNBASE 130 +#define PEOF -130 + +#define PEOA -129 + +#define TEOF 0 +#define TNL 1 +#define TSEMI 2 +#define TBACKGND 3 +#define TAND 4 +#define TOR 5 +#define TPIPE 6 +#define TLP 7 +#define TRP 8 +#define TENDCASE 9 +#define TENDBQUOTE 10 +#define TREDIR 11 +#define TWORD 12 +#define TASSIGN 13 +#define TNOT 14 +#define TCASE 15 +#define TDO 16 +#define TDONE 17 +#define TELIF 18 +#define TELSE 19 +#define TESAC 20 +#define TFI 21 +#define TFOR 22 +#define TIF 23 +#define TIN 24 +#define TTHEN 25 +#define TUNTIL 26 +#define TWHILE 27 +#define TBEGIN 28 +#define TEND 29 + + +#define BASESYNTAX (basesyntax + SYNBASE) +#define DQSYNTAX (dqsyntax + SYNBASE) +#define SQSYNTAX (sqsyntax + SYNBASE) +#define ARISYNTAX (arisyntax + SYNBASE) + +/* control characters in argument strings */ +#define CTLESC '\201' +#define CTLVAR '\202' +#define CTLENDVAR '\203' +#define CTLBACKQ '\204' +#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ +/* CTLBACKQ | CTLQUOTE == '\205' */ +#define CTLARI '\206' +#define CTLENDARI '\207' +#define CTLQUOTEMARK '\210' + +#define is_digit(c) ((((unsigned char)(c)) - '0') <= 9) +#define is_alpha(c) (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c))) +#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c)))) +#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c)))) +#define is_special(c) ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT)) +#define digit_val(c) ((c) - '0') #define _DIAGASSERT(x) #define ATABSIZE 39 -#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 */ +#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 */ +/* variable substitution byte (follows CTLVAR) */ +#define VSTYPE 0x0f /* type of variable substitution */ +#define VSNUL 0x10 /* colon--treat the empty string as unset */ +#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ -struct alias *atab[ATABSIZE]; +/* 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 VSTRIMLEFT 0x6 /* ${var#pattern} */ +#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */ +#define VSTRIMRIGHT 0x8 /* ${var%pattern} */ +#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */ +#define VSLENGTH 0xa /* ${#var} */ -static void setalias __P((char *, char *)); -static struct alias **hashalias __P((const char *)); -static struct alias *freealias __P((struct alias *)); -static struct alias **__lookupalias __P((const char *)); -static char *trap[NSIG]; /* trap handler commands */ -static char sigmode[NSIG - 1]; /* current value of signal */ -static char gotsig[NSIG - 1]; /* indicates specified signal received */ -static int pendingsigs; /* indicates some signal received */ +/* flags passed to redirect */ +#define REDIR_PUSH 01 /* save previous values of file descriptors */ +#define REDIR_BACKQ 02 /* save the command output in memory */ +/* + * BSD setjmp saves the signal mask, which violates ANSI C and takes time, + * so we use _setjmp instead. + */ -static void -setalias(name, val) - char *name, *val; -{ - struct alias *ap, **app; +#if !defined(__GLIBC__) +#define setjmp(jmploc) _setjmp(jmploc) +#define longjmp(jmploc, val) _longjmp(jmploc, val) +#endif - 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; -} +/* + * Most machines require the value returned from malloc to be aligned + * in some way. The following macro will get this right on many machines. + */ -static int -unalias(name) - char *name; - { - struct alias **app; +#ifndef ALIGN +union align { + int i; + char *cp; +}; - app = __lookupalias(name); +#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1)) +#endif - if (*app) { - INTOFF; - *app = freealias(*app); - INTON; - return (0); - } +#ifdef BB_LOCALE_SUPPORT +#include +static void change_lc_all(const char *value); +static void change_lc_ctype(const char *value); +#endif - return (1); -} +/* + * 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. :-)) + */ -#ifdef mkinit -static void rmaliases __P((void)); +static void onint (void); +static volatile int suppressint; +static volatile int intpending; -SHELLPROC { - rmaliases(); -} +#define INTOFF suppressint++ +#ifdef ASH_BBAPPS_AS_BUILTINS +#define INTON { if (--suppressint == 0 && intpending) onint(); } +#else +static void __inton (void); +#define INTON __inton() #endif +#define FORCEINTON {suppressint = 0; if (intpending) onint();} +#define CLEAR_PENDING_INT intpending = 0 +#define int_pending() intpending -static void -rmaliases() { - 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(name, check) - const char *name; - int check; -{ - struct alias *ap = *__lookupalias(name); +typedef void *pointer; +#ifndef NULL +#define NULL (void *)0 +#endif - if (check && ap && (ap->flag & ALIASINUSE)) - return (NULL); - return (ap); -} +static inline pointer ckmalloc (int sz) { return xmalloc(sz); } +static inline pointer ckrealloc(void *p, int sz) { return xrealloc(p, sz); } +static inline char * savestr (const char *s) { return xstrdup(s); } +static pointer stalloc (int); +static void stunalloc (pointer); +static void ungrabstackstr (char *, char *); +static char * growstackstr(void); +static char *sstrdup (const char *); /* - * TODO - sort output + * 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. */ -static int -aliascmd(argc, argv) - int argc; - char **argv; -{ - char *n, *v; - int ret = 0; - struct alias *ap; - if (argc == 1) { - int i; +#define MINSIZE 504 /* minimum size of a block */ - 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); -} +struct stack_block { + struct stack_block *prev; + char space[MINSIZE]; +}; -static int -unaliascmd(argc, argv) - int argc; - char **argv; -{ - int i; +static struct stack_block stackbase; +static struct stack_block *stackp = &stackbase; +static struct stackmark *markp; +static char *stacknxt = stackbase.space; +static int stacknleft = MINSIZE; - 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); -} +#define equal(s1, s2) (strcmp(s1, s2) == 0) -static struct alias ** -hashalias(p) - const char *p; - { - unsigned int hashval; +#define stackblock() stacknxt +#define stackblocksize() stacknleft +#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize() +#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c))) +#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); } +#define USTPUTC(c, p) (--sstrnleft, *p++ = (c)) +#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0')) +#define STUNPUTC(p) (++sstrnleft, --p) +#define STTOPC(p) p[-1] +#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount)) +#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft) - hashval = *p << 4; - while (*p) - hashval+= *p++; - return &atab[hashval % ATABSIZE]; -} +#define ckfree(p) free((pointer)(p)) -static struct alias * -freealias(struct alias *ap) { - struct alias *next; +static char * makestrspace(size_t newlen); - if (ap->flag & ALIASINUSE) { - ap->flag |= ALIASDEAD; - return ap; - } +#ifdef DEBUG +#define TRACE(param) trace param +static void trace (const char *, ...); +static void trargs (char **); +static void showtree (union node *); +static void trputc (int); +static void trputs (const char *); +static void opentrace (void); +#else +#define TRACE(param) +#endif + +#define NSEMI 0 +#define NCMD 1 +#define NPIPE 2 +#define NREDIR 3 +#define NBACKGND 4 +#define NSUBSHELL 5 +#define NAND 6 +#define NOR 7 +#define NIF 8 +#define NWHILE 9 +#define NUNTIL 10 +#define NFOR 11 +#define NCASE 12 +#define NCLIST 13 +#define NDEFUN 14 +#define NARG 15 +#define NTO 16 +#define NFROM 17 +#define NFROMTO 18 +#define NAPPEND 19 +#define NTOOV 20 +#define NTOFD 21 +#define NFROMFD 22 +#define NHERE 23 +#define NXHERE 24 +#define NNOT 25 + +/* + * 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_RECORD 0x20 /* need to record arguments for ifs breakup */ + + +#define NOPTS 16 + +static char optet_vals[NOPTS]; + +static const char * const optlist[NOPTS] = { + "e" "errexit", + "f" "noglob", + "I" "ignoreeof", + "i" "interactive", + "m" "monitor", + "n" "noexec", + "s" "stdin", + "x" "xtrace", + "v" "verbose", + "V" "vi", + "E" "emacs", + "C" "noclobber", + "a" "allexport", + "b" "notify", + "u" "nounset", + "q" "quietprofile" +}; - next = ap->next; - ckfree(ap->name); - ckfree(ap->val); - ckfree(ap); - return next; -} +#define optent_name(optent) (optent+1) +#define optent_letter(optent) optent[0] +#define optent_val(optent) optet_vals[optent] + +#define eflag optent_val(0) +#define fflag optent_val(1) +#define Iflag optent_val(2) +#define iflag optent_val(3) +#define mflag optent_val(4) +#define nflag optent_val(5) +#define sflag optent_val(6) +#define xflag optent_val(7) +#define vflag optent_val(8) +#define Vflag optent_val(9) +#define Eflag optent_val(10) +#define Cflag optent_val(11) +#define aflag optent_val(12) +#define bflag optent_val(13) +#define uflag optent_val(14) +#define qflag optent_val(15) + + +/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ +#define FORK_FG 0 +#define FORK_BG 1 +#define FORK_NOJOB 2 + + +struct nbinary { + int type; + union node *ch1; + union node *ch2; +}; -static void -printalias(const struct alias *ap) { - char *p; - p = single_quote(ap->val); - out1fmt("alias %s=%s\n", ap->name, p); - stunalloc(p); -} +struct ncmd { + int type; + int backgnd; + union node *assign; + union node *args; + union node *redirect; +}; -static struct alias ** -__lookupalias(const char *name) { - struct alias **app = hashalias(name); - for (; *app; app = &(*app)->next) { - if (equal(name, (*app)->name)) { - break; - } - } +struct npipe { + int type; + int backgnd; + struct nodelist *cmdlist; +}; - return app; -} -#ifdef ASH_MATH_SUPPORT -/* The generated file arith.c has been snipped. If you want this - * stuff back in, feel free to add it to your own copy. */ -#endif +struct nredir { + int type; + union node *n; + union node *redirect; +}; -/* - * This file was generated by the mkbuiltins program. - */ -static int bgcmd __P((int, char **)); -static int breakcmd __P((int, char **)); -static int cdcmd __P((int, char **)); -static int commandcmd __P((int, char **)); -static int dotcmd __P((int, char **)); -static int evalcmd __P((int, char **)); -static int execcmd __P((int, char **)); -static int exitcmd __P((int, char **)); -static int exportcmd __P((int, char **)); -static int histcmd __P((int, char **)); -static int fgcmd __P((int, char **)); -static int hashcmd __P((int, char **)); -static int jobscmd __P((int, char **)); -static int killcmd __P((int, char **)); -static int localcmd __P((int, char **)); -static int pwdcmd __P((int, char **)); -static int readcmd __P((int, char **)); -static int returncmd __P((int, char **)); -static int setcmd __P((int, char **)); -static int setvarcmd __P((int, char **)); -static int shiftcmd __P((int, char **)); -static int trapcmd __P((int, char **)); -static int umaskcmd __P((int, char **)); -static int unaliascmd __P((int, char **)); -static int unsetcmd __P((int, char **)); -static int waitcmd __P((int, char **)); -static int aliascmd __P((int, char **)); -static int ulimitcmd __P((int, char **)); -static int timescmd __P((int, char **)); -#ifdef ASH_MATH_SUPPORT -static int expcmd __P((int, char **)); -#endif -#ifdef ASH_TYPE -static int typecmd __P((int, char **)); -#endif -#ifdef ASH_GETOPTS -static int getoptscmd __P((int, char **)); -#endif -#ifndef BB_TRUE_FALSE -static int true_main __P((int, char **)); -static int false_main __P((int, char **)); -#endif +struct nif { + int type; + union node *test; + union node *ifpart; + union node *elsepart; +}; -static struct builtincmd *DOTCMD; -static struct builtincmd *BLTINCMD; -static struct builtincmd *COMMANDCMD; -static struct builtincmd *EXECCMD; -static struct builtincmd *EVALCMD; -/* It is CRUCIAL that this listing be kept in ascii order, otherwise - * the binary search in find_builtin() will stop working. If you value - * your kneecaps, you'll be sure to *make sure* that any changes made - * to this array result in the listing remaining in ascii order. You - * have been warned. - */ -static const struct builtincmd builtincmds[] = { - { ".", dotcmd, 1 }, - { ":", true_main, 1 }, - { "alias", aliascmd, 6 }, - { "bg", bgcmd, 2 }, - { "break", breakcmd, 1 }, - { "builtin", bltincmd, 1 }, - { "cd", cdcmd, 2 }, - { "chdir", cdcmd, 0 }, - { "command", commandcmd, 2 }, - { "continue", breakcmd, 1 }, - { "eval", evalcmd, 1 }, - { "exec", execcmd, 1 }, - { "exit", exitcmd, 1 }, -#ifdef ASH_MATH_SUPPORT - { "exp", expcmd, 0 }, -#endif - { "export", exportcmd, 5 }, - { "false", false_main, 2 }, - { "fc", histcmd, 2 }, - { "fg", fgcmd, 2 }, -#ifdef ASH_GETOPTS - { "getopts", getoptscmd, 2 }, -#endif - { "hash", hashcmd, 0 }, - { "jobs", jobscmd, 2 }, - { "kill", killcmd, 2 }, -#ifdef ASH_MATH_SUPPORT - { "let", expcmd, 0 }, -#endif - { "local", localcmd, 4 }, - { "pwd", pwdcmd, 0 }, - { "read", readcmd, 2 }, - { "readonly", exportcmd, 5 }, - { "return", returncmd, 1 }, - { "set", setcmd, 1 }, - { "setvar", setvarcmd, 0 }, - { "shift", shiftcmd, 1 }, - { "times", timescmd, 1 }, - { "trap", trapcmd, 1 }, - { "true", true_main, 2 }, -#ifdef ASH_TYPE - { "type", typecmd, 0 }, -#endif - { "ulimit", ulimitcmd, 0 }, - { "umask", umaskcmd, 2 }, - { "unalias", unaliascmd, 2 }, - { "unset", unsetcmd, 1 }, - { "wait", waitcmd, 2 }, +struct nfor { + int type; + union node *args; + union node *body; + char *var; }; -#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) ) -/* $NetBSD: cd.c,v 1.27 1999/07/09 03:05:49 christos Exp $ */ +struct ncase { + int type; + union node *expr; + union node *cases; +}; -static int docd __P((char *, int)); -static char *getcomponent __P((void)); -static void updatepwd __P((char *)); -static void getpwd __P((void)); -static char *curdir = nullstr; /* current working directory */ -static char *cdcomppath; +struct nclist { + int type; + union node *next; + union node *pattern; + union node *body; +}; -#ifdef mkinit -INCLUDE "cd.h" -INIT { - setpwd(0, 0); -} -#endif -static int -cdcmd(argc, argv) - int argc; - char **argv; -{ - const char *dest; - const char *path; - char *p; - struct stat statb; - int print = 0; - - nextopt(nullstr); - if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL) - error("HOME not set"); - if (*dest == '\0') - dest = "."; - if (dest[0] == '-' && dest[1] == '\0') { - dest = bltinlookup("OLDPWD"); - if (!dest || !*dest) { - dest = curdir; - } - print = 1; - if (dest) - print = 1; - else - dest = "."; - } - if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL) - path = nullstr; - while ((p = padvance(&path, dest)) != NULL) { - if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { - if (!print) { - /* - * XXX - rethink - */ - if (p[0] == '.' && p[1] == '/' && p[2] != '\0') - p += 2; - print = strcmp(p, dest); - } - if (docd(p, print) >= 0) - return 0; - - } - } - error("can't cd to %s", dest); - /* NOTREACHED */ -} +struct narg { + int type; + union node *next; + char *text; + struct nodelist *backquote; +}; -/* - * Actually do the chdir. In an interactive shell, print the - * directory name if "print" is nonzero. - */ +struct nfile { + int type; + union node *next; + int fd; + union node *fname; + char *expfname; +}; -static int -docd(dest, print) - char *dest; - int print; -{ - char *p; - char *q; - char *component; - struct stat statb; - int first; - int badstat; - TRACE(("docd(\"%s\", %d) called\n", dest, print)); +struct ndup { + int type; + union node *next; + int fd; + int dupfd; + union node *vname; +}; - /* - * Check each component of the path. If we find a symlink or - * something we can't stat, clear curdir to force a getcwd() - * next time we get the value of the current directory. - */ - badstat = 0; - cdcomppath = sstrdup(dest); - STARTSTACKSTR(p); - if (*dest == '/') { - STPUTC('/', p); - cdcomppath++; - } - first = 1; - while ((q = getcomponent()) != NULL) { - if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0')) - continue; - if (! first) - STPUTC('/', p); - first = 0; - component = q; - while (*q) - STPUTC(*q++, p); - if (equal(component, "..")) - continue; - STACKSTRNUL(p); - if ((lstat(stackblock(), &statb) < 0) - || (S_ISLNK(statb.st_mode))) { - /* print = 1; */ - badstat = 1; - break; - } - } - INTOFF; - if (chdir(dest) < 0) { - INTON; - return -1; - } - updatepwd(badstat ? NULL : dest); - INTON; - if (print && iflag) - out1fmt(snlfmt, curdir); - return 0; -} +struct nhere { + int type; + union node *next; + int fd; + union node *doc; +}; -/* - * Get the next component of the path name pointed to by cdcomppath. - * This routine overwrites the string pointed to by cdcomppath. - */ +struct nnot { + int type; + union node *com; +}; -static char * -getcomponent() { - char *p; - char *start; - if ((p = cdcomppath) == NULL) - return NULL; - start = cdcomppath; - while (*p != '/' && *p != '\0') - p++; - if (*p == '\0') { - cdcomppath = NULL; - } else { - *p++ = '\0'; - cdcomppath = p; - } - return start; -} +union node { + int type; + struct nbinary nbinary; + struct ncmd ncmd; + struct npipe npipe; + struct nredir nredir; + struct nif nif; + struct nfor nfor; + struct ncase ncase; + struct nclist nclist; + struct narg narg; + struct nfile nfile; + struct ndup ndup; + struct nhere nhere; + struct nnot nnot; +}; +struct nodelist { + struct nodelist *next; + union node *n; +}; -/* - * Update curdir (the name of the current directory) in response to a - * cd command. We also call hashcd to let the routines in exec.c know - * that the current directory has changed. - */ +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 */ +}; -static void -updatepwd(dir) - char *dir; - { - char *new; - char *p; - size_t len; +struct cmdentry { + int cmdtype; + union param { + int index; + union node *func; + const struct builtincmd *cmd; + } u; +}; - hashcd(); /* update command hash table */ +struct strlist { + struct strlist *next; + char *text; +}; - /* - * If our argument is NULL, we don't know the current directory - * any more because we traversed a symbolic link or something - * we couldn't stat(). - */ - if (dir == NULL || curdir == nullstr) { - setpwd(0, 1); - return; - } - len = strlen(dir); - cdcomppath = sstrdup(dir); - STARTSTACKSTR(new); - if (*dir != '/') { - p = curdir; - while (*p) - STPUTC(*p++, new); - if (p[-1] == '/') - STUNPUTC(new); - } - while ((p = getcomponent()) != NULL) { - if (equal(p, "..")) { - while (new > stackblock() && (STUNPUTC(new), *new) != '/'); - } else if (*p != '\0' && ! equal(p, ".")) { - STPUTC('/', new); - while (*p) - STPUTC(*p++, new); - } - } - if (new == stackblock()) - STPUTC('/', new); - STACKSTRNUL(new); - setpwd(stackblock(), 1); -} +struct arglist { + struct strlist *list; + struct strlist **lastp; +}; +struct strpush { + struct strpush *prev; /* preceding string on stack */ + char *prevstring; + int prevnleft; +#ifdef ASH_ALIAS + struct alias *ap; /* if push was associated with an alias */ +#endif + char *string; /* remember the string since it may change */ +}; -static int -pwdcmd(argc, argv) - int argc; - char **argv; -{ - out1fmt(snlfmt, curdir); - return 0; -} +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 */ +}; +struct stackmark { + struct stack_block *stackp; + char *stacknxt; + int stacknleft; + struct stackmark *marknext; +}; +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 */ +}; +struct output { +#ifdef USE_GLIBC_STDIO + FILE *stream; +#endif + char *nextc; + int nleft; + char *buf; + int bufsize; + int fd; + short flags; +}; -#define MAXPWD 256 +#define OUTBUFSIZ BUFSIZ +#define MEM_OUT -3 /* output to dynamically allocated memory */ -/* - * Find out what the current directory is. If we already know the current - * directory, this routine returns immediately. - */ -static void -getpwd() -{ - char buf[MAXPWD]; - /* - * Things are a bit complicated here; we could have just used - * getcwd, but traditionally getcwd is implemented using popen - * to /bin/pwd. This creates a problem for us, since we cannot - * keep track of the job if it is being ran behind our backs. - * So we re-implement getcwd(), and we suppress interrupts - * throughout the process. This is not completely safe, since - * the user can still break out of it by killing the pwd program. - * We still try to use getcwd for systems that we know have a - * c implementation of getcwd, that does not open a pipe to - * /bin/pwd. - */ -#if defined(__NetBSD__) || defined(__SVR4) || defined(__GLIBC__) - - if (getcwd(buf, sizeof(buf)) == NULL) { - char *pwd = getenv("PWD"); - struct stat stdot, stpwd; - - if (pwd && *pwd == '/' && stat(".", &stdot) != -1 && - stat(pwd, &stpwd) != -1 && - stdot.st_dev == stpwd.st_dev && - stdot.st_ino == stpwd.st_ino) { - curdir = savestr(pwd); - return; - } - error("getcwd() failed: %s", strerror(errno)); - } - curdir = savestr(buf); +#ifdef USE_GLIBC_STDIO +static struct output output = {NULL, NULL, 0, NULL, 0, 1, 0}; +static struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0}; +static struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0}; #else - { - char *p; - int i; - int status; - struct job *jp; - int pip[2]; - - if (pipe(pip) < 0) - error("Pipe call failed"); - jp = makejob((union node *)NULL, 1); - if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) { - (void) close(pip[0]); - if (pip[1] != 1) { - close(1); - dup_as_newfd(pip[1], 1); - close(pip[1]); - } - (void) execl("/bin/pwd", "pwd", (char *)0); - error("Cannot exec /bin/pwd"); - } - (void) close(pip[1]); - pip[1] = -1; - p = buf; - while ((i = read(pip[0], p, buf + MAXPWD - p)) > 0 - || (i == -1 && errno == EINTR)) { - if (i > 0) - p += i; - } - (void) close(pip[0]); - pip[0] = -1; - status = waitforjob(jp); - if (status != 0) - error((char *)0); - if (i < 0 || p == buf || p[-1] != '\n') - error("pwd command failed"); - p[-1] = '\0'; - } - curdir = savestr(buf); +static struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; +static struct output errout = {NULL, 0, NULL, 0, 2, 0}; +static struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; #endif -} +static struct output *out1 = &output; +static struct output *out2 = &errout; -static void -setpwd(const char *val, int setold) -{ - if (setold) { - setvar("OLDPWD", curdir, VEXPORT); - } - INTOFF; - if (curdir != nullstr) { - free(curdir); - curdir = nullstr; - } - if (!val) { - getpwd(); - } else { - curdir = savestr(val); - } - INTON; - setvar("PWD", curdir, VEXPORT); -} +#ifndef USE_GLIBC_STDIO +static void outcslow (char, struct output *); +#endif +static void flushall (void); +static void flushout (struct output *); +static void freestdout (void); +static void outfmt (struct output *, const char *, ...) + __attribute__((__format__(__printf__,2,3))); +static void out1fmt (const char *, ...) + __attribute__((__format__(__printf__,1,2))); +static void fmtstr (char *, size_t, const char *, ...) + __attribute__((__format__(__printf__,3,4))); +#ifndef USE_GLIBC_STDIO +static void doformat (struct output *, const char *, va_list); +#endif +static int xwrite (int, const char *, int); +#ifdef USE_GLIBC_STDIO +static void initstreams (void); +static void openmemout (void); +static int __closememout (void); +#endif -/* $NetBSD: error.c,v 1.23 2000/07/03 03:26:19 matt Exp $ */ +static void outstr(const char *p, struct output *file); -/* - * Errors and exceptions. - */ +#define OUTPUT_ERR 01 /* error occurred on output */ -/* - * Code to handle exceptions in C. - */ - -struct jmploc *handler; -static int exception; -volatile int suppressint; -volatile int intpending; - - -static void exverror __P((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". - */ - -static void -exraise(e) - int e; -{ -#ifdef DEBUG - if (handler == NULL) - abort(); -#endif - 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 call to _exit is necessary because - * there is a short period after a fork before the signal handlers are - * set to the appropriate value for the child. (The test for iflag is - * just defensive programming.) - */ - -static void -onint() { - sigset_t mysigset; - - if (suppressint) { - intpending++; - return; - } - intpending = 0; - sigemptyset(&mysigset); - sigprocmask(SIG_SETMASK, &mysigset, NULL); - if (rootshell && iflag) - exraise(EXINT); - else { - signal(SIGINT, SIG_DFL); - raise(SIGINT); - } - /* NOTREACHED */ -} - - -/* - * Exverror is called to raise the error exception. If the first argument - * is not NULL then error prints an error message using printf style - * formatting. It then raises the error exception. - */ -static void -exverror(cond, msg, ap) - int cond; - const char *msg; - va_list ap; -{ - CLEAR_PENDING_INT; - INTOFF; - -#ifdef DEBUG - if (msg) - TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid())); - else - TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid())); -#endif - if (msg) { - if (commandname) - outfmt(&errout, "%s: ", commandname); - doformat(&errout, msg, ap); -#if FLUSHERR - outc('\n', &errout); -#else - outcslow('\n', &errout); -#endif - } - flushall(); - exraise(cond); - /* NOTREACHED */ -} - - -#ifdef __STDC__ -static void -error(const char *msg, ...) -#else -static void -error(va_alist) - va_dcl -#endif -{ -#ifndef __STDC__ - const char *msg; -#endif - va_list ap; -#ifdef __STDC__ - va_start(ap, msg); -#else - va_start(ap); - msg = va_arg(ap, const char *); -#endif - exverror(EXERROR, msg, ap); - /* NOTREACHED */ - va_end(ap); -} - - -#ifdef __STDC__ -static void -exerror(int cond, const char *msg, ...) -#else -static void -exerror(va_alist) - va_dcl -#endif -{ -#ifndef __STDC__ - int cond; - const char *msg; -#endif - va_list ap; -#ifdef __STDC__ - va_start(ap, msg); +#ifdef USE_GLIBC_STDIO +#define outc(c, o) putc((c), (o)->stream) +#define doformat(d, f, a) vfprintf((d)->stream, (f), (a)) #else - va_start(ap); - cond = va_arg(ap, int); - msg = va_arg(ap, const char *); +#define outc(c, file) (--(file)->nleft < 0? outcslow((c), (file)) : (*(file)->nextc = (c), (file)->nextc++)) #endif - exverror(cond, msg, ap); - /* NOTREACHED */ - va_end(ap); -} - - - -/* - * Table of error messages. - */ - -struct errname { - short errcode; /* error number */ - short action; /* operation which encountered the error */ - const char *msg; /* text describing the error */ -}; - - -#define ALL (E_OPEN|E_CREAT|E_EXEC) +#define out1c(c) outc((c), out1) +#define out2c(c) outc((c), out2) +#define out1str(s) outstr((s), out1) +#define out2str(s) outstr((s), out2) +#define outerr(f) ((f)->flags & OUTPUT_ERR) -static const struct errname errormsg[] = { - { EINTR, ALL, "interrupted" }, - { EACCES, ALL, "permission denied" }, - { EIO, ALL, "I/O error" }, - { ENOENT, E_OPEN, "no such file" }, - { ENOENT, E_CREAT,"directory nonexistent" }, - { ENOENT, E_EXEC, "not found" }, - { ENOTDIR, E_OPEN, "no such file" }, - { ENOTDIR, E_CREAT,"directory nonexistent" }, - { ENOTDIR, E_EXEC, "not found" }, - { EISDIR, ALL, "is a directory" }, - { EEXIST, E_CREAT,"file exists" }, -#ifdef notdef - { EMFILE, ALL, "too many open files" }, -#endif - { ENFILE, ALL, "file table overflow" }, - { ENOSPC, ALL, "file system full" }, -#ifdef EDQUOT - { EDQUOT, ALL, "disk quota exceeded" }, -#endif -#ifdef ENOSR - { ENOSR, ALL, "no streams resources" }, -#endif - { ENXIO, ALL, "no such device or address" }, - { EROFS, ALL, "read-only file system" }, - { ETXTBSY, ALL, "text busy" }, -#ifdef SYSV - { EAGAIN, E_EXEC, "not enough memory" }, -#endif - { ENOMEM, ALL, "not enough memory" }, -#ifdef ENOLINK - { ENOLINK, ALL, "remote access failed" }, -#endif -#ifdef EMULTIHOP - { EMULTIHOP, ALL, "remote access failed" }, -#endif -#ifdef ECOMM - { ECOMM, ALL, "remote access failed" }, -#endif -#ifdef ESTALE - { ESTALE, ALL, "remote access failed" }, -#endif -#ifdef ETIMEDOUT - { ETIMEDOUT, ALL, "remote access failed" }, -#endif -#ifdef ELOOP - { ELOOP, ALL, "symbolic link loop" }, -#endif - { E2BIG, E_EXEC, "argument list too long" }, -#ifdef ELIBACC - { ELIBACC, E_EXEC, "shared library missing" }, -#endif - { 0, 0, NULL }, +/* syntax table used when not in quotes */ +static const char basesyntax[257] = { + CENDFILE, CSPCL, CWORD, CCTL, + CCTL, CCTL, CCTL, CCTL, + CCTL, CCTL, CCTL, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CSPCL, + CNL, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CSPCL, CWORD, + CDQUOTE, CWORD, CVAR, CWORD, + CSPCL, CSQUOTE, CSPCL, CSPCL, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CSPCL, CSPCL, CWORD, + CSPCL, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CBACK, CWORD, + CWORD, CWORD, CBQUOTE, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CSPCL, CENDVAR, + CWORD }; - -/* - * 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. - */ - -static const char * -errmsg(e, action) - int e; - int action; -{ - struct errname const *ep; - static char buf[12]; - - for (ep = errormsg ; ep->errcode ; ep++) { - if (ep->errcode == e && (ep->action & action) != 0) - return ep->msg; - } - fmtstr(buf, sizeof buf, "error %d", e); - return buf; +/* syntax table used when in double quotes */ +static const char dqsyntax[257] = { + CENDFILE, CIGN, CWORD, CCTL, + CCTL, CCTL, CCTL, CCTL, + CCTL, CCTL, CCTL, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CNL, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CCTL, + CENDQUOTE,CWORD, CVAR, CWORD, + CWORD, CWORD, CWORD, CWORD, + CCTL, CWORD, CWORD, CCTL, + CWORD, CCTL, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CCTL, CWORD, CWORD, CCTL, + CWORD, CCTL, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CCTL, CBACK, CCTL, + CWORD, CWORD, CBQUOTE, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CENDVAR, + CCTL +}; + +/* syntax table used when in single quotes */ +static const char sqsyntax[257] = { + CENDFILE, CIGN, CWORD, CCTL, + CCTL, CCTL, CCTL, CCTL, + CCTL, CCTL, CCTL, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CNL, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CCTL, + CWORD, CWORD, CWORD, CWORD, + CWORD, CENDQUOTE,CWORD, CWORD, + CCTL, CWORD, CWORD, CCTL, + CWORD, CCTL, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CCTL, CWORD, CWORD, CCTL, + CWORD, CCTL, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CCTL, CCTL, CCTL, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CCTL +}; + +/* syntax table used when in arithmetic */ +static const char arisyntax[257] = { + CENDFILE, CIGN, CWORD, CCTL, + CCTL, CCTL, CCTL, CCTL, + CCTL, CCTL, CCTL, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CNL, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CDQUOTE, CWORD, CVAR, CWORD, + CWORD, CSQUOTE, CLP, CRP, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CBACK, CWORD, + CWORD, CWORD, CBQUOTE, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CWORD, + CWORD, CWORD, CWORD, CENDVAR, + CWORD +}; + +/* character classification table */ +static const char is_type[257] = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, ISSPECL, + 0, ISSPECL, ISSPECL, 0, + 0, 0, 0, 0, + ISSPECL, 0, 0, ISSPECL, + 0, 0, ISDIGIT, ISDIGIT, + ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, + ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, + 0, 0, 0, 0, + 0, ISSPECL, ISSPECL, ISUPPER, + ISUPPER, ISUPPER, ISUPPER, ISUPPER, + ISUPPER, ISUPPER, ISUPPER, ISUPPER, + ISUPPER, ISUPPER, ISUPPER, ISUPPER, + ISUPPER, ISUPPER, ISUPPER, ISUPPER, + ISUPPER, ISUPPER, ISUPPER, ISUPPER, + ISUPPER, ISUPPER, ISUPPER, ISUPPER, + ISUPPER, 0, 0, 0, + 0, ISUNDER, 0, ISLOWER, + ISLOWER, ISLOWER, ISLOWER, ISLOWER, + ISLOWER, ISLOWER, ISLOWER, ISLOWER, + ISLOWER, ISLOWER, ISLOWER, ISLOWER, + ISLOWER, ISLOWER, ISLOWER, ISLOWER, + ISLOWER, ISLOWER, ISLOWER, ISLOWER, + ISLOWER, ISLOWER, ISLOWER, ISLOWER, + ISLOWER, 0, 0, 0, + 0 +}; + +/* Array indicating which tokens mark the end of a list */ +static const char tokendlist[] = { + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, +}; + +static const char *const tokname[] = { + "end of file", + "newline", + "\";\"", + "\"&\"", + "\"&&\"", + "\"||\"", + "\"|\"", + "\"(\"", + "\")\"", + "\";;\"", + "\"`\"", + "redirection", + "word", + "assignment", + "\"!\"", + "\"case\"", + "\"do\"", + "\"done\"", + "\"elif\"", + "\"else\"", + "\"esac\"", + "\"fi\"", + "\"for\"", + "\"if\"", + "\"in\"", + "\"then\"", + "\"until\"", + "\"while\"", + "\"{\"", + "\"}\"", +}; + +#define KWDOFFSET 14 + +static const char *const parsekwd[] = { + "!", + "case", + "do", + "done", + "elif", + "else", + "esac", + "fi", + "for", + "if", + "in", + "then", + "until", + "while", + "{", + "}" +}; + + +static int plinno = 1; /* input line number */ + +static int parselleft; /* copy of parsefile->lleft */ + +static struct parsefile basepf; /* top level input file */ +static char basebuf[BUFSIZ]; /* buffer for top level input file */ +static struct parsefile *parsefile = &basepf; /* current input file */ + +/* + * 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. + */ + +static int tokpushback; /* last token pushed back */ +#define NEOF ((union node *)&tokpushback) +static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ + + +static void error (const char *, ...) __attribute__((__noreturn__)); +static void exerror (int, const char *, ...) __attribute__((__noreturn__)); +static void shellexec (char **, char **, const char *, int) + __attribute__((noreturn)); +static void exitshell (int) __attribute__((noreturn)); + +static int goodname(const char *); +static void ignoresig (int); +static void onsig (int); +static void dotrap (void); +static int decode_signal (const char *, int); + +static void shprocvar(void); +static void deletefuncs(void); +static void setparam (char **); +static void freeparam (volatile struct shparam *); + +/* reasons for skipping commands (see comment on breakcmd routine) */ +#define SKIPBREAK 1 +#define SKIPCONT 2 +#define SKIPFUNC 3 +#define SKIPFILE 4 + +/* values of cmdtype */ +#define CMDUNKNOWN -1 /* no entry in table for command */ +#define CMDNORMAL 0 /* command is an executable program */ +#define CMDBUILTIN 1 /* command is a shell builtin */ +#define CMDFUNCTION 2 /* command is a shell function */ + +#define DO_ERR 1 /* find_command prints errors */ +#define DO_ABS 2 /* find_command checks absolute paths */ +#define DO_NOFUN 4 /* find_command ignores functions */ +#define DO_BRUTE 8 /* find_command ignores hash table */ + +/* + * Shell variables. + */ + +/* flags */ +#define VEXPORT 0x01 /* variable is exported */ +#define VREADONLY 0x02 /* variable cannot be modified */ +#define VSTRFIXED 0x04 /* variable struct is staticly allocated */ +#define VTEXTFIXED 0x08 /* text is staticly 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 */ + + +struct var { + struct var *next; /* next entry in hash list */ + int flags; /* flags are defined above */ + 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 */ + char *text; /* saved text */ +}; + + +#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) +#define rmescapes(p) _rmescapes((p), 0) +static char *_rmescapes (char *, int); +#else +static void rmescapes (char *); +#endif + +static int casematch (union node *, const char *); +static void clearredir(void); +static void popstring(void); +static void readcmdfile (const char *); + +static int number (const char *); +static int is_number (const char *, int *num); +static char *single_quote (const char *); +static int nextopt (const char *); + +static void redirect (union node *, int); +static void popredir (void); +static int dup_as_newfd (int, int); + +static void changepath(const char *newval); +static void getoptsreset(const char *value); + + +static int parsenleft; /* copy of parsefile->nleft */ +static char *parsenextc; /* copy of parsefile->nextc */ +static int rootpid; /* pid of main shell */ +static int rootshell; /* true if we aren't a child of the main shell */ + +static const char spcstr[] = " "; +static const char snlfmt[] = "%s\n"; + +static int sstrnleft; +static int herefd = -1; + +static struct localvar *localvars; + +static struct var vifs; +static struct var vmail; +static struct var vmpath; +static struct var vpath; +static struct var vps1; +static struct var vps2; +static struct var voptind; +#ifdef BB_LOCALE_SUPPORT +static struct var vlc_all; +static struct var vlc_ctype; +#endif + +struct varinit { + struct var *var; + int flags; + const char *text; + void (*func) (const char *); +}; + +static const char defpathvar[] = + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; +#define defpath (defpathvar + 5) + +#ifdef IFS_BROKEN +static const char defifsvar[] = "IFS= \t\n"; +#define defifs (defifsvar + 4) +#else +static const char defifs[] = " \t\n"; +#endif + +static const struct varinit varinit[] = { +#ifdef IFS_BROKEN + { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar, +#else + { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=", +#endif + NULL }, + { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", + NULL }, + { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", + NULL }, + { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar, + changepath }, + /* + * vps1 depends on uid + */ + { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ", + NULL }, + { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1", + getoptsreset }, +#ifdef BB_LOCALE_SUPPORT + { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=", + change_lc_all }, + { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=", + change_lc_ctype }, +#endif + { NULL, 0, NULL, + NULL } +}; + +#define VTABSIZE 39 + +static struct var *vartab[VTABSIZE]; + +/* + * 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 optindval() (voptind.text + 7) + +#define mpathset() ((vmpath.flags & VUNSET) == 0) + +static void initvar (void); +static void setvar (const char *, const char *, int); +static void setvareq (char *, int); +static void listsetvar (struct strlist *); +static char *lookupvar (const char *); +static char *bltinlookup (const char *); +static char **environment (void); +static int showvarscmd (int, char **); +static void mklocal (char *); +static void poplocalvars (void); +static int unsetvar (const char *); +static int varequal (const char *, const char *); + + +static char *arg0; /* value of $0 */ +static struct shparam shellparam; /* current positional parameters */ +static char **argptr; /* argument list for builtin commands */ +static char *optionarg; /* set by nextopt (like getopt) */ +static char *optptr; /* used by nextopt */ +static char *minusc; /* argument to -c option */ + + +#ifdef ASH_ALIAS + +#define ALIASINUSE 1 +#define ALIASDEAD 2 + +struct alias { + struct alias *next; + char *name; + char *val; + int flag; +}; + +static struct alias *atab[ATABSIZE]; + +static void setalias (char *, char *); +static struct alias **hashalias (const char *); +static struct alias *freealias (struct alias *); +static struct alias **__lookupalias (const char *); + +static void +setalias(name, val) + char *name, *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; +} + +static int +unalias(char *name) +{ + struct alias **app; + + app = __lookupalias(name); + + if (*app) { + INTOFF; + *app = freealias(*app); + INTON; + return (0); + } + + return (1); +} + +static 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; +} + +static struct alias * +lookupalias(const char *name, int check) +{ + struct alias *ap = *__lookupalias(name); + + if (check && ap && (ap->flag & ALIASINUSE)) + return (NULL); + return (ap); +} + +static void +printalias(const struct alias *ap) { + char *p; + + p = single_quote(ap->val); + out1fmt("alias %s=%s\n", ap->name, p); + stunalloc(p); +} + + +/* + * TODO - sort output + */ +static 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); +} + +static 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 ** +hashalias(p) + const char *p; + { + unsigned int hashval; + + hashval = *p << 4; + while (*p) + hashval+= *p++; + return &atab[hashval % ATABSIZE]; +} + +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; +} + + +static struct alias ** +__lookupalias(const char *name) { + struct alias **app = hashalias(name); + + for (; *app; app = &(*app)->next) { + if (equal(name, (*app)->name)) { + break; + } + } + + return app; +} +#endif + +#ifdef ASH_MATH_SUPPORT +/* The generated file arith.c has been snipped. If you want this + * stuff back in, feel free to add it to your own copy. */ +#define ARITH_NUM 257 +#define ARITH_LPAREN 258 +#define ARITH_RPAREN 259 +#define ARITH_OR 260 +#define ARITH_AND 261 +#define ARITH_BOR 262 +#define ARITH_BXOR 263 +#define ARITH_BAND 264 +#define ARITH_EQ 265 +#define ARITH_NE 266 +#define ARITH_LT 267 +#define ARITH_GT 268 +#define ARITH_GE 269 +#define ARITH_LE 270 +#define ARITH_LSHIFT 271 +#define ARITH_RSHIFT 272 +#define ARITH_ADD 273 +#define ARITH_SUB 274 +#define ARITH_MUL 275 +#define ARITH_DIV 276 +#define ARITH_REM 277 +#define ARITH_UNARYMINUS 278 +#define ARITH_UNARYPLUS 279 +#define ARITH_NOT 280 +#define ARITH_BNOT 281 + +static void expari (int); +/* From arith.y */ +static int arith (const char *); +static int expcmd (int , char **); +static void arith_lex_reset (void); +static int yylex (void); + +#endif + +static char *trap[NSIG]; /* trap handler commands */ +static char sigmode[NSIG - 1]; /* current value of signal */ +static char gotsig[NSIG - 1]; /* indicates specified signal received */ +static int pendingsigs; /* indicates some signal received */ + +/* + * This file was generated by the mkbuiltins program. + */ + +#ifdef JOBS +static int bgcmd (int, char **); +static int fgcmd (int, char **); +static int killcmd (int, char **); +#endif +#ifdef ASH_BBAPPS_AS_BUILTINS +static int bltincmd (int, char **); +#endif +static int cdcmd (int, char **); +static int breakcmd (int, char **); +#ifdef ASH_CMDCMD +static int commandcmd (int, char **); +#endif +static int dotcmd (int, char **); +static int evalcmd (int, char **); +static int execcmd (int, char **); +static int exitcmd (int, char **); +static int exportcmd (int, char **); +static int histcmd (int, char **); +static int hashcmd (int, char **); +static int jobscmd (int, char **); +static int localcmd (int, char **); +#ifdef ASH_PWD +static int pwdcmd (int, char **); +#endif +static int readcmd (int, char **); +static int returncmd (int, char **); +static int setcmd (int, char **); +static int setvarcmd (int, char **); +static int shiftcmd (int, char **); +static int trapcmd (int, char **); +static int umaskcmd (int, char **); +#ifdef ASH_ALIAS +static int aliascmd (int, char **); +static int unaliascmd (int, char **); +#endif +static int unsetcmd (int, char **); +static int waitcmd (int, char **); +static int ulimitcmd (int, char **); +static int timescmd (int, char **); +#ifdef ASH_MATH_SUPPORT +static int expcmd (int, char **); +#endif +#ifdef ASH_TYPE +static int typecmd (int, char **); +#endif +#ifdef ASH_GETOPTS +static int getoptscmd (int, char **); +#endif + +#ifndef BB_TRUE_FALSE +# ifdef ASH_BBAPPS_AS_BUILTINS +static int true_main (int, char **); +static int false_main (int, char **); +# endif +#endif + +static void setpwd (const char *, int); + + +#define BUILTIN_NOSPEC "0" +#define BUILTIN_SPECIAL "1" +#define BUILTIN_REGULAR "2" +#define BUILTIN_ASSIGN "4" +#define BUILTIN_SPEC_ASSG "5" +#define BUILTIN_REG_ASSG "6" + +#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1) +#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2) +#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4) + +struct builtincmd { + const char *name; + int (*const builtinfunc) (int, char **); + //unsigned flags; +}; + + +/* It is CRUCIAL that this listing be kept in ascii order, otherwise + * the binary search in find_builtin() will stop working. If you value + * your kneecaps, you'll be sure to *make sure* that any changes made + * to this array result in the listing remaining in ascii order. You + * have been warned. + */ +static const struct builtincmd builtincmds[] = { + { BUILTIN_SPECIAL ".", dotcmd }, + { BUILTIN_SPECIAL ":", true_main }, +#ifdef ASH_ALIAS + { BUILTIN_REG_ASSG "alias", aliascmd }, +#endif +#ifdef JOBS + { BUILTIN_REGULAR "bg", bgcmd }, +#endif + { BUILTIN_SPECIAL "break", breakcmd }, +#ifdef ASH_BBAPPS_AS_BUILTINS + { BUILTIN_SPECIAL "builtin", bltincmd }, +#endif + { BUILTIN_REGULAR "cd", cdcmd }, +#ifdef ASH_BBAPPS_AS_BUILTINS + { BUILTIN_NOSPEC "chdir", cdcmd }, +#endif +#ifdef ASH_CMDCMD + { BUILTIN_REGULAR "command", commandcmd }, +#endif + { BUILTIN_SPECIAL "continue", breakcmd }, + { BUILTIN_SPECIAL "eval", evalcmd }, + { BUILTIN_SPECIAL "exec", execcmd }, + { BUILTIN_SPECIAL "exit", exitcmd }, +#ifdef ASH_MATH_SUPPORT + { BUILTIN_NOSPEC "exp", expcmd }, +#endif + { BUILTIN_SPEC_ASSG "export", exportcmd }, +#ifdef ASH_BBAPPS_AS_BUILTINS + { BUILTIN_REGULAR "false", false_main }, +#endif + { BUILTIN_REGULAR "fc", histcmd }, +#ifdef JOBS + { BUILTIN_REGULAR "fg", fgcmd }, +#endif +#ifdef ASH_GETOPTS + { BUILTIN_REGULAR "getopts", getoptscmd }, +#endif + { BUILTIN_NOSPEC "hash", hashcmd }, + { BUILTIN_REGULAR "jobs", jobscmd }, +#ifdef JOBS + { BUILTIN_REGULAR "kill", killcmd }, +#endif +#ifdef ASH_MATH_SUPPORT + { BUILTIN_NOSPEC "let", expcmd }, +#endif + { BUILTIN_ASSIGN "local", localcmd }, +#ifdef ASH_PWD + { BUILTIN_NOSPEC "pwd", pwdcmd }, +#endif + { BUILTIN_REGULAR "read", readcmd }, + { BUILTIN_SPEC_ASSG "readonly", exportcmd }, + { BUILTIN_SPECIAL "return", returncmd }, + { BUILTIN_SPECIAL "set", setcmd }, + { BUILTIN_NOSPEC "setvar", setvarcmd }, + { BUILTIN_SPECIAL "shift", shiftcmd }, + { BUILTIN_SPECIAL "times", timescmd }, + { BUILTIN_SPECIAL "trap", trapcmd }, +#ifdef ASH_BBAPPS_AS_BUILTINS + { BUILTIN_REGULAR "true", true_main }, +#endif +#ifdef ASH_TYPE + { BUILTIN_NOSPEC "type", typecmd }, +#endif + { BUILTIN_NOSPEC "ulimit", ulimitcmd }, + { BUILTIN_REGULAR "umask", umaskcmd }, +#ifdef ASH_ALIAS + { BUILTIN_REGULAR "unalias", unaliascmd }, +#endif + { BUILTIN_SPECIAL "unset", unsetcmd }, + { BUILTIN_REGULAR "wait", waitcmd }, +}; +#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) ) + +static const struct builtincmd *DOTCMD = &builtincmds[0]; +static struct builtincmd *BLTINCMD; +static struct builtincmd *EXECCMD; +static struct builtincmd *EVALCMD; + +/* states */ +#define JOBSTOPPED 1 /* all procs are stopped */ +#define JOBDONE 2 /* all procs are completed */ + +/* + * 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; /* status flags (defined above) */ + char *cmd; /* text of command being run */ +}; + + +static int job_warning; /* user was warned about stopped jobs */ + +#ifdef JOBS +static void setjobctl(int enable); +#else +#define setjobctl(on) /* do nothing */ +#endif + + +struct job { + struct procstat ps0; /* status of process */ + struct procstat *ps; /* status or processes when more than one */ + short nprocs; /* number of processes */ + short pgrp; /* process group of this job */ + char state; /* true if job is finished */ + char used; /* true if this entry is in used */ + char changed; /* true if status has changed */ +#ifdef JOBS + char jobctl; /* job running under job control */ +#endif +}; + +static struct job *jobtab; /* array of jobs */ +static int njobs; /* size of array */ +static int backgndpid = -1; /* pid of last background process */ +#ifdef JOBS +static int initialpgrp; /* pgrp of shell on invocation */ +static int curjob; /* current job */ +static int jobctl; +#endif +static int intreceived; + +static struct job *makejob (union node *, int); +static int forkshell (struct job *, union node *, int); +static int waitforjob (struct job *); + +static int docd (char *, int); +static char *getcomponent (void); +static void updatepwd (const char *); +static void getpwd (void); + +static char *padvance (const char **, const char *); + +static char nullstr[1]; /* zero length string */ +static char *curdir = nullstr; /* current working directory */ +static char *cdcomppath; + +static int +cdcmd(argc, argv) + int argc; + char **argv; +{ + const char *dest; + const char *path; + char *p; + struct stat statb; + int print = 0; + + nextopt(nullstr); + if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL) + error("HOME not set"); + if (*dest == '\0') + dest = "."; + if (dest[0] == '-' && dest[1] == '\0') { + dest = bltinlookup("OLDPWD"); + if (!dest || !*dest) { + dest = curdir; + } + print = 1; + if (dest) + print = 1; + else + dest = "."; + } + if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL) + path = nullstr; + while ((p = padvance(&path, dest)) != NULL) { + if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { + if (!print) { + /* + * XXX - rethink + */ + if (p[0] == '.' && p[1] == '/' && p[2] != '\0') + p += 2; + print = strcmp(p, dest); + } + if (docd(p, print) >= 0) + return 0; + + } + } + error("can't cd to %s", dest); + /* NOTREACHED */ +} + + +/* + * Actually do the chdir. In an interactive shell, print the + * directory name if "print" is nonzero. + */ + +static int +docd(dest, print) + char *dest; + int print; +{ + char *p; + char *q; + char *component; + struct stat statb; + int first; + int badstat; + + TRACE(("docd(\"%s\", %d) called\n", dest, print)); + + /* + * Check each component of the path. If we find a symlink or + * something we can't stat, clear curdir to force a getcwd() + * next time we get the value of the current directory. + */ + badstat = 0; + cdcomppath = sstrdup(dest); + STARTSTACKSTR(p); + if (*dest == '/') { + STPUTC('/', p); + cdcomppath++; + } + first = 1; + while ((q = getcomponent()) != NULL) { + if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0')) + continue; + if (! first) + STPUTC('/', p); + first = 0; + component = q; + while (*q) + STPUTC(*q++, p); + if (equal(component, "..")) + continue; + STACKSTRNUL(p); + if ((lstat(stackblock(), &statb) < 0) + || (S_ISLNK(statb.st_mode))) { + /* print = 1; */ + badstat = 1; + break; + } + } + + INTOFF; + if (chdir(dest) < 0) { + INTON; + return -1; + } + updatepwd(badstat ? NULL : dest); + INTON; + if (print && iflag) + out1fmt(snlfmt, curdir); + return 0; +} + + +/* + * Get the next component of the path name pointed to by cdcomppath. + * This routine overwrites the string pointed to by cdcomppath. + */ + +static char * +getcomponent() { + char *p; + char *start; + + if ((p = cdcomppath) == NULL) + return NULL; + start = cdcomppath; + while (*p != '/' && *p != '\0') + p++; + if (*p == '\0') { + cdcomppath = NULL; + } else { + *p++ = '\0'; + cdcomppath = p; + } + return start; +} + + + +/* + * Update curdir (the name of the current directory) in response to a + * cd command. We also call hashcd to let the routines in exec.c know + * that the current directory has changed. + */ + +static void hashcd (void); + +static void +updatepwd(const char *dir) +{ + char *new; + char *p; + size_t len; + + hashcd(); /* update command hash table */ + + /* + * If our argument is NULL, we don't know the current directory + * any more because we traversed a symbolic link or something + * we couldn't stat(). + */ + if (dir == NULL || curdir == nullstr) { + setpwd(0, 1); + return; + } + len = strlen(dir); + cdcomppath = sstrdup(dir); + STARTSTACKSTR(new); + if (*dir != '/') { + p = curdir; + while (*p) + STPUTC(*p++, new); + if (p[-1] == '/') + STUNPUTC(new); + } + while ((p = getcomponent()) != NULL) { + if (equal(p, "..")) { + while (new > stackblock() && (STUNPUTC(new), *new) != '/'); + } else if (*p != '\0' && ! equal(p, ".")) { + STPUTC('/', new); + while (*p) + STPUTC(*p++, new); + } + } + if (new == stackblock()) + STPUTC('/', new); + STACKSTRNUL(new); + setpwd(stackblock(), 1); +} + + +#ifdef ASH_PWD +static int +pwdcmd(argc, argv) + int argc; + char **argv; +{ + out1fmt(snlfmt, curdir); + return 0; +} +#endif + +/* + * Find out what the current directory is. If we already know the current + * directory, this routine returns immediately. + */ +static void +getpwd(void) +{ + curdir = xgetcwd(0); + if(curdir==0) + curdir = nullstr; +} + +static void +setpwd(const char *val, int setold) +{ + if (setold) { + setvar("OLDPWD", curdir, VEXPORT); + } + INTOFF; + if (curdir != nullstr) { + free(curdir); + curdir = nullstr; + } + if (!val) { + getpwd(); + } else { + curdir = savestr(val); + } + INTON; + setvar("PWD", curdir, VEXPORT); } +/* + * Errors and exceptions. + */ + +/* + * Code to handle exceptions in C. + */ + +/* + * 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; +}; + +/* exceptions */ +#define EXINT 0 /* SIGINT received */ +#define EXERROR 1 /* a generic error */ +#define EXSHELLPROC 2 /* execute a shell procedure */ +#define EXEXEC 3 /* command execution failed */ + +static struct jmploc *handler; +static int exception; + +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". + */ + +static void exraise (int) __attribute__((__noreturn__)); -#ifdef REALLY_SMALL static void -__inton() { - if (--suppressint == 0 && intpending) { - onint(); +exraise(int e) +{ +#ifdef DEBUG + if (handler == NULL) + abort(); +#endif + 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 call to _exit is necessary because + * there is a short period after a fork before the signal handlers are + * set to the appropriate value for the child. (The test for iflag is + * just defensive programming.) + */ + +static void +onint(void) { + sigset_t mysigset; + + if (suppressint) { + intpending++; + return; + } + intpending = 0; + sigemptyset(&mysigset); + sigprocmask(SIG_SETMASK, &mysigset, NULL); + if (rootshell && iflag) + exraise(EXINT); + else { + signal(SIGINT, SIG_DFL); + raise(SIGINT); } + /* NOTREACHED */ } -#endif -/* $NetBSD: eval.c,v 1.57 2001/02/04 19:52:06 christos Exp $ */ -/* flags in argument to evaltree */ -#define EV_EXIT 01 /* exit after evaluating tree */ -#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ -#define EV_BACKCMD 04 /* command executing within back quotes */ +static char *commandname; /* currently executing command */ + +/* + * Exverror is called to raise the error exception. If the first 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) +{ + CLEAR_PENDING_INT; + INTOFF; -static int evalskip; /* set if we are skipping commands */ -static int skipcount; /* number of levels to skip */ -static int loopnest; /* current loop nesting level */ -static int funcnest; /* depth of function calls */ +#ifdef DEBUG + if (msg) + TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid())); + else + TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid())); +#endif + if (msg) { + if (commandname) + outfmt(&errout, "%s: ", commandname); + doformat(&errout, msg, ap); +#if FLUSHERR + outc('\n', &errout); +#else + outcslow('\n', &errout); +#endif + } + flushall(); + exraise(cond); + /* NOTREACHED */ +} -static char *commandname; -struct strlist *cmdenviron; -static int exitstatus; /* exit status of last command */ -static int oexitstatus; /* saved exit status */ +#ifdef __STDC__ +static void +error(const char *msg, ...) +#else +static void +error(va_alist) + va_dcl +#endif +{ +#ifndef __STDC__ + const char *msg; +#endif + va_list ap; +#ifdef __STDC__ + va_start(ap, msg); +#else + va_start(ap); + msg = va_arg(ap, const char *); +#endif + exverror(EXERROR, msg, ap); + /* NOTREACHED */ + va_end(ap); +} -static void evalloop __P((union node *, int)); -static void evalfor __P((union node *, int)); -static void evalcase __P((union node *, int)); -static void evalsubshell __P((union node *, int)); -static void expredir __P((union node *)); -static void evalpipe __P((union node *)); -#ifdef notyet -static void evalcommand __P((union node *, int, struct backcmd *)); +#ifdef __STDC__ +static void +exerror(int cond, const char *msg, ...) +#else +static void +exerror(va_alist) + va_dcl +#endif +{ +#ifndef __STDC__ + int cond; + const char *msg; +#endif + va_list ap; +#ifdef __STDC__ + va_start(ap, msg); #else -static void evalcommand __P((union node *, int)); + va_start(ap); + cond = va_arg(ap, int); + msg = va_arg(ap, const char *); #endif -static void prehash __P((union node *)); -static void eprintlist __P((struct strlist *)); + exverror(cond, msg, ap); + /* NOTREACHED */ + va_end(ap); +} + /* - * Called to reset things after an exception. + * Table of error messages. + */ + +struct errname { + short errcode; /* error number */ + short action; /* operation which encountered the error */ +}; + +/* + * 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 */ + +#define ALL (E_OPEN|E_CREAT|E_EXEC) + +static const struct errname errormsg[] = { + { EINTR, ALL }, + { EACCES, ALL }, + { EIO, ALL }, + { ENOENT, E_OPEN }, + { ENOENT, E_CREAT }, + { ENOENT, E_EXEC }, + { ENOTDIR, E_OPEN }, + { ENOTDIR, E_CREAT }, + { ENOTDIR, E_EXEC }, + { EISDIR, ALL }, + { EEXIST, E_CREAT }, +#ifdef EMFILE + { EMFILE, ALL }, +#endif + { ENFILE, ALL }, + { ENOSPC, ALL }, +#ifdef EDQUOT + { EDQUOT, ALL }, +#endif +#ifdef ENOSR + { ENOSR, ALL }, +#endif + { ENXIO, ALL }, + { EROFS, ALL }, + { ETXTBSY, ALL }, +#ifdef EAGAIN + { EAGAIN, E_EXEC }, +#endif + { ENOMEM, ALL }, +#ifdef ENOLINK + { ENOLINK, ALL }, +#endif +#ifdef EMULTIHOP + { EMULTIHOP, ALL }, +#endif +#ifdef ECOMM + { ECOMM, ALL }, +#endif +#ifdef ESTALE + { ESTALE, ALL }, +#endif +#ifdef ETIMEDOUT + { ETIMEDOUT, ALL }, +#endif +#ifdef ELOOP + { ELOOP, ALL }, +#endif + { E2BIG, E_EXEC }, +#ifdef ELIBACC + { ELIBACC, E_EXEC }, +#endif +}; + +#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname)) + +/* + * 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. */ -#ifdef mkinit -INCLUDE "eval.h" +static const char * +errmsg(int e, int action) +{ + struct errname const *ep; + static char buf[12]; -RESET { - evalskip = 0; - loopnest = 0; - funcnest = 0; + for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) { + if (ep->errcode == e && (ep->action & action) != 0) + return strerror(e); + } + + fmtstr(buf, sizeof buf, "error %d", e); + return buf; } -SHELLPROC { - exitstatus = 0; + +#ifndef ASH_BBAPPS_AS_BUILTINS +static void +__inton() { + if (--suppressint == 0 && intpending) { + onint(); + } } #endif +/* flags in argument to evaltree */ +#define EV_EXIT 01 /* exit after evaluating tree */ +#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ +#define EV_BACKCMD 04 /* command executing within back quotes */ + +static int evalskip; /* set if we are skipping commands */ +static int skipcount; /* number of levels to skip */ +static int loopnest; /* current loop nesting level */ +static int funcnest; /* depth of function calls */ + + + +static struct strlist *cmdenviron; /* environment for builtin command */ +static int exitstatus; /* exit status of last command */ +static int oexitstatus; /* saved exit status */ + + +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 *); +#ifdef notyet +static void evalcommand (union node *, int, struct backcmd *); +#else +static void evalcommand (union node *, int); +#endif +static void prehash (union node *); +static void eprintlist (struct strlist *); +static union node *parsecmd(int); +/* + * Called to reset things after an exception. + */ /* * The eval commmand. */ +static void evalstring (char *, int); static int evalcmd(argc, argv) int argc; char **argv; { - char *p; - char *concat; - char **ap; + char *p; + char *concat; + char **ap; - if (argc > 1) { - p = argv[1]; - if (argc > 2) { - STARTSTACKSTR(concat); - ap = argv + 2; - for (;;) { - while (*p) - STPUTC(*p++, concat); - if ((p = *ap++) == NULL) - break; - STPUTC(' ', concat); - } - STPUTC('\0', concat); - p = grabstackstr(concat); - } - evalstring(p, EV_TESTED); - } - return exitstatus; + if (argc > 1) { + p = argv[1]; + if (argc > 2) { + STARTSTACKSTR(concat); + ap = argv + 2; + for (;;) { + while (*p) + STPUTC(*p++, concat); + if ((p = *ap++) == NULL) + break; + STPUTC(' ', concat); + } + STPUTC('\0', concat); + p = grabstackstr(concat); + } + evalstring(p, EV_TESTED); + } + return exitstatus; } - /* * Execute a command or commands contained in a string. */ +static void evaltree (union node *, int); +static void setinputstring (char *); +static void popfile (void); +static void setstackmark(struct stackmark *mark); +static void popstackmark(struct stackmark *mark); + + static void -evalstring(s, flag) - char *s; - int flag; - { +evalstring(char *s, int flag) +{ union node *n; struct stackmark smark; @@ -1109,12 +2472,12 @@ evalstring(s, flag) popstackmark(&smark); } - - /* * Evaluate a parse tree. The value is left in the global variable * exitstatus. */ +static struct builtincmd *find_builtin (const char *); +static void defun (char *, union node *); static void evaltree(n, flags) @@ -1184,7 +2547,7 @@ evaltree(n, flags) struct builtincmd *bcmd; if ( (bcmd = find_builtin(n->narg.text)) && - bcmd->flags & BUILTIN_SPECIAL + IS_BUILTIN_SPECIAL(bcmd) ) { outfmt(out2, "%s is a special built-in\n", n->narg.text); exitstatus = 1; @@ -1243,7 +2606,7 @@ evalloop(n, flags) for (;;) { evaltree(n->nbinary.ch1, EV_TESTED); if (evalskip) { -skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { +skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { evalskip = 0; continue; } @@ -1267,7 +2630,8 @@ skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { exitstatus = status; } - +static void expandarg (union node *, struct arglist *, int); +static void fixredir(union node *n, const char *text, int err); static void evalfor(n, flags) @@ -1310,7 +2674,6 @@ out: } - static void evalcase(n, flags) union node *n; @@ -1339,8 +2702,6 @@ out: popstackmark(&smark); } - - /* * Kick off a subshell to evaluate a tree. */ @@ -1359,7 +2720,7 @@ evalsubshell(n, flags) if (backgnd) flags &=~ EV_TESTED; redirect(n->nredir.redirect, 0); - evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ + evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ } if (! backgnd) { INTOFF; @@ -1404,8 +2765,6 @@ expredir(n) } } - - /* * Evaluate a pipeline. All the processes in the pipeline are children * of the process creating the pipeline. (This differs from some versions @@ -1485,13 +2844,11 @@ evalpipe(n) */ static void -evalbackcmd(n, result) - union node *n; - struct backcmd *result; +evalbackcmd(union node *n, struct backcmd *result) { int pip[2]; struct job *jp; - struct stackmark smark; /* unnecessary */ + struct stackmark smark; /* unnecessary */ setstackmark(&smark); result->fd = -1; @@ -1540,12 +2897,25 @@ out: result->fd, result->buf, result->nleft, result->jp)); } - - -/* - * Execute a simple command. - */ - + + +/* + * Execute a simple command. + */ + +static void find_command (const char *, struct cmdentry *, int, const char *); + +static int +isassignment(const char *word) { + if (!is_name(*word)) { + return 0; + } + do { + word++; + } while (is_in_name(*word)); + return *word == '='; +} + static void #ifdef notyet evalcommand(cmd, flags, backcmd) @@ -1611,7 +2981,7 @@ evalcommand(cmd, flags) struct builtincmd *bcmd; bool pseudovarflag; bcmd = find_builtin(arglist.list->text); - pseudovarflag = bcmd && bcmd->flags & BUILTIN_ASSIGN; + pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); for (; argp; argp = argp->narg.next) { if (pseudovarflag && isassignment(argp->narg.text)) { expandarg(argp, &arglist, EXP_VARTILDE); @@ -1678,7 +3048,7 @@ evalcommand(cmd, flags) firstbltin = 0; for(;;) { find_command(argv[0], &cmdentry, findflag, path); - if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ + if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ exitstatus = 127; #ifdef FLUSHERR flushout(&errout); @@ -1712,7 +3082,7 @@ evalcommand(cmd, flags) break; } } - if (cmdentry.u.cmd == COMMANDCMD) { + if (cmdentry.u.cmd == find_builtin("command")) { argv++; if (--argc == 0) { goto found; @@ -1761,7 +3131,7 @@ found: } #endif if (forkshell(jp, cmd, mode) != 0) - goto parent; /* at end of routine */ + goto parent; /* at end of routine */ #ifdef notyet if (flags & EV_BACKCMD) { FORCEINTON; @@ -1849,7 +3219,7 @@ found: #endif redirect(cmd->ncmd.redirect, mode); savecmdname = commandname; - if (firstbltin->flags & BUILTIN_SPECIAL) { + if (IS_BUILTIN_SPECIAL(firstbltin)) { listsetvar(varlist.list); } else { cmdenviron = varlist.list; @@ -1864,7 +3234,7 @@ found: handler = &jmploc; commandname = argv[0]; argptr = argv + 1; - optptr = NULL; /* initialize nextopt */ + optptr = NULL; /* initialize nextopt */ exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv); flushall(); cmddone: @@ -1894,12 +3264,8 @@ cmddone: if (flags == EV_BACKCMD) { INTOFF; #ifdef USE_GLIBC_STDIO - if (__closememout()) { - error( - "__closememout() failed: %s", - strerror(errno) - ); - } + if (__closememout()) + error("__closememout() failed: %m"); #endif backcmd->buf = memout.buf; #ifdef USE_GLIBC_STDIO @@ -1924,8 +3290,8 @@ cmddone: } goto out; -parent: /* parent process gets here (if we forked) */ - if (mode == 0) { /* argument to fork */ +parent: /* parent process gets here (if we forked) */ + if (mode == 0) { /* argument to fork */ INTOFF; exitstatus = waitforjob(jp); INTON; @@ -2043,6 +3409,7 @@ returncmd(argc, argv) #ifndef BB_TRUE_FALSE +#ifdef ASH_BBAPPS_AS_BUILTINS static int false_main(argc, argv) int argc; @@ -2060,6 +3427,37 @@ true_main(argc, argv) return 0; } #endif +#endif + +/* + * Controls whether the shell is interactive or not. + */ + +static void setsignal(int signo); +static void chkmail(int silent); + + +static void +setinteractive(int on) +{ + static int is_interactive; + + if (on == is_interactive) + return; + setsignal(SIGINT); + setsignal(SIGQUIT); + setsignal(SIGTERM); + chkmail(1); + is_interactive = on; +} + +static void +optschanged(void) +{ + setinteractive(iflag); + setjobctl(mflag); +} + static int execcmd(argc, argv) @@ -2069,7 +3467,7 @@ execcmd(argc, argv) if (argc > 1) { struct strlist *sp; - iflag = 0; /* exit on error */ + iflag = 0; /* exit on error */ mflag = 0; optschanged(); for (sp = cmdenviron; sp ; sp = sp->next) @@ -2086,8 +3484,6 @@ eprintlist(struct strlist *sp) outfmt(&errout, " %s",sp->text); } } -/* $NetBSD: exec.c,v 1.32 2001/02/04 19:52:06 christos Exp $ */ - /* * 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 @@ -2096,37 +3492,34 @@ eprintlist(struct strlist *sp) * We should investigate converting to a linear search, even though that * would make the command name "hash" a misnomer. */ -#define CMDTABLESIZE 31 /* should be prime */ -#define ARB 1 /* actual size determined at run time */ +#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 */ + 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 int exerrno = 0; /* Last exec error */ +static int builtinloc = -1; /* index in path of %builtin, or -1 */ +static int exerrno = 0; /* Last exec error */ -static void tryexec __P((char *, char **, char **)); -#if !defined(BSD) && !defined(linux) -static void execinterp __P((char **, char **)); -#endif -static void printentry __P((struct tblentry *, int)); -static void clearcmdentry __P((int)); -static struct tblentry *cmdlookup __P((char *, int)); -static void delete_cmd_entry __P((void)); +static void tryexec (char *, char **, char **); +static void printentry (struct tblentry *, int); +static void clearcmdentry (int); +static struct tblentry *cmdlookup (const char *, int); +static void delete_cmd_entry (void); #ifdef ASH_TYPE -static int describe_command __P((char *, int)); +static int describe_command (char *, int); #endif -static int path_change __P((const char *, int *)); +static int path_change (const char *, int *); /* @@ -2134,6 +3527,8 @@ static int path_change __P((const char *, int *)); * have to change the find_command routine as well. */ +static const char *pathopt; /* set by padvance */ + static void shellexec(argv, envp, path, idx) char **argv, **envp; @@ -2174,127 +3569,248 @@ shellexec(argv, envp, path, idx) /* NOTREACHED */ } +/* + * Clear traps on a fork. + */ +static void +clear_traps(void) { + char **tp; + + for (tp = trap ; tp < &trap[NSIG] ; tp++) { + if (*tp && **tp) { /* trap not NULL or SIG_IGN */ + INTOFF; + ckfree(*tp); + *tp = NULL; + if (tp != &trap[0]) + setsignal(tp - trap); + INTON; + } + } +} + static void -tryexec(cmd, argv, envp) - char *cmd; - char **argv; - char **envp; - { - int e; -#if !defined(BSD) && !defined(linux) - char *p; +initshellproc(void) { + +#ifdef ASH_ALIAS + /* from alias.c: */ + { + rmaliases(); + } #endif + /* from eval.c: */ + { + exitstatus = 0; + } -#ifdef SYSV - do { - execve(cmd, argv, envp); - } while (errno == EINTR); -#else - execve(cmd, argv, envp); + /* from exec.c: */ + { + deletefuncs(); + } + + /* from jobs.c: */ + { + backgndpid = -1; +#ifdef JOBS + jobctl = 0; #endif - e = errno; - if (e == ENOEXEC) { - INTOFF; - initshellproc(); - setinputfile(cmd, 0); - commandname = arg0 = savestr(argv[0]); -#if !defined(BSD) && !defined(linux) - INTON; - pgetc(); pungetc(); /* fill up input buffer */ - p = parsenextc; - if (parsenleft > 2 && p[0] == '#' && p[1] == '!') { - argv[0] = cmd; - execinterp(argv, envp); - } - INTOFF; + } + + /* from options.c: */ + { + int i; + + for (i = 0; i < NOPTS; i++) + optent_val(i) = 0; + optschanged(); + + } + + /* from redir.c: */ + { + clearredir(); + } + + /* from trap.c: */ + { + char *sm; + + clear_traps(); + for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) { + if (*sm == S_IGN) + *sm = S_HARD_IGN; + } + } + + /* from var.c: */ + { + shprocvar(); + } +} + +static int preadbuffer(void); +static void pushfile (void); +static int preadfd (void); + +/* + * Read a character from the script, returning PEOF on end of file. + * Nul characters in the input are silently discarded. + */ + +#ifdef ASH_BBAPPS_AS_BUILTINS +#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer()) +static int +pgetc(void) +{ + return pgetc_macro(); +} +#else +static int +pgetc_macro(void) +{ + return --parsenleft >= 0? *parsenextc++ : preadbuffer(); +} + +static inline int +pgetc(void) +{ + return pgetc_macro(); +} #endif - setparam(argv + 1); - exraise(EXSHELLPROC); + + +/* + * Undo the last call to pgetc. Only one character may be pushed back. + * PEOF may be pushed back. + */ + +static void +pungetc() { + parsenleft++; + parsenextc--; +} + + +static 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. + */ + +static void +popallfiles(void) { + while (parsefile != &basepf) + popfile(); +} + +/* + * Close the file(s) that the shell is reading commands from. Called + * after a fork is done. + */ + +static void +closescript() { + popallfiles(); + if (parsefile->fd > 0) { + close(parsefile->fd); + parsefile->fd = 0; } - errno = e; } -#if !defined(BSD) && !defined(linux) /* - * Execute an interpreter introduced by "#!", for systems where this - * feature has not been built into the kernel. If the interpreter is - * the shell, return (effectively ignoring the "#!"). If the execution - * of the interpreter fails, exit. - * - * This code peeks inside the input buffer in order to avoid actually - * reading any input. It would benefit from a rewrite. + * Like setinputfile, but takes an open file descriptor. Call this with + * interrupts off. */ -#define NEWARGS 5 +static void +setinputfd(fd, push) + int fd, push; +{ + (void) fcntl(fd, F_SETFD, FD_CLOEXEC); + if (push) { + pushfile(); + parsefile->buf = 0; + } else { + closescript(); + while (parsefile->strpush) + popstring(); + } + parsefile->fd = fd; + if (parsefile->buf == NULL) + parsefile->buf = ckmalloc(BUFSIZ); + parselleft = parsenleft = 0; + plinno = 1; +} + + +/* + * Set the input to take input from a file. If push is set, push the + * old input onto the stack first. + */ static void -execinterp(argv, envp) - char **argv, **envp; - { - int n; - char *inp; - char *outp; - char c; - char *p; - char **ap; - char *newargs[NEWARGS]; - int i; - char **ap2; - char **new; +setinputfile(const char *fname, int push) +{ + int fd; + int myfileno2; - n = parsenleft - 2; - inp = parsenextc + 2; - ap = newargs; - for (;;) { - while (--n >= 0 && (*inp == ' ' || *inp == '\t')) - inp++; - if (n < 0) - goto bad; - if ((c = *inp++) == '\n') - break; - if (ap == &newargs[NEWARGS]) -bad: error("Bad #! line"); - STARTSTACKSTR(outp); - do { - STPUTC(c, outp); - } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n'); - STPUTC('\0', outp); - n++, inp--; - *ap++ = grabstackstr(outp); - } - if (ap == newargs + 1) { /* if no args, maybe no exec is needed */ - p = newargs[0]; - for (;;) { - if (equal(p, "sh") || equal(p, "ash")) { - return; - } - while (*p != '/') { - if (*p == '\0') - goto break2; - p++; - } - p++; - } -break2:; - } - i = (char *)ap - (char *)newargs; /* size in bytes */ - if (i == 0) - error("Bad #! line"); - for (ap2 = argv ; *ap2++ != NULL ; ); - new = ckmalloc(i + ((char *)ap2 - (char *)argv)); - ap = newargs, ap2 = new; - while ((i -= sizeof (char **)) >= 0) - *ap2++ = *ap++; - ap = argv; - while (*ap2++ = *ap++); - shellexec(new, envp, pathval(), 0); - /* NOTREACHED */ + INTOFF; + if ((fd = open(fname, O_RDONLY)) < 0) + error("Can't open %s", fname); + if (fd < 10) { + myfileno2 = dup_as_newfd(fd, 10); + close(fd); + if (myfileno2 < 0) + error("Out of file descriptors"); + fd = myfileno2; + } + setinputfd(fd, push); + INTON; } -#endif +static void +tryexec(cmd, argv, envp) + char *cmd; + char **argv; + char **envp; + { + int e; + + execve(cmd, argv, envp); + e = errno; + if (e == ENOEXEC) { + INTOFF; + initshellproc(); + setinputfile(cmd, 0); + commandname = arg0 = savestr(argv[0]); + setparam(argv + 1); + exraise(EXSHELLPROC); + } + errno = e; +} + +static char *commandtext (const union node *); /* * Do a path search. The variable path (passed by reference) should be @@ -2308,11 +3824,12 @@ break2:; static const char *pathopt; +static void growstackblock(void); + + static char * -padvance(path, name) - const char **path; - const char *name; - { +padvance(const char **path, const char *name) +{ const char *p; char *q; const char *start; @@ -2322,7 +3839,7 @@ padvance(path, name) return NULL; start = *path; for (p = start ; *p && *p != ':' && *p != '%' ; p++); - len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ + len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ while (stackblocksize() < len) growstackblock(); q = stackblock(); @@ -2442,12 +3959,10 @@ printentry(cmdp, verbose) * change the shellexec routine as well. */ +static int prefix (const char *, const char *); + static void -find_command(name, entry, act, path) - char *name; - struct cmdentry *entry; - int act; - const char *path; +find_command(const char *name, struct cmdentry *entry, int act, const char *path) { struct tblentry *cmdp; int idx; @@ -2465,10 +3980,6 @@ find_command(name, entry, act, path) if (strchr(name, '/') != NULL) { if (act & DO_ABS) { while (stat(name, &statb) < 0) { - #ifdef SYSV - if (errno == EINTR) - continue; - #endif if (errno != ENOENT && errno != ENOTDIR) e = errno; entry->cmdtype = CMDUNKNOWN; @@ -2516,11 +4027,11 @@ find_command(name, entry, act, path) } bcmd = find_builtin(name); - regular = bcmd && bcmd->flags & BUILTIN_REGULAR; + regular = bcmd && IS_BUILTIN_REGULAR(bcmd); if (regular) { if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) { - goto success; + goto success; } } else if (act & DO_BRUTE) { if (firstchange == 0) { @@ -2545,8 +4056,8 @@ builtin: } /* We have to search path. */ - prev = -1; /* where to start */ - if (cmdp && cmdp->rehash) { /* doing a rehash */ + prev = -1; /* where to start */ + if (cmdp && cmdp->rehash) { /* doing a rehash */ if (cmdp->cmdtype == CMDBUILTIN) prev = builtinloc; else @@ -2572,7 +4083,7 @@ loop: prefix("func", pathopt)) { /* handled below */ } else { - continue; /* ignore unimplemented options */ + continue; /* ignore unimplemented options */ } } /* if rehash, don't redo absolute path names */ @@ -2584,18 +4095,14 @@ loop: goto success; } while (stat(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 */ + e = EACCES; /* if we fail, this will be the error */ if (!S_ISREG(statb.st_mode)) continue; - if (pathopt) { /* this is a %func directory */ + if (pathopt) { /* this is a %func directory */ stalloc(strlen(fullname) + 1); readcmdfile(fullname); if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION) @@ -2603,18 +4110,6 @@ loop: stunalloc(fullname); goto success; } -#ifdef notdef - 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 we aren't called with DO_BRUTE and cmdp is set, it must be a function and we're being called with DO_NOFUN */ @@ -2651,14 +4146,19 @@ success: * Search the table of builtin commands. */ -struct builtincmd * -find_builtin(name) - char *name; +static int +bstrcmp(const void *name, const void *b) +{ + return strcmp((const char *)name, (*(const char *const *) b)+1); +} + +static struct builtincmd * +find_builtin(const char *name) { struct builtincmd *bp; - bp = bsearch( &name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd), - pstrcmp + bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd), + bstrcmp ); return bp; } @@ -2670,7 +4170,7 @@ find_builtin(name) */ static void -hashcd() { +hashcd(void) { struct tblentry **pp; struct tblentry *cmdp; @@ -2692,15 +4192,14 @@ hashcd() { */ static void -changepath(newval) - const char *newval; +changepath(const char *newval) { int firstchange; int bltin; firstchange = path_change(newval, &bltin); if (builtinloc < 0 && bltin >= 0) - builtinloc = bltin; /* zap builtins */ + builtinloc = bltin; /* zap builtins */ clearcmdentry(firstchange); builtinloc = bltin; } @@ -2737,21 +4236,24 @@ clearcmdentry(firstchange) INTON; } - /* - * Delete all functions. + * Free a parse tree. */ -#ifdef mkinit -static void deletefuncs __P((void)); - -SHELLPROC { - deletefuncs(); +static void +freefunc(union node *n) +{ + if (n) + ckfree(n); } -#endif + + +/* + * Delete all functions. + */ static void -deletefuncs() { +deletefuncs(void) { struct tblentry **tblp; struct tblentry **pp; struct tblentry *cmdp; @@ -2782,16 +4284,13 @@ deletefuncs() { * entry. */ -struct tblentry **lastcmdentry; - +static struct tblentry **lastcmdentry; static struct tblentry * -cmdlookup(name, add) - char *name; - int add; +cmdlookup(const char *name, int add) { int hashval; - char *p; + const char *p; struct tblentry *cmdp; struct tblentry **pp; @@ -2837,35 +4336,14 @@ delete_cmd_entry() { -#ifdef notdef -static void -getcmdentry(name, entry) - 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. */ static void -addcmdentry(name, entry) - char *name; - struct cmdentry *entry; - { +addcmdentry(char *name, struct cmdentry *entry) +{ struct tblentry *cmdp; INTOFF; @@ -2883,11 +4361,11 @@ addcmdentry(name, entry) * Define a shell function. */ +static union node *copyfunc(union node *); + static void -defun(name, func) - char *name; - union node *func; - { +defun(char *name, union node *func) +{ struct cmdentry entry; entry.cmdtype = CMDFUNCTION; @@ -2901,9 +4379,8 @@ defun(name, func) */ static void -unsetfunc(name) - char *name; - { +unsetfunc(char *name) +{ struct tblentry *cmdp; if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) { @@ -2912,6 +4389,26 @@ unsetfunc(name) } } +/* + * Wrapper around strcmp for qsort/bsearch/... + */ +static int +pstrcmp(const void *a, const void *b) +{ + return strcmp((const char *) a, *(const char *const *) b); +} + +/* + * Find a keyword is in a sorted array. + */ + +static const char *const * +findkwd(const char *s) +{ + return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *), + sizeof(const char *), pstrcmp); +} + #ifdef ASH_TYPE /* * Locate and print what a word is... @@ -2932,13 +4429,13 @@ typecmd(argc, argv) } static int -describe_command(command, verbose) - char *command; - int verbose; +describe_command(char *command, int verbose) { struct cmdentry entry; struct tblentry *cmdp; +#ifdef ASH_ALIAS const struct alias *ap; +#endif const char *path = pathval(); if (verbose) { @@ -2951,6 +4448,7 @@ describe_command(command, verbose) goto out; } +#ifdef ASH_ALIAS /* Then look at the aliases */ if ((ap = lookupalias(command, 0)) != NULL) { if (verbose) { @@ -2960,7 +4458,7 @@ describe_command(command, verbose) } goto out; } - +#endif /* Then check if it is a tracked alias */ if ((cmdp = cmdlookup(command, 0)) != NULL) { entry.cmdtype = cmdp->cmdtype; @@ -3005,7 +4503,7 @@ describe_command(command, verbose) if (verbose) { out1fmt( " is a %sshell builtin", - entry.u.cmd->flags & BUILTIN_SPECIAL ? + IS_BUILTIN_SPECIAL(entry.u.cmd) ? "special " : nullstr ); } else { @@ -3024,8 +4522,9 @@ out: out1c('\n'); return 0; } -#endif +#endif +#ifdef ASH_CMDCMD static int commandcmd(argc, argv) int argc; @@ -3066,10 +4565,11 @@ commandcmd(argc, argv) if (verify_only || verbose_verify_only) { return describe_command(*argptr, verbose_verify_only); } -#endif +#endif return 0; } +#endif static int path_change(newval, bltin) @@ -3082,7 +4582,7 @@ path_change(newval, bltin) old = pathval(); new = newval; - firstchange = 9999; /* assume no change */ + firstchange = 9999; /* assume no change */ idx = 0; *bltin = -1; for (;;) { @@ -3091,7 +4591,7 @@ path_change(newval, bltin) if ((*old == '\0' && *new == ':') || (*old == ':' && *new == '\0')) firstchange++; - old = new; /* ignore subsequent differences */ + old = new; /* ignore subsequent differences */ } if (*new == '\0') break; @@ -3106,8 +4606,6 @@ path_change(newval, bltin) firstchange = 0; return firstchange; } -/* $NetBSD: expand.c,v 1.50 2001/02/04 19:52:06 christos Exp $ */ - /* * Routines to expand arguments to commands. We have to deal with * backquotes, shell variables, and file metacharacters. @@ -3115,8 +4613,8 @@ path_change(newval, bltin) /* * _rmescape() flags */ -#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ -#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ +#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ +#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ /* * Structure specifying which parts of the string should be searched @@ -3124,66 +4622,62 @@ path_change(newval, bltin) */ 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 */ + 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 */ }; -static char *expdest; /* output of current string */ -struct nodelist *argbackq; /* list of back quote expressions */ -struct ifsregion ifsfirst; /* first struct in list of ifs regions */ -struct ifsregion *ifslastp; /* last struct in list */ -struct arglist exparg; /* holds expanded arg list */ - -static void argstr __P((char *, int)); -static char *exptilde __P((char *, int)); -static void expbackq __P((union node *, int, int)); -static int subevalvar __P((char *, char *, int, int, int, int, int)); -static char *evalvar __P((char *, int)); -static int varisset __P((char *, int)); -static void strtodest __P((const char *, const char *, int)); -static void varvalue __P((char *, int, int)); -static void recordregion __P((int, int, int)); -static void removerecordregions __P((int)); -static void ifsbreakup __P((char *, struct arglist *)); -static void ifsfree __P((void)); -static void expandmeta __P((struct strlist *, int)); +static char *expdest; /* output of current string */ +static struct nodelist *argbackq; /* list of back quote expressions */ +static struct ifsregion ifsfirst; /* first struct in list of ifs regions */ +static struct ifsregion *ifslastp; /* last struct in list */ +static struct arglist exparg; /* holds expanded arg list */ + +static void argstr (char *, int); +static char *exptilde (char *, int); +static void expbackq (union node *, int, int); +static int subevalvar (char *, char *, int, int, int, int, int); +static char *evalvar (char *, int); +static int varisset (char *, int); +static void strtodest (const char *, const char *, int); +static void varvalue (char *, int, int); +static void recordregion (int, int, int); +static void removerecordregions (int); +static void ifsbreakup (char *, struct arglist *); +static void ifsfree (void); +static void expandmeta (struct strlist *, int); #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) #define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB) #if !defined(GLOB_BROKEN) -static void addglob __P((const glob_t *)); +static void addglob (const glob_t *); #endif #endif #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) -static void expmeta __P((char *, char *)); +static void expmeta (char *, char *); #endif -static void addfname __P((char *)); #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) -static struct strlist *expsort __P((struct strlist *)); -static struct strlist *msort __P((struct strlist *, int)); +static struct strlist *expsort (struct strlist *); +static struct strlist *msort (struct strlist *, int); #endif #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) -static int patmatch __P((char *, char *, int)); -static int patmatch2 __P((char *, char *, int)); +static int patmatch (char *, char *, int); +static int patmatch2 (char *, char *, int); #else -static int pmatch __P((char *, char *, int)); +static int pmatch (char *, char *, int); #define patmatch2 patmatch #endif -static char *cvtnum __P((int, char *)); - -extern int oexitstatus; +static char *cvtnum (int, char *); /* * Expand shell variables and backquotes inside a here document. */ +/* arg: the document, fd: where to write the expanded version */ static void -expandhere(arg, fd) - union node *arg; /* the document */ - int fd; /* where to write the expanded version */ - { +expandhere(union node *arg, int fd) +{ herefd = fd; expandarg(arg, (struct arglist *)NULL, 0); xwrite(fd, stackblock(), expdest - stackblock()); @@ -3212,7 +4706,7 @@ expandarg(arg, arglist, flag) ifslastp = NULL; argstr(arg->narg.text, flag); if (arglist == NULL) { - return; /* here document expanded */ + return; /* here document expanded */ } STPUTC('\0', expdest); p = grabstackstr(expdest); @@ -3255,7 +4749,7 @@ argstr(p, flag) int flag; { char c; - int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ + int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ int firsteq = 1; if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) @@ -3290,7 +4784,7 @@ argstr(p, flag) case CTLENDARI: expari(flag); break; -#endif +#endif case ':': case '=': /* @@ -3362,9 +4856,8 @@ lose: } -static void -removerecordregions(endoff) - int endoff; +static void +removerecordregions(int endoff) { if (ifslastp == NULL) return; @@ -3386,7 +4879,7 @@ removerecordregions(endoff) } return; } - + ifslastp = &ifsfirst; while (ifslastp->next && ifslastp->next->begoff < endoff) ifslastp=ifslastp->next; @@ -3409,8 +4902,7 @@ removerecordregions(endoff) * evaluate, place result in (backed up) result, adjust string position. */ static void -expari(flag) - int flag; +expari(int flag) { char *p, *start; int result; @@ -3418,7 +4910,7 @@ expari(flag) int quotes = flag & (EXP_FULL | EXP_CASE); int quoted; - /* ifsfree(); */ + /* ifsfree(); */ /* * This routine is slightly over-complicated for @@ -3462,8 +4954,7 @@ expari(flag) result = expdest - p + 1; STADJUST(-result, expdest); } -#endif - +#endif /* * Expand stuff in backwards quotes. @@ -3573,8 +5064,6 @@ err2: INTON; } - - static int subevalvar(p, str, strloc, subtype, startloc, varflags, quotes) char *p; @@ -3630,7 +5119,7 @@ subevalvar(p, str, strloc, subtype, startloc, varflags, quotes) goto recordleft; *loc = c; if (quotes && *loc == CTLESC) - loc++; + loc++; } return 0; @@ -3653,11 +5142,11 @@ subevalvar(p, str, strloc, subtype, startloc, varflags, quotes) return 0; case VSTRIMRIGHT: - for (loc = str - 1; loc >= startp;) { + for (loc = str - 1; loc >= startp;) { if (patmatch2(str, loc, quotes)) goto recordright; loc--; - if (quotes && loc > startp && *(loc - 1) == CTLESC) { + if (quotes && loc > startp && *(loc - 1) == CTLESC) { for (q = startp; q < loc; q++) if (*q == CTLESC) q++; @@ -3672,7 +5161,7 @@ subevalvar(p, str, strloc, subtype, startloc, varflags, quotes) if (patmatch2(str, loc, quotes)) goto recordright; if (quotes && *loc == CTLESC) - loc++; + loc++; } return 0; @@ -3788,7 +5277,7 @@ record: case VSPLUS: case VSMINUS: if (!set) { - argstr(p, flag); + argstr(p, flag); break; } if (easy) @@ -3822,9 +5311,9 @@ record: if (subevalvar(p, var, 0, subtype, startloc, varflags, quotes)) { varflags &= ~VSNUL; - /* - * Remove any recorded regions beyond - * start of variable + /* + * Remove any recorded regions beyond + * start of variable */ removerecordregions(startloc); goto again; @@ -3841,7 +5330,7 @@ record: #endif } - if (subtype != VSNORMAL) { /* skip to end of alternative */ + if (subtype != VSNORMAL) { /* skip to end of alternative */ int nesting = 1; for (;;) { if ((c = *p++) == CTLESC) @@ -3861,8 +5350,6 @@ record: return p; } - - /* * Test whether a specialized variable is set. */ @@ -3904,8 +5391,6 @@ varisset(name, nulok) return 1; } - - /* * Put a string on the stack. */ @@ -3923,8 +5408,6 @@ strtodest(p, syntax, quotes) } } - - /* * Add the value of a specialized variable to the stack string. */ @@ -3963,8 +5446,8 @@ numvar: break; case '-': for (i = 0 ; i < NOPTS ; i++) { - if (optlist[i].val) - STPUTC(optlist[i].letter, expdest); + if (optent_val(i)) + STPUTC(optent_letter(optlist[i]), expdest); } break; case '@': @@ -4001,7 +5484,6 @@ param: } - /* * Record the fact that we have to scan this region of the * string for IFS characters. @@ -4136,7 +5618,22 @@ ifsfree() ifsfirst.next = NULL; } +/* + * Add a file name to the list. + */ + +static void +addfname(const char *name) +{ + char *p; + struct strlist *sp; + p = sstrdup(name); + sp = (struct strlist *)stalloc(sizeof *sp); + sp->text = p; + *exparg.lastp = sp; + exparg.lastp = &sp->next; +} /* * Expand shell metacharacters. At this point, the only control characters @@ -4175,7 +5672,7 @@ nometa: rmescapes(str->text); exparg.lastp = &str->next; break; - default: /* GLOB_NOSPACE */ + default: /* GLOB_NOSPACE */ error("Out of space"); } str = str->next; @@ -4199,7 +5696,7 @@ addglob(pglob) } -#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ +#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ static char *expdir; @@ -4218,7 +5715,7 @@ expandmeta(str, flag) if (fflag) goto nometa; p = str->text; - for (;;) { /* fast check for meta chars */ + for (;;) { /* fast check for meta chars */ if ((c = *p++) == '\0') goto nometa; if (c == '*' || c == '?' || c == '[' || c == '!') @@ -4297,7 +5794,7 @@ expmeta(enddir, name) break; } } - } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { + } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { metaflag = 1; } else if (*p == '\0') break; @@ -4311,7 +5808,7 @@ expmeta(enddir, name) start = p + 1; } } - if (metaflag == 0) { /* we've reached the end of the file name */ + if (metaflag == 0) { /* we've reached the end of the file name */ if (enddir != expdir) metaflag++; for (p = name ; ; p++) { @@ -4369,7 +5866,7 @@ expmeta(enddir, name) continue; if (patmatch(start, dp->d_name, 0)) { if (atend) { - scopy(dp->d_name, enddir); + strcpy(enddir, dp->d_name); addfname(expdir); } else { for (p = enddir, cp = dp->d_name; @@ -4384,26 +5881,8 @@ expmeta(enddir, name) if (! atend) endname[-1] = '/'; } -#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ - - -/* - * Add a file name to the list. - */ +#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ -static void -addfname(name) - char *name; - { - char *p; - struct strlist *sp; - - p = sstrdup(name); - sp = (struct strlist *)stalloc(sizeof *sp); - sp->text = p; - *exparg.lastp = sp; - exparg.lastp = &sp->next; -} #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) @@ -4445,9 +5924,9 @@ msort(list, len) 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 */ + 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) { @@ -4477,12 +5956,10 @@ msort(list, len) */ #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) +/* squoted: string might have quote chars */ static int -patmatch(pattern, string, squoted) - char *pattern; - char *string; - int squoted; /* string might have quote chars */ - { +patmatch(char *pattern, char *string, int squoted) +{ const char *p; char *q; @@ -4494,11 +5971,8 @@ patmatch(pattern, string, squoted) static int -patmatch2(pattern, string, squoted) - char *pattern; - char *string; - int squoted; /* string might have quote chars */ - { +patmatch2(char *pattern, char *string, int squoted) +{ char *p; int res; @@ -4510,26 +5984,14 @@ patmatch2(pattern, string, squoted) } #else static int -patmatch(pattern, string, squoted) - char *pattern; - char *string; - int squoted; /* string might have quote chars */ - { -#ifdef notdef - if (pattern[0] == '!' && pattern[1] == '!') - return 1 - pmatch(pattern + 2, string); - else -#endif - return pmatch(pattern, string, squoted); +patmatch(char *pattern, char *string, int squoted) { + return pmatch(pattern, string, squoted); } static int -pmatch(pattern, string, squoted) - char *pattern; - char *string; - int squoted; - { +pmatch(char *pattern, char *string, int squoted) +{ char *p, *q; char c; @@ -4589,7 +6051,7 @@ pmatch(pattern, string, squoted) while (*endp == CTLQUOTEMARK) endp++; if (*endp == '\0') - goto dft; /* no matching ] */ + goto dft; /* no matching ] */ if (*endp == CTLESC) endp++; if (*++endp == ']') @@ -4630,7 +6092,7 @@ pmatch(pattern, string, squoted) return 0; break; } -dft: default: +dft: default: if (squoted && *q == CTLESC) q++; if (*q++ != c) @@ -4653,9 +6115,7 @@ breakloop: #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) static char * -_rmescapes(str, flag) - char *str; - int flag; +_rmescapes(char *str, int flag) { char *p, *q, *r; static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 }; @@ -4727,10 +6187,8 @@ rmescapes(str) */ static int -casematch(pattern, val) - union node *pattern; - char *val; - { +casematch(union node *pattern, const char *val) +{ struct stackmark smark; int result; char *p; @@ -4742,7 +6200,7 @@ casematch(pattern, val) argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); STPUTC('\0', expdest); p = grabstackstr(expdest); - result = patmatch(p, val, 0); + result = patmatch(p, (char *)val, 0); popstackmark(&smark); return result; } @@ -4763,8 +6221,6 @@ cvtnum(num, buf) STADJUST(len, buf); return buf; } -/* $NetBSD: histedit.c,v 1.25 2001/02/04 19:52:06 christos Exp $ */ - /* * Editline and history functions (and glue). */ @@ -4777,54 +6233,15 @@ static int histcmd(argc, argv) } -/* - * This file was generated by the mkinit program. - */ - -extern void rmaliases __P((void)); - -extern int loopnest; /* current loop nesting level */ - -extern void deletefuncs __P((void)); - -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 */ -}; - -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 */ -}; - -extern int parselleft; /* copy of parsefile->lleft */ -extern struct parsefile basepf; /* top level input file */ -extern char basebuf[BUFSIZ]; /* buffer for top level input file */ - -extern short backgndpid; /* pid of last background process */ -extern int jobctl; +static int whichprompt; /* 1 == PS1, 2 == PS2 */ -extern int tokpushback; /* last token pushed back */ -extern int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ struct redirtab { struct redirtab *next; short renamed[10]; }; -extern struct redirtab *redirlist; - -extern char sigmode[NSIG - 1]; /* current value of signal */ +static struct redirtab *redirlist; extern char **environ; @@ -4835,7 +6252,7 @@ extern char **environ; */ static void -init() { +init(void) { /* from cd.c: */ { @@ -4878,115 +6295,59 @@ init() { * interactive shell and control is returned to the main command loop. */ -static void -reset() { - - /* from eval.c: */ - { - evalskip = 0; - loopnest = 0; - funcnest = 0; - } - - /* from input.c: */ - { - if (exception != EXSHELLPROC) - parselleft = parsenleft = 0; /* clear input buffer */ - popallfiles(); - } - - /* from parser.c: */ - { - tokpushback = 0; - checkkwd = 0; - checkalias = 0; - } - - /* from redir.c: */ - { - while (redirlist) - popredir(); - } - - /* from output.c: */ - { - out1 = &output; - out2 = &errout; -#ifdef USE_GLIBC_STDIO - if (memout.stream != NULL) - __closememout(); +#ifdef ASH_ALIAS +/* 1 == check for aliases, 2 == also check for assignments */ +static int checkalias; #endif - if (memout.buf != NULL) { - ckfree(memout.buf); - memout.buf = NULL; - } - } -} - - - -/* - * This routine is called to initialize the shell to run a shell procedure. - */ - -static void -initshellproc() { - - /* from alias.c: */ - { - rmaliases(); - } + +static void +reset(void) { /* from eval.c: */ { - exitstatus = 0; + evalskip = 0; + loopnest = 0; + funcnest = 0; } - /* from exec.c: */ + /* from input.c: */ { - deletefuncs(); + if (exception != EXSHELLPROC) + parselleft = parsenleft = 0; /* clear input buffer */ + popallfiles(); } - /* from jobs.c: */ + /* from parser.c: */ { - backgndpid = -1; -#if JOBS - jobctl = 0; + tokpushback = 0; + checkkwd = 0; +#ifdef ASH_ALIAS + checkalias = 0; #endif } - /* from options.c: */ - { - int i; - - for (i = 0; i < NOPTS; i++) - optlist[i].val = 0; - optschanged(); - - } - /* from redir.c: */ { - clearredir(); + while (redirlist) + popredir(); } - /* from trap.c: */ + /* from output.c: */ { - char *sm; - - clear_traps(); - for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) { - if (*sm == S_IGN) - *sm = S_HARD_IGN; + out1 = &output; + out2 = &errout; +#ifdef USE_GLIBC_STDIO + if (memout.stream != NULL) + __closememout(); +#endif + if (memout.buf != NULL) { + ckfree(memout.buf); + memout.buf = NULL; } } - - /* from var.c: */ - { - shprocvar(); - } } -/* $NetBSD: input.c,v 1.35 2001/02/04 19:52:06 christos Exp $ */ + + /* * This file implements the input routines used by the parser. @@ -5004,45 +6365,34 @@ static inline void putprompt(const char *s) { } #endif -#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ +#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ -static int plinno = 1; /* input line number */ -static int parsenleft; /* copy of parsefile->nleft */ -static int parselleft; /* copy of parsefile->lleft */ -static char *parsenextc; /* copy of parsefile->nextc */ -struct parsefile basepf; /* top level input file */ -static char basebuf[BUFSIZ]; /* buffer for top level input file */ -struct parsefile *parsefile = &basepf; /* current input file */ -static int whichprompt; /* 1 == PS1, 2 == PS2 */ -static void pushfile __P((void)); -static int preadfd __P((void)); -#ifdef mkinit -INCLUDE -INCLUDE "input.h" -INCLUDE "error.h" - -INIT { - basepf.nextc = basepf.buf = basebuf; -} +/* + * Same as pgetc(), but ignores PEOA. + */ -RESET { - if (exception != EXSHELLPROC) - parselleft = parsenleft = 0; /* clear input buffer */ - popallfiles(); +#ifdef ASH_ALIAS +static int +pgetc2() +{ + int c; + do { + c = pgetc_macro(); + } while (c == PEOA); + return c; } +#else +static inline int pgetc2() { return pgetc_macro(); } #endif - /* * Read a line from the script. */ static char * -pfgets(line, len) - char *line; - int len; +pfgets(char *line, int len) { char *p = line; int nleft = len; @@ -5063,36 +6413,8 @@ pfgets(line, len) return line; } - -/* - * Read a character from the script, returning PEOF on end of file. - * Nul characters in the input are silently discarded. - */ - -static int -pgetc() -{ - return pgetc_macro(); -} - - -/* - * Same as pgetc(), but ignores PEOA. - */ - -static int -pgetc2() -{ - int c; - do { - c = pgetc_macro(); - } while (c == PEOA); - return c; -} - - static int -preadfd() +preadfd(void) { int nr; char *buf = parsefile->buf; @@ -5103,7 +6425,7 @@ retry: { if (parsefile->fd) nr = read(parsefile->fd, buf, BUFSIZ - 1); - else { + else { do { cmdedit_read_input((char*)cmdedit_prompt, buf); nr = strlen(buf); @@ -5132,6 +6454,39 @@ retry: return nr; } +static void +popstring(void) +{ + struct strpush *sp = parsefile->strpush; + + INTOFF; +#ifdef ASH_ALIAS + if (sp->ap) { + if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { + if (!checkalias) { + checkalias = 1; + } + } + if (sp->string != sp->ap->val) { + ckfree(sp->string); + } + + sp->ap->flag &= ~ALIASINUSE; + if (sp->ap->flag & ALIASDEAD) { + unalias(sp->ap->name); + } + } +#endif + 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; +} + + /* * Refill the input buffer and return the next input character: * @@ -5143,19 +6498,19 @@ retry: */ static int -preadbuffer() +preadbuffer(void) { char *p, *q; int more; char savec; while (parsefile->strpush) { - if ( - parsenleft == -1 && parsefile->strpush->ap && - parsenextc[-1] != ' ' && parsenextc[-1] != '\t' - ) { +#ifdef ASH_ALIAS + if (parsenleft == -1 && parsefile->strpush->ap && + parsenextc[-1] != ' ' && parsenextc[-1] != '\t') { return PEOA; } +#endif popstring(); if (--parsenleft >= 0) return (*parsenextc++); @@ -5181,7 +6536,7 @@ again: for (more = 1; more;) { switch (*p) { case '\0': - p++; /* Skip nul */ + p++; /* Skip nul */ goto check; @@ -5216,27 +6571,14 @@ check: return *parsenextc++; } -/* - * Undo the last call to pgetc. Only one character may be pushed back. - * PEOF may be pushed back. - */ - -static void -pungetc() { - parsenleft++; - parsenextc--; -} /* * Push a string back onto the input at this current parsefile level. * We handle aliases this way. */ static void -pushstring(s, len, ap) - char *s; - int len; - void *ap; - { +pushstring(char *s, int len, void *ap) +{ struct strpush *sp; INTOFF; @@ -5249,97 +6591,19 @@ pushstring(s, len, ap) sp = parsefile->strpush = &(parsefile->basestrpush); sp->prevstring = parsenextc; sp->prevnleft = parsenleft; +#ifdef ASH_ALIAS sp->ap = (struct alias *)ap; if (ap) { ((struct alias *)ap)->flag |= ALIASINUSE; sp->string = s; } +#endif parsenextc = s; parsenleft = len; INTON; } -static void -popstring() -{ - struct strpush *sp = parsefile->strpush; - - INTOFF; - if (sp->ap) { - if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { - if (!checkalias) { - checkalias = 1; - } - } - 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. - */ - -static void -setinputfile(fname, push) - const char *fname; - int push; -{ - int fd; - int myfileno2; - - INTOFF; - if ((fd = open(fname, O_RDONLY)) < 0) - error("Can't open %s", fname); - if (fd < 10) { - myfileno2 = dup_as_newfd(fd, 10); - close(fd); - if (myfileno2 < 0) - error("Out of file descriptors"); - fd = myfileno2; - } - setinputfd(fd, push); - INTON; -} - - -/* - * Like setinputfile, but takes an open file descriptor. Call this with - * interrupts off. - */ -static void -setinputfd(fd, push) - int fd, push; -{ - (void) fcntl(fd, F_SETFD, FD_CLOEXEC); - if (push) { - pushfile(); - parsefile->buf = 0; - } else { - closescript(); - while (parsefile->strpush) - popstring(); - } - parsefile->fd = fd; - if (parsefile->buf == NULL) - parsefile->buf = ckmalloc(BUFSIZ); - parselleft = parsenleft = 0; - plinno = 1; -} /* @@ -5367,7 +6631,7 @@ setinputstring(string) */ static void -pushfile() { +pushfile(void) { struct parsefile *pf; parsefile->nleft = parsenleft; @@ -5377,84 +6641,47 @@ pushfile() { pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); pf->prev = parsefile; pf->fd = -1; - pf->strpush = NULL; - pf->basestrpush.prev = NULL; - parsefile = pf; -} - - -static void -popfile() { - 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. - */ - -static void -popallfiles() { - while (parsefile != &basepf) - popfile(); + pf->strpush = NULL; + pf->basestrpush.prev = NULL; + parsefile = pf; } +#ifdef JOBS +static void restartjob (struct job *); +#endif +static void freejob (struct job *); +static struct job *getjob (const char *); +static int dowait (int, struct job *); +static int waitproc (int, int *); +static void waitonint(int); /* - * Close the file(s) that the shell is reading commands from. Called - * after a fork is done. - */ + * We keep track of whether or not fd0 has been redirected. This is for + * background commands, where we want to redirect fd0 to /dev/null only + * if it hasn't already been redirected. +*/ +static int fd0_redirected = 0; -static void -closescript() { - popallfiles(); - if (parsefile->fd > 0) { - close(parsefile->fd); - parsefile->fd = 0; - } +/* Return true if fd 0 has already been redirected at least once. */ +static inline int +fd0_redirected_p () { + return fd0_redirected != 0; } -/* $NetBSD: jobs.c,v 1.36 2000/05/22 10:18:47 elric Exp $ */ +/* + * We also keep track of where fileno2 goes. + */ +static int fileno2 = 2; -struct job *jobtab; /* array of jobs */ -static int njobs; /* size of array */ -short backgndpid = -1; /* pid of last background process */ -#if JOBS -static int initialpgrp; /* pgrp of shell on invocation */ -short curjob; /* current job */ -#endif -static int intreceived; +static int openredirect (union node *); +static void dupredirect (union node *, int, char[10 ]); +static int openhere (union node *); +static int noclobberopen (const char *); -static void restartjob __P((struct job *)); -static void freejob __P((struct job *)); -static struct job *getjob __P((char *)); -static int dowait __P((int, struct job *)); -#ifdef SYSV -static int onsigchild __P((void)); -#endif -static int waitproc __P((int, int *)); -static void cmdtxt __P((union node *)); -static void cmdputs __P((const char *)); -static void waitonint(int); -#if JOBS +#ifdef JOBS /* * Turn job control on and off. * @@ -5463,7 +6690,7 @@ static void waitonint(int); * System V doesn't have job control yet, this isn't a problem now. */ -static int jobctl; + static void setjobctl(int enable) { @@ -5524,22 +6751,6 @@ static void setjobctl(int enable) #endif -#ifdef mkinit -INCLUDE - -SHELLPROC { - backgndpid = -1; -#if JOBS - jobctl = 0; -#endif -} - -#endif - - -/* This file was automatically created by ./mksignames. - Do not edit. Edit support/mksignames.c instead. */ - /* A translation list so we can be polite to our users. */ static char *signal_names[NSIG + 2] = { "EXIT", @@ -5612,7 +6823,7 @@ static char *signal_names[NSIG + 2] = { -#if JOBS +#ifdef JOBS static int killcmd(argc, argv) int argc; @@ -5650,7 +6861,7 @@ usage: optionarg ); } - break; + break; #ifdef DEBUG default: error( @@ -5697,7 +6908,7 @@ usage: } else pid = atoi(*argptr); if (kill(pid, signo) != 0) - error("%s: %s", *argptr, strerror(errno)); + error("%s: %m", *argptr); } while (*++argptr); return 0; @@ -5767,6 +6978,8 @@ restartjob(jp) } #endif +static void showjobs(int change); + static int jobscmd(argc, argv) @@ -5811,12 +7024,12 @@ showjobs(change) if (change && ! jp->changed) continue; procno = jp->nprocs; - for (ps = jp->ps ; ; ps++) { /* for each process */ + for (ps = jp->ps ; ; ps++) { /* for each process */ if (ps == jp->ps) - fmtstr(s, 64, "[%d] %ld ", jobno, + fmtstr(s, 64, "[%d] %ld ", jobno, (long)ps->pid); else - fmtstr(s, 64, " %ld ", + fmtstr(s, 64, " %ld ", (long)ps->pid); out1str(s); col = strlen(s); @@ -5824,17 +7037,17 @@ showjobs(change) if (ps->status == -1) { /* don't print anything */ } else if (WIFEXITED(ps->status)) { - fmtstr(s, 64, "Exit %d", + fmtstr(s, 64, "Exit %d", WEXITSTATUS(ps->status)); } else { -#if JOBS - if (WIFSTOPPED(ps->status)) +#ifdef JOBS + if (WIFSTOPPED(ps->status)) i = WSTOPSIG(ps->status); else /* WIFSIGNALED(ps->status) */ #endif i = WTERMSIG(ps->status); if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F]) - scopy(sys_siglist[i & 0x7F], s); + strcpy(s, sys_siglist[i & 0x7F]); else fmtstr(s, 64, "Signal %d", i & 0x7F); if (WCOREDUMP(ps->status)) @@ -5876,7 +7089,7 @@ freejob(jp) if (jp->ps != &jp->ps0) ckfree(jp->ps); jp->used = 0; -#if JOBS +#ifdef JOBS if (curjob == jp - jobtab + 1) curjob = 0; #endif @@ -5900,7 +7113,7 @@ start: } else { job = NULL; } - for (;;) { /* loop until process terminated or stopped */ + for (;;) { /* loop until process terminated or stopped */ if (job != NULL) { if (job->state) { status = job->ps[job->nprocs - 1].status; @@ -5911,7 +7124,7 @@ start: } if (WIFEXITED(status)) retval = WEXITSTATUS(status); -#if JOBS +#ifdef JOBS else if (WIFSTOPPED(status)) retval = WSTOPSIG(status) + 128; #endif @@ -5923,7 +7136,7 @@ start: } } else { for (jp = jobtab ; ; jp++) { - if (jp >= jobtab + njobs) { /* no running procs */ + if (jp >= jobtab + njobs) { /* no running procs */ return 0; } if (jp->used && jp->state == 0) @@ -5943,16 +7156,15 @@ start: */ static struct job * -getjob(name) - char *name; - { +getjob(const char *name) +{ int jobno; struct job *jp; int pid; int i; if (name == NULL) { -#if JOBS +#ifdef JOBS currentjob: if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0) error("No current job"); @@ -5966,7 +7178,7 @@ currentjob: if (jobno > 0 && jobno <= njobs && jobtab[jobno - 1].used != 0) return &jobtab[jobno - 1]; -#if JOBS +#ifdef JOBS } else if (name[1] == '%' && name[2] == '\0') { goto currentjob; #endif @@ -5983,8 +7195,7 @@ currentjob: if (found) return found; } - } else if (is_number(name)) { - pid = number(name); + } else if (is_number(name, &pid)) { for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { if (jp->used && jp->nprocs > 0 && jp->ps[jp->nprocs - 1].pid == pid) @@ -6001,7 +7212,7 @@ currentjob: * Return a new job structure, */ -struct job * +static struct job * makejob(node, nprocs) union node *node; int nprocs; @@ -6037,7 +7248,7 @@ makejob(node, nprocs) jp->used = 1; jp->changed = 0; jp->nprocs = 0; -#if JOBS +#ifdef JOBS jp->jobctl = jobctl; #endif if (nprocs > 1) { @@ -6057,21 +7268,20 @@ makejob(node, nprocs) * 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. + * 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). */ + + static int -forkshell(jp, n, mode) - union node *n; - struct job *jp; - int mode; +forkshell(struct job *jp, union node *n, int mode) { int pid; int pgrp; @@ -6098,8 +7308,8 @@ forkshell(jp, n, mode) closescript(); INTON; clear_traps(); -#if JOBS - jobctl = 0; /* do job control only in root shell */ +#ifdef JOBS + jobctl = 0; /* do job control only in root shell */ if (wasroot && mode != FORK_NOJOB && mflag) { if (jp == NULL || jp->nprocs == 0) pgrp = getpid(); @@ -6158,7 +7368,7 @@ forkshell(jp, n, mode) setpgid(pid, pgrp); } if (mode == FORK_BG) - backgndpid = pid; /* set $! */ + backgndpid = pid; /* set $! */ if (jp) { struct procstat *ps = &jp->ps[jp->nprocs++]; ps->pid = pid; @@ -6197,7 +7407,7 @@ static int waitforjob(jp) struct job *jp; { -#if JOBS +#ifdef JOBS int mypgrp = getpgrp(); #endif int status; @@ -6206,7 +7416,7 @@ waitforjob(jp) INTOFF; intreceived = 0; -#if JOBS +#ifdef JOBS if (!jobctl) { #else if (!iflag) { @@ -6219,7 +7429,7 @@ waitforjob(jp) while (jp->state == 0) { dowait(1, jp); } -#if JOBS +#ifdef JOBS if (!jobctl) { #else if (!iflag) { @@ -6227,7 +7437,7 @@ waitforjob(jp) sigaction(SIGINT, &oact, 0); if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT); } -#if JOBS +#ifdef JOBS if (jp->jobctl) { #ifdef OLD_TTY_DRIVER if (ioctl(fileno2, TIOCSPGRP, (char *)&mypgrp) < 0) @@ -6244,13 +7454,13 @@ waitforjob(jp) /* convert to 8 bits */ if (WIFEXITED(status)) st = WEXITSTATUS(status); -#if JOBS +#ifdef JOBS else if (WIFSTOPPED(status)) st = WSTOPSIG(status) + 128; #endif else st = WTERMSIG(status) + 128; -#if JOBS +#ifdef JOBS if (jp->jobctl) { /* * This is truly gross. @@ -6263,8 +7473,9 @@ waitforjob(jp) if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) raise(SIGINT); } + if (jp->state == JOBDONE) + #endif - if (! JOBS || jp->state == JOBDONE) freejob(jp); INTON; return st; @@ -6317,14 +7528,14 @@ dowait(block, job) else if (WIFSTOPPED(sp->status)) done = 0; } - if (stopped) { /* stopped or done */ + if (stopped) { /* stopped or done */ int state = done? JOBDONE : JOBSTOPPED; if (jp->state != state) { TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state)); jp->state = state; -#if JOBS +#ifdef JOBS if (done && curjob == jp - jobtab + 1) - curjob = 0; /* no current job */ + curjob = 0; /* no current job */ #endif } } @@ -6333,7 +7544,7 @@ dowait(block, job) INTON; if (! rootshell || ! iflag || (job && thisjob == job)) { core = WCOREDUMP(status); -#if JOBS +#ifdef JOBS if (WIFSTOPPED(status)) sig = WSTOPSIG(status); else #endif @@ -6343,7 +7554,7 @@ dowait(block, job) if (sig != 0 && sig != SIGINT && sig != SIGPIPE) { if (thisjob != job) outfmt(out2, "%d: ", pid); -#if JOBS +#ifdef JOBS if (sig == SIGTSTP && rootshell && iflag) outfmt(out2, "%%%ld ", (long)(job - jobtab + 1)); @@ -6359,7 +7570,7 @@ dowait(block, job) flushout(&errout); #endif } else { - TRACE(("Not printing status: status=%d, sig=%d\n", + TRACE(("Not printing status: status=%d, sig=%d\n", status, sig)); } } else { @@ -6394,64 +7605,30 @@ dowait(block, job) * 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(block, status) int block; int *status; { -#ifdef BSD int flags; flags = 0; -#if JOBS +#ifdef JOBS if (jobctl) flags |= WUNTRACED; #endif if (block == 0) flags |= WNOHANG; return wait3(status, flags, (struct rusage *)NULL); -#else -#ifdef SYSV - int (*save)(); - - if (block == 0) { - gotsigchild = 0; - save = signal(SIGCLD, onsigchild); - signal(SIGCLD, save); - if (gotsigchild == 0) - return 0; - } - return wait(status); -#else - if (block == 0) - return 0; - return wait(status); -#endif -#endif } /* * return 1 if there are stopped jobs, otherwise 0 */ -static int job_warning = 0; static int -stoppedjobs() +stoppedjobs(void) { int jobno; struct job *jp; @@ -6478,26 +7655,51 @@ stoppedjobs() static char *cmdnextc; static int cmdnleft; -#define MAXCMDTEXT 200 +#define MAXCMDTEXT 200 -static char * -commandtext(n) - union node *n; - { - char *name; +static void +cmdputs(const char *s) +{ + const char *p; + char *q; + char c; + int subtype = 0; - cmdnextc = name = ckmalloc(MAXCMDTEXT); - cmdnleft = MAXCMDTEXT - 4; - cmdtxt(n); - *cmdnextc = '\0'; - return name; + if (cmdnleft <= 0) + return; + p = s; + q = cmdnextc; + while ((c = *p++) != '\0') { + if (c == CTLESC) + *q++ = *p++; + else if (c == CTLVAR) { + *q++ = '$'; + if (--cmdnleft > 0) + *q++ = '{'; + subtype = *p++; + } else if (c == '=' && subtype != 0) { + *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL]; + subtype = 0; + } else if (c == CTLENDVAR) { + *q++ = '}'; + } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) + cmdnleft++; /* ignore it */ + else + *q++ = c; + if (--cmdnleft <= 0) { + *q++ = '.'; + *q++ = '.'; + *q++ = '.'; + break; + } + } + cmdnextc = q; } static void -cmdtxt(n) - union node *n; - { +cmdtxt(const union node *n) +{ union node *np; struct nodelist *lp; const char *p; @@ -6624,53 +7826,23 @@ redir: } +static char * +commandtext(const union node *n) +{ + char *name; -static void -cmdputs(s) - const char *s; - { - const char *p; - char *q; - char c; - int subtype = 0; - - if (cmdnleft <= 0) - return; - p = s; - q = cmdnextc; - while ((c = *p++) != '\0') { - if (c == CTLESC) - *q++ = *p++; - else if (c == CTLVAR) { - *q++ = '$'; - if (--cmdnleft > 0) - *q++ = '{'; - subtype = *p++; - } else if (c == '=' && subtype != 0) { - *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL]; - subtype = 0; - } else if (c == CTLENDVAR) { - *q++ = '}'; - } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) - cmdnleft++; /* ignore it */ - else - *q++ = c; - if (--cmdnleft <= 0) { - *q++ = '.'; - *q++ = '.'; - *q++ = '.'; - break; - } - } - cmdnextc = q; + cmdnextc = name = ckmalloc(MAXCMDTEXT); + cmdnleft = MAXCMDTEXT - 4; + cmdtxt(n); + *cmdnextc = '\0'; + return name; } + static void waitonint(int sig) { intreceived = 1; return; } -/* $NetBSD: mail.c,v 1.14 2000/07/03 03:26:19 matt Exp $ */ - /* * Routines to check for mail. (Perhaps make part of main.c?) */ @@ -6679,8 +7851,8 @@ static void waitonint(int sig) { #define MAXMBOXES 10 -static int nmboxes; /* number of mailboxes */ -static time_t mailtime[MAXMBOXES]; /* times of mailboxes */ +static int nmboxes; /* number of mailboxes */ +static time_t mailtime[MAXMBOXES]; /* times of mailboxes */ @@ -6691,8 +7863,7 @@ static time_t mailtime[MAXMBOXES]; /* times of mailboxes */ */ static void -chkmail(silent) - int silent; +chkmail(int silent) { int i; const char *mpath; @@ -6718,18 +7889,7 @@ chkmail(silent) if (q[-1] != '/') abort(); #endif - q[-1] = '\0'; /* delete trailing '/' */ -#ifdef notdef /* this is what the System V shell claims to do (it lies) */ - if (stat(p, &statb) < 0) - statb.st_mtime = 0; - if (statb.st_mtime > mailtime[i] && ! silent) { - outfmt( - &errout, snlfmt, - pathopt? pathopt : "you have mail" - ); - } - mailtime[i] = statb.st_mtime; -#else /* this is what it should do */ + q[-1] = '\0'; /* delete trailing '/' */ if (stat(p, &statb) < 0) statb.st_size = 0; if (statb.st_size > mailtime[i] && ! silent) { @@ -6739,28 +7899,27 @@ chkmail(silent) ); } mailtime[i] = statb.st_size; -#endif } nmboxes = i; popstackmark(&smark); } -/* $NetBSD: main.c,v 1.40 2001/02/04 19:52:06 christos Exp $ */ - #define PROFILE 0 -static int rootpid; -static int rootshell; #if PROFILE -short profile_buf[16384]; +static short profile_buf[16384]; extern int etext(); #endif -static void read_profile __P((const char *)); -static char *find_dot_file __P((char *)); -int shell_main __P((int, char **)); +static void read_profile (const char *); +static char *find_dot_file (char *); +static void cmdloop (int); +static void options (int); +static void minus_o (char *, int); +static void setoption (int, int); +static void procargs (int, char **); + -extern int oexitstatus; /* * Main routine. We initialize things, parse the arguments, execute * profiles if we're a login shell, and then call cmdloop to execute @@ -6781,7 +7940,6 @@ shell_main(argc, argv) DOTCMD = find_builtin("."); BLTINCMD = find_builtin("builtin"); - COMMANDCMD = find_builtin("command"); EXECCMD = find_builtin("exec"); EVALCMD = find_builtin("eval"); @@ -6824,18 +7982,14 @@ shell_main(argc, argv) exitshell(exitstatus); } reset(); - if (exception == EXINT -#if ATTY - && (! attyset() || equal(termval(), "emacs")) -#endif - ) { + if (exception == EXINT) { out2c('\n'); #ifdef FLUSHERR flushout(out2); #endif } popstackmark(&smark); - FORCEINTON; /* enable interrupts */ + FORCEINTON; /* enable interrupts */ if (state == 1) goto state1; else if (state == 2) @@ -6878,7 +8032,7 @@ state3: state = 4; if (sflag == 0 || minusc) { static int sigs[] = { - SIGINT, SIGQUIT, SIGHUP, + SIGINT, SIGQUIT, SIGHUP, #ifdef SIGTSTP SIGTSTP, #endif @@ -6895,7 +8049,7 @@ state3: evalstring(minusc, 0); if (sflag || minusc == NULL) { -state4: /* XXX ??? - why isn't this before the "if" statement */ +state4: /* XXX ??? - why isn't this before the "if" statement */ cmdloop(1); } #if PROFILE @@ -6912,8 +8066,7 @@ state4: /* XXX ??? - why isn't this before the "if" statement */ */ static void -cmdloop(top) - int top; +cmdloop(int top) { union node *n; struct stackmark smark; @@ -7002,8 +8155,7 @@ read_profile(name) */ static void -readcmdfile(name) - char *name; +readcmdfile(const char *name) { int fd; @@ -7064,7 +8216,7 @@ dotcmd(argc, argv) for (sp = cmdenviron; sp ; sp = sp->next) setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED); - if (argc >= 2) { /* That's what SVR2 does */ + if (argc >= 2) { /* That's what SVR2 does */ char *fullname; struct stackmark smark; @@ -7094,38 +8246,8 @@ exitcmd(argc, argv) exitshell(exitstatus); /* NOTREACHED */ } -/* $NetBSD: memalloc.c,v 1.23 2000/11/01 19:56:01 christos Exp $ */ - -/* - * 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. - */ - -#define MINSIZE 504 /* minimum size of a block */ - - -struct stack_block { - struct stack_block *prev; - char space[MINSIZE]; -}; - -struct stack_block stackbase; -struct stack_block *stackp = &stackbase; -struct stackmark *markp; -static char *stacknxt = stackbase.space; -static int stacknleft = MINSIZE; -static int sstrnleft; -static int herefd = -1; - - - -pointer -stalloc(nbytes) - int nbytes; +static pointer +stalloc(int nbytes) { char *p; @@ -7153,11 +8275,10 @@ stalloc(nbytes) static void -stunalloc(p) - pointer p; - { +stunalloc(pointer p) +{ #ifdef DEBUG - if (p == NULL) { /*DEBUG */ + if (p == NULL) { /*DEBUG */ write(2, "stunalloc\n", 10); abort(); } @@ -7170,11 +8291,9 @@ stunalloc(p) } - static void -setstackmark(mark) - struct stackmark *mark; - { +setstackmark(struct stackmark *mark) +{ mark->stackp = stackp; mark->stacknxt = stacknxt; mark->stacknleft = stacknleft; @@ -7184,9 +8303,8 @@ setstackmark(mark) static void -popstackmark(mark) - struct stackmark *mark; - { +popstackmark(struct stackmark *mark) +{ struct stack_block *sp; INTOFF; @@ -7213,7 +8331,7 @@ popstackmark(mark) */ static void -growstackblock() { +growstackblock(void) { char *p; int newlen = ALIGN(stacknleft * 2 + 100); char *oldspace = stacknxt; @@ -7233,7 +8351,7 @@ growstackblock() { stacknleft = newlen; { /* Stack marks pointing to the start of the old block - * must be relocated to point to the new block + * must be relocated to point to the new block */ struct stackmark *xmark; xmark = markp; @@ -7248,16 +8366,15 @@ growstackblock() { } else { p = stalloc(newlen); memcpy(p, oldspace, oldlen); - stacknxt = p; /* free the space */ - stacknleft += newlen; /* we just allocated */ + stacknxt = p; /* free the space */ + stacknleft += newlen; /* we just allocated */ } } -static void -grabstackblock(len) - int len; +static inline void +grabstackblock(int len) { len = ALIGN(len); stacknxt += len; @@ -7286,7 +8403,7 @@ grabstackblock(len) static char * -growstackstr() { +growstackstr(void) { int len = stackblocksize(); if (herefd >= 0 && len >= 1024) { xwrite(herefd, stackblock(), len); @@ -7316,16 +8433,12 @@ makestrspace(size_t newlen) { static void -ungrabstackstr(s, p) - char *s; - char *p; - { +ungrabstackstr(char *s, char *p) +{ stacknleft += stacknxt - s; stacknxt = s; sstrnleft = stacknleft - (p - s); } -/* $NetBSD: miscbltin.c,v 1.30 2001/02/04 19:52:06 christos Exp $ */ - /* * Miscelaneous builtins. */ @@ -7334,7 +8447,7 @@ ungrabstackstr(s, p) #undef rflag #ifdef __GLIBC__ -mode_t getmode(const void *, mode_t); +static mode_t getmode(const void *, mode_t); static void *setmode(const char *); #if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 @@ -7531,46 +8644,46 @@ umaskcmd(argc, argv) struct limits { const char *name; - int cmd; - int factor; /* multiply by to get rlim_{cur,max} values */ - char option; + 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' }, + { "time(seconds)", RLIMIT_CPU, 1, 't' }, #endif #ifdef RLIMIT_FSIZE - { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, + { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, #endif #ifdef RLIMIT_DATA - { "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, + { "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, #endif #ifdef RLIMIT_STACK - { "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, + { "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, #endif #ifdef RLIMIT_CORE - { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, + { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, #endif #ifdef RLIMIT_RSS - { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, + { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, #endif #ifdef RLIMIT_MEMLOCK - { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, + { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, #endif #ifdef RLIMIT_NPROC - { "process(processes)", RLIMIT_NPROC, 1, 'p' }, + { "process(processes)", RLIMIT_NPROC, 1, 'p' }, #endif #ifdef RLIMIT_NOFILE - { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' }, + { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' }, #endif #ifdef RLIMIT_VMEM - { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' }, + { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' }, #endif #ifdef RLIMIT_SWAP - { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' }, + { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' }, #endif - { (char *) 0, 0, 0, '\0' } + { (char *) 0, 0, 0, '\0' } }; static int @@ -7578,14 +8691,14 @@ ulimitcmd(argc, argv) int argc; char **argv; { - int c; + int c; rlim_t val = 0; enum { SOFT = 0x1, HARD = 0x2 } how = SOFT | HARD; - const struct limits *l; - int set, all = 0; - int optc, what; - struct rlimit limit; + const struct limits *l; + int set, all = 0; + int optc, what; + struct rlimit limit; what = 'f'; while ((optc = nextopt("HSatfdsmcnpl")) != '\0') @@ -7644,11 +8757,7 @@ ulimitcmd(argc, argv) else { val /= l->factor; -#ifdef BSD4_4 out1fmt("%lld\n", (long long) val); -#else - out1fmt("%ld\n", (long) val); -#endif } } return 0; @@ -7661,7 +8770,7 @@ ulimitcmd(argc, argv) if (how & SOFT) limit.rlim_cur = val; if (setrlimit(l->cmd, &limit) < 0) - error("error setting limit (%s)", strerror(errno)); + error("error setting limit (%m)"); } else { if (how & SOFT) val = limit.rlim_cur; @@ -7673,63 +8782,11 @@ ulimitcmd(argc, argv) else { val /= l->factor; -#ifdef BSD4_4 out1fmt("%lld\n", (long long) val); -#else - out1fmt("%ld\n", (long) val); -#endif } } return 0; } -/* $NetBSD: mystring.c,v 1.14 1999/07/09 03:05:50 christos Exp $ */ - -/* - * 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. - */ - -static char nullstr[1]; /* zero length string */ -static const char spcstr[] = " "; -static const char snlfmt[] = "%s\n"; - -/* - * 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". - */ - -static void -scopyn(from, to, size) - char const *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. */ @@ -7746,40 +8803,42 @@ prefix(pfx, string) return 1; } - /* - * Convert a string of digits to an integer, printing an error message on - * failure. + * Return true if s is a string of digits, and save munber in intptr + * nagative is bad */ static int -number(s) - const char *s; - { - - if (! is_number(s)) - error("Illegal number: %s", s); - return atoi(s); -} +is_number(const char *p, int *intptr) +{ + int ret = 0; + do { + if (! is_digit(*p)) + return 0; + ret *= 10; + ret += digit_val(*p); + p++; + } while (*p != '\0'); + *intptr = ret; + return 1; +} /* - * Check for a valid number. This should be elsewhere. + * Convert a string of digits to an integer, printing an error message on + * failure. */ static int -is_number(p) - const char *p; - { - do { - if (! is_digit(*p)) - return 0; - } while (*++p != '\0'); - return 1; +number(const char *s) +{ + int i; + if (! is_number(s, &i)) + error("Illegal number: %s", s); + return i; } - /* * Produce a possibly single quoted string suitable as input to the shell. * The return string is allocated on the stack. @@ -7863,38 +8922,20 @@ sstrdup(const char *p) return memcpy(stalloc(len), p, len); } -/* - * Wrapper around strcmp for qsort/bsearch/... - */ -static 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. - */ -static const char *const * -findstring(const char *s, const char *const *array, size_t nmemb) -{ - return bsearch(&s, array, nmemb, sizeof(const char *), pstrcmp); -} /* * This file was generated by the mknodes program. */ -/* $NetBSD: nodes.c.pat,v 1.8 1997/04/11 23:03:09 christos Exp $ */ - /* * Routine for dealing with parsed shell commands. */ -static int funcblocksize; /* size of structures in function */ -static int funcstringsize; /* size of strings in node */ -pointer funcblock; /* block to allocate function from */ -static char *funcstring; /* block to allocate strings from */ +static int funcblocksize; /* size of structures in function */ +static int funcstringsize; /* size of strings in node */ +static pointer funcblock; /* block to allocate function from */ +static char *funcstring; /* block to allocate strings from */ static const short nodesize[26] = { ALIGN(sizeof (struct nbinary)), @@ -7926,11 +8967,11 @@ static const short nodesize[26] = { }; -static void calcsize __P((union node *)); -static void sizenodelist __P((struct nodelist *)); -static union node *copynode __P((union node *)); -static struct nodelist *copynodelist __P((struct nodelist *)); -static char *nodesavestr __P((char *)); +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 *); @@ -7938,9 +8979,8 @@ static char *nodesavestr __P((char *)); * Make a copy of a parse tree. */ -union node * -copyfunc(n) - union node *n; +static union node * +copyfunc(union node *n) { if (n == NULL) return NULL; @@ -8181,54 +9221,8 @@ nodesavestr(s) #endif } - - -/* - * Free a parse tree. - */ - -static void -freefunc(n) - union node *n; -{ - if (n) - ckfree(n); -} -/* $NetBSD: options.c,v 1.31 2001/02/26 13:06:43 wiz Exp $ */ - - -struct optent optlist[NOPTS] = { - { "errexit", 'e', 0 }, - { "noglob", 'f', 0 }, - { "ignoreeof", 'I', 0 }, - { "interactive",'i', 0 }, - { "monitor", 'm', 0 }, - { "noexec", 'n', 0 }, - { "stdin", 's', 0 }, - { "xtrace", 'x', 0 }, - { "verbose", 'v', 0 }, - { "vi", 'V', 0 }, - { "emacs", 'E', 0 }, - { "noclobber", 'C', 0 }, - { "allexport", 'a', 0 }, - { "notify", 'b', 0 }, - { "nounset", 'u', 0 }, - { "quietprofile", 'q', 0 }, -}; -static char *arg0; /* value of $0 */ -struct shparam shellparam; /* current positional parameters */ -static char **argptr; /* argument list for builtin commands */ -static char *optionarg; /* set by nextopt (like getopt) */ -static char *optptr; /* used by nextopt */ - -static char *minusc; /* argument to -c option */ - - -static void options __P((int)); -static void minus_o __P((char *, int)); -static void setoption __P((int, int)); #ifdef ASH_GETOPTS -static int getopts __P((char *, char *, char **, int *, int *)); +static int getopts (char *, char *, char **, int *, int *); #endif @@ -8247,7 +9241,7 @@ procargs(argc, argv) if (argc > 0) argptr++; for (i = 0; i < NOPTS; i++) - optlist[i].val = 2; + optent_val(i) = 2; options(1); if (*argptr == NULL && minusc == NULL) sflag = 1; @@ -8256,8 +9250,8 @@ procargs(argc, argv) if (mflag == 2) mflag = iflag; for (i = 0; i < NOPTS; i++) - if (optlist[i].val == 2) - optlist[i].val = 0; + if (optent_val(i) == 2) + optent_val(i) = 0; arg0 = argv[0]; if (sflag == 0 && minusc == NULL) { commandname = argv[0]; @@ -8267,7 +9261,7 @@ procargs(argc, argv) } /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ if (argptr && minusc && *argptr) - arg0 = *argptr++; + arg0 = *argptr++; shellparam.p = argptr; shellparam.optind = 1; @@ -8281,12 +9275,6 @@ procargs(argc, argv) } -static void -optschanged() -{ - setinteractive(iflag); - setjobctl(mflag); -} /* * Process shell options. The global variable argptr contains a pointer @@ -8307,16 +9295,16 @@ options(cmdline) 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) + 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 */ + } + break; /* "-" or "--" terminates options */ } } else if (c == '+') { val = 0; @@ -8327,7 +9315,7 @@ options(cmdline) while ((c = *p++) != '\0') { if (c == 'c' && cmdline) { char *q; -#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ +#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ if (*p == '\0') #endif q = *argptr++; @@ -8358,12 +9346,12 @@ minus_o(name, val) if (name == NULL) { out1str("Current option settings\n"); for (i = 0; i < NOPTS; i++) - out1fmt("%-16s%s\n", optlist[i].name, - optlist[i].val ? "on" : "off"); + out1fmt("%-16s%s\n", optent_name(optlist[i]), + optent_val(i) ? "on" : "off"); } else { for (i = 0; i < NOPTS; i++) - if (equal(name, optlist[i].name)) { - setoption(optlist[i].letter, val); + if (equal(name, optent_name(optlist[i]))) { + setoption(optent_letter(optlist[i]), val); return; } error("Illegal option -o %s", name); @@ -8372,15 +9360,13 @@ minus_o(name, val) static void -setoption(flag, val) - char flag; - int val; - { +setoption(int flag, int val) +{ int i; for (i = 0; i < NOPTS; i++) - if (optlist[i].letter == flag) { - optlist[i].val = val; + if (optent_letter(optlist[i]) == flag) { + optent_val(i) = val; if (val) { /* #%$ hack for ksh semantics */ if (flag == 'V') @@ -8396,26 +9382,13 @@ setoption(flag, val) -#ifdef mkinit -SHELLPROC { - int i; - - for (i = 0; i < NOPTS; i++) - optlist[i].val = 0; - optschanged(); - -} -#endif - - /* * Set the shell parameters. */ static void -setparam(argv) - char **argv; - { +setparam(char **argv) +{ char **newparam; char **ap; int nparam; @@ -8440,9 +9413,8 @@ setparam(argv) */ static void -freeparam(param) - volatile struct shparam *param; - { +freeparam(volatile struct shparam *param) +{ char **ap; if (param->malloc) { @@ -8510,13 +9482,27 @@ setcmd(argc, argv) static void -getoptsreset(value) - const char *value; +getoptsreset(const char *value) { shellparam.optind = number(value); shellparam.optoff = -1; } +#ifdef BB_LOCALE_SUPPORT +static void change_lc_all(const char *value) +{ + if(value != 0 && *value != 0) + setlocale(LC_ALL, value); +} + +static void change_lc_ctype(const char *value) +{ + if(value != 0 && *value != 0) + setlocale(LC_CTYPE, value); +} + +#endif + #ifdef ASH_GETOPTS /* * The getopts builtin. Shellparam.optnext points to the next argument @@ -8612,7 +9598,7 @@ atend: goto out; } optnext++; - if (p[0] == '-' && p[1] == '\0') /* check for "--" */ + if (p[0] == '-' && p[1] == '\0') /* check for "--" */ goto atend; } @@ -8679,7 +9665,7 @@ out: } return done; } -#endif +#endif /* * XXX - should get rid of. have all builtins use getopt(3). the @@ -8705,7 +9691,7 @@ nextopt(optstring) if (p == NULL || *p != '-' || *++p == '\0') return '\0'; argptr++; - if (p[0] == '-' && p[1] == '\0') /* check for "--" */ + if (p[0] == '-' && p[1] == '\0') /* check for "--" */ return '\0'; } c = *p++; @@ -8726,66 +9712,21 @@ nextopt(optstring) } -/* $NetBSD: output.c,v 1.23 2001/01/07 23:39:07 lukem Exp $ */ - /* * 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. + * 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. */ -#define OUTBUFSIZ BUFSIZ -#define MEM_OUT -3 /* output to dynamically allocated memory */ - - -#ifdef USE_GLIBC_STDIO -struct output output = {NULL, NULL, 0, NULL, 0, 1, 0}; -struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0}; -struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0}; -#else -struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; -struct output errout = {NULL, 0, NULL, 0, 2, 0}; -struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; -#endif -struct output *out1 = &output; -struct output *out2 = &errout; - #ifndef USE_GLIBC_STDIO -static void __outstr __P((const char *, size_t, struct output*)); -#endif - - -#ifdef mkinit - -INCLUDE "output.h" -INCLUDE "memalloc.h" - -INIT { -#ifdef USE_GLIBC_STDIO - initstreams(); -#endif -} - -RESET { - out1 = &output; - out2 = &errout; -#ifdef USE_GLIBC_STDIO - if (memout.stream != NULL) - __closememout(); -#endif - if (memout.buf != NULL) { - ckfree(memout.buf); - memout.buf = NULL; - } -} - +static void __outstr (const char *, size_t, struct output*); #endif @@ -8835,10 +9776,8 @@ __outstr(const char *p, size_t len, struct output *dest) { static void -outstr(p, file) - const char *p; - struct output *file; - { +outstr(const char *p, struct output *file) +{ #ifdef USE_GLIBC_STDIO INTOFF; fputs(p, file->stream); @@ -8990,232 +9929,26 @@ fmtstr(va_alist) } #ifndef USE_GLIBC_STDIO -/* - * Formatted output. This routine handles a subset of the printf formats: - * - Formats supported: d, u, o, p, X, s, and c. - * - The x format is also accepted but is treated like X. - * - The l, ll and q modifiers are accepted. - * - The - and # flags are accepted; # only works with the o format. - * - Width and precision may be specified with any format except c. - * - An * may be given for the width or precision. - * - The obsolete practice of preceding the width with a zero to get - * zero padding is not supported; use the precision field. - * - A % may be printed by writing %% in the format string. - */ - -#define TEMPSIZE 24 - -#ifdef BSD4_4 -#define HAVE_VASPRINTF 1 -#endif - -#if !HAVE_VASPRINTF -static const char digit[] = "0123456789ABCDEF"; -#endif - static void -doformat(dest, f, ap) - struct output *dest; - const char *f; /* format string */ - va_list ap; +doformat(struct output *dest, const char *f, va_list ap) { -#if HAVE_VASPRINTF - char *s, *t; - int len; + char *pm; + int size = BUFSIZ; - INTOFF; - len = vasprintf(&t, f, ap); - if (len < 0) { - return; - } - s = stalloc(++len); - memcpy(s, t, len); - free(t); - INTON; - outstr(s, dest); - stunalloc(s); -#else /* !HAVE_VASPRINTF */ - char c; - char temp[TEMPSIZE]; - int flushleft; - int sharp; - int width; - int prec; - int islong; - int isquad; - char *p; - int sign; -#ifdef BSD4_4 - quad_t l; - u_quad_t num; -#else - long l; - u_long num; -#endif - unsigned base; - int len; - int size; - int pad; + while(size) { + int nchars; - while ((c = *f++) != '\0') { - if (c != '%') { - outc(c, dest); - continue; - } - flushleft = 0; - sharp = 0; - width = 0; - prec = -1; - islong = 0; - isquad = 0; - for (;;) { - if (*f == '-') - flushleft++; - else if (*f == '#') - sharp++; - else - break; - f++; - } - if (*f == '*') { - width = va_arg(ap, int); - f++; - } else { - while (is_digit(*f)) { - width = 10 * width + digit_val(*f++); + pm = xmalloc(size); + nchars = vsnprintf(pm, size, f, ap); + if(nchars > -1) { + outstr(pm, dest); + size = 0; } - } - if (*f == '.') { - if (*++f == '*') { - prec = va_arg(ap, int); - f++; - } else { - prec = 0; - while (is_digit(*f)) { - prec = 10 * prec + digit_val(*f++); - } - } - } - if (*f == 'l') { - f++; - if (*f == 'l') { - isquad++; - f++; - } else - islong++; - } else if (*f == 'q') { - isquad++; - f++; - } - switch (*f) { - case 'd': -#ifdef BSD4_4 - if (isquad) - l = va_arg(ap, quad_t); - else -#endif - if (islong) - l = va_arg(ap, long); - else - l = va_arg(ap, int); - sign = 0; - num = l; - if (l < 0) { - num = -l; - sign = 1; - } - base = 10; - goto number; - case 'u': - base = 10; - goto uns_number; - case 'o': - base = 8; - goto uns_number; - case 'p': - outc('0', dest); - outc('x', dest); - /*FALLTHROUGH*/ - case 'x': - /* we don't implement 'x'; treat like 'X' */ - case 'X': - base = 16; -uns_number: /* an unsigned number */ - sign = 0; -#ifdef BSD4_4 - if (isquad) - num = va_arg(ap, u_quad_t); - else -#endif - if (islong) - num = va_arg(ap, unsigned long); - else - num = va_arg(ap, unsigned int); -number: /* process a number */ - p = temp + TEMPSIZE - 1; - *p = '\0'; - while (num) { - *--p = digit[num % base]; - num /= base; - } - len = (temp + TEMPSIZE - 1) - p; - if (prec < 0) - prec = 1; - if (sharp && *f == 'o' && prec <= len) - prec = len + 1; - pad = 0; - if (width) { - size = len; - if (size < prec) - size = prec; - size += sign; - pad = width - size; - if (flushleft == 0) { - while (--pad >= 0) - outc(' ', dest); - } - } - if (sign) - outc('-', dest); - prec -= len; - while (--prec >= 0) - outc('0', dest); - while (*p) - outc(*p++, dest); - while (--pad >= 0) - outc(' ', dest); - break; - case 's': - p = va_arg(ap, char *); - pad = 0; - if (width) { - len = strlen(p); - if (prec >= 0 && len > prec) - len = prec; - pad = width - len; - if (flushleft == 0) { - while (--pad >= 0) - outc(' ', dest); - } - } - prec++; - while (--prec != 0 && *p) - outc(*p++, dest); - while (--pad >= 0) - outc(' ', dest); - break; - case 'c': - c = va_arg(ap, int); - outc(c, dest); - break; - default: - outc(*f, dest); - break; - } - f++; + else + size *= 2; + free(pm); } -#endif /* !HAVE_VASPRINTF */ } #endif @@ -9226,11 +9959,8 @@ number: /* process a number */ */ static int -xwrite(fd, buf, nbytes) - int fd; - const char *buf; - int nbytes; - { +xwrite(int fd, const char *buf, int nbytes) +{ int ntry; int i; int n; @@ -9254,26 +9984,6 @@ xwrite(fd, buf, nbytes) } -#ifdef notdef -/* - * Version of ioctl that retries after a signal is caught. - * XXX unused function - */ - -static int -xioctl(fd, request, arg) - int fd; - unsigned long request; - char * arg; -{ - int i; - - while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); - return i; -} -#endif - - #ifdef USE_GLIBC_STDIO static void initstreams() { output.stream = stdout; @@ -9297,8 +10007,6 @@ __closememout() { return error; } #endif -/* $NetBSD: parser.c,v 1.46 2001/02/04 19:52:06 christos Exp $ */ - /* * Shell command parser. */ @@ -9308,47 +10016,42 @@ __closememout() { 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 *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 */ }; +static struct heredoc *heredoclist; /* list of here documents to read */ +static int parsebackquote; /* nonzero if we are inside backquotes */ +static int doprompt; /* if set, prompt the user */ +static int needprompt; /* true if interactive and at start of line */ +static int lasttoken; /* last token read */ +static char *wordtext; /* text of last word returned by readtoken */ -struct heredoc *heredoclist; /* list of here documents to read */ -static int parsebackquote; /* nonzero if we are inside backquotes */ -static int doprompt; /* if set, prompt the user */ -static int needprompt; /* true if interactive and at start of line */ -static int lasttoken; /* last token read */ -static int tokpushback; /* last token pushed back */ -static char *wordtext; /* text of last word returned by readtoken */ -static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ -/* 1 == check for aliases, 2 == also check for assignments */ -static int checkalias; -struct nodelist *backquotelist; -union node *redirnode; +static struct nodelist *backquotelist; +static union node *redirnode; struct heredoc *heredoc; -static int quoteflag; /* set if (part of) last token was quoted */ -static int startlinno; /* line # where last token started */ +static int quoteflag; /* set if (part of) last token was quoted */ +static int startlinno; /* line # where last token started */ -static union node *list __P((int)); -static union node *andor __P((void)); -static union node *pipeline __P((void)); -static union node *command __P((void)); -static union node *simplecmd __P((void)); -static union node *makename __P((void)); -static void parsefname __P((void)); -static void parseheredoc __P((void)); -static int peektoken __P((void)); -static int readtoken __P((void)); -static int xxreadtoken __P((void)); -static int readtoken1 __P((int, char const *, char *, int)); -static int noexpand __P((char *)); -static void synexpect __P((int)) __attribute__((noreturn)); -static void synerror __P((const char *)) __attribute__((noreturn)); -static void setprompt __P((int)); +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 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 int noexpand (char *); +static void synexpect (int) __attribute__((noreturn)); +static void synerror (const char *) __attribute__((noreturn)); +static void setprompt (int); /* @@ -9356,7 +10059,7 @@ static void setprompt __P((int)); * valid parse tree indicating a blank line.) */ -union node * +static union node * parsecmd(int interact) { int t; @@ -9436,7 +10139,7 @@ list(nlflag) if (heredoclist) parseheredoc(); else - pungetc(); /* push back EOF on input */ + pungetc(); /* push back EOF on input */ return n1; default: if (nlflag) @@ -9746,7 +10449,9 @@ simplecmd() { redir = NULL; rpp = &redir; +#ifdef ASH_ALIAS checkalias = 2; +#endif for (;;) { switch (readtoken()) { case TWORD: @@ -9766,7 +10471,7 @@ simplecmd() { case TREDIR: *rpp = n = redirnode; rpp = &n->nfile.next; - parsefname(); /* read name of redirection file */ + parsefname(); /* read name of redirection file */ break; case TLP: if ( @@ -9776,10 +10481,6 @@ simplecmd() { /* We have a function */ if (readtoken() != TRP) synexpect(TRP); -#ifdef notdef - if (! goodname(n->narg.text)) - synerror("Bad function name"); -#endif n->type = NDEFUN; checkkwd = 2; n->narg.next = command(); @@ -9805,7 +10506,7 @@ out: } static union node * -makename() { +makename(void) { union node *n; n = (union node *)stalloc(sizeof (struct narg)); @@ -9817,7 +10518,7 @@ makename() { } static void fixredir(union node *n, const char *text, int err) - { +{ TRACE(("Fix redir %s %d\n", text, err)); if (!err) n->ndup.vname = NULL; @@ -9837,7 +10538,7 @@ static void fixredir(union node *n, const char *text, int err) static void -parsefname() { +parsefname(void) { union node *n = redirnode; if (readtoken() != TWORD) @@ -9912,16 +10613,25 @@ peektoken() { static int readtoken() { int t; +#ifdef ASH_ALIAS int savecheckkwd = checkkwd; int savecheckalias = checkalias; struct alias *ap; +#endif + #ifdef DEBUG int alreadyseen = tokpushback; #endif +#ifdef ASH_ALIAS top: +#endif + t = xxreadtoken(); + +#ifdef ASH_ALIAS checkalias = savecheckalias; +#endif if (checkkwd) { /* @@ -9950,6 +10660,7 @@ top: } } +#ifdef ASH_ALIAS if (t != TWORD) { if (t != TREDIR) { checkalias = 0; @@ -9966,6 +10677,7 @@ top: } checkalias = 0; } +#endif out: #ifdef DEBUG if (!alreadyseen) @@ -9980,12 +10692,12 @@ out: /* * 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. + * 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. + * the redirection. * In all cases, the variable startlinno is set to the number of the line - * on which the token starts. + * on which the token starts. * * [Change comment: here documents and internal procedures] * [Readtoken shouldn't have any arguments. Perhaps we should make the @@ -9995,7 +10707,7 @@ out: * have parseword (readtoken1?) handle both words and redirection.] */ -#define RETURN(token) return lasttoken = token +#define RETURN(token) return lasttoken = token static int xxreadtoken() { @@ -10010,7 +10722,7 @@ xxreadtoken() { needprompt = 0; } startlinno = plinno; - for (;;) { /* until token or start of word found */ + for (;;) { /* until token or start of word found */ c = pgetc_macro(); switch (c) { case ' ': case '\t': @@ -10079,12 +10791,12 @@ breakloop: * 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:;} +#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(firstc, syntax, eofmark, striptabs) @@ -10100,12 +10812,12 @@ readtoken1(firstc, syntax, eofmark, striptabs) 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 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; - char const *prevsyntax; /* syntax before arithmetic */ + char const *prevsyntax; /* syntax before arithmetic */ #if __GNUC__ /* Avoid longjmp clobbering */ (void) &out; @@ -10132,24 +10844,14 @@ readtoken1(firstc, syntax, eofmark, striptabs) 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(3, out); /* permit 3 calls to USTPUTC */ + loop: { /* for each line, until end of word */ + CHECKEND(); /* set c to PEOF if at end of here document */ + for (;;) { /* until end of line or end of word */ + CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ switch(syntax[c]) { - case CNL: /* '\n' */ + case CNL: /* '\n' */ if (syntax == BASESYNTAX) - goto endword; /* exit outer loop */ + goto endword; /* exit outer loop */ USTPUTC(c, out); plinno++; if (doprompt) @@ -10157,7 +10859,7 @@ readtoken1(firstc, syntax, eofmark, striptabs) else setprompt(0); c = pgetc(); - goto loop; /* continue outer loop */ + goto loop; /* continue outer loop */ case CWORD: USTPUTC(c, out); break; @@ -10167,7 +10869,7 @@ readtoken1(firstc, syntax, eofmark, striptabs) USTPUTC(CTLESC, out); USTPUTC(c, out); break; - case CBACK: /* backslash */ + case CBACK: /* backslash */ c = pgetc2(); if (c == PEOF) { USTPUTC('\\', out); @@ -10216,10 +10918,10 @@ readtoken1(firstc, syntax, eofmark, striptabs) quotef++; } break; - case CVAR: /* '$' */ - PARSESUB(); /* parse substitution */ + case CVAR: /* '$' */ + PARSESUB(); /* parse substitution */ break; - case CENDVAR: /* '}' */ + case CENDVAR: /* '}' */ if (varnest > 0) { varnest--; if (dqvarnest > 0) { @@ -10231,11 +10933,11 @@ readtoken1(firstc, syntax, eofmark, striptabs) } break; #ifdef ASH_MATH_SUPPORT - case CLP: /* '(' in arithmetic */ + case CLP: /* '(' in arithmetic */ parenlevel++; USTPUTC(c, out); break; - case CRP: /* ')' in arithmetic */ + case CRP: /* ')' in arithmetic */ if (parenlevel > 0) { USTPUTC(c, out); --parenlevel; @@ -10261,16 +10963,16 @@ readtoken1(firstc, syntax, eofmark, striptabs) } break; #endif - case CBQUOTE: /* '`' */ + case CBQUOTE: /* '`' */ PARSEBACKQOLD(); break; - case CEOF: - goto endword; /* exit outer loop */ + case CENDFILE: + goto endword; /* exit outer loop */ case CIGN: break; default: if (varnest == 0) - goto endword; /* exit outer loop */ + goto endword; /* exit outer loop */ if (c != PEOA) { USTPUTC(c, out); } @@ -10318,9 +11020,11 @@ endword: checkend: { if (eofmark) { +#ifdef ASH_ALIAS if (c == PEOA) { c = pgetc2(); } +#endif if (striptabs) { while (c == '\t') { c = pgetc2(); @@ -10370,7 +11074,7 @@ parseredir: { np->type = NTO; pungetc(); } - } else { /* c == '<' */ + } else { /* c == '<' */ np->nfile.fd = 0; switch (c = pgetc()) { case '<': @@ -10429,7 +11133,7 @@ parsesub: { ) { USTPUTC('$', out); pungetc(); - } else if (c == '(') { /* $(command) or $((arith)) */ + } else if (c == '(') { /* $(command) or $((arith)) */ if (pgetc() == '(') { PARSEARITH(); } else { @@ -10468,7 +11172,7 @@ parsesub: { c = pgetc(); } else -badsub: synerror("Bad substitution"); +badsub: synerror("Bad substitution"); STPUTC('=', out); flags = 0; @@ -10553,17 +11257,17 @@ parsebackq: { savehandler = handler; handler = &jmploc; INTON; - 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; - int psavelen; - char *pstr; + 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; + int psavelen; + char *pstr; - STARTSTACKSTR(pout); + STARTSTACKSTR(pout); for (;;) { if (needprompt) { setprompt(2); @@ -10574,7 +11278,7 @@ parsebackq: { goto done; case '\\': - if ((pc = pgetc()) == '\n') { + if ((pc = pgetc()) == '\n') { plinno++; if (doprompt) setprompt(2); @@ -10588,17 +11292,19 @@ parsebackq: { */ continue; } - if (pc != '\\' && pc != '`' && pc != '$' - && (!dblquote || pc != '"')) - STPUTC('\\', pout); + if (pc != '\\' && pc != '`' && pc != '$' + && (!dblquote || pc != '"')) + STPUTC('\\', pout); if (pc > PEOA) { break; } /* fall through */ case PEOF: +#ifdef ASH_ALIAS case PEOA: - startlinno = plinno; +#endif + startlinno = plinno; synerror("EOF in backquote substitution"); case '\n': @@ -10610,15 +11316,15 @@ parsebackq: { break; } STPUTC(pc, pout); - } + } done: - STPUTC('\0', pout); - psavelen = pout - stackblock(); - if (psavelen > 0) { + STPUTC('\0', pout); + psavelen = pout - stackblock(); + if (psavelen > 0) { pstr = grabstackstr(pout); setinputstring(pstr); - } - } + } + } nlpp = &bqlist; while (*nlpp) nlpp = &(*nlpp)->next; @@ -10641,12 +11347,12 @@ done: } (*nlpp)->n = n; - if (oldstyle) { + if (oldstyle) { /* * Start reading from old file again, ignoring any pushed back * tokens left from the backquote parsing */ - popfile(); + popfile(); tokpushback = 0; } while (stackblocksize() <= savelen) @@ -10698,16 +11404,6 @@ parsearith: { } /* end of readtoken */ - -#ifdef mkinit -INCLUDE "parser.h" -RESET { - tokpushback = 0; - checkkwd = 0; - checkalias = 0; -} -#endif - /* * Returns true if the text contains nothing to expand (no dollar signs * or backquotes). @@ -10739,9 +11435,9 @@ noexpand(text) */ static int -goodname(char *name) - { - char *p; +goodname(const char *name) +{ + const char *p; p = name; if (! is_name(*p)) @@ -10778,9 +11474,8 @@ synexpect(token) static void -synerror(msg) - const char *msg; - { +synerror(const char *msg) +{ if (commandname) outfmt(&errout, "%s: %d: ", commandname, startlinno); outfmt(&errout, "Syntax error: %s\n", msg); @@ -10788,12 +11483,6 @@ synerror(msg) /* NOTREACHED */ } -static void -setprompt(int which) -{ - whichprompt = which; - putprompt(getprompt(NULL)); -} /* * called by editline -- any expansions to the prompt @@ -10801,7 +11490,7 @@ setprompt(int which) */ static const char * getprompt(void *unused) - { +{ switch (whichprompt) { case 0: return ""; @@ -10814,55 +11503,25 @@ getprompt(void *unused) } } -static int -isassignment(const char *word) { - if (!is_name(*word)) { - return 0; - } - do { - word++; - } while (is_in_name(*word)); - return *word == '='; -} - -static const char *const * -findkwd(const char *s) { - return findstring( - s, parsekwd, sizeof(parsekwd) / sizeof(const char *) - ); -} -/* $NetBSD: redir.c,v 1.22 2000/05/22 10:18:47 elric Exp $ */ - -/* - * Code for dealing with input/output redirection. - */ - -#define EMPTY -2 /* marks an unused slot in redirtab */ -#ifndef PIPE_BUF -# define PIPESIZE 4096 /* amount of buffering in a pipe */ -#else -# define PIPESIZE PIPE_BUF -#endif - - -struct redirtab *redirlist; - -/* - * We keep track of whether or not fd0 has been redirected. This is for - * background commands, where we want to redirect fd0 to /dev/null only - * if it hasn't already been redirected. -*/ -static int fd0_redirected = 0; +static void +setprompt(int which) +{ + whichprompt = which; + putprompt(getprompt(NULL)); +} + /* - * We also keep track of where fileno2 goes. + * Code for dealing with input/output redirection. */ -static int fileno2 = 2; -static int openredirect __P((union node *)); -static void dupredirect __P((union node *, int, char[10 ])); -static int openhere __P((union node *)); -static int noclobberopen __P((const char *)); +#define EMPTY -2 /* marks an unused slot in redirtab */ +#ifndef PIPE_BUF +# define PIPESIZE 4096 /* amount of buffering in a pipe */ +#else +# define PIPESIZE PIPE_BUF +#endif + /* @@ -10884,7 +11543,7 @@ redirect(redir, flags) int fd; int newfd; int try; - char memory[10]; /* file descriptors to write to memory */ + char memory[10]; /* file descriptors to write to memory */ for (i = 10 ; --i >= 0 ; ) memory[i] = 0; @@ -10923,7 +11582,7 @@ redirect(redir, flags) close(newfd); } INTON; - error("%d: %s", fd, strerror(errno)); + error("%d: %m", fd); /* NOTREACHED */ } } @@ -10939,8 +11598,8 @@ redirect(redir, flags) } else if (fd != newfd) { close(fd); } - if (fd == 0) - fd0_redirected++; + if (fd == 0) + fd0_redirected++; if (!try) dupredirect(n, newfd, memory); INTON; @@ -11024,16 +11683,13 @@ eopen: static void -dupredirect(redir, f, memory) - union node *redir; - int f; - char memory[10]; - { +dupredirect(union node *redir, int f, char memory[10]) +{ int fd = redir->nfile.fd; memory[fd] = 0; if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { - if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ + if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ if (memory[redir->ndup.dupfd]) memory[fd] = 1; else @@ -11093,21 +11749,21 @@ out: } - /* * Undo the effects of the last redirection. */ static void -popredir() { +popredir(void) +{ struct redirtab *rp = redirlist; int i; INTOFF; for (i = 0 ; i < 10 ; i++) { if (rp->renamed[i] != EMPTY) { - if (i == 0) - fd0_redirected--; + if (i == 0) + fd0_redirected--; close(i); if (rp->renamed[i] >= 0) { dup_as_newfd(rp->renamed[i], i); @@ -11123,37 +11779,12 @@ popredir() { INTON; } -/* - * Undo all redirections. Called on error or interrupt. - */ - -#ifdef mkinit - -INCLUDE "redir.h" - -RESET { - while (redirlist) - popredir(); -} - -SHELLPROC { - clearredir(); -} - -#endif - -/* Return true if fd 0 has already been redirected at least once. */ -static int -fd0_redirected_p () { - return fd0_redirected != 0; -} - /* * Discard all saved file descriptors. */ static void -clearredir() { +clearredir(void) { struct redirtab *rp; int i; @@ -11175,7 +11806,6 @@ clearredir() { } - /* * Copy a file descriptor to be >= to. Returns -1 * if the source file descriptor is closed, EMPTY if there are no unused @@ -11194,7 +11824,7 @@ dup_as_newfd(from, to) if (errno == EMFILE) return EMPTY; else - error("%d: %s", from, strerror(errno)); + error("%d: %m", from); } return newfd; } @@ -11204,8 +11834,7 @@ dup_as_newfd(from, to) * The code was copied from bash. */ static int -noclobberopen(fname) - const char *fname; +noclobberopen(const char *fname) { int r, fd; struct stat finfo, finfo2; @@ -11250,43 +11879,41 @@ noclobberopen(fname) */ if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) - return fd; + return fd; /* The file has been replaced. badness. */ close(fd); errno = EEXIST; return -1; } -/* $NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $ */ - -#ifdef __weak_alias +/*#ifdef __weak_alias __weak_alias(getmode,_getmode) __weak_alias(setmode,_setmode) -#endif +#endif*/ #ifdef __GLIBC__ #define S_ISTXT __S_ISVTX #endif -#define SET_LEN 6 /* initial # of bitcmd struct to malloc */ -#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */ +#define SET_LEN 6 /* initial # of bitcmd struct to malloc */ +#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */ typedef struct bitcmd { - char cmd; - char cmd2; - mode_t bits; + char cmd; + char cmd2; + mode_t bits; } BITCMD; -#define CMD2_CLR 0x01 -#define CMD2_SET 0x02 -#define CMD2_GBITS 0x04 -#define CMD2_OBITS 0x08 -#define CMD2_UBITS 0x10 +#define CMD2_CLR 0x01 +#define CMD2_SET 0x02 +#define CMD2_GBITS 0x04 +#define CMD2_OBITS 0x08 +#define CMD2_UBITS 0x10 -static BITCMD *addcmd __P((BITCMD *, int, int, int, u_int)); -static void compress_mode __P((BITCMD *)); +static BITCMD *addcmd (BITCMD *, int, int, int, u_int); +static void compress_mode (BITCMD *); #ifdef SETMODE_DEBUG -static void dumpmode __P((BITCMD *)); +static void dumpmode (BITCMD *); #endif /* @@ -11295,7 +11922,7 @@ static void dumpmode __P((BITCMD *)); * Note that there is no '=' command; a strict assignment is just a '-' (clear * bits) followed by a '+' (set bits). */ -mode_t +static mode_t getmode(bbox, omode) const void *bbox; mode_t omode; @@ -11325,7 +11952,7 @@ getmode(bbox, omode) case 'o': value = newmode & S_IRWXO; -common: if (set->cmd2 & CMD2_CLR) { +common: if (set->cmd2 & CMD2_CLR) { clrval = (set->cmd2 & CMD2_SET) ? S_IRWXO : value; if (set->cmd2 & CMD2_UBITS) @@ -11367,23 +11994,23 @@ common: if (set->cmd2 & CMD2_CLR) { } } -#define ADDCMD(a, b, c, d) do { \ - if (set >= endset) { \ - BITCMD *newset; \ - setlen += SET_LEN_INCR; \ - newset = realloc(saveset, sizeof(BITCMD) * setlen); \ - if (newset == NULL) { \ - free(saveset); \ - return (NULL); \ - } \ - set = newset + (set - saveset); \ - saveset = newset; \ - endset = newset + (setlen - 2); \ - } \ - set = addcmd(set, (a), (b), (c), (d)); \ +#define ADDCMD(a, b, c, d) do { \ + if (set >= endset) { \ + BITCMD *newset; \ + setlen += SET_LEN_INCR; \ + newset = realloc(saveset, sizeof(BITCMD) * setlen); \ + if (newset == NULL) { \ + free(saveset); \ + return (NULL); \ + } \ + set = newset + (set - saveset); \ + saveset = newset; \ + endset = newset + (setlen - 2); \ + } \ + set = addcmd(set, (a), (b), (c), (d)); \ } while (/*CONSTCOND*/0) -#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) +#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) static void * setmode(p) @@ -11394,7 +12021,7 @@ setmode(p) BITCMD *set, *saveset, *endset; sigset_t mysigset, sigoset; mode_t mask; - int equalopdone = 0; /* pacify gcc */ + int equalopdone = 0; /* pacify gcc */ int permXbits, setlen; if (!*p) @@ -11413,7 +12040,7 @@ setmode(p) (void)sigprocmask(SIG_SETMASK, &sigoset, NULL); setlen = SET_LEN + 2; - + if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL) return (NULL); saveset = set; @@ -11459,7 +12086,7 @@ setmode(p) } } -getop: if ((op = *p++) != '+' && op != '-' && op != '=') { +getop: if ((op = *p++) != '+' && op != '-' && op != '=') { free(saveset); return (NULL); } @@ -11474,16 +12101,16 @@ getop: if ((op = *p++) != '+' && op != '-' && op != '=') { break; case 's': /* - * If specific bits where requested and - * only "other" bits ignore set-id. + * If specific bits where requested and + * only "other" bits ignore set-id. */ if (who == 0 || (who & ~S_IRWXO)) perm |= S_ISUID|S_ISGID; break; case 't': /* - * If specific bits where requested and - * only "other" bits ignore set-id. + * If specific bits where requested and + * only "other" bits ignore set-id. */ if (who == 0 || (who & ~S_IRWXO)) { who |= S_ISTXT; @@ -11539,7 +12166,7 @@ getop: if ((op = *p++) != '+' && op != '-' && op != '=') { } } -apply: if (!*p) +apply: if (!*p) break; if (*p != ',') goto getop; @@ -11596,7 +12223,7 @@ addcmd(set, op, who, oparg, mask) set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS; set->bits = mask; } - + if (oparg == '+') set->cmd2 |= CMD2_SET; else if (oparg == '-') @@ -11630,7 +12257,7 @@ dumpmode(set) /* * Given an array of bitcmd structures, compress by compacting consecutive * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u', - * 'g' and 'o' commands continue to be separate. They could probably be + * 'g' and 'o' commands continue to be separate. They could probably be * compacted, but it's not worth the effort. */ static void @@ -11684,15 +12311,12 @@ compress_mode(set) } } } -/* $NetBSD: show.c,v 1.18 1999/10/08 21:10:44 pk Exp $ */ - - #ifdef DEBUG -static void shtree __P((union node *, int, char *, FILE*)); -static void shcmd __P((union node *, FILE *)); -static void sharg __P((union node *, FILE *)); -static void indent __P((int, char *, FILE *)); -static void trstring __P((char *)); +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 *); static void @@ -11780,14 +12404,14 @@ shcmd(cmd, fp) if (! first) putchar(' '); switch (np->nfile.type) { - case NTO: s = ">"; dftfd = 1; break; - case NAPPEND: s = ">>"; dftfd = 1; break; - case NTOFD: s = ">&"; dftfd = 1; break; - case NTOOV: 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; + case NTO: s = ">"; dftfd = 1; break; + case NAPPEND: s = ">>"; dftfd = 1; break; + case NTOFD: s = ">&"; dftfd = 1; break; + case NTOOV: 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); @@ -11918,499 +12542,149 @@ FILE *tracefile; #if DEBUG == 2 static int debug = 1; -#else -static int debug = 0; -#endif - - -static void -trputc(c) - int c; -{ - if (tracefile == NULL) - return; - putc(c, tracefile); - if (c == '\n') - fflush(tracefile); -} - -static void -trace(const char *fmt, ...) -{ - va_list va; -#ifdef __STDC__ - va_start(va, fmt); -#else - char *fmt; - va_start(va); - fmt = va_arg(va, char *); -#endif - if (tracefile != NULL) { - (void) vfprintf(tracefile, fmt, va); - if (strchr(fmt, '\n')) - (void) fflush(tracefile); - } - va_end(va); -} - - -static void -trputs(s) - const char *s; -{ - if (tracefile == NULL) - return; - fputs(s, tracefile); - if (strchr(s, '\n')) - fflush(tracefile); -} - - -static void -trstring(s) - char *s; -{ - char *p; - char c; - - if (tracefile == NULL) - return; - putc('"', tracefile); - for (p = s ; *p ; p++) { - switch (*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 CTLVAR+CTLQUOTE: c = 'V'; goto backslash; - case CTLBACKQ: c = 'q'; goto backslash; - case CTLBACKQ+CTLQUOTE: 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); -} - - -static void -trargs(ap) - char **ap; -{ - if (tracefile == NULL) - return; - while (*ap) { - trstring(*ap++); - if (*ap) - putc(' ', tracefile); - else - putc('\n', tracefile); - } - fflush(tracefile); -} - - -static void -opentrace() { - char s[100]; -#ifdef O_APPEND - int flags; -#endif - - if (!debug) - return; -#ifdef not_this_way - { - char *p; - if ((p = getenv("HOME")) == NULL) { - if (geteuid() == 0) - p = "/"; - else - p = "/tmp"; - } - scopy(p, s); - strcat(s, "/trace"); - } -#else - scopy("./trace", s); -#endif /* not_this_way */ - if ((tracefile = fopen(s, "a")) == NULL) { - fprintf(stderr, "Can't open %s\n", s); - return; - } -#ifdef O_APPEND - if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) - fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); -#endif - fputs("\nTracing started.\n", tracefile); - fflush(tracefile); -} -#endif /* DEBUG */ - - -/* - * This file was generated by the mksyntax program. - */ - -/* syntax table used when not in quotes */ -static const char basesyntax[257] = { - CEOF, CSPCL, CWORD, CCTL, - CCTL, CCTL, CCTL, CCTL, - CCTL, CCTL, CCTL, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CSPCL, - CNL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CSPCL, CWORD, - CDQUOTE, CWORD, CVAR, CWORD, - CSPCL, CSQUOTE, CSPCL, CSPCL, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CSPCL, CSPCL, CWORD, - CSPCL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CBACK, CWORD, - CWORD, CWORD, CBQUOTE, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CSPCL, CENDVAR, - CWORD -}; +#else +static int debug = 0; +#endif -/* syntax table used when in double quotes */ -static const char dqsyntax[257] = { - CEOF, CIGN, CWORD, CCTL, - CCTL, CCTL, CCTL, CCTL, - CCTL, CCTL, CCTL, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CNL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CCTL, - CENDQUOTE,CWORD, CVAR, CWORD, - CWORD, CWORD, CWORD, CWORD, - CCTL, CWORD, CWORD, CCTL, - CWORD, CCTL, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CCTL, CWORD, CWORD, CCTL, - CWORD, CCTL, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CCTL, CBACK, CCTL, - CWORD, CWORD, CBQUOTE, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CENDVAR, - CCTL -}; -/* syntax table used when in single quotes */ -static const char sqsyntax[257] = { - CEOF, CIGN, CWORD, CCTL, - CCTL, CCTL, CCTL, CCTL, - CCTL, CCTL, CCTL, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CNL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CCTL, - CWORD, CWORD, CWORD, CWORD, - CWORD, CENDQUOTE,CWORD, CWORD, - CCTL, CWORD, CWORD, CCTL, - CWORD, CCTL, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CCTL, CWORD, CWORD, CCTL, - CWORD, CCTL, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CCTL, CCTL, CCTL, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CCTL -}; +static void +trputc(c) + int c; +{ + if (tracefile == NULL) + return; + putc(c, tracefile); + if (c == '\n') + fflush(tracefile); +} -/* syntax table used when in arithmetic */ -static const char arisyntax[257] = { - CEOF, CIGN, CWORD, CCTL, - CCTL, CCTL, CCTL, CCTL, - CCTL, CCTL, CCTL, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CNL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CDQUOTE, CWORD, CVAR, CWORD, - CWORD, CSQUOTE, CLP, CRP, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CBACK, CWORD, - CWORD, CWORD, CBQUOTE, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CENDVAR, - CWORD -}; +static void +trace(const char *fmt, ...) +{ + va_list va; +#ifdef __STDC__ + va_start(va, fmt); +#else + char *fmt; + va_start(va); + fmt = va_arg(va, char *); +#endif + if (tracefile != NULL) { + (void) vfprintf(tracefile, fmt, va); + if (strchr(fmt, '\n')) + (void) fflush(tracefile); + } + va_end(va); +} + + +static void +trputs(s) + const char *s; +{ + if (tracefile == NULL) + return; + fputs(s, tracefile); + if (strchr(s, '\n')) + fflush(tracefile); +} + + +static void +trstring(s) + char *s; +{ + char *p; + char c; + + if (tracefile == NULL) + return; + putc('"', tracefile); + for (p = s ; *p ; p++) { + switch (*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 CTLVAR+CTLQUOTE: c = 'V'; goto backslash; + case CTLBACKQ: c = 'q'; goto backslash; + case CTLBACKQ+CTLQUOTE: 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); +} + + +static void +trargs(ap) + char **ap; +{ + if (tracefile == NULL) + return; + while (*ap) { + trstring(*ap++); + if (*ap) + putc(' ', tracefile); + else + putc('\n', tracefile); + } + fflush(tracefile); +} + + +static void +opentrace() { + char s[100]; +#ifdef O_APPEND + int flags; +#endif + + if (!debug) + return; +#ifdef not_this_way + { + char *p; + if ((p = getenv("HOME")) == NULL) { + if (geteuid() == 0) + p = "/"; + else + p = "/tmp"; + } + strcpy(s, p); + strcat(s, "/trace"); + } +#else + strcpy(s, "./trace"); +#endif /* not_this_way */ + if ((tracefile = fopen(s, "a")) == NULL) { + fprintf(stderr, "Can't open %s\n", s); + return; + } +#ifdef O_APPEND + if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) + fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); +#endif + fputs("\nTracing started.\n", tracefile); + fflush(tracefile); +} +#endif /* DEBUG */ -/* character classification table */ -static const char is_type[257] = { - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, ISSPECL, - 0, ISSPECL, ISSPECL, 0, - 0, 0, 0, 0, - ISSPECL, 0, 0, ISSPECL, - 0, 0, ISDIGIT, ISDIGIT, - ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, - ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, - 0, 0, 0, 0, - 0, ISSPECL, ISSPECL, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, 0, 0, 0, - 0, ISUNDER, 0, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, 0, 0, 0, - 0 -}; -/* $NetBSD: trap.c,v 1.25 2001/02/04 19:52:07 christos Exp $ */ /* * The trap builtin. @@ -12467,25 +12741,6 @@ trapcmd(argc, argv) -/* - * Clear traps on a fork. - */ - -static void -clear_traps() { - char **tp; - - for (tp = trap ; tp < &trap[NSIG] ; tp++) { - if (*tp && **tp) { /* trap not NULL or SIG_IGN */ - INTOFF; - ckfree(*tp); - *tp = NULL; - if (tp != &trap[0]) - setsignal(tp - trap); - INTON; - } - } -} @@ -12495,8 +12750,7 @@ clear_traps() { */ static void -setsignal(signo) - int signo; +setsignal(int signo) { int action; char *t; @@ -12517,7 +12771,6 @@ setsignal(signo) case SIGQUIT: #ifdef DEBUG { - extern int debug; if (debug) break; @@ -12528,7 +12781,7 @@ setsignal(signo) if (iflag) action = S_IGN; break; -#if JOBS +#ifdef JOBS case SIGTSTP: case SIGTTOU: if (mflag) @@ -12554,11 +12807,11 @@ setsignal(signo) if (act.sa_handler == SIG_IGN) { if (mflag && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)) { - *t = S_IGN; /* don't hard ignore these */ + *t = S_IGN; /* don't hard ignore these */ } else *t = S_HARD_IGN; } else { - *t = S_RESET; /* force to be set */ + *t = S_RESET; /* force to be set */ } } if (*t == S_HARD_IGN || *t == action) @@ -12594,30 +12847,12 @@ ignoresig(signo) } -#ifdef mkinit -INCLUDE -INCLUDE "trap.h" - -SHELLPROC { - char *sm; - - clear_traps(); - for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) { - if (*sm == S_IGN) - *sm = S_HARD_IGN; - } -} -#endif - - - /* * Signal handler. */ static void -onsig(signo) - int signo; +onsig(int signo) { if (signo == SIGINT && trap[SIGINT] == NULL) { onint(); @@ -12628,14 +12863,14 @@ onsig(signo) } - /* * Called to execute a trap. Perhaps we should avoid entering new trap * handlers while we are executing a trap handler. */ static void -dotrap() { +dotrap(void) +{ int i; int savestatus; @@ -12655,37 +12890,12 @@ done: pendingsigs = 0; } - - -/* - * Controls whether the shell is interactive or not. - */ - - -static void -setinteractive(on) - int on; -{ - static int is_interactive; - - if (on == is_interactive) - return; - setsignal(SIGINT); - setsignal(SIGQUIT); - setsignal(SIGTERM); - chkmail(1); - is_interactive = on; -} - - - /* * Called to exit the shell. */ static void -exitshell(status) - int status; +exitshell(int status) { struct jmploc loc1, loc2; char *p; @@ -12702,9 +12912,9 @@ exitshell(status) trap[0] = NULL; evalstring(p, 0); } -l1: handler = &loc2; /* probably unnecessary */ +l1: handler = &loc2; /* probably unnecessary */ flushall(); -#if JOBS +#ifdef JOBS setjobctl(0); #endif l2: _exit(status); @@ -12715,8 +12925,7 @@ static int decode_signal(const char *string, int minsig) { int signo; - if (is_number(string)) { - signo = atoi(string); + if (is_number(string, &signo)) { if (signo >= NSIG) { return -1; } @@ -12739,100 +12948,14 @@ zero: return -1; } -/* $NetBSD: var.c,v 1.27 2001/02/04 19:52:07 christos Exp $ */ - -#define VTABSIZE 39 - - -struct varinit { - struct var *var; - int flags; - const char *text; - void (*func) __P((const char *)); -}; - -struct localvar *localvars; - -#if ATTY -struct var vatty; -#endif -struct var vifs; -struct var vmail; -struct var vmpath; -struct var vpath; -struct var vps1; -struct var vps2; -struct var vvers; -struct var voptind; - -static const char defpathvar[] = - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; -#ifdef IFS_BROKEN -static const char defifsvar[] = "IFS= \t\n"; -#else -static const char defifs[] = " \t\n"; -#endif - -static const struct varinit varinit[] = { -#if ATTY - { &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=", - NULL }, -#endif -#ifdef IFS_BROKEN - { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar, -#else - { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=", -#endif - NULL }, - { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", - NULL }, - { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", - NULL }, - { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar, - changepath }, - /* - * vps1 depends on uid - */ - { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ", - NULL }, - { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1", - getoptsreset }, - { NULL, 0, NULL, - NULL } -}; - -struct var *vartab[VTABSIZE]; - -static struct var **hashvar __P((const char *)); -static void showvars __P((const char *, int, int)); -static struct var **findvar __P((struct var **, const char *)); +static struct var **hashvar (const char *); +static void showvars (const char *, int, int); +static struct var **findvar (struct var **, const char *); /* * Initialize the varable symbol tables and import the environment */ -#ifdef mkinit -INCLUDE -INCLUDE "output.h" -INCLUDE "var.h" -static char **environ; -INIT { - char **envp; - char ppid[32]; - - initvar(); - for (envp = environ ; *envp ; envp++) { - if (strchr(*envp, '=')) { - setvareq(*envp, VEXPORT|VTEXTFIXED); - } - } - - fmtstr(ppid, sizeof(ppid), "%d", (int) getppid()); - setvar("PPID", ppid, 0); -} -#endif - - /* * This routine initializes the builtin variables. It is called when the * shell is initialized and again when a shell procedure is spawned. @@ -12899,7 +13022,7 @@ setvar(name, val, flags) namelen = p - name; if (isbad) error("%.*s: bad variable name", namelen, name); - len = namelen + 2; /* 2 is space for '=' and '\0' */ + len = namelen + 2; /* 2 is space for '=' and '\0' */ if (val == NULL) { flags |= VUNSET; } else { @@ -13065,16 +13188,8 @@ environment() { * VSTACK set since these are currently allocated on the stack. */ -#ifdef mkinit -static void shprocvar __P((void)); - -SHELLPROC { - shprocvar(); -} -#endif - static void -shprocvar() { +shprocvar(void) { struct var **vpp; struct var *vp, **prev; @@ -13158,6 +13273,8 @@ found:; * The "local" command. */ +/* funcnest nonzero if we are currently evaluating a function */ + static int localcmd(argc, argv) int argc; @@ -13165,7 +13282,7 @@ localcmd(argc, argv) { char *name; - if (! in_function()) + if (! funcnest) error("Not in a function"); while ((name = *argptr++) != NULL) { mklocal(name); @@ -13193,8 +13310,8 @@ mklocal(name) lvp = ckmalloc(sizeof (struct localvar)); if (name[0] == '-' && name[1] == '\0') { char *p; - p = ckmalloc(sizeof optlist); - lvp->text = memcpy(p, optlist, sizeof optlist); + p = ckmalloc(sizeof optet_vals); + lvp->text = memcpy(p, optet_vals, sizeof optet_vals); vp = NULL; } else { vpp = hashvar(name); @@ -13204,7 +13321,7 @@ mklocal(name) setvareq(savestr(name), VSTRFIXED); else setvar(name, NULL, VSTRFIXED); - vp = *vpp; /* the new variable */ + vp = *vpp; /* the new variable */ lvp->text = NULL; lvp->flags = VUNSET; } else { @@ -13234,8 +13351,8 @@ poplocalvars() { while ((lvp = localvars) != NULL) { localvars = lvp->next; vp = lvp->vp; - if (vp == NULL) { /* $- saved */ - memcpy(optlist, lvp->text, sizeof optlist); + if (vp == NULL) { /* $- saved */ + memcpy(optet_vals, lvp->text, sizeof optet_vals); ckfree(lvp->text); } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { (void)unsetvar(vp->text); @@ -13415,7 +13532,7 @@ findvar(struct var **vpp, const char *name) /* * Copyright (c) 1999 Herbert Xu * This file contains code for the times builtin. - * $Id: ash.c,v 1.3 2001/06/28 16:43:57 andersen Exp $ + * $Id: ash.c,v 1.4 2001/07/02 17:27:21 andersen Exp $ */ static int timescmd (int argc, char **argv) { @@ -13438,7 +13555,7 @@ static int timescmd (int argc, char **argv) /*- * Copyright (c) 1989, 1991, 1993, 1994 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. @@ -13452,8 +13569,8 @@ static int timescmd (int argc, char **argv) * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * 3. + * 3. * * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software -- cgit v1.2.3