changes, esp describing all the current ash configuration options.
Now ash adds 66k in the default configuration.
* 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.
* 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 <andersee@debian.org> and
+ * Vladimir Oleynik <vodz@usa.net> to be used in busybox
*
- * Modified by Erik Andersen <andersee@debian.org> 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 <assert.h>
#include <ctype.h>
#include <glob.h>
#endif
-#if JOBS
+#ifdef JOBS
#include <termios.h>
-#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 <locale.h>
+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;
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)
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;
for (;;) {
evaltree(n->nbinary.ch1, EV_TESTED);
if (evalskip) {
-skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
+skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
evalskip = 0;
continue;
}
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)
}
-
static void
evalcase(n, flags)
union node *n;
popstackmark(&smark);
}
-
-
/*
* Kick off a subshell to evaluate a tree.
*/
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;
}
}
-
-
/*
* Evaluate a pipeline. All the processes in the pipeline are children
* of the process creating the pipeline. (This differs from some versions
*/
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;
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)
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);
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);
break;
}
}
- if (cmdentry.u.cmd == COMMANDCMD) {
+ if (cmdentry.u.cmd == find_builtin("command")) {
argv++;
if (--argc == 0) {
goto 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;
#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;
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:
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
}
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;
#ifndef BB_TRUE_FALSE
+#ifdef ASH_BBAPPS_AS_BUILTINS
static int
false_main(argc, argv)
int argc;
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)
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)
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
* 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 *);
/*
* 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;
/* 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
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;
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();
* 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;
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;
}
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) {
}
/* 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
prefix("func", pathopt)) {
/* handled below */
} else {
- continue; /* ignore unimplemented options */
+ continue; /* ignore unimplemented options */
}
}
/* if rehash, don't redo absolute path names */
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)
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 */
* 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;
}
*/
static void
-hashcd() {
+hashcd(void) {
struct tblentry **pp;
struct tblentry *cmdp;
*/
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;
}
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;
* 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;
-#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;
* 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;
*/
static void
-unsetfunc(name)
- char *name;
- {
+unsetfunc(char *name)
+{
struct tblentry *cmdp;
if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
}
}
+/*
+ * 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...
}
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) {
goto out;
}
+#ifdef ASH_ALIAS
/* Then look at the aliases */
if ((ap = lookupalias(command, 0)) != NULL) {
if (verbose) {
}
goto out;
}
-
+#endif
/* Then check if it is a tracked alias */
if ((cmdp = cmdlookup(command, 0)) != NULL) {
entry.cmdtype = cmdp->cmdtype;
if (verbose) {
out1fmt(
" is a %sshell builtin",
- entry.u.cmd->flags & BUILTIN_SPECIAL ?
+ IS_BUILTIN_SPECIAL(entry.u.cmd) ?
"special " : nullstr
);
} else {
out1c('\n');
return 0;
}
-#endif
+#endif
+#ifdef ASH_CMDCMD
static int
commandcmd(argc, argv)
int argc;
if (verify_only || verbose_verify_only) {
return describe_command(*argptr, verbose_verify_only);
}
-#endif
+#endif
return 0;
}
+#endif
static int
path_change(newval, bltin)
old = pathval();
new = newval;
- firstchange = 9999; /* assume no change */
+ firstchange = 9999; /* assume no change */
idx = 0;
*bltin = -1;
for (;;) {
if ((*old == '\0' && *new == ':')
|| (*old == ':' && *new == '\0'))
firstchange++;
- old = new; /* ignore subsequent differences */
+ old = new; /* ignore subsequent differences */
}
if (*new == '\0')
break;
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.
/*
* _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
*/
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());
ifslastp = NULL;
argstr(arg->narg.text, flag);
if (arglist == NULL) {
- return; /* here document expanded */
+ return; /* here document expanded */
}
STPUTC('\0', expdest);
p = grabstackstr(expdest);
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)))
case CTLENDARI:
expari(flag);
break;
-#endif
+#endif
case ':':
case '=':
/*
}
-static void
-removerecordregions(endoff)
- int endoff;
+static void
+removerecordregions(int endoff)
{
if (ifslastp == NULL)
return;
}
return;
}
-
+
ifslastp = &ifsfirst;
while (ifslastp->next && ifslastp->next->begoff < endoff)
ifslastp=ifslastp->next;
* evaluate, place result in (backed up) result, adjust string position.
*/
static void
-expari(flag)
- int flag;
+expari(int flag)
{
char *p, *start;
int result;
int quotes = flag & (EXP_FULL | EXP_CASE);
int quoted;
- /* ifsfree(); */
+ /* ifsfree(); */
/*
* This routine is slightly over-complicated for
result = expdest - p + 1;
STADJUST(-result, expdest);
}
-#endif
-
+#endif
/*
* Expand stuff in backwards quotes.
INTON;
}
-
-
static int
subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
char *p;
goto recordleft;
*loc = c;
if (quotes && *loc == CTLESC)
- loc++;
+ loc++;
}
return 0;
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++;
if (patmatch2(str, loc, quotes))
goto recordright;
if (quotes && *loc == CTLESC)
- loc++;
+ loc++;
}
return 0;
case VSPLUS:
case VSMINUS:
if (!set) {
- argstr(p, flag);
+ argstr(p, flag);
break;
}
if (easy)
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;
#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)
return p;
}
-
-
/*
* Test whether a specialized variable is set.
*/
return 1;
}
-
-
/*
* Put a string on the stack.
*/
}
}
-
-
/*
* Add the value of a specialized variable to the stack string.
*/
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 '@':
}
-
/*
* Record the fact that we have to scan this region of the
* string for IFS characters.
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
rmescapes(str->text);
exparg.lastp = &str->next;
break;
- default: /* GLOB_NOSPACE */
+ default: /* GLOB_NOSPACE */
error("Out of space");
}
str = str->next;
}
-#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
+#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
static char *expdir;
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 == '!')
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;
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++) {
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;
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))
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) {
*/
#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;
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;
}
#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;
while (*endp == CTLQUOTEMARK)
endp++;
if (*endp == '\0')
- goto dft; /* no matching ] */
+ goto dft; /* no matching ] */
if (*endp == CTLESC)
endp++;
if (*++endp == ']')
return 0;
break;
}
-dft: default:
+dft: default:
if (squoted && *q == CTLESC)
q++;
if (*q++ != c)
#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 };
*/
static int
-casematch(pattern, val)
- union node *pattern;
- char *val;
- {
+casematch(union node *pattern, const char *val)
+{
struct stackmark smark;
int result;
char *p;
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;
}
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).
*/
}
-/*
- * 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;
*/
static void
-init() {
+init(void) {
/* from cd.c: */
{
* 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.
}
#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 <stdio.h>
-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;
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;
{
if (parsefile->fd)
nr = read(parsefile->fd, buf, BUFSIZ - 1);
- else {
+ else {
do {
cmdedit_read_input((char*)cmdedit_prompt, buf);
nr = strlen(buf);
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:
*
*/
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++);
for (more = 1; more;) {
switch (*p) {
case '\0':
- p++; /* Skip nul */
+ p++; /* Skip nul */
goto 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;
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;
-}
/*
*/
static void
-pushfile() {
+pushfile(void) {
struct parsefile *pf;
parsefile->nleft = parsenleft;
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.
*
* System V doesn't have job control yet, this isn't a problem now.
*/
-static int jobctl;
+
static void setjobctl(int enable)
{
#endif
-#ifdef mkinit
-INCLUDE <stdlib.h>
-
-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",
-#if JOBS
+#ifdef JOBS
static int
killcmd(argc, argv)
int argc;
optionarg
);
}
- break;
+ break;
#ifdef DEBUG
default:
error(
} else
pid = atoi(*argptr);
if (kill(pid, signo) != 0)
- error("%s: %s", *argptr, strerror(errno));
+ error("%s: %m", *argptr);
} while (*++argptr);
return 0;
}
#endif
+static void showjobs(int change);
+
static int
jobscmd(argc, argv)
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);
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))
if (jp->ps != &jp->ps0)
ckfree(jp->ps);
jp->used = 0;
-#if JOBS
+#ifdef JOBS
if (curjob == jp - jobtab + 1)
curjob = 0;
#endif
} 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;
}
if (WIFEXITED(status))
retval = WEXITSTATUS(status);
-#if JOBS
+#ifdef JOBS
else if (WIFSTOPPED(status))
retval = WSTOPSIG(status) + 128;
#endif
}
} 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)
*/
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");
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
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)
* Return a new job structure,
*/
-struct job *
+static struct job *
makejob(node, nprocs)
union node *node;
int nprocs;
jp->used = 1;
jp->changed = 0;
jp->nprocs = 0;
-#if JOBS
+#ifdef JOBS
jp->jobctl = jobctl;
#endif
if (nprocs > 1) {
* 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;
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();
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;
waitforjob(jp)
struct job *jp;
{
-#if JOBS
+#ifdef JOBS
int mypgrp = getpgrp();
#endif
int status;
INTOFF;
intreceived = 0;
-#if JOBS
+#ifdef JOBS
if (!jobctl) {
#else
if (!iflag) {
while (jp->state == 0) {
dowait(1, jp);
}
-#if JOBS
+#ifdef JOBS
if (!jobctl) {
#else
if (!iflag) {
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)
/* 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.
if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
raise(SIGINT);
}
+ if (jp->state == JOBDONE)
+
#endif
- if (! JOBS || jp->state == JOBDONE)
freejob(jp);
INTON;
return st;
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
}
}
INTON;
if (! rootshell || ! iflag || (job && thisjob == job)) {
core = WCOREDUMP(status);
-#if JOBS
+#ifdef JOBS
if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
else
#endif
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));
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 {
* 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;
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;
}
+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?)
*/
#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 */
*/
static void
-chkmail(silent)
- int silent;
+chkmail(int silent)
{
int i;
const char *mpath;
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) {
);
}
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
DOTCMD = find_builtin(".");
BLTINCMD = find_builtin("builtin");
- COMMANDCMD = find_builtin("command");
EXECCMD = find_builtin("exec");
EVALCMD = find_builtin("eval");
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)
state = 4;
if (sflag == 0 || minusc) {
static int sigs[] = {
- SIGINT, SIGQUIT, SIGHUP,
+ SIGINT, SIGQUIT, SIGHUP,
#ifdef SIGTSTP
SIGTSTP,
#endif
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
*/
static void
-cmdloop(top)
- int top;
+cmdloop(int top)
{
union node *n;
struct stackmark smark;
*/
static void
-readcmdfile(name)
- char *name;
+readcmdfile(const char *name)
{
int fd;
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;
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;
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();
}
}
-
static void
-setstackmark(mark)
- struct stackmark *mark;
- {
+setstackmark(struct stackmark *mark)
+{
mark->stackp = stackp;
mark->stacknxt = stacknxt;
mark->stacknleft = stacknleft;
static void
-popstackmark(mark)
- struct stackmark *mark;
- {
+popstackmark(struct stackmark *mark)
+{
struct stack_block *sp;
INTOFF;
*/
static void
-growstackblock() {
+growstackblock(void) {
char *p;
int newlen = ALIGN(stacknleft * 2 + 100);
char *oldspace = stacknxt;
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;
} 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;
static char *
-growstackstr() {
+growstackstr(void) {
int len = stackblocksize();
if (herefd >= 0 && len >= 1024) {
xwrite(herefd, stackblock(), len);
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.
*/
#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
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
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')
else
{
val /= l->factor;
-#ifdef BSD4_4
out1fmt("%lld\n", (long long) val);
-#else
- out1fmt("%ld\n", (long) val);
-#endif
}
}
return 0;
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;
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.
*/
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.
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)),
};
-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 *);
* 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;
#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
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;
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];
}
/* 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;
}
-static void
-optschanged()
-{
- setinteractive(iflag);
- setjobctl(mflag);
-}
/*
* Process shell options. The global variable argptr contains a pointer
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;
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++;
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);
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')
-#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;
*/
static void
-freeparam(param)
- volatile struct shparam *param;
- {
+freeparam(volatile struct shparam *param)
+{
char **ap;
if (param->malloc) {
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
goto out;
}
optnext++;
- if (p[0] == '-' && p[1] == '\0') /* check for "--" */
+ if (p[0] == '-' && p[1] == '\0') /* check for "--" */
goto atend;
}
}
return done;
}
-#endif
+#endif
/*
* XXX - should get rid of. have all builtins use getopt(3). the
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++;
}
-/* $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
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);
}
#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
*/
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;
}
-#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;
return error;
}
#endif
-/* $NetBSD: parser.c,v 1.46 2001/02/04 19:52:06 christos Exp $ */
-
/*
* Shell command parser.
*/
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);
/*
* valid parse tree indicating a blank line.)
*/
-union node *
+static union node *
parsecmd(int interact)
{
int t;
if (heredoclist)
parseheredoc();
else
- pungetc(); /* push back EOF on input */
+ pungetc(); /* push back EOF on input */
return n1;
default:
if (nlflag)
redir = NULL;
rpp = &redir;
+#ifdef ASH_ALIAS
checkalias = 2;
+#endif
for (;;) {
switch (readtoken()) {
case TWORD:
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 (
/* 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();
}
static union node *
-makename() {
+makename(void) {
union node *n;
n = (union node *)stalloc(sizeof (struct narg));
}
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;
static void
-parsefname() {
+parsefname(void) {
union node *n = redirnode;
if (readtoken() != TWORD)
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) {
/*
}
}
+#ifdef ASH_ALIAS
if (t != TWORD) {
if (t != TREDIR) {
checkalias = 0;
}
checkalias = 0;
}
+#endif
out:
#ifdef DEBUG
if (!alreadyseen)
/*
* 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
* have parseword (readtoken1?) handle both words and redirection.]
*/
-#define RETURN(token) return lasttoken = token
+#define RETURN(token) return lasttoken = token
static int
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':
* 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)
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;
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)
else
setprompt(0);
c = pgetc();
- goto loop; /* continue outer loop */
+ goto loop; /* continue outer loop */
case CWORD:
USTPUTC(c, out);
break;
USTPUTC(CTLESC, out);
USTPUTC(c, out);
break;
- case CBACK: /* backslash */
+ case CBACK: /* backslash */
c = pgetc2();
if (c == PEOF) {
USTPUTC('\\', out);
quotef++;
}
break;
- case CVAR: /* '$' */
- PARSESUB(); /* parse substitution */
+ case CVAR: /* '$' */
+ PARSESUB(); /* parse substitution */
break;
- case CENDVAR: /* '}' */
+ case CENDVAR: /* '}' */
if (varnest > 0) {
varnest--;
if (dqvarnest > 0) {
}
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;
}
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);
}
checkend: {
if (eofmark) {
+#ifdef ASH_ALIAS
if (c == PEOA) {
c = pgetc2();
}
+#endif
if (striptabs) {
while (c == '\t') {
c = pgetc2();
np->type = NTO;
pungetc();
}
- } else { /* c == '<' */
+ } else { /* c == '<' */
np->nfile.fd = 0;
switch (c = pgetc()) {
case '<':
) {
USTPUTC('$', out);
pungetc();
- } else if (c == '(') { /* $(command) or $((arith)) */
+ } else if (c == '(') { /* $(command) or $((arith)) */
if (pgetc() == '(') {
PARSEARITH();
} else {
c = pgetc();
}
else
-badsub: synerror("Bad substitution");
+badsub: synerror("Bad substitution");
STPUTC('=', out);
flags = 0;
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);
goto done;
case '\\':
- if ((pc = pgetc()) == '\n') {
+ if ((pc = pgetc()) == '\n') {
plinno++;
if (doprompt)
setprompt(2);
*/
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':
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;
}
(*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)
} /* 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).
*/
static int
-goodname(char *name)
- {
- char *p;
+goodname(const char *name)
+{
+ const char *p;
p = name;
if (! is_name(*p))
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);
/* NOTREACHED */
}
-static void
-setprompt(int which)
-{
- whichprompt = which;
- putprompt(getprompt(NULL));
-}
/*
* called by editline -- any expansions to the prompt
*/
static const char *
getprompt(void *unused)
- {
+{
switch (whichprompt) {
case 0:
return "";
}
}
-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
+
/*
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;
close(newfd);
}
INTON;
- error("%d: %s", fd, strerror(errno));
+ error("%d: %m", fd);
/* NOTREACHED */
}
}
} else if (fd != newfd) {
close(fd);
}
- if (fd == 0)
- fd0_redirected++;
+ if (fd == 0)
+ fd0_redirected++;
if (!try)
dupredirect(n, newfd, memory);
INTON;
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
}
-
/*
* 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);
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;
}
-
/*
* Copy a file descriptor to be >= to. Returns -1
* if the source file descriptor is closed, EMPTY if there are no unused
if (errno == EMFILE)
return EMPTY;
else
- error("%d: %s", from, strerror(errno));
+ error("%d: %m", from);
}
return newfd;
}
* The code was copied from bash.
*/
static int
-noclobberopen(fname)
- const char *fname;
+noclobberopen(const char *fname)
{
int r, fd;
struct stat finfo, finfo2;
*/
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
/*
* 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;
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)
}
}
-#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)
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)
(void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
setlen = SET_LEN + 2;
-
+
if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
return (NULL);
saveset = set;
}
}
-getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
+getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
free(saveset);
return (NULL);
}
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;
}
}
-apply: if (!*p)
+apply: if (!*p)
break;
if (*p != ',')
goto getop;
set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
set->bits = mask;
}
-
+
if (oparg == '+')
set->cmd2 |= CMD2_SET;
else if (oparg == '-')
/*
* 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
}
}
}
-/* $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
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);
#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.
-/*
- * 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;
- }
- }
-}
*/
static void
-setsignal(signo)
- int signo;
+setsignal(int signo)
{
int action;
char *t;
case SIGQUIT:
#ifdef DEBUG
{
- extern int debug;
if (debug)
break;
if (iflag)
action = S_IGN;
break;
-#if JOBS
+#ifdef JOBS
case SIGTSTP:
case SIGTTOU:
if (mflag)
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)
}
-#ifdef mkinit
-INCLUDE <signal.h>
-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();
}
-
/*
* 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;
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;
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);
{
int signo;
- if (is_number(string)) {
- signo = atoi(string);
+ if (is_number(string, &signo)) {
if (signo >= NSIG) {
return -1;
}
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 <unistd.h>
-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.
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 {
* 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;
* The "local" command.
*/
+/* funcnest nonzero if we are currently evaluating a function */
+
static int
localcmd(argc, argv)
int argc;
{
char *name;
- if (! in_function())
+ if (! funcnest)
error("Not in a function");
while ((name = *argptr++) != NULL) {
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);
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 {
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);
/*
* Copyright (c) 1999 Herbert Xu <herbert@debian.org>
* 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)
{
/*-
* 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.
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
- * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
+ * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
+ * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
*
* 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
+++ /dev/null
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 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
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/* $NetBSD: alias.h,v 1.4 1995/05/11 21:28:42 christos Exp $ */
-
-#define ALIASINUSE 1
-#define ALIASDEAD 2
-
-struct alias {
- struct alias *next;
- char *name;
- char *val;
- int flag;
-};
-
-struct alias *lookupalias __P((const char *, int));
-static int aliascmd __P((int, char **));
-static int unaliascmd __P((int, char **));
-static void rmaliases __P((void));
-static int unalias __P((char *));
-static void printalias __P((const struct alias *));
-#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
-
-/*
- * This file was generated by the mkbuiltins program.
- */
-
-
-#define BUILTIN_SPECIAL 0x1
-#define BUILTIN_REGULAR 0x2
-#define BUILTIN_ASSIGN 0x4
-
-struct builtincmd {
- const char *name;
- int (*const builtinfunc) __P((int, char **));
- unsigned flags;
-};
-
-extern const struct builtincmd builtincmds[];
-
-
-
-/* $NetBSD: cd.h,v 1.2 1997/07/04 21:01:52 christos Exp $ */
-static int cdcmd __P((int, char **));
-static int pwdcmd __P((int, char **));
-static void setpwd __P((const char *, int));
-
-
-/* $NetBSD: error.h,v 1.14 2001/02/04 19:52:06 christos Exp $ */
-
-/*
- * Types of operations (passed to the errmsg routine).
- */
-
-#define E_OPEN 01 /* opening a file */
-#define E_CREAT 02 /* creating a file */
-#define E_EXEC 04 /* executing a program */
-
-
-/*
- * We enclose jmp_buf in a structure so that we can declare pointers to
- * jump locations. The global variable handler contains the location to
- * jump to when an exception occurs, and the global variable exception
- * contains a code identifying the exeception. To implement nested
- * exception handlers, the user should save the value of handler on entry
- * to an inner scope, set handler to point to a jmploc structure for the
- * inner scope, and restore handler on exit from the scope.
- */
-
-struct jmploc {
- jmp_buf loc;
-};
-
-extern struct jmploc *handler;
-extern int exception;
-
-/* exceptions */
-#define EXINT 0 /* SIGINT received */
-#define EXERROR 1 /* a generic error */
-#define EXSHELLPROC 2 /* execute a shell procedure */
-#define EXEXEC 3 /* command execution failed */
-
-
-/*
- * These macros allow the user to suspend the handling of interrupt signals
- * over a period of time. This is similar to SIGHOLD to or sigblock, but
- * much more efficient and portable. (But hacking the kernel is so much
- * more fun than worrying about efficiency and portability. :-))
- */
-
-extern int suppressint;
-extern volatile int intpending;
-
-#define INTOFF suppressint++
-#ifdef REALLY_SMALL
-static void __inton __P((void));
-#define INTON __inton()
-#else
-#define INTON { if (--suppressint == 0 && intpending) onint(); }
-#endif
-#define FORCEINTON {suppressint = 0; if (intpending) onint();}
-#define CLEAR_PENDING_INT intpending = 0
-#define int_pending() intpending
-
-static void exraise __P((int)) __attribute__((__noreturn__));
-static void onint __P((void));
-static void error __P((const char *, ...)) __attribute__((__noreturn__));
-static void exerror __P((int, const char *, ...)) __attribute__((__noreturn__));
-static const char *errmsg __P((int, int));
-
-
-/*
- * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
- * so we use _setjmp instead.
- */
-
-#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
-#define setjmp(jmploc) _setjmp(jmploc)
-#define longjmp(jmploc, val) _longjmp(jmploc, val)
-#endif
-
-
-
-/* $NetBSD: shell.h,v 1.13 2000/05/22 10:18:47 elric Exp $ */
-
-/*
- * The follow should be set to reflect the type of system you have:
- * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
- * SHORTNAMES -> 1 if your linker cannot handle long names.
- * define BSD if you are running 4.2 BSD or later.
- * define SYSV if you are running under System V.
- * define DEBUG=1 to compile in debugging (set global "debug" to turn on)
- * define DEBUG=2 to compile in and turn on debugging.
- *
- * When debugging is on, debugging info will be written to $HOME/trace and
- * a quit signal will generate a core dump.
- */
-
-
-#define JOBS 1
-#ifndef BSD
-#define BSD 1
-#endif
-
-#ifdef __STDC__
-typedef void *pointer;
-#ifndef NULL
-#define NULL (void *)0
-#endif
-#else /* not __STDC__ */
-typedef char *pointer;
-#ifndef NULL
-#define NULL 0
-#endif
-#endif /* not __STDC__ */
-
-extern char nullstr[1]; /* null string */
-
-
-#ifdef DEBUG
-#define TRACE(param) trace param
-#else
-#define TRACE(param)
-#endif
-
-
-
-
-/*
- * This file was generated by the mknodes program.
- */
-
-#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
-
-
-
-struct nbinary {
- int type;
- union node *ch1;
- union node *ch2;
-};
-
-
-struct ncmd {
- int type;
- int backgnd;
- union node *assign;
- union node *args;
- union node *redirect;
-};
-
-
-struct npipe {
- int type;
- int backgnd;
- struct nodelist *cmdlist;
-};
-
-
-struct nredir {
- int type;
- union node *n;
- union node *redirect;
-};
-
-
-struct nif {
- int type;
- union node *test;
- union node *ifpart;
- union node *elsepart;
-};
-
-
-struct nfor {
- int type;
- union node *args;
- union node *body;
- char *var;
-};
-
-
-struct ncase {
- int type;
- union node *expr;
- union node *cases;
-};
-
-
-struct nclist {
- int type;
- union node *next;
- union node *pattern;
- union node *body;
-};
-
-
-struct narg {
- int type;
- union node *next;
- char *text;
- struct nodelist *backquote;
-};
-
-
-struct nfile {
- int type;
- union node *next;
- int fd;
- union node *fname;
- char *expfname;
-};
-
-
-struct ndup {
- int type;
- union node *next;
- int fd;
- int dupfd;
- union node *vname;
-};
-
-
-struct nhere {
- int type;
- union node *next;
- int fd;
- union node *doc;
-};
-
-
-struct nnot {
- int type;
- union node *com;
-};
-
-
-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;
-};
-
-
-#ifdef __STDC__
-union node *copyfunc(union node *);
-static void freefunc(union node *);
-#else
-union node *copyfunc();
-static void freefunc();
-#endif
-
-
-
-/* $NetBSD: eval.h,v 1.10 2000/01/27 23:39:40 christos Exp $ */
-extern char *commandname; /* currently executing command */
-extern int exitstatus; /* exit status of last command */
-extern struct strlist *cmdenviron; /* environment for builtin command */
-
-
-struct backcmd { /* result of evalbackcmd */
- int fd; /* file descriptor to read from */
- char *buf; /* buffer */
- int nleft; /* number of chars in buffer */
- struct job *jp; /* job structure for command */
-};
-
-static int evalcmd __P((int, char **));
-static void evalstring __P((char *, int));
-static void evaltree __P((union node *, int));
-static void evalbackcmd __P((union node *, struct backcmd *));
-static int bltincmd __P((int, char **));
-static int breakcmd __P((int, char **));
-static int returncmd __P((int, char **));
-static int execcmd __P((int, char **));
-
-/* in_function returns nonzero if we are currently evaluating a function */
-#define in_function() funcnest
-extern int funcnest;
-extern int evalskip;
-
-/* reasons for skipping commands (see comment on breakcmd routine) */
-#define SKIPBREAK 1
-#define SKIPCONT 2
-#define SKIPFUNC 3
-#define SKIPFILE 4
-
-
-
-
-/* $NetBSD: exec.h,v 1.17 2000/05/22 10:18:47 elric Exp $ */
-
-/* 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 */
-
-
-struct cmdentry {
- int cmdtype;
- union param {
- int index;
- union node *func;
- const struct builtincmd *cmd;
- } u;
-};
-
-
-#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 */
-
-extern const char *pathopt; /* set by padvance */
-extern int exerrno; /* last exec error */
-
-static void shellexec __P((char **, char **, const char *, int))
- __attribute__((noreturn));
-static char *padvance __P((const char **, const char *));
-static int hashcmd __P((int, char **));
-static void find_command __P((char *, struct cmdentry *, int, const char *));
-struct builtincmd *find_builtin __P((char *));
-static void hashcd __P((void));
-static void changepath __P((const char *));
-static void deletefuncs __P((void));
-#ifdef notdef
-static void getcmdentry __P((char *, struct cmdentry *));
-#endif
-static void addcmdentry __P((char *, struct cmdentry *));
-static void defun __P((char *, union node *));
-static void unsetfunc __P((char *));
-#ifdef ASH_TYPE
-static int typecmd __P((int, char **));
-#endif
-static int commandcmd __P((int, char **));
-
-
-
-/* $NetBSD: expand.h,v 1.12 1999/07/09 03:05:50 christos Exp $ */
-struct strlist {
- struct strlist *next;
- char *text;
-};
-
-
-struct arglist {
- struct strlist *list;
- struct strlist **lastp;
-};
-
-/*
- * expandarg() flags
- */
-#define EXP_FULL 0x1 /* perform word splitting & file globbing */
-#define EXP_TILDE 0x2 /* do normal tilde expansion */
-#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
-#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
-#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
-#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
-
-
-static void expandhere __P((union node *, int));
-static void expandarg __P((union node *, struct arglist *, int));
-#ifdef ASH_MATH_SUPPORT
-static void expari __P((int));
-#endif
-#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
-static int patmatch __P((char *, char *, int));
-#endif
-#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
-#define rmescapes(p) _rmescapes((p), 0)
-static char *_rmescapes __P((char *, int));
-#else
-static void rmescapes __P((char *));
-#endif
-static int casematch __P((union node *, char *));
-
-
-#ifdef ASH_MATH_SUPPORT
-/* From arith.y */
-static int arith __P((const char *));
-static int expcmd __P((int , char **));
-static void arith_lex_reset __P((void));
-static int yylex __P((void));
-#endif
-
-
-
-
-/* $NetBSD: init.h,v 1.8 1995/05/11 21:29:14 christos Exp $ */
-static void init __P((void));
-static void reset __P((void));
-static void initshellproc __P((void));
-
-
-
-/* $NetBSD: input.h,v 1.12 2000/05/22 10:18:47 elric Exp $ */
-
-/* PEOF (the end of file marker) is defined in syntax.h */
-/*
- * The input line number. Input.c just defines this variable, and saves
- * and restores it when files are pushed and popped. The user of this
- * package must set its value.
- */
-extern int plinno;
-extern int parsenleft; /* number of characters left in input buffer */
-extern char *parsenextc; /* next character in input buffer */
-
-static char *pfgets __P((char *, int));
-static int pgetc __P((void));
-static int pgetc2 __P((void));
-static int preadbuffer __P((void));
-static void pungetc __P((void));
-static void pushstring __P((char *, int, void *));
-static void popstring __P((void));
-static void setinputfile __P((const char *, int));
-static void setinputfd __P((int, int));
-static void setinputstring __P((char *));
-static void popfile __P((void));
-static void popallfiles __P((void));
-static void closescript __P((void));
-
-#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
-
-
-
-/* $NetBSD: jobs.h,v 1.12 2000/05/22 10:18:47 elric Exp $ */
-
-/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
-#define FORK_FG 0
-#define FORK_BG 1
-#define FORK_NOJOB 2
-
-
-/*
- * 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 */
-};
-
-
-/* states */
-#define JOBSTOPPED 1 /* all procs are stopped */
-#define JOBDONE 2 /* all procs are completed */
-
-
-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 */
-#if JOBS
- char jobctl; /* job running under job control */
-#endif
-};
-
-extern short backgndpid; /* pid of last background process */
-extern int job_warning; /* user was warned about stopped jobs */
-
-static void setjobctl __P((int));
-static int killcmd __P((int, char **));
-static int fgcmd __P((int, char **));
-static int bgcmd __P((int, char **));
-static int jobscmd __P((int, char **));
-static void showjobs __P((int));
-static int waitcmd __P((int, char **));
-struct job *makejob __P((union node *, int));
-static int forkshell __P((struct job *, union node *, int));
-static int waitforjob __P((struct job *));
-static int stoppedjobs __P((void));
-static char *commandtext __P((union node *));
-
-#if ! JOBS
-#define setjobctl(on) /* do nothing */
-#endif
-
-
-
-/* $NetBSD: machdep.h,v 1.8 1995/05/11 21:29:21 christos Exp $ */
-
-/*
- * Most machines require the value returned from malloc to be aligned
- * in some way. The following macro will get this right on many machines.
- */
-
-#ifndef ALIGN
-union align {
- int i;
- char *cp;
-};
-
-#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
-#endif
-
-
-
-/* $NetBSD: mail.h,v 1.8 1995/05/11 21:29:23 christos Exp $ */
-
-static void chkmail __P((int));
-
-
-
-/* $NetBSD: main.h,v 1.8 1995/05/11 21:29:27 christos Exp $ */
-extern int rootpid; /* pid of main shell */
-extern int rootshell; /* true if we aren't a child of the main shell */
-
-static void readcmdfile __P((char *));
-static void cmdloop __P((int));
-static int dotcmd __P((int, char **));
-static int exitcmd __P((int, char **));
-
-
-
-/* $NetBSD: memalloc.h,v 1.11 2000/11/01 19:56:01 christos Exp $ */
-struct stackmark {
- struct stack_block *stackp;
- char *stacknxt;
- int stacknleft;
- struct stackmark *marknext;
-};
-
-
-extern char *stacknxt;
-extern int stacknleft;
-extern int sstrnleft;
-extern int herefd;
-
-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); }
-
-pointer stalloc __P((int));
-static void stunalloc __P((pointer));
-static void setstackmark __P((struct stackmark *));
-static void popstackmark __P((struct stackmark *));
-static void growstackblock __P((void));
-static void grabstackblock __P((int));
-static char *growstackstr __P((void));
-static char *makestrspace __P((size_t));
-static void ungrabstackstr __P((char *, char *));
-
-
-
-#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)
-
-#define ckfree(p) free((pointer)(p))
-
-
-
-/* $NetBSD: miscbltin.h,v 1.1 1997/07/04 21:02:10 christos Exp $ */
-static int readcmd __P((int, char **));
-static int umaskcmd __P((int, char **));
-static int ulimitcmd __P((int, char **));
-
-
-
-/* $NetBSD: mystring.h,v 1.9 1995/05/11 21:29:42 christos Exp $ */
-
-extern const char snlfmt[];
-extern const char spcstr[];
-
-#if 0
-static void scopyn __P((const char *, char *, int));
-#endif
-static int prefix __P((const char *, const char *));
-static int number __P((const char *));
-static int is_number __P((const char *));
-static char *single_quote __P((const char *));
-static char *sstrdup __P((const char *));
-static int pstrcmp __P((const void *, const void *));
-static const char *const *findstring __P((const char *, const char *const *, size_t));
-
-#define equal(s1, s2) (strcmp(s1, s2) == 0)
-#define scopy(s1, s2) ((void)strcpy(s2, s1))
-
-
-/* $NetBSD: options.h,v 1.14 2001/02/04 19:52:06 christos Exp $ */
-
-struct shparam {
- int nparam; /* # of positional parameters (without $0) */
- unsigned char malloc; /* if parameter list dynamically allocated */
- char **p; /* parameter list */
- int optind; /* next parameter to be processed by getopts */
- int optoff; /* used by getopts */
-};
-
-
-
-#define eflag optlist[0].val
-#define fflag optlist[1].val
-#define Iflag optlist[2].val
-#define iflag optlist[3].val
-#define mflag optlist[4].val
-#define nflag optlist[5].val
-#define sflag optlist[6].val
-#define xflag optlist[7].val
-#define vflag optlist[8].val
-#define Vflag optlist[9].val
-#define Eflag optlist[10].val
-#define Cflag optlist[11].val
-#define aflag optlist[12].val
-#define bflag optlist[13].val
-#define uflag optlist[14].val
-#define qflag optlist[15].val
-
-#define NOPTS 16
-
-struct optent {
- const char *name;
- const char letter;
- char val;
-};
-
-extern struct optent optlist[NOPTS];
-
-
-extern char *minusc; /* argument to -c option */
-extern char *arg0; /* $0 */
-extern struct shparam shellparam; /* $@ */
-extern char **argptr; /* argument list for builtin commands */
-extern char *optionarg; /* set by nextopt */
-extern char *optptr; /* used by nextopt */
-
-static void procargs __P((int, char **));
-static void optschanged __P((void));
-static void setparam __P((char **));
-static void freeparam __P((volatile struct shparam *));
-static int shiftcmd __P((int, char **));
-static int setcmd __P((int, char **));
-#ifdef ASH_GETOPTS
-static int getoptscmd __P((int, char **));
-static int setvarsafe __P((const char *, const char *, int));
-#endif
-static int nextopt __P((const char *));
-static void getoptsreset __P((const char *));
-
-
-
-/* $NetBSD: output.h,v 1.14 1998/01/31 12:37:55 christos Exp $ */
-struct output {
-#ifdef USE_GLIBC_STDIO
- FILE *stream;
-#endif
- char *nextc;
- int nleft;
- char *buf;
- int bufsize;
- int fd;
- short flags;
-};
-
-extern struct output output;
-extern struct output errout;
-extern struct output memout;
-extern struct output *out1;
-extern struct output *out2;
-
-static void outstr __P((const char *, struct output *));
-#ifndef USE_GLIBC_STDIO
-static void outcslow __P((char, struct output *));
-#endif
-static void flushall __P((void));
-static void flushout __P((struct output *));
-static void freestdout __P((void));
-static void outfmt __P((struct output *, const char *, ...))
- __attribute__((__format__(__printf__,2,3)));
-static void out1fmt __P((const char *, ...))
- __attribute__((__format__(__printf__,1,2)));
-static void fmtstr __P((char *, size_t, const char *, ...))
- __attribute__((__format__(__printf__,3,4)));
-#ifndef USE_GLIBC_STDIO
-static void doformat __P((struct output *, const char *, va_list));
-#endif
-static int xwrite __P((int, const char *, int));
-#ifdef USE_GLIBC_STDIO
-static void initstreams __P((void));
-static void openmemout __P((void));
-static int __closememout __P((void));
-#endif
-
-#define OUTPUT_ERR 01 /* error occurred on output */
-
-#ifdef USE_GLIBC_STDIO
-#define outc(c, o) putc((c), (o)->stream)
-#define doformat(d, f, a) vfprintf((d)->stream, (f), (a))
-#else
-#define outc(c, file) (--(file)->nleft < 0? outcslow((c), (file)) : (*(file)->nextc = (c), (file)->nextc++))
-#endif
-#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)
-
-
-
-/* $NetBSD: parser.h,v 1.14 2000/07/27 04:09:28 cgd Exp $ */
-/* 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'
-
-/* 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 */
-
-/* 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} */
-
-
-/*
- * NEOF is returned by parsecmd when it encounters an end of file. It
- * must be distinct from NULL, so we use the address of a variable that
- * happens to be handy.
- */
-extern int tokpushback;
-#define NEOF ((union node *)&tokpushback)
-extern int whichprompt; /* 1 == PS1, 2 == PS2 */
-extern int checkalias;
-
-
-union node *parsecmd(int);
-static void fixredir(union node *, const char *, int);
-static int goodname(char *);
-static const char *getprompt(void *);
-static int isassignment __P((const char *));
-static const char *const *findkwd __P((const char *));
-
-
-/* $NetBSD: redir.h,v 1.12 2000/05/22 10:18:47 elric Exp $ */
-/* flags passed to redirect */
-#define REDIR_PUSH 01 /* save previous values of file descriptors */
-#define REDIR_BACKQ 02 /* save the command output in memory */
-
-extern int fileno2;
-
-static void redirect __P((union node *, int));
-static void popredir __P((void));
-static int fd0_redirected_p __P((void));
-static void clearredir __P((void));
-static int dup_as_newfd __P((int, int));
-
-
-
-
-/* $NetBSD: show.h,v 1.4 1999/10/08 21:10:44 pk Exp $ */
-#ifdef DEBUG
-static void trace __P((const char *, ...));
-static void trargs __P((char **));
-static void showtree __P((union node *));
-static void trputc __P((int));
-static void trputs __P((const char *));
-static void opentrace __P((void));
-#endif
-/*
- * This file was generated by the mksyntax program.
- */
-
-#ifdef CEOF
-#undef CEOF
-#endif
-
-/* 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 CEOF 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 BASESYNTAX (basesyntax + SYNBASE)
-#define DQSYNTAX (dqsyntax + SYNBASE)
-#define SQSYNTAX (sqsyntax + SYNBASE)
-#define ARISYNTAX (arisyntax + SYNBASE)
-
-#define is_digit(c) ((unsigned)((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')
-
-extern const char basesyntax[];
-extern const char dqsyntax[];
-extern const char sqsyntax[];
-extern const char arisyntax[];
-extern const char is_type[];
-#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
-
-/* 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",
- "{",
- "}"
-};
-
-
-
-
-/* $NetBSD: trap.h,v 1.14 2000/05/22 10:18:47 elric Exp $ */
-extern int pendingsigs;
-
-static int trapcmd __P((int, char **));
-static void clear_traps __P((void));
-static void setsignal __P((int));
-static void ignoresig __P((int));
-static void onsig __P((int));
-static void dotrap __P((void));
-static void setinteractive __P((int));
-static void exitshell __P((int)) __attribute__((noreturn));
-static int decode_signal __P((const char *, int));
-
-
-
-/* $NetBSD: var.h,v 1.18 2000/05/22 10:18:47 elric Exp $ */
-
-/*
- * 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) __P((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 */
-};
-
-
-extern struct localvar *localvars;
-
-#if ATTY
-extern struct var vatty;
-#endif
-extern struct var vifs;
-extern struct var vmail;
-extern struct var vmpath;
-extern struct var vpath;
-extern struct var vps1;
-extern struct var vps2;
-#ifndef SMALL
-extern struct var vterm;
-extern struct var vtermcap;
-extern struct var vhistsize;
-#endif
-
-#ifdef IFS_BROKEN
-extern const char defifsvar[];
-#define defifs (defifsvar + 4)
-#else
-extern const char defifs[];
-#endif
-extern const char defpathvar[];
-#define defpath (defpathvar + 5)
-
-/*
- * 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)
-#ifndef SMALL
-#define histsizeval() (vhistsize.text + 9)
-#define termval() (vterm.text + 5)
-#endif
-
-#if ATTY
-#define attyset() ((vatty.flags & VUNSET) == 0)
-#endif
-#define mpathset() ((vmpath.flags & VUNSET) == 0)
-
-static void initvar __P((void));
-static void setvar __P((const char *, const char *, int));
-static void setvareq __P((char *, int));
-struct strlist;
-static void listsetvar __P((struct strlist *));
-static char *lookupvar __P((const char *));
-static char *bltinlookup __P((const char *));
-static char **environment __P((void));
-static void shprocvar __P((void));
-static int showvarscmd __P((int, char **));
-static int exportcmd __P((int, char **));
-static int localcmd __P((int, char **));
-static void mklocal __P((char *));
-static void poplocalvars __P((void));
-static int setvarcmd __P((int, char **));
-static int unsetcmd __P((int, char **));
-static int unsetvar __P((const char *));
-static int varequal __P((const char *, const char *));
-
* 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.
* 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 <andersee@debian.org> and
+ * Vladimir Oleynik <vodz@usa.net> to be used in busybox
*
- * Modified by Erik Andersen <andersee@debian.org> 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 <assert.h>
#include <ctype.h>
#include <glob.h>
#endif
-#if JOBS
+#ifdef JOBS
#include <termios.h>
-#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 <locale.h>
+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;
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)
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;
for (;;) {
evaltree(n->nbinary.ch1, EV_TESTED);
if (evalskip) {
-skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
+skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
evalskip = 0;
continue;
}
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)
}
-
static void
evalcase(n, flags)
union node *n;
popstackmark(&smark);
}
-
-
/*
* Kick off a subshell to evaluate a tree.
*/
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;
}
}
-
-
/*
* Evaluate a pipeline. All the processes in the pipeline are children
* of the process creating the pipeline. (This differs from some versions
*/
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;
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)
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);
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);
break;
}
}
- if (cmdentry.u.cmd == COMMANDCMD) {
+ if (cmdentry.u.cmd == find_builtin("command")) {
argv++;
if (--argc == 0) {
goto 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;
#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;
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:
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
}
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;
#ifndef BB_TRUE_FALSE
+#ifdef ASH_BBAPPS_AS_BUILTINS
static int
false_main(argc, argv)
int argc;
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)
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)
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
* 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 *);
/*
* 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;
/* 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
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;
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();
* 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;
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;
}
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) {
}
/* 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
prefix("func", pathopt)) {
/* handled below */
} else {
- continue; /* ignore unimplemented options */
+ continue; /* ignore unimplemented options */
}
}
/* if rehash, don't redo absolute path names */
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)
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 */
* 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;
}
*/
static void
-hashcd() {
+hashcd(void) {
struct tblentry **pp;
struct tblentry *cmdp;
*/
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;
}
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;
* 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;
-#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;
* 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;
*/
static void
-unsetfunc(name)
- char *name;
- {
+unsetfunc(char *name)
+{
struct tblentry *cmdp;
if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
}
}
+/*
+ * 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...
}
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) {
goto out;
}
+#ifdef ASH_ALIAS
/* Then look at the aliases */
if ((ap = lookupalias(command, 0)) != NULL) {
if (verbose) {
}
goto out;
}
-
+#endif
/* Then check if it is a tracked alias */
if ((cmdp = cmdlookup(command, 0)) != NULL) {
entry.cmdtype = cmdp->cmdtype;
if (verbose) {
out1fmt(
" is a %sshell builtin",
- entry.u.cmd->flags & BUILTIN_SPECIAL ?
+ IS_BUILTIN_SPECIAL(entry.u.cmd) ?
"special " : nullstr
);
} else {
out1c('\n');
return 0;
}
-#endif
+#endif
+#ifdef ASH_CMDCMD
static int
commandcmd(argc, argv)
int argc;
if (verify_only || verbose_verify_only) {
return describe_command(*argptr, verbose_verify_only);
}
-#endif
+#endif
return 0;
}
+#endif
static int
path_change(newval, bltin)
old = pathval();
new = newval;
- firstchange = 9999; /* assume no change */
+ firstchange = 9999; /* assume no change */
idx = 0;
*bltin = -1;
for (;;) {
if ((*old == '\0' && *new == ':')
|| (*old == ':' && *new == '\0'))
firstchange++;
- old = new; /* ignore subsequent differences */
+ old = new; /* ignore subsequent differences */
}
if (*new == '\0')
break;
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.
/*
* _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
*/
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());
ifslastp = NULL;
argstr(arg->narg.text, flag);
if (arglist == NULL) {
- return; /* here document expanded */
+ return; /* here document expanded */
}
STPUTC('\0', expdest);
p = grabstackstr(expdest);
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)))
case CTLENDARI:
expari(flag);
break;
-#endif
+#endif
case ':':
case '=':
/*
}
-static void
-removerecordregions(endoff)
- int endoff;
+static void
+removerecordregions(int endoff)
{
if (ifslastp == NULL)
return;
}
return;
}
-
+
ifslastp = &ifsfirst;
while (ifslastp->next && ifslastp->next->begoff < endoff)
ifslastp=ifslastp->next;
* evaluate, place result in (backed up) result, adjust string position.
*/
static void
-expari(flag)
- int flag;
+expari(int flag)
{
char *p, *start;
int result;
int quotes = flag & (EXP_FULL | EXP_CASE);
int quoted;
- /* ifsfree(); */
+ /* ifsfree(); */
/*
* This routine is slightly over-complicated for
result = expdest - p + 1;
STADJUST(-result, expdest);
}
-#endif
-
+#endif
/*
* Expand stuff in backwards quotes.
INTON;
}
-
-
static int
subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
char *p;
goto recordleft;
*loc = c;
if (quotes && *loc == CTLESC)
- loc++;
+ loc++;
}
return 0;
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++;
if (patmatch2(str, loc, quotes))
goto recordright;
if (quotes && *loc == CTLESC)
- loc++;
+ loc++;
}
return 0;
case VSPLUS:
case VSMINUS:
if (!set) {
- argstr(p, flag);
+ argstr(p, flag);
break;
}
if (easy)
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;
#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)
return p;
}
-
-
/*
* Test whether a specialized variable is set.
*/
return 1;
}
-
-
/*
* Put a string on the stack.
*/
}
}
-
-
/*
* Add the value of a specialized variable to the stack string.
*/
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 '@':
}
-
/*
* Record the fact that we have to scan this region of the
* string for IFS characters.
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
rmescapes(str->text);
exparg.lastp = &str->next;
break;
- default: /* GLOB_NOSPACE */
+ default: /* GLOB_NOSPACE */
error("Out of space");
}
str = str->next;
}
-#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
+#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
static char *expdir;
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 == '!')
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;
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++) {
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;
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))
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) {
*/
#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;
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;
}
#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;
while (*endp == CTLQUOTEMARK)
endp++;
if (*endp == '\0')
- goto dft; /* no matching ] */
+ goto dft; /* no matching ] */
if (*endp == CTLESC)
endp++;
if (*++endp == ']')
return 0;
break;
}
-dft: default:
+dft: default:
if (squoted && *q == CTLESC)
q++;
if (*q++ != c)
#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 };
*/
static int
-casematch(pattern, val)
- union node *pattern;
- char *val;
- {
+casematch(union node *pattern, const char *val)
+{
struct stackmark smark;
int result;
char *p;
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;
}
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).
*/
}
-/*
- * 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;
*/
static void
-init() {
+init(void) {
/* from cd.c: */
{
* 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.
}
#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 <stdio.h>
-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;
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;
{
if (parsefile->fd)
nr = read(parsefile->fd, buf, BUFSIZ - 1);
- else {
+ else {
do {
cmdedit_read_input((char*)cmdedit_prompt, buf);
nr = strlen(buf);
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:
*
*/
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++);
for (more = 1; more;) {
switch (*p) {
case '\0':
- p++; /* Skip nul */
+ p++; /* Skip nul */
goto 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;
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;
-}
/*
*/
static void
-pushfile() {
+pushfile(void) {
struct parsefile *pf;
parsefile->nleft = parsenleft;
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.
*
* System V doesn't have job control yet, this isn't a problem now.
*/
-static int jobctl;
+
static void setjobctl(int enable)
{
#endif
-#ifdef mkinit
-INCLUDE <stdlib.h>
-
-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",
-#if JOBS
+#ifdef JOBS
static int
killcmd(argc, argv)
int argc;
optionarg
);
}
- break;
+ break;
#ifdef DEBUG
default:
error(
} else
pid = atoi(*argptr);
if (kill(pid, signo) != 0)
- error("%s: %s", *argptr, strerror(errno));
+ error("%s: %m", *argptr);
} while (*++argptr);
return 0;
}
#endif
+static void showjobs(int change);
+
static int
jobscmd(argc, argv)
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);
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))
if (jp->ps != &jp->ps0)
ckfree(jp->ps);
jp->used = 0;
-#if JOBS
+#ifdef JOBS
if (curjob == jp - jobtab + 1)
curjob = 0;
#endif
} 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;
}
if (WIFEXITED(status))
retval = WEXITSTATUS(status);
-#if JOBS
+#ifdef JOBS
else if (WIFSTOPPED(status))
retval = WSTOPSIG(status) + 128;
#endif
}
} 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)
*/
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");
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
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)
* Return a new job structure,
*/
-struct job *
+static struct job *
makejob(node, nprocs)
union node *node;
int nprocs;
jp->used = 1;
jp->changed = 0;
jp->nprocs = 0;
-#if JOBS
+#ifdef JOBS
jp->jobctl = jobctl;
#endif
if (nprocs > 1) {
* 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;
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();
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;
waitforjob(jp)
struct job *jp;
{
-#if JOBS
+#ifdef JOBS
int mypgrp = getpgrp();
#endif
int status;
INTOFF;
intreceived = 0;
-#if JOBS
+#ifdef JOBS
if (!jobctl) {
#else
if (!iflag) {
while (jp->state == 0) {
dowait(1, jp);
}
-#if JOBS
+#ifdef JOBS
if (!jobctl) {
#else
if (!iflag) {
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)
/* 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.
if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
raise(SIGINT);
}
+ if (jp->state == JOBDONE)
+
#endif
- if (! JOBS || jp->state == JOBDONE)
freejob(jp);
INTON;
return st;
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
}
}
INTON;
if (! rootshell || ! iflag || (job && thisjob == job)) {
core = WCOREDUMP(status);
-#if JOBS
+#ifdef JOBS
if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
else
#endif
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));
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 {
* 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;
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;
}
+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?)
*/
#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 */
*/
static void
-chkmail(silent)
- int silent;
+chkmail(int silent)
{
int i;
const char *mpath;
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) {
);
}
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
DOTCMD = find_builtin(".");
BLTINCMD = find_builtin("builtin");
- COMMANDCMD = find_builtin("command");
EXECCMD = find_builtin("exec");
EVALCMD = find_builtin("eval");
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)
state = 4;
if (sflag == 0 || minusc) {
static int sigs[] = {
- SIGINT, SIGQUIT, SIGHUP,
+ SIGINT, SIGQUIT, SIGHUP,
#ifdef SIGTSTP
SIGTSTP,
#endif
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
*/
static void
-cmdloop(top)
- int top;
+cmdloop(int top)
{
union node *n;
struct stackmark smark;
*/
static void
-readcmdfile(name)
- char *name;
+readcmdfile(const char *name)
{
int fd;
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;
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;
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();
}
}
-
static void
-setstackmark(mark)
- struct stackmark *mark;
- {
+setstackmark(struct stackmark *mark)
+{
mark->stackp = stackp;
mark->stacknxt = stacknxt;
mark->stacknleft = stacknleft;
static void
-popstackmark(mark)
- struct stackmark *mark;
- {
+popstackmark(struct stackmark *mark)
+{
struct stack_block *sp;
INTOFF;
*/
static void
-growstackblock() {
+growstackblock(void) {
char *p;
int newlen = ALIGN(stacknleft * 2 + 100);
char *oldspace = stacknxt;
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;
} 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;
static char *
-growstackstr() {
+growstackstr(void) {
int len = stackblocksize();
if (herefd >= 0 && len >= 1024) {
xwrite(herefd, stackblock(), len);
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.
*/
#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
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
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')
else
{
val /= l->factor;
-#ifdef BSD4_4
out1fmt("%lld\n", (long long) val);
-#else
- out1fmt("%ld\n", (long) val);
-#endif
}
}
return 0;
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;
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.
*/
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.
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)),
};
-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 *);
* 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;
#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
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;
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];
}
/* 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;
}
-static void
-optschanged()
-{
- setinteractive(iflag);
- setjobctl(mflag);
-}
/*
* Process shell options. The global variable argptr contains a pointer
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;
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++;
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);
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')
-#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;
*/
static void
-freeparam(param)
- volatile struct shparam *param;
- {
+freeparam(volatile struct shparam *param)
+{
char **ap;
if (param->malloc) {
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
goto out;
}
optnext++;
- if (p[0] == '-' && p[1] == '\0') /* check for "--" */
+ if (p[0] == '-' && p[1] == '\0') /* check for "--" */
goto atend;
}
}
return done;
}
-#endif
+#endif
/*
* XXX - should get rid of. have all builtins use getopt(3). the
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++;
}
-/* $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
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);
}
#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
*/
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;
}
-#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;
return error;
}
#endif
-/* $NetBSD: parser.c,v 1.46 2001/02/04 19:52:06 christos Exp $ */
-
/*
* Shell command parser.
*/
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);
/*
* valid parse tree indicating a blank line.)
*/
-union node *
+static union node *
parsecmd(int interact)
{
int t;
if (heredoclist)
parseheredoc();
else
- pungetc(); /* push back EOF on input */
+ pungetc(); /* push back EOF on input */
return n1;
default:
if (nlflag)
redir = NULL;
rpp = &redir;
+#ifdef ASH_ALIAS
checkalias = 2;
+#endif
for (;;) {
switch (readtoken()) {
case TWORD:
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 (
/* 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();
}
static union node *
-makename() {
+makename(void) {
union node *n;
n = (union node *)stalloc(sizeof (struct narg));
}
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;
static void
-parsefname() {
+parsefname(void) {
union node *n = redirnode;
if (readtoken() != TWORD)
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) {
/*
}
}
+#ifdef ASH_ALIAS
if (t != TWORD) {
if (t != TREDIR) {
checkalias = 0;
}
checkalias = 0;
}
+#endif
out:
#ifdef DEBUG
if (!alreadyseen)
/*
* 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
* have parseword (readtoken1?) handle both words and redirection.]
*/
-#define RETURN(token) return lasttoken = token
+#define RETURN(token) return lasttoken = token
static int
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':
* 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)
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;
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)
else
setprompt(0);
c = pgetc();
- goto loop; /* continue outer loop */
+ goto loop; /* continue outer loop */
case CWORD:
USTPUTC(c, out);
break;
USTPUTC(CTLESC, out);
USTPUTC(c, out);
break;
- case CBACK: /* backslash */
+ case CBACK: /* backslash */
c = pgetc2();
if (c == PEOF) {
USTPUTC('\\', out);
quotef++;
}
break;
- case CVAR: /* '$' */
- PARSESUB(); /* parse substitution */
+ case CVAR: /* '$' */
+ PARSESUB(); /* parse substitution */
break;
- case CENDVAR: /* '}' */
+ case CENDVAR: /* '}' */
if (varnest > 0) {
varnest--;
if (dqvarnest > 0) {
}
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;
}
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);
}
checkend: {
if (eofmark) {
+#ifdef ASH_ALIAS
if (c == PEOA) {
c = pgetc2();
}
+#endif
if (striptabs) {
while (c == '\t') {
c = pgetc2();
np->type = NTO;
pungetc();
}
- } else { /* c == '<' */
+ } else { /* c == '<' */
np->nfile.fd = 0;
switch (c = pgetc()) {
case '<':
) {
USTPUTC('$', out);
pungetc();
- } else if (c == '(') { /* $(command) or $((arith)) */
+ } else if (c == '(') { /* $(command) or $((arith)) */
if (pgetc() == '(') {
PARSEARITH();
} else {
c = pgetc();
}
else
-badsub: synerror("Bad substitution");
+badsub: synerror("Bad substitution");
STPUTC('=', out);
flags = 0;
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);
goto done;
case '\\':
- if ((pc = pgetc()) == '\n') {
+ if ((pc = pgetc()) == '\n') {
plinno++;
if (doprompt)
setprompt(2);
*/
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':
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;
}
(*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)
} /* 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).
*/
static int
-goodname(char *name)
- {
- char *p;
+goodname(const char *name)
+{
+ const char *p;
p = name;
if (! is_name(*p))
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);
/* NOTREACHED */
}
-static void
-setprompt(int which)
-{
- whichprompt = which;
- putprompt(getprompt(NULL));
-}
/*
* called by editline -- any expansions to the prompt
*/
static const char *
getprompt(void *unused)
- {
+{
switch (whichprompt) {
case 0:
return "";
}
}
-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
+
/*
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;
close(newfd);
}
INTON;
- error("%d: %s", fd, strerror(errno));
+ error("%d: %m", fd);
/* NOTREACHED */
}
}
} else if (fd != newfd) {
close(fd);
}
- if (fd == 0)
- fd0_redirected++;
+ if (fd == 0)
+ fd0_redirected++;
if (!try)
dupredirect(n, newfd, memory);
INTON;
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
}
-
/*
* 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);
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;
}
-
/*
* Copy a file descriptor to be >= to. Returns -1
* if the source file descriptor is closed, EMPTY if there are no unused
if (errno == EMFILE)
return EMPTY;
else
- error("%d: %s", from, strerror(errno));
+ error("%d: %m", from);
}
return newfd;
}
* The code was copied from bash.
*/
static int
-noclobberopen(fname)
- const char *fname;
+noclobberopen(const char *fname)
{
int r, fd;
struct stat finfo, finfo2;
*/
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
/*
* 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;
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)
}
}
-#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)
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)
(void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
setlen = SET_LEN + 2;
-
+
if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
return (NULL);
saveset = set;
}
}
-getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
+getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
free(saveset);
return (NULL);
}
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;
}
}
-apply: if (!*p)
+apply: if (!*p)
break;
if (*p != ',')
goto getop;
set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
set->bits = mask;
}
-
+
if (oparg == '+')
set->cmd2 |= CMD2_SET;
else if (oparg == '-')
/*
* 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
}
}
}
-/* $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
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);
#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.
-/*
- * 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;
- }
- }
-}
*/
static void
-setsignal(signo)
- int signo;
+setsignal(int signo)
{
int action;
char *t;
case SIGQUIT:
#ifdef DEBUG
{
- extern int debug;
if (debug)
break;
if (iflag)
action = S_IGN;
break;
-#if JOBS
+#ifdef JOBS
case SIGTSTP:
case SIGTTOU:
if (mflag)
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)
}
-#ifdef mkinit
-INCLUDE <signal.h>
-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();
}
-
/*
* 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;
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;
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);
{
int signo;
- if (is_number(string)) {
- signo = atoi(string);
+ if (is_number(string, &signo)) {
if (signo >= NSIG) {
return -1;
}
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 <unistd.h>
-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.
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 {
* 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;
* The "local" command.
*/
+/* funcnest nonzero if we are currently evaluating a function */
+
static int
localcmd(argc, argv)
int argc;
{
char *name;
- if (! in_function())
+ if (! funcnest)
error("Not in a function");
while ((name = *argptr++) != NULL) {
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);
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 {
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);
/*
* Copyright (c) 1999 Herbert Xu <herbert@debian.org>
* 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)
{
/*-
* 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.
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
- * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
+ * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
+ * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
*
* 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