]> Zhao Yanbai Git Server - minix.git/commitdiff
New version of ash. From FreeBSD 5.4 via Minix-vmd.
authorPhilip Homburg <philip@cs.vu.nl>
Tue, 23 May 2006 12:59:34 +0000 (12:59 +0000)
committerPhilip Homburg <philip@cs.vu.nl>
Tue, 23 May 2006 12:59:34 +0000 (12:59 +0000)
84 files changed:
commands/ash/Makefile
commands/ash/TOUR
commands/ash/alias.c [new file with mode: 0644]
commands/ash/alias.h [new file with mode: 0644]
commands/ash/arith.h [new file with mode: 0644]
commands/ash/arith.y [new file with mode: 0644]
commands/ash/arith_lex.h [new file with mode: 0644]
commands/ash/arith_lex.l [new file with mode: 0644]
commands/ash/bltin/bltin.h
commands/ash/bltin/echo.c
commands/ash/bltin/expr.c
commands/ash/bltin/mkexpr
commands/ash/bltin/myregexp.h [new file with mode: 0644]
commands/ash/bltin/regexp.c
commands/ash/bltin/unary_op
commands/ash/build [deleted file]
commands/ash/builtins [moved from commands/ash/builtins.table with 88% similarity, mode: 0644]
commands/ash/builtins.def [new file with mode: 0644]
commands/ash/cd.c
commands/ash/cd.h [new file with mode: 0644]
commands/ash/complete.c [new file with mode: 0644]
commands/ash/complete.h [new file with mode: 0644]
commands/ash/dirent.c [deleted file]
commands/ash/errmsg.c [new file with mode: 0644]
commands/ash/errmsg.h [new file with mode: 0644]
commands/ash/error.c
commands/ash/error.h
commands/ash/eval.c
commands/ash/eval.h
commands/ash/exec.c
commands/ash/exec.h
commands/ash/expand.c
commands/ash/expand.h
commands/ash/funcs/cmv
commands/ash/funcs/dirs
commands/ash/funcs/kill
commands/ash/funcs/login
commands/ash/funcs/newgrp
commands/ash/funcs/popd
commands/ash/funcs/pushd
commands/ash/funcs/suspend
commands/ash/histedit.c [new file with mode: 0644]
commands/ash/init.h
commands/ash/input.c
commands/ash/input.h
commands/ash/jobs.c
commands/ash/jobs.h
commands/ash/machdep.h
commands/ash/mail.c
commands/ash/mail.h
commands/ash/main.c
commands/ash/main.h
commands/ash/memalloc.c
commands/ash/memalloc.h
commands/ash/miscbltin.c
commands/ash/mkbuiltins
commands/ash/mkinit.c
commands/ash/mknodes.c
commands/ash/mksignames.c
commands/ash/mksyntax.c
commands/ash/mktokens
commands/ash/myhistedit.h [new file with mode: 0644]
commands/ash/mystring.c
commands/ash/mystring.h
commands/ash/nodes.c.pat
commands/ash/nodetypes
commands/ash/options.c
commands/ash/options.h
commands/ash/output.c
commands/ash/output.h
commands/ash/parser.c
commands/ash/parser.h
commands/ash/redir.c
commands/ash/redir.h
commands/ash/setmode.c [new file with mode: 0644]
commands/ash/shell.h
commands/ash/show.c
commands/ash/show.h [new file with mode: 0644]
commands/ash/sys/cdefs.h [deleted file]
commands/ash/test/malloc.c [deleted file]
commands/ash/trap.c
commands/ash/trap.h
commands/ash/var.c
commands/ash/var.h

index cbbb0e588d049e4519a6341fdf8d73482b3cb47d..37799751eaef53b4ec29f4315012089d4606b089 100755 (executable)
@@ -1,41 +1,61 @@
 # Makefile for ash.
 
-SRCS=  builtins.c cd.c dirent.c error.c eval.c exec.c expand.c input.c \
+SRCS=  alias.c builtins.c cd.c error.c eval.c exec.c expand.c histedit.c \
+       input.c \
        jobs.c mail.c main.c memalloc.c miscbltin.c mystring.c nodes.c \
-       options.c parser.c redir.c show.c signames.c syntax.c trap.c \
+       options.c parser.c redir.c setmode.c show.c signames.c syntax.c \
+       trap.c \
        output.c var.c
 
-OBJS=  builtins.o cd.o dirent.o error.o eval.o exec.o expand.o input.o \
+OBJS=  alias.o builtins.o cd.o error.o eval.o exec.o expand.o histedit.o \
+       input.o \
        jobs.o mail.o main.o memalloc.o miscbltin.o mystring.o nodes.o \
-       options.o parser.o redir.o show.o signames.o syntax.o trap.o \
+       options.o parser.o redir.o setmode.o show.o signames.o syntax.o \
+       trap.o \
        output.o var.o init.o \
-       bltin/echo.o bltin/expr.o bltin/operators.o bltin/regexp.o
+       bltin/echo.o bltin/expr.o bltin/operators.o bltin/regexp.o \
+       arith.o arith_lex.o
 
-#
-# Set READLINE in shell.h and add -ledit to LIBS if you want to use the
-# editline package by Simmule Turner and Rich Salz.  (The big, bloated
-# and GPL contaminated FSF readline should work too.)
-#
-CPPFLAGS= -DSHELL -I. -D_MINIX -D_POSIX_SOURCE
-CFLAGS=        -wo -i $(CPPFLAGS)
-LIBS=  -ledit
-CC = exec cc
+LEX=flex
+YACC=yacc
+.c.o:
+       $(CC) $(CFLAGS) -c $< -o $@
+
+# Enable this line to disable command line editing
+#EDIT=-DNO_HISTORY
+# Enable this line to use the editline library instead of libedit
+EDIT=-DEDITLINE
+EDITLIB=-ledit
+
+FLEXLIB=-lfl
+
+# Enable this line if your system does not have a <paths.h>
+NO_PATHS_H=-DNO_PATHS_H 
+
+# Enable this if you don't want job control
+NO_JOBS=-DJOBS=0
+MKB_NO_JOBS=-j
+
+CPPFLAGS= -DSHELL -I. -D_MINIX $(EDIT) $(NO_PATHS_H) $(NO_JOBS)
+CFLAGS=        $(OPT) $(CPPFLAGS)
+LIBS=  $(EDITLIB) $(FLEXLIB)
 
 CLEANFILES= $(OBJS) \
-       builtins.c builtins.h init.c mkinit mknodes mksignames mksyntax \
-       nodes.c nodes.h signames.c signames.h syntax.c syntax.h token.def \
+       arith.c arith_y.h arith_lex.c builtins.c builtins.h init.c \
+       mkinit mknodes mksignames mksyntax \
+       nodes.c nodes.h signames.c signames.h syntax.c syntax.h token.h \
        bltin/operators.h bltin/operators.c
 
 all:   sh
 
 sh:    $(OBJS)
-       $(CC) $(CFLAGS) -o sh $(OBJS) $(LIBS)
-       install -S 100k sh
+       $(CC) $(CFLAGS) -fnone -o sh $(OBJS) $(LIBS)
 
-install:       /usr/bin/ash /usr/bin/sh /bin/sh /bin/bigsh
+install:       /usr/bin/ash /usr/bin/sh /bin/sh /usr/man/man1/ash.1 \
+               /usr/man/man1/echo.1 /usr/man/man1/expr.1
 
 /usr/bin/ash:  sh
-       install -cs -o bin $? $@
+       install -c $? $@
 
 /usr/bin/sh:   /usr/bin/ash
        install -l $? $@
@@ -43,8 +63,14 @@ install:     /usr/bin/ash /usr/bin/sh /bin/sh /bin/bigsh
 /bin/sh:       /usr/bin/ash
        install -lcs $? $@
 
-/bin/bigsh:    /usr/bin/ash
-       install -S 1500000 -lcs $? $@
+/usr/man/man1/ash.1:   sh.1
+       install -lc $? $@
+
+/usr/man/man1/echo.1:  bltin/echo.1
+       install -lc $? $@
+
+/usr/man/man1/expr.1:  bltin/expr.1
+       install -lc $? $@
 
 clean:
        rm -f $(CLEANFILES) sh core
@@ -54,11 +80,18 @@ parser.o: token.def
 token.def: mktokens
        sh mktokens
 
-builtins.c builtins.h: builtins.table shell.h
-       sh mkbuiltins shell.h builtins.table
+arith.c:       arith.y
+       $(YACC) -d $?
+       mv y.tab.c $@
+       mv y.tab.h arith_y.h
 
-init.o: mkinit $(SRCS)
-       ./mkinit '$(CC) -c $(CFLAGS) init.c' $(SRCS)
+arith_lex.c:   arith_lex.l
+
+builtins.c builtins.h: builtins.def shell.h
+       sh mkbuiltins $(MKB_NO_JOBS) . shell.h builtins.def
+
+init.c: mkinit $(SRCS)
+       ./mkinit $(SRCS)
 
 mkinit: mkinit.c
        $(CC) $(CFLAGS) mkinit.c -o $@
@@ -81,20 +114,8 @@ syntax.c syntax.h: mksyntax
 mksyntax: mksyntax.c parser.h
        $(CC) $(CFLAGS) mksyntax.c -o $@
 
-bltin/operators.h:     bltin/mkexpr bltin/binary_op bltin/unary_op
-       cd bltin && sh mkexpr
-
-bltin/echo.o:  bltin/echo.c
-       cd bltin && $(CC) -I.. $(CFLAGS) -c echo.c
-
-bltin/expr.o:  bltin/expr.c
-       cd bltin && $(CC) -I.. $(CFLAGS) -c expr.c
-
-bltin/operators.o:     bltin/operators.c
-       cd bltin && $(CC) -I.. $(CFLAGS) -c operators.c
-
-bltin/regexp.o:        bltin/regexp.c
-       cd bltin && $(CC) -I.. $(CFLAGS) -c regexp.c
+bltin/operators.h:     bltin/mkexpr bltin/unary_op bltin/binary_op
+       cd bltin && sh mkexpr unary_op binary_op
 
 # Dependencies you say?  This will have to do.
 $(OBJS): error.h eval.h exec.h expand.h init.h input.h \
@@ -103,3 +124,6 @@ $(OBJS): error.h eval.h exec.h expand.h init.h input.h \
        builtins.h nodes.h signames.h syntax.h
 
 bltin/expr.o bltin/operators.o:        bltin/operators.h
+
+#
+# $PchId: Makefile,v 1.4 2006/05/22 12:40:46 philip Exp $
index 669c0a933466f4fc8b1b0c484f096852e2500ce2..afd0c8dd255639277454272ce3bc8407f08af54f 100755 (executable)
@@ -1,4 +1,13 @@
-#      @(#)TOUR        5.1 (Berkeley) 3/7/91
+#      @(#)TOUR        8.1 (Berkeley) 5/31/93
+# $FreeBSD: src/bin/sh/TOUR,v 1.6 1999/08/27 23:15:07 peter Exp $
+
+NOTE -- This is the original TOUR paper distributed with ash and
+does not represent the current state of the shell.  It is provided anyway
+since it provides helpful information for how the shell is structured,
+but be warned that things have changed -- the current shell is
+still under development.
+
+================================================================
 
                        A Tour through Ash
 
@@ -20,7 +29,7 @@ programs is:
         mknodes         nodetypes           nodes.h nodes.c
         mksignames          -               signames.h signames.c
         mksyntax            -               syntax.h syntax.c
-        mktokens            -               token.def
+        mktokens            -               token.h
         bltin/mkexpr    unary_op binary_op  operators.h operators.c
 
 There are undoubtedly too many of these.  Mkinit searches all the
@@ -346,3 +355,6 @@ cause the preprocessor can't handle functions with a variable
 number of arguments.  Defining DEBUG also causes the shell to
 generate a core dump if it is sent a quit signal.  The tracing
 code is in show.c.
+
+#
+# $PchId: TOUR,v 1.3 2006/03/31 11:33:46 philip Exp $
diff --git a/commands/ash/alias.c b/commands/ash/alias.c
new file mode 100644 (file)
index 0000000..90ef85b
--- /dev/null
@@ -0,0 +1,265 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)alias.c    8.3 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/alias.c,v 1.18 2004/04/06 20:06:51 markm Exp $");
+*/
+
+#include <stdlib.h>
+#include "shell.h"
+#include "input.h"
+#include "output.h"
+#include "error.h"
+#include "memalloc.h"
+#include "mystring.h"
+#include "alias.h"
+#include "options.h"   /* XXX for argptr (should remove?) */
+#include "builtins.h"
+
+#define ATABSIZE 39
+
+STATIC struct alias *atab[ATABSIZE];
+
+STATIC void setalias(char *, char *);
+STATIC int unalias(char *);
+STATIC struct alias **hashalias(char *);
+
+STATIC
+void
+setalias(char *name, char *val)
+{
+       struct alias *ap, **app;
+
+       app = hashalias(name);
+       for (ap = *app; ap; ap = ap->next) {
+               if (equal(name, ap->name)) {
+                       INTOFF;
+                       ckfree(ap->val);
+                       ap->val = savestr(val);
+                       INTON;
+                       return;
+               }
+       }
+       /* not found */
+       INTOFF;
+       ap = ckmalloc(sizeof (struct alias));
+       ap->name = savestr(name);
+       /*
+        * XXX - HACK: in order that the parser will not finish reading the
+        * alias value off the input before processing the next alias, we
+        * dummy up an extra space at the end of the alias.  This is a crock
+        * and should be re-thought.  The idea (if you feel inclined to help)
+        * is to avoid alias recursions.  The mechanism used is: when
+        * expanding an alias, the value of the alias is pushed back on the
+        * input as a string and a pointer to the alias is stored with the
+        * string.  The alias is marked as being in use.  When the input
+        * routine finishes reading the string, it marks the alias not
+        * in use.  The problem is synchronization with the parser.  Since
+        * it reads ahead, the alias is marked not in use before the
+        * resulting token(s) is next checked for further alias sub.  The
+        * H A C K is that we add a little fluff after the alias value
+        * so that the string will not be exhausted.  This is a good
+        * idea ------- ***NOT***
+        */
+#ifdef notyet
+       ap->val = savestr(val);
+#else /* hack */
+       {
+       int len = strlen(val);
+       ap->val = ckmalloc(len + 2);
+       memcpy(ap->val, val, len);
+       ap->val[len] = ' ';     /* fluff */
+       ap->val[len+1] = '\0';
+       }
+#endif
+       ap->flag = 0;
+       ap->next = *app;
+       *app = ap;
+       INTON;
+}
+
+STATIC int
+unalias(char *name)
+{
+       struct alias *ap, **app;
+
+       app = hashalias(name);
+
+       for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
+               if (equal(name, ap->name)) {
+                       /*
+                        * if the alias is currently in use (i.e. its
+                        * buffer is being used by the input routine) we
+                        * just null out the name instead of freeing it.
+                        * We could clear it out later, but this situation
+                        * is so rare that it hardly seems worth it.
+                        */
+                       if (ap->flag & ALIASINUSE)
+                               *ap->name = '\0';
+                       else {
+                               INTOFF;
+                               *app = ap->next;
+                               ckfree(ap->name);
+                               ckfree(ap->val);
+                               ckfree(ap);
+                               INTON;
+                       }
+                       return (0);
+               }
+       }
+
+       return (1);
+}
+
+#ifdef mkinit
+INCLUDE "alias.h"
+SHELLPROC {
+       rmaliases();
+}
+#endif
+
+void
+rmaliases(void)
+{
+       struct alias *ap, *tmp;
+       int i;
+
+       INTOFF;
+       for (i = 0; i < ATABSIZE; i++) {
+               ap = atab[i];
+               atab[i] = NULL;
+               while (ap) {
+                       ckfree(ap->name);
+                       ckfree(ap->val);
+                       tmp = ap;
+                       ap = ap->next;
+                       ckfree(tmp);
+               }
+       }
+       INTON;
+}
+
+struct alias *
+lookupalias(char *name, int check)
+{
+       struct alias *ap = *hashalias(name);
+
+       for (; ap; ap = ap->next) {
+               if (equal(name, ap->name)) {
+                       if (check && (ap->flag & ALIASINUSE))
+                               return (NULL);
+                       return (ap);
+               }
+       }
+
+       return (NULL);
+}
+
+/*
+ * TODO - sort output
+ */
+int
+aliascmd(int argc, char **argv)
+{
+       char *n, *v;
+       int ret = 0;
+       struct alias *ap;
+
+       if (argc == 1) {
+               int i;
+
+               for (i = 0; i < ATABSIZE; i++)
+                       for (ap = atab[i]; ap; ap = ap->next) {
+                               if (*ap->name != '\0') {
+                                       out1fmt("alias %s=", ap->name);
+                                       out1qstr(ap->val);
+                                       out1c('\n');
+                               }
+                       }
+               return (0);
+       }
+       while ((n = *++argv) != NULL) {
+               if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
+                       if ((ap = lookupalias(n, 0)) == NULL) {
+                               outfmt(out2, "alias: %s not found\n", n);
+                               ret = 1;
+                       } else {
+                               out1fmt("alias %s=", n);
+                               out1qstr(ap->val);
+                               out1c('\n');
+                       }
+               else {
+                       *v++ = '\0';
+                       setalias(n, v);
+               }
+       }
+
+       return (ret);
+}
+
+int
+unaliascmd(int argc __unused, char **argv __unused)
+{
+       int i;
+
+       while ((i = nextopt("a")) != '\0') {
+               if (i == 'a') {
+                       rmaliases();
+                       return (0);
+               }
+       }
+       for (i = 0; *argptr; argptr++)
+               i = unalias(*argptr);
+
+       return (i);
+}
+
+STATIC struct alias **
+hashalias(char *p)
+{
+       unsigned int hashval;
+
+       hashval = *p << 4;
+       while (*p)
+               hashval+= *p++;
+       return &atab[hashval % ATABSIZE];
+}
+
+/*
+ * $PchId: alias.c,v 1.5 2006/05/22 12:41:12 philip Exp $
+ */
diff --git a/commands/ash/alias.h b/commands/ash/alias.h
new file mode 100644 (file)
index 0000000..e541908
--- /dev/null
@@ -0,0 +1,52 @@
+/*-
+ * 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.
+ * 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.
+ *
+ *     @(#)alias.h     8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/alias.h,v 1.8 2004/04/06 20:06:51 markm Exp $
+ */
+
+#define ALIASINUSE     1
+
+struct alias {
+       struct alias *next;
+       char *name;
+       char *val;
+       int flag;
+};
+
+struct alias *lookupalias(char *, int);
+int aliascmd(int, char **);
+int unaliascmd(int, char **);
+void rmaliases(void);
+
+/*
+ * $PchId: alias.h,v 1.4 2006/03/31 11:30:54 philip Exp $
+ */
diff --git a/commands/ash/arith.h b/commands/ash/arith.h
new file mode 100644 (file)
index 0000000..90c0a67
--- /dev/null
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 1995
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 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.
+ *
+ *     @(#)arith.h     1.1 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/arith.h,v 1.9 2004/04/06 20:06:51 markm Exp $
+ */
+
+int arith(char *);
+int arith_assign(char *, arith_t);
+int expcmd(int, char **);
+
+/*
+ * $PchId: arith.h,v 1.3 2006/03/31 11:25:25 philip Exp $
+ */
diff --git a/commands/ash/arith.y b/commands/ash/arith.y
new file mode 100644 (file)
index 0000000..f20eb32
--- /dev/null
@@ -0,0 +1,366 @@
+%{
+/*-
+ * 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.
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)arith.y    8.3 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/arith.y,v 1.19 2004/05/24 10:11:31 stefanf Exp $");
+*/
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "shell.h"
+#include "arith.h"
+#include "arith_lex.h"
+#include "var.h"
+%}
+%union {
+       arith_t l_value;
+       char* s_value;
+}
+%token <l_value> ARITH_NUM ARITH_LPAREN ARITH_RPAREN
+%token <s_value> ARITH_VAR
+
+%type <l_value>        expr
+%right ARITH_ASSIGN
+%right ARITH_ADDASSIGN ARITH_SUBASSIGN
+%right ARITH_MULASSIGN ARITH_DIVASSIGN ARITH_REMASSIGN
+%right ARITH_RSHASSIGN ARITH_LSHASSIGN
+%right ARITH_BANDASSIGN ARITH_BXORASSIGN ARITH_BORASSIGN
+%left ARITH_OR
+%left ARITH_AND
+%left ARITH_BOR
+%left ARITH_BXOR
+%left ARITH_BAND
+%left ARITH_EQ ARITH_NE
+%left ARITH_LT ARITH_GT ARITH_GE ARITH_LE
+%left ARITH_LSHIFT ARITH_RSHIFT
+%left ARITH_ADD ARITH_SUB
+%left ARITH_MUL ARITH_DIV ARITH_REM
+%left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT
+%%
+
+exp:
+       expr
+               { return ($1); }
+       ;
+
+expr:
+       ARITH_LPAREN expr ARITH_RPAREN
+               { $$ = $2; } |
+       expr ARITH_OR expr
+               { $$ = $1 ? $1 : $3 ? $3 : 0; } |
+       expr ARITH_AND expr
+               { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } |
+       expr ARITH_BOR expr
+               { $$ = $1 | $3; } |
+       expr ARITH_BXOR expr
+               { $$ = $1 ^ $3; } |
+       expr ARITH_BAND expr
+               { $$ = $1 & $3; } |
+       expr ARITH_EQ expr
+               { $$ = $1 == $3; } |
+       expr ARITH_GT expr
+               { $$ = $1 > $3; } |
+       expr ARITH_GE expr
+               { $$ = $1 >= $3; } |
+       expr ARITH_LT expr
+               { $$ = $1 < $3; } |
+       expr ARITH_LE expr
+               { $$ = $1 <= $3; } |
+       expr ARITH_NE expr
+               { $$ = $1 != $3; } |
+       expr ARITH_LSHIFT expr
+               { $$ = $1 << $3; } |
+       expr ARITH_RSHIFT expr
+               { $$ = $1 >> $3; } |
+       expr ARITH_ADD expr
+               { $$ = $1 + $3; } |
+       expr ARITH_SUB expr
+               { $$ = $1 - $3; } |
+       expr ARITH_MUL expr
+               { $$ = $1 * $3; } |
+       expr ARITH_DIV expr
+               {
+               if ($3 == 0)
+                       yyerror("division by zero");
+               $$ = $1 / $3;
+               } |
+       expr ARITH_REM expr
+               {
+               if ($3 == 0)
+                       yyerror("division by zero");
+               $$ = $1 % $3;
+               } |
+       ARITH_NOT expr
+               { $$ = !($2); } |
+       ARITH_BNOT expr
+               { $$ = ~($2); } |
+       ARITH_SUB expr %prec ARITH_UNARYMINUS
+               { $$ = -($2); } |
+       ARITH_ADD expr %prec ARITH_UNARYPLUS
+               { $$ = $2; } |
+       ARITH_NUM |
+       ARITH_VAR
+               {
+               char *p;
+               arith_t arith_val;
+               char *str_val;
+
+               if (lookupvar($1) == NULL)
+                       setvarsafe($1, "0", 0);
+               str_val = lookupvar($1);
+               arith_val = strtoarith_t(str_val, &p, 0);
+               /*
+                * Conversion is successful only in case
+                * we've converted _all_ characters.
+                */
+               if (*p != '\0')
+                       yyerror("variable conversion error");
+               $$ = arith_val;
+               } |
+       ARITH_VAR ARITH_ASSIGN expr
+               {
+               if (arith_assign($1, $3) != 0)
+                       yyerror("variable assignment error");
+               $$ = $3;
+               } |
+       ARITH_VAR ARITH_ADDASSIGN expr
+               {
+               arith_t value;
+
+               value = atoarith_t(lookupvar($1)) + $3;
+               if (arith_assign($1, value) != 0)
+                       yyerror("variable assignment error");
+               $$ = value;
+               } |
+       ARITH_VAR ARITH_SUBASSIGN expr
+               {
+               arith_t value;
+
+               value = atoarith_t(lookupvar($1)) - $3;
+               if (arith_assign($1, value) != 0)
+                       yyerror("variable assignment error");
+               $$ = value;
+               } |
+       ARITH_VAR ARITH_MULASSIGN expr
+               {
+               arith_t value;
+
+               value = atoarith_t(lookupvar($1)) * $3;
+               if (arith_assign($1, value) != 0)
+                       yyerror("variable assignment error");
+               $$ = value;
+               } |
+       ARITH_VAR ARITH_DIVASSIGN expr
+               {
+               arith_t value;
+
+               if ($3 == 0)
+                       yyerror("division by zero");
+
+               value = atoarith_t(lookupvar($1)) / $3;
+               if (arith_assign($1, value) != 0)
+                       yyerror("variable assignment error");
+               $$ = value;
+               } |
+       ARITH_VAR ARITH_REMASSIGN expr
+               {
+               arith_t value;
+
+               if ($3 == 0)
+                       yyerror("division by zero");
+
+               value = atoarith_t(lookupvar($1)) % $3;
+               if (arith_assign($1, value) != 0)
+                       yyerror("variable assignment error");
+               $$ = value;
+               } |
+       ARITH_VAR ARITH_RSHASSIGN expr
+               {
+               arith_t value;
+
+               value = atoarith_t(lookupvar($1)) >> $3;
+               if (arith_assign($1, value) != 0)
+                       yyerror("variable assignment error");
+               $$ = value;
+               } |
+       ARITH_VAR ARITH_LSHASSIGN expr
+               {
+               arith_t value;
+
+               value = atoarith_t(lookupvar($1)) << $3;
+               if (arith_assign($1, value) != 0)
+                       yyerror("variable assignment error");
+               $$ = value;
+               } |
+       ARITH_VAR ARITH_BANDASSIGN expr
+               {
+               arith_t value;
+
+               value = atoarith_t(lookupvar($1)) & $3;
+               if (arith_assign($1, value) != 0)
+                       yyerror("variable assignment error");
+               $$ = value;
+               } |
+       ARITH_VAR ARITH_BXORASSIGN expr
+               {
+               arith_t value;
+
+               value = atoarith_t(lookupvar($1)) ^ $3;
+               if (arith_assign($1, value) != 0)
+                       yyerror("variable assignment error");
+               $$ = value;
+               } |
+       ARITH_VAR ARITH_BORASSIGN expr
+               {
+               arith_t value;
+
+               value = atoarith_t(lookupvar($1)) | $3;
+               if (arith_assign($1, value) != 0)
+                       yyerror("variable assignment error");
+               $$ = value;
+               } ;
+%%
+#include "error.h"
+#include "output.h"
+#include "memalloc.h"
+#include "builtins.h"
+
+#define lstrlen(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3)
+
+char *arith_buf, *arith_startbuf;
+
+int yylex(void);
+int yyparse(void);
+
+int
+arith_assign(char *name, arith_t value)
+{
+       char *str;
+       int ret;
+
+       str = (char *)ckmalloc(lstrlen(value));
+       sprintf(str, ARITH_FORMAT_STR, value);
+       ret = setvarsafe(name, str, 0);
+       free(str);
+       return ret;
+}
+
+int
+arith(char *s)
+{
+       long result;
+
+       arith_buf = arith_startbuf = s;
+
+       INTOFF;
+       result = yyparse();
+       arith_lex_reset();      /* Reprime lex. */
+       INTON;
+
+       return result;
+}
+
+void
+yyerror(char *s)
+{
+
+       yyerrok;
+       yyclearin;
+       arith_lex_reset();      /* Reprime lex. */
+       error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
+}
+
+/*
+ *  The exp(1) builtin.
+ */
+int
+expcmd(int argc, char **argv)
+{
+       char *p;
+       char *concat;
+       char **ap;
+       long i;
+
+       if (argc > 1) {
+               p = argv[1];
+               if (argc > 2) {
+                       /*
+                        * Concatenate arguments.
+                        */
+                       STARTSTACKSTR(concat);
+                       ap = argv + 2;
+                       for (;;) {
+                               while (*p)
+                                       STPUTC(*p++, concat);
+                               if ((p = *ap++) == NULL)
+                                       break;
+                               STPUTC(' ', concat);
+                       }
+                       STPUTC('\0', concat);
+                       p = grabstackstr(concat);
+               }
+       } else
+               p = "";
+
+       i = arith(p);
+
+       out1fmt("%ld\n", i);
+       return !i;
+}
+
+/*************************/
+#ifdef TEST_ARITH
+#include <stdio.h>
+main(int argc, char *argv[])
+{
+       printf("%d\n", exp(argv[1]));
+}
+
+error(char *s)
+{
+       fprintf(stderr, "exp: %s\n", s);
+       exit(1);
+}
+#endif
+
+/*
+ * $PchId: arith.y,v 1.6 2006/05/22 12:41:47 philip Exp $
+ */
diff --git a/commands/ash/arith_lex.h b/commands/ash/arith_lex.h
new file mode 100644 (file)
index 0000000..301befa
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+arith_lex.h
+
+Created:       July 1995 by Philip Homburg <philip@cs.vu.nl>
+*/
+
+int yylex(void);
+void arith_lex_reset(void);
+
+/*
+ * $PchId: arith_lex.h,v 1.1 2001/05/18 19:57:55 philip Exp $
+ */
diff --git a/commands/ash/arith_lex.l b/commands/ash/arith_lex.l
new file mode 100644 (file)
index 0000000..6c5a361
--- /dev/null
@@ -0,0 +1,138 @@
+%{
+/*-
+ * 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.
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)arith_lex.l        8.3 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/arith_lex.l,v 1.22 2004/04/06 20:06:51 markm Exp $");
+*/
+
+#include <string.h>
+
+#include "shell.h"
+#include "arith_lex.h"
+#include "arith_y.h"
+#include "error.h"
+#include "memalloc.h"
+#include "var.h"
+
+extern char *arith_buf, *arith_startbuf;
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max) \
+       result = (*buf = *arith_buf++) ? 1 : YY_NULL;
+#define YY_NO_UNPUT
+%}
+
+%%
+[ \t\n]        { ; }
+
+0x[a-fA-F0-9]+ {
+                       yylval.l_value = strtoarith_t(yytext, NULL, 16);
+                       return ARITH_NUM;
+               }
+
+0[0-7]+                {
+                       yylval.l_value = strtoarith_t(yytext, NULL, 8);
+                       return ARITH_NUM;
+               }
+
+[0-9]+         {
+                       yylval.l_value = strtoarith_t(yytext, NULL, 10);
+                       return ARITH_NUM;
+               }
+
+[A-Za-z][A-Za-z0-9_]*  {
+                       /*
+                        * If variable doesn't exist, we should initialize
+                        * it to zero.
+                        */
+                       char *temp;
+                       if (lookupvar(yytext) == NULL)
+                               setvarsafe(yytext, "0", 0);
+                       temp = (char *)ckmalloc(strlen(yytext) + 1);
+                       yylval.s_value = strcpy(temp, yytext);
+
+                       return ARITH_VAR;
+               }
+
+"("            {       return ARITH_LPAREN;    }
+")"            {       return ARITH_RPAREN;    }
+"||"           {       return ARITH_OR;        }
+"&&"           {       return ARITH_AND;       }
+"|"            {       return ARITH_BOR;       }
+"^"            {       return ARITH_BXOR;      }
+"&"            {       return ARITH_BAND;      }
+"=="           {       return ARITH_EQ;        }
+"!="           {       return ARITH_NE;        }
+">"            {       return ARITH_GT;        }
+">="           {       return ARITH_GE;        }
+"<"            {       return ARITH_LT;        }
+"<="           {       return ARITH_LE;        }
+"<<"           {       return ARITH_LSHIFT;    }
+">>"           {       return ARITH_RSHIFT;    }
+"*"            {       return ARITH_MUL;       }
+"/"            {       return ARITH_DIV;       }
+"%"            {       return ARITH_REM;       }
+"+"            {       return ARITH_ADD;       }
+"-"            {       return ARITH_SUB;       }
+"~"            {       return ARITH_BNOT;      }
+"!"            {       return ARITH_NOT;       }
+"="            {       return ARITH_ASSIGN;    }
+"+="           {       return ARITH_ADDASSIGN; }
+"-="           {       return ARITH_SUBASSIGN; }
+"*="           {       return ARITH_MULASSIGN; }
+"/="           {       return ARITH_DIVASSIGN; }
+"%="           {       return ARITH_REMASSIGN; }
+">>="          {       return ARITH_RSHASSIGN; }
+"<<="          {       return ARITH_LSHASSIGN; }
+"&="           {       return ARITH_BANDASSIGN; }
+"^="           {       return ARITH_BXORASSIGN; }
+"|="           {       return ARITH_BORASSIGN; }
+.              {
+                       error("arith: syntax error: \"%s\"\n", arith_startbuf);
+               }
+%%
+
+void
+arith_lex_reset(void)
+{
+       YY_NEW_FILE;
+}
+
+/*
+ * $PchId: arith_lex.l,v 1.5 2006/04/10 14:35:29 philip Exp $
+ */
index 5859a01bc2bc770259ec90b9b90bbe018bf3f33e..4dc41fac6f9df0364b6c7f87735d3b19ac489f2b 100755 (executable)
@@ -1,26 +1,78 @@
+/*-
+ * Copyright (c) 1991, 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.
+ * 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.
+ *
+ *     @(#)bltin.h     8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/bltin/bltin.h,v 1.13 2004/04/06 20:06:53 markm Exp $
+ */
+
 /*
  * This file is included by programs which are optionally built into the
  * shell.  If SHELL is defined, we try to map the standard UNIX library
  * routines to ash routines using defines.
- *
- * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
- * This file is part of ash, which is distributed under the terms specified
- * by the Ash General Public License.  See the file named LICENSE.
  */
 
 #include "../shell.h"
 #include "../mystring.h"
 #ifdef SHELL
+#include "builtins.h"
 #include "../output.h"
+#undef stdout
 #define stdout out1
+#undef stderr
 #define stderr out2
 #define printf out1fmt
+#undef putc
 #define putc(c, file)  outc(c, file)
+#undef putchar
 #define putchar(c)     out1c(c)
 #define fprintf outfmt
 #define fputs outstr
 #define fflush flushout
 #define INITARGS(argv)
+#define warnx1(a, b, c) {                              \
+       char buf[64];                                   \
+       (void)snprintf(buf, sizeof(buf), a);            \
+       error("%s", buf);                               \
+}
+#define warnx2(a, b, c) {                              \
+       char buf[64];                                   \
+       (void)snprintf(buf, sizeof(buf), a, b);         \
+       error("%s", buf);                               \
+}
+#define warnx3(a, b, c) {                              \
+       char buf[64];                                   \
+       (void)snprintf(buf, sizeof(buf), a, b, c);      \
+       error("%s", buf);                               \
+}
+
 #else
 #undef NULL
 #include <stdio.h>
 #define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
 #endif
 
-#ifdef __STDC__
 pointer stalloc(int);
-void error(char *, ...);
-#else
-pointer stalloc();
-void error();
-#endif
+void error(const char *, ...);
 
 
 extern char *commandname;
+
+/*
+ * $PchId: bltin.h,v 1.4 2006/03/29 11:39:00 philip Exp $
+ */
index 8855af2dda794c566f39c31c4d36f611565cb862..9051c0c2cb81470bc55a5b1f97ceecd607430da0 100755 (executable)
+/*-
+ * Copyright (c) 1991, 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.
+ * 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.
+ *
+ *     @(#)echo.c      8.2 (Berkeley) 5/4/95
+ */
+
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/bltin/echo.c,v 1.14 2004/04/06 20:06:53 markm Exp $");
+*/
+
 /*
  * Echo command.
- *
- * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
- * This file is part of ash, which is distributed under the terms specified
- * by the Ash General Public License.  See the file named LICENSE.
  */
 
-#define main echocmd
+#ifdef __minix
+#define MINIX
+#endif
 
 #include "bltin.h"
 
+#ifndef MINIX
+/* #define eflag 1 */
+#else
 #undef eflag
+#endif
 
-
-main(argc, argv)  char **argv; {
-      register char **ap;
-      register char *p;
-      register char c;
-      int count;
-      int nflag = 0;
+int
+echocmd(argc, argv)
+       int argc;
+       char **argv;
+{
+       char **ap;
+       char *p;
+       char c;
+       int count;
+       int nflag = 0;
 #ifndef eflag
-      int eflag = 0;
+       int eflag = 0;
 #endif
 
-      ap = argv;
-      if (argc)
-           ap++;
-      if ((p = *ap) != NULL) {
-           if (equal(p, "--")) {
-                 ap++;
-           }
-           if (equal(p, "-n")) {
-                 nflag++;
-                 ap++;
-           } else if (equal(p, "-e")) {
+       ap = argv;
+       if (argc)
+               ap++;
+       if ((p = *ap) != NULL) {
+#ifdef MINIX
+               if (equal(p, "--")) {
+                       ap++;
+               }
+#endif
+               if (equal(p, "-n")) {
+                       nflag++;
+                       ap++;
+               } else if (equal(p, "-e")) {
 #ifndef eflag
-                 eflag++;
+                       eflag++;
 #endif
-                 ap++;
-           }
-      }
-      while ((p = *ap++) != NULL) {
-           while ((c = *p++) != '\0') {
-                 if (c == '\\' && eflag) {
-                       switch (*p++) {
-                       case 'b':  c = '\b';  break;
-                       case 'c':  return 0;            /* exit */
-                       case 'f':  c = '\f';  break;
-                       case 'n':  c = '\n';  break;
-                       case 'r':  c = '\r';  break;
-                       case 't':  c = '\t';  break;
-                       case 'v':  c = '\v';  break;
-                       case '\\':  break;              /* c = '\\' */
-                       case '0':
-                             c = 0;
-                             count = 3;
-                             while (--count >= 0 && (unsigned)(*p - '0') < 8)
-                                   c = (c << 3) + (*p++ - '0');
-                             break;
-                       default:
-                             p--;
-                             break;
+                       ap++;
+               }
+       }
+       while ((p = *ap++) != NULL) {
+               while ((c = *p++) != '\0') {
+                       if (c == '\\' && eflag) {
+                               switch (*p++) {
+                               case 'a':  c = '\a';  break;
+                               case 'b':  c = '\b';  break;
+                               case 'c':  return 0;            /* exit */
+                               case 'e':  c = '\033';  break;
+                               case 'f':  c = '\f';  break;
+                               case 'n':  c = '\n';  break;
+                               case 'r':  c = '\r';  break;
+                               case 't':  c = '\t';  break;
+                               case 'v':  c = '\v';  break;
+                               case '\\':  break;              /* c = '\\' */
+                               case '0':
+                                       c = 0;
+                                       count = 3;
+                                       while (--count >= 0 && (unsigned)(*p - '0') < 8)
+                                               c = (c << 3) + (*p++ - '0');
+                                       break;
+                               default:
+                                       p--;
+                                       break;
+                               }
                        }
-                 }
-                 putchar(c);
-           }
-           if (*ap)
-                 putchar(' ');
-      }
-      if (! nflag)
-           putchar('\n');
-      return 0;
+                       putchar(c);
+               }
+               if (*ap)
+                       putchar(' ');
+       }
+       if (! nflag)
+               putchar('\n');
+       return 0;
 }
+
+/*
+ * $PchId: echo.c,v 1.5 2006/05/23 12:05:56 philip Exp $
+ */
index 3e9305d866354e82f0ec94a3396673f1cb083394..07052186cd74f7d358cb8facbc866a2b64d97eb0 100755 (executable)
@@ -7,17 +7,14 @@
  */
 
 
-#define main exprcmd
-
 #include "bltin.h"
 #include "operators.h"
+#include <regex.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
 
-#ifndef S_ISLNK
-#define lstat          stat
-#define S_ISLNK(mode)  (0)
-#endif
 
 #define STACKSIZE 12
 #define NESTINCR 16
@@ -50,7 +47,6 @@ struct operator {
 
 
 struct filestat {
-      int op;                  /* OP_FILE or OP_LFILE */
       char *name;              /* name of file */
       int rcode;               /* return code from stat */
       struct stat stat;                /* status info on file */
@@ -63,24 +59,18 @@ extern short number_parens; /* number of \( \) pairs */
 
 
 #ifdef __STDC__
-int expr_is_false(struct value *);
-void expr_operator(int, struct value *, struct filestat *);
-int lookup_op(char *, char *const*);
-char *re_compile(char *);      /* defined in regexp.c */
-int re_match(char *, char *);  /* defined in regexp.c */
-long atol(const char *);
+static int expr_is_false(struct value *);
+static void expr_operator(int, struct value *, struct filestat *);
+static int lookup_op(char *, char *const*);
 #else
-int expr_is_false();
-void expr_operator();
-int lookup_op();
-char *re_compile();    /* defined in regexp.c */
-int re_match();        /* defined in regexp.c */
-long atol();
+static int expr_is_false();
+static void expr_operator();
+static int lookup_op();
 #endif
 
 
 
-main(argc, argv)  char **argv; {
+exprcmd(argc, argv)  char **argv; {
       char **ap;
       char *opname;
       char c;
@@ -146,6 +136,13 @@ overflow:          error("Expression too complex");
                  continue;
 
            } else {
+                 if (opname[0] == '\'') {
+                       for (p = opname ; *++p != '\0' ; );
+                       if (--p > opname && *p == '\'') {
+                             *p = '\0';
+                             opname++;
+                       }
+                 }
                  valsp->type = STRING;
                  valsp->u.string = opname;
                  valsp++;
@@ -193,19 +190,11 @@ overflow:         error("Expression too complex");
                                          valsp->u.string = "";
                              }
                              valsp->type = STRING;
-                             if (c >= OP_FILE
-                              && (fs.op != c
-                                  || fs.name == NULL
+                             if (c == OP_FILE
+                              && (fs.name == NULL
                                   || ! equal(fs.name, valsp->u.string))) {
-                                   fs.op = c;
                                    fs.name = valsp->u.string;
-                                   if (c == OP_FILE) {
-                                       fs.rcode = stat(valsp->u.string,
-                                                               &fs.stat);
-                                   } else {
-                                       fs.rcode = lstat(valsp->u.string,
-                                                               &fs.stat);
-                                   }
+                                   fs.rcode = stat(valsp->u.string, &fs.stat);
                              }
                        }
                        if (binary < FIRST_BINARY_OP)
@@ -250,7 +239,7 @@ done:
 }
 
 
-int
+static int
 expr_is_false(val)
       struct value *val;
       {
@@ -274,14 +263,16 @@ expr_is_false(val)
  * to stat, to avoid repeated stat calls on the same file.
  */
 
-void
+static void
 expr_operator(op, sp, fs)
       int op;
       struct value *sp;
       struct filestat *fs;
       {
-      int i;
+      int i, r;
       struct stat st1, st2;
+      regex_t pat;
+      regmatch_t rm[2];
 
       switch (op) {
       case NOT:
@@ -343,16 +334,16 @@ filebit:
            if (fs->stat.st_mode & i && fs->rcode >= 0)
                  goto true;
            goto false;
+      case ISSLINK:
+           if (lstat(fs->name, &st1) == -1)
+               goto false;
+           if (S_ISLNK(st1.st_mode))
+               goto true;
+           goto false;
       case ISSIZE:
            sp->u.num = fs->rcode >= 0? fs->stat.st_size : 0L;
            sp->type = INTEGER;
            break;
-      case ISLINK1:
-      case ISLINK2:
-           if (S_ISLNK(fs->stat.st_mode) && fs->rcode >= 0)
-                 goto true;
-           fs->op = OP_FILE;   /* not a symlink, so expect a -d or so next */
-           goto false;
       case NEWER:
            if (stat(sp->u.string, &st1) != 0) {
                  sp->u.num = 0;
@@ -439,19 +430,21 @@ filebit:
            break;
       case MATCHPAT:
            {
-                 char *pat;
-
-                 pat = re_compile((sp + 1)->u.string);
-                 if (re_match(pat, sp->u.string)) {
-                       if (number_parens > 0) {
-                             sp->u.string = match_begin[1];
-                             sp->u.string[match_length[1]] = '\0';
+                 r = regcomp(&pat, (sp + 1)->u.string, 0);
+                 if (r)
+                       error("Bad regular expression");
+                 if (regexec(&pat, sp->u.string, 2, rm, 0) == 0 &&
+                       rm[0].rm_so == 0)
+                 {
+                       if (pat.re_nsub > 0) {
+                             sp->u.string[rm[1].rm_eo] = '\0';
+                             sp->u.string = sp->u.string+rm[1].rm_so;
                        } else {
-                             sp->u.num = match_length[0];
+                             sp->u.num = rm[0].rm_eo;
                              sp->type = INTEGER;
                        }
                  } else {
-                       if (number_parens > 0) {
+                       if (pat.re_nsub > 0) {
                              sp->u.string[0] = '\0';
                        } else {
                              sp->u.num = 0;
@@ -464,7 +457,7 @@ filebit:
 }
 
 
-int
+static int
 lookup_op(name, table)
       char *name;
       char *const*table;
index a5b9b9d87e7c598354a7e0413e7ce377cfab519b..7b7397f9c57787ea7c1ac9a82e28e108bf19fdde 100755 (executable)
@@ -5,21 +5,28 @@
 
 # All calls to awk removed, because Minix bawk is deficient.  (kjb)
 
+if [ $# -ne 2 ]
+then
+       echo "Usage: $0 <unary_op> <binary_op>" >&2
+       exit 1
+fi
+unary_op="$1"
+binary_op="$2"
+
 exec > operators.h
 i=0
-sed -e '/^[^#]/!d' unary_op binary_op | while read line
+sed -e '/^[^#]/!d' "$unary_op" "$binary_op" | while read line
 do
        set -$- $line
        echo "#define $1 $i"
        i=`expr $i + 1`
 done
 echo
-echo "#define FIRST_BINARY_OP" `sed -e '/^[^#]/!d' unary_op | wc -l`
+echo "#define FIRST_BINARY_OP" `sed -e '/^[^#]/!d' "$unary_op" | wc -l`
 echo '
 #define OP_INT 1               /* arguments to operator are integer */
 #define OP_STRING 2            /* arguments to operator are string */
 #define OP_FILE 3              /* argument is a file name */
-#define OP_LFILE 4             /* argument is a file name of a symlink? */
 
 extern char *const unary_op[];
 extern char *const binary_op[];
@@ -31,14 +38,15 @@ echo '/*
  * Operators used in the expr/test command.
  */
 
-#include "../shell.h"
+#include <stddef.h>
+#include "shell.h"
 #include "operators.h"
 
 char *const unary_op[] = {'
 sed -e '/^[^#]/!d
        s/[     ][      ]*/ /g
        s/^[^ ][^ ]* \([^ ][^ ]*\).*/      "\1",/
-       ' unary_op
+       ' "$unary_op"
 echo '      NULL
 };
 
@@ -46,7 +54,7 @@ char *const binary_op[] = {'
 sed -e '/^[^#]/!d
        s/[     ][      ]*/ /g
        s/^[^ ][^ ]* \([^ ][^ ]*\).*/      "\1",/
-       ' binary_op
+       ' "$binary_op"
 echo '      NULL
 };
 
@@ -54,7 +62,7 @@ const char op_priority[] = {'
 sed -e '/^[^#]/!d
        s/[     ][      ]*/ /g
        s/^[^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\).*/      \1,/
-       ' unary_op binary_op
+       ' "$unary_op" "$binary_op"
 echo '};
 
 const char op_argflag[] = {'
@@ -62,5 +70,5 @@ sed -e '/^[^#]/!d
        s/[     ][      ]*/ /g
        s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]*$/& 0/
        s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\)/      \1,/
-       ' unary_op binary_op
+       ' "$unary_op" "$binary_op"
 echo '};'
diff --git a/commands/ash/bltin/myregexp.h b/commands/ash/bltin/myregexp.h
new file mode 100644 (file)
index 0000000..83006a1
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+myregexp.h
+
+Created:       July 1995 by Philip Homburg <philip@cs.vu.nl>
+*/
+
+char *re_compile(char *pattern);
+int re_match(char *pattern, char *string);
index cd026ac95f2cb43cb3342f8acb78109cb4a6fd1a..7ef68ba1fa0e95db6109636116ad7fa1ef4abacf 100755 (executable)
@@ -8,7 +8,9 @@
  */
 
 #include "bltin.h"
+#include "myregexp.h"
 
+#include <stdlib.h>
 
 #define RE_END 0               /* end of regular expression */
 #define RE_LITERAL 1           /* normal character follows */
@@ -27,7 +29,7 @@
 char *match_begin[10];
 short match_length[10];
 short number_parens;
-static int match();
+static int match(char *pattern, char *string);
 
 
 
@@ -48,7 +50,6 @@ re_compile(pattern)
        char stack[10];
        int paren_num;
        int i;
-       char *malloc();
 
        p = pattern;
        if (*p == '^')
@@ -176,6 +177,7 @@ out:
 
 
 
+int
 re_match(pattern, string)
        char *pattern;
        char *string;
@@ -246,7 +248,7 @@ ccl:
                                p++;
                        }
                        p++;
-                       if (found == negate || c == 0)
+                       if (found == negate)
                                goto bad;
                        break;
                case RE_LP:
index 4a9ddccf77730b890a8148948a6bad6d833499b7..26748aa625c33ab91c5b0a8339403650d738fdf1 100755 (executable)
@@ -16,9 +16,8 @@ ISFIFO         -p     12   OP_FILE
 ISSETUID -u    12   OP_FILE
 ISSETGID -g    12   OP_FILE
 ISSTICKY -k    12   OP_FILE
+ISSLINK         -h     12   OP_FILE
 ISSIZE  -s     12   OP_FILE
-ISLINK1  -h    12   OP_LFILE
-ISLINK2  -L    12   OP_LFILE
 ISTTY   -t     12   OP_INT
 NULSTR  -z     12   OP_STRING
 STRLEN  -n     12   OP_STRING
diff --git a/commands/ash/build b/commands/ash/build
deleted file mode 100755 (executable)
index 3ee5f03..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-make clean
-make && make install
old mode 100755 (executable)
new mode 100644 (file)
similarity index 88%
rename from commands/ash/builtins.table
rename to commands/ash/builtins
index 864cdb3..57409b1
@@ -1,7 +1,7 @@
 #!/bin/sh -
 #
-# Copyright (c) 1991 The Regents of the University of California.
-# All rights reserved.
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
 #
 # This code is derived from software contributed to Berkeley by
 # Kenneth Almquist.
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-#      @(#)builtins    5.1 (Berkeley) 3/7/91
+#      @(#)builtins    8.1 (Berkeley) 5/31/93
 
 #
 # This file lists all the builtin commands.  The first column is the name
 # of a C routine.  The -j flag, if present, specifies that this command
 # is to be excluded from systems without job control.  The rest of the line
 # specifies the command name or names used to run the command.  The entry
-# for nullcmd, which is run when the user does not specify a command, must
+# for bltincmd, which is run when the user does not specify a command, must
 # come first.
 #
 # Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
 # This file is part of ash, which is distributed under the terms specified
 # by the Ash General Public License.  See the file named LICENSE.
+#
+# NOTE: bltincmd must come first!
 
 bltincmd       command
 #alloccmd      alloc
@@ -59,17 +61,19 @@ echocmd             echo
 evalcmd                eval
 execcmd                exec
 exitcmd                exit
+expcmd         exp let
 exportcmd      export readonly
-exprcmd                expr test [
+#exprcmd       expr test [
+histcmd                fc
 fgcmd -j       fg
 getoptscmd     getopts
 hashcmd                hash
 jobidcmd       jobid
 jobscmd                jobs
-#lccmd         lc
 #linecmd               line
 localcmd       local
 #nlechocmd     nlecho
+printfcmd      printf
 pwdcmd         pwd
 readcmd                read
 returncmd      return
@@ -77,7 +81,10 @@ setcmd               set
 setvarcmd      setvar
 shiftcmd       shift
 trapcmd                trap
-truecmd                : true false
+truecmd                : true
 umaskcmd       umask
+unaliascmd     unalias
 unsetcmd       unset
 waitcmd                wait
+#foocmd                foo
+aliascmd       alias
diff --git a/commands/ash/builtins.def b/commands/ash/builtins.def
new file mode 100644 (file)
index 0000000..0deae59
--- /dev/null
@@ -0,0 +1,94 @@
+#!/bin/sh -
+#
+# Copyright (c) 1991, 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.
+# 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.
+#
+#      @(#)builtins.def        8.4 (Berkeley) 5/4/95
+# $FreeBSD: src/bin/sh/builtins.def,v 1.14 2004/04/06 20:06:51 markm Exp $
+
+#
+# This file lists all the builtin commands.  The first column is the name
+# of a C routine.  The -j flag, if present, specifies that this command
+# is to be excluded from systems without job control, and the -h flag,
+# if present specifies that this command is to be excluded from systems
+# based on the NO_HISTORY compile-time symbol.  The rest of the line
+# specifies the command name or names used to run the command.  The entry
+# for bltincmd, which is run when the user does not specify a command, must
+# come first.
+#
+# NOTE: bltincmd must come first!
+
+bltincmd       builtin
+commandcmd     command
+#alloccmd      alloc
+bgcmd -j       bg
+breakcmd       break continue
+#catfcmd       catf
+cdcmd          cd chdir
+dotcmd         .
+echocmd                echo
+evalcmd                eval
+execcmd                exec
+exitcmd                exit
+expcmd         exp let
+exportcmd      export readonly
+exprcmd                expr test [
+falsecmd       false
+histcmd -h     fc
+fgcmd -j       fg
+getoptscmd     getopts
+hashcmd                hash
+jobidcmd       jobid
+jobscmd                jobs
+#linecmd       line
+localcmd       local
+#nlechocmd     nlecho
+#printfcmd     printf
+pwdcmd         pwd
+readcmd                read
+returncmd      return
+setcmd         set
+setvarcmd      setvar
+shiftcmd       shift
+trapcmd                trap
+truecmd                : true
+typecmd                type
+umaskcmd       umask
+unaliascmd     unalias
+unsetcmd       unset
+waitcmd                wait
+#foocmd                foo
+aliascmd       alias
+ulimitcmd      ulimit
+bindcmd                bind
+wordexpcmd     wordexp
+
+#
+# $PchId: builtins.def,v 1.5 2006/03/31 10:50:57 philip Exp $
index d1baf375492b54b27b5fff2e4ca98898c77413d1..e54289d7c34c9452e44599f269db98b7129565de 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)cd.c       5.2 (Berkeley) 3/13/91";
+#if 0
+static char sccsid[] = "@(#)cd.c       8.2 (Berkeley) 5/4/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.34 2004/04/06 20:06:51 markm Exp $");
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
 
 /*
  * The cd and pwd commands.
@@ -50,115 +60,124 @@ static char sccsid[] = "@(#)cd.c  5.2 (Berkeley) 3/13/91";
 #include "output.h"
 #include "memalloc.h"
 #include "error.h"
+#include "exec.h"
+#include "redir.h"
 #include "mystring.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
+#include "builtins.h"
+#include "show.h"
+#include "cd.h"
 
-
-#ifdef __STDC__
+STATIC int cdlogical(char *);
+STATIC int cdphysical(char *);
 STATIC int docd(char *, int, int);
-STATIC void updatepwd(char *);
-STATIC void getpwd(void);
 STATIC char *getcomponent(void);
-#else
-STATIC int docd();
-STATIC void updatepwd();
-STATIC void getpwd();
-STATIC char *getcomponent();
-#endif
+STATIC int updatepwd(char *);
 
-
-char *curdir;                  /* current working directory */
+STATIC char *curdir = NULL;    /* current working directory */
+STATIC char *prevdir;          /* previous working directory */
 STATIC char *cdcomppath;
 
-#if UDIR || TILDE
-extern int didudir;            /* set if /u/logname or ~logname expanded */
-#endif
-
-
 int
-cdcmd(argc, argv)  char **argv; {
+cdcmd(int argc, char **argv)
+{
        char *dest;
        char *path;
        char *p;
        struct stat statb;
-       char *padvance();
-       int tohome= 0;
-
-       nextopt(nullstr);
-       if ((dest = *argptr) == NULL) {
-               if ((dest = bltinlookup("HOME", 1)) == NULL)
-                       error("HOME not set");
-               tohome = 1;
+       int ch, phys, print = 0;
+
+       optreset = 1; optind = 1; opterr = 0; /* initialize getopt */
+       phys = Pflag;
+       while ((ch = getopt(argc, argv, "LP")) != -1) {
+               switch (ch) {
+               case 'L':
+                       phys = 0;
+                       break;
+               case 'P':
+                       phys = 1;
+                       break;
+               default:
+                       error("unknown option: -%c", optopt);
+                       break;
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (argc > 1)
+               error("too many arguments");
+
+       if ((dest = *argv) == NULL && (dest = bltinlookup("HOME", 1)) == NULL)
+               error("HOME not set");
+       if (*dest == '\0')
+               dest = ".";
+       if (dest[0] == '-' && dest[1] == '\0') {
+               dest = prevdir ? prevdir : curdir;
+               if (dest)
+                       print = 1;
+               else
+                       dest = ".";
        }
        if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
                path = nullstr;
        while ((p = padvance(&path, dest)) != NULL) {
-               if (stat(p, &statb) >= 0
-                && (statb.st_mode & S_IFMT) == S_IFDIR
-                && docd(p, strcmp(p, dest), tohome) >= 0)
-                       return 0;
+               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, phys) >= 0)
+                               return 0;
+               }
        }
        error("can't cd to %s", dest);
+       /*NOTREACHED*/
+       return 0;
 }
 
 
 /*
- * Actually do the chdir.  If the name refers to symbolic links, we
- * compute the actual directory name before doing the cd.  In an
- * interactive shell, print the directory name if "print" is nonzero
- * or if the name refers to a symbolic link.  We also print the name
- * if "/u/logname" was expanded in it, since this is similar to a
- * symbolic link.  (The check for this breaks if the user gives the
- * cd command some additional, unused arguments.)
+ * Actually change the directory.  In an interactive shell, print the
+ * directory name if "print" is nonzero.
  */
-
-#if SYMLINKS == 0
 STATIC int
-docd(dest, print, tohome)
-       char *dest;
-       {
-#if UDIR || TILDE
-       if (didudir)
-               print = 1;
-#endif
-       INTOFF;
-       if (chdir(dest) < 0) {
-               INTON;
-               return -1;
-       }
-       updatepwd(dest);
-       INTON;
-       if (print && iflag)
-               out1fmt("%s\n", stackblock());
-       return 0;
-}
+docd(char *dest, int print, int phys)
+{
+
+       TRACE(("docd(\"%s\", %d, %d) called\n", dest, print, phys));
 
-#else
+       /* If logical cd fails, fall back to physical. */
+       if ((phys || cdlogical(dest) < 0) && cdphysical(dest) < 0)
+               return (-1);
 
+       if (print && iflag && curdir)
+               out1fmt("%s\n", curdir);
 
+       return 0;
+}
 
 STATIC int
-docd(dest, print, tohome)
-       char *dest;
-       {
-       register char *p;
-       register char *q;
-       char *symlink;
+cdlogical(char *dest)
+{
+       char *p;
+       char *q;
        char *component;
        struct stat statb;
        int first;
-       int i;
-
-       TRACE(("docd(\"%s\", %d, %d) called\n", dest, print, tohome));
-#if UDIR || TILDE
-       if (didudir)
-               print = 1;
-#endif
-
-top:
-       cdcomppath = dest;
+       int badstat;
+
+       /*
+        *  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 = stalloc(strlen(dest) + 1);
+       scopy(dest, cdcomppath);
        STARTSTACKSTR(p);
        if (*dest == '/') {
                STPUTC('/', p);
@@ -166,7 +185,7 @@ top:
        }
        first = 1;
        while ((q = getcomponent()) != NULL) {
-               if (q[0] == '\0' || q[0] == '.' && q[1] == '\0')
+               if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
                        continue;
                if (! first)
                        STPUTC('/', p);
@@ -177,71 +196,42 @@ top:
                if (equal(component, ".."))
                        continue;
                STACKSTRNUL(p);
-               if (lstat(stackblock(), &statb) < 0)
-                       error("lstat %s failed", stackblock());
-               if ((statb.st_mode & S_IFMT) != S_IFLNK)
-                       continue;
-
-               /* Hit a symbolic link.  We have to start all over again. */
-               print = 1;
-               STPUTC('\0', p);
-               symlink = grabstackstr(p);
-               i = (int)statb.st_size + 2;             /* 2 for '/' and '\0' */
-               if (cdcomppath != NULL)
-                       i += strlen(cdcomppath);
-               p = stalloc(i);
-               if (readlink(symlink, p, (int)statb.st_size) < 0) {
-                       error("readlink %s failed", stackblock());
-               }
-               if (cdcomppath != NULL) {
-                       p[(int)statb.st_size] = '/';
-                       scopy(cdcomppath, p + (int)statb.st_size + 1);
-               } else {
-                       p[(int)statb.st_size] = '\0';
-               }
-               if (p[0] != '/') {      /* relative path name */
-                       char *r;
-                       q = r = symlink;
-                       while (*q) {
-                               if (*q++ == '/')
-                                       r = q;
-                       }
-                       *r = '\0';
-                       dest = stalloc(strlen(symlink) + strlen(p) + 1);
-                       scopy(symlink, dest);
-                       strcat(dest, p);
-               } else {
-                       dest = p;
+               if (lstat(stackblock(), &statb) < 0) {
+                       badstat = 1;
+                       break;
                }
-               goto top;
        }
-       STPUTC('\0', p);
-       p = grabstackstr(p);
+
        INTOFF;
-       /* The empty string is not a legal argument to chdir on a POSIX 1003.1 
-        * system. */
-       if (p[0] != '\0' && chdir(p) < 0) {
+       if (updatepwd(badstat ? NULL : dest) < 0 || chdir(curdir) < 0) {
                INTON;
-               return -1;
+               return (-1);
        }
-       updatepwd(p);
        INTON;
-       if (print && !tohome && iflag)
-               out1fmt("%s\n", p);
-       return 0;
+       return (0);
 }
-#endif /* SYMLINKS */
 
+STATIC int
+cdphysical(char *dest)
+{
 
+       INTOFF;
+       if (chdir(dest) < 0 || updatepwd(NULL) < 0) {
+               INTON;
+               return (-1);
+       }
+       INTON;
+       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() {
-       register char *p;
+getcomponent(void)
+{
+       char *p;
        char *start;
 
        if ((p = cdcomppath) == NULL)
@@ -259,29 +249,43 @@ getcomponent() {
 }
 
 
-
 /*
  * 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.
  */
-
-void hashcd();
-
-STATIC void
-updatepwd(dir)
-       char *dir;
-       {
+STATIC int
+updatepwd(char *dir)
+{
        char *new;
        char *p;
 
        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 == NULL)  {
+               if (prevdir)
+                       ckfree(prevdir);
+               INTOFF;
+               prevdir = curdir;
+               curdir = NULL;
+               if (getpwd() == NULL) {
+                       INTON;
+                       return (-1);
+               }
+               setvar("PWD", curdir, VEXPORT);
+               setvar("OLDPWD", prevdir, VEXPORT);
+               INTON;
+               return (0);
+       }
        cdcomppath = stalloc(strlen(dir) + 1);
        scopy(dir, cdcomppath);
        STARTSTACKSTR(new);
        if (*dir != '/') {
-               if (curdir == NULL)
-                       return;
                p = curdir;
                while (*p)
                        STPUTC(*p++, new);
@@ -300,73 +304,87 @@ updatepwd(dir)
        if (new == stackblock())
                STPUTC('/', new);
        STACKSTRNUL(new);
-       if (curdir)
-               ckfree(curdir);
+       INTOFF;
+       if (prevdir)
+               ckfree(prevdir);
+       prevdir = curdir;
        curdir = savestr(stackblock());
+       setvar("PWD", curdir, VEXPORT);
+       setvar("OLDPWD", prevdir, VEXPORT);
+       INTON;
+
+       return (0);
 }
 
+int
+pwdcmd(int argc, char **argv)
+{
+       char buf[PATH_MAX];
+       int ch, phys;
+
+       optreset = 1; optind = 1; opterr = 0; /* initialize getopt */
+       phys = Pflag;
+       while ((ch = getopt(argc, argv, "LP")) != -1) {
+               switch (ch) {
+               case 'L':
+                       phys = 0;
+                       break;
+               case 'P':
+                       phys = 1;
+                       break;
+               default:
+                       error("unknown option: -%c", optopt);
+                       break;
+               }
+       }
+       argc -= optind;
+       argv += optind;
 
+       if (argc != 0)
+               error("too many arguments");
+
+       if (!phys && getpwd()) {
+               out1str(curdir);
+               out1c('\n');
+       } else {
+               if (getcwd(buf, sizeof(buf)) == NULL)
+                       error(".: %s", strerror(errno));
+               out1str(buf);
+               out1c('\n');
+       }
 
-int
-pwdcmd(argc, argv)  char **argv; {
-       getpwd();
-       out1str(curdir);
-       out1c('\n');
        return 0;
 }
 
-
-
 /*
- * Run /bin/pwd to find out what the current directory is.  We suppress
- * interrupts throughout most of this, but the user can still break out
- * of it by killing the pwd program.  If we already know the current
+ * Find out what the current directory is. If we already know the current
  * directory, this routine returns immediately.
  */
-
-#define MAXPWD 256
-
-STATIC void
-getpwd() {
-       char buf[MAXPWD];
-       char *p;
-       int i;
-       int status;
-       struct job *jp;
-       int pip[2];
+char *
+getpwd(void)
+{
+       char buf[PATH_MAX];
 
        if (curdir)
-               return;
-       INTOFF;
-       if (pipe(pip) < 0)
-               error("Pipe call failed");
-       jp = makejob((union node *)NULL, 1);
-       if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) {
-               close(pip[0]);
-               if (pip[1] != 1) {
-                       close(1);
-                       copyfd(pip[1], 1);
-                       close(pip[1]);
+               return curdir;
+       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 curdir;
                }
-               execl("/bin/pwd", "pwd", (char *)0);
-               error("Cannot exec /bin/pwd");
-       }
-       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;
+               return NULL;
        }
-       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);
-       INTON;
+
+       return curdir;
 }
+
+/*
+ * $PchId: cd.c,v 1.6 2006/05/22 12:42:03 philip Exp $
+ */
diff --git a/commands/ash/cd.h b/commands/ash/cd.h
new file mode 100644 (file)
index 0000000..f4546f2
--- /dev/null
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 1995
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 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.
+ *
+ * $FreeBSD: src/bin/sh/cd.h,v 1.7 2004/04/06 20:06:51 markm Exp $
+ */
+
+char   *getpwd(void);
+int     cdcmd (int, char **);
+int     pwdcmd(int, char **);
+
+/*
+ * $PchId: cd.h,v 1.3 2006/03/31 09:59:04 philip Exp $
+ */
diff --git a/commands/ash/complete.c b/commands/ash/complete.c
new file mode 100644 (file)
index 0000000..b7ebd30
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+complete.c
+
+Created:       July 1995 by Philip Homburg <philip@cs.vu.nl>
+*/
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include "myhistedit.h"
+#include "shell.h"
+
+#include "complete.h"
+#include "error.h"
+#include "expand.h"
+#include "nodes.h"
+#include "memalloc.h"
+
+static char **getlist(EditLine *el, int *baselen, int *isdir);
+static char **getlist_tilde(char *prefix);
+static int vstrcmp(const void *v1, const void *v2);
+static void print_list(char **list);
+static int install_extra(EditLine *el, char **list, int baselen, int isdir);
+
+unsigned char complete(EditLine *el, int ch)
+{
+       struct stackmark mark;
+       const LineInfo *lf;
+       char **list;
+       int baselen, prefix, isdir;
+
+       /* Direct the cursor the the end of the word. */
+       for(;;)
+       {
+               lf = el_line(el);
+               if (lf->cursor < lf->lastchar &&
+                       !isspace((unsigned char)*lf->cursor))
+               {
+                       (*(char **)&lf->cursor)++;      /* XXX */
+               }
+               else
+                       break;
+       }
+
+       setstackmark(&mark);
+       list= getlist(el, &baselen, &isdir);
+       if (list)
+       {
+               prefix= install_extra(el, list, baselen, isdir);
+               el_push(el, "i");
+       }
+       popstackmark(&mark);
+       if (list)
+               return CC_REFRESH;
+       else
+               return CC_ERROR;
+}
+
+unsigned char complete_list(EditLine *el, int ch)
+{
+       struct stackmark mark;
+       char **list;
+
+       setstackmark(&mark);
+       list= getlist(el, NULL, NULL);
+       if (list)
+       {
+               print_list(list);
+               re_goto_bottom(el);
+       }
+       popstackmark(&mark);
+       if (list)
+       {
+               return CC_REFRESH;
+       }
+       else
+               return CC_ERROR;
+}
+
+unsigned char complete_or_list(EditLine *el, int ch)
+{
+       struct stackmark mark;
+       const LineInfo *lf;
+       char **list;
+       int baselen, prefix, isdir;
+
+       setstackmark(&mark);
+       list= getlist(el, &baselen, &isdir);
+       if (list)
+       {
+               prefix= install_extra(el, list, baselen, isdir);
+               if (prefix == baselen)
+               {
+                       print_list(list);
+                       re_goto_bottom(el);
+               }
+       }
+       popstackmark(&mark);
+       if (list)
+               return CC_REFRESH;
+       else
+               return CC_ERROR;
+}
+
+unsigned char complete_expand(EditLine *el, int ch)
+{
+       printf("complete_expand\n");
+       return CC_ERROR;
+}
+
+static char **getlist(EditLine *el, int *baselen, int *isdir)
+{
+       const LineInfo *lf;
+       const char *begin, *end;
+       char *dirnam, *basenam;
+       union node arg;
+       struct arglist arglist;
+       DIR *dir;
+       struct dirent *dirent;
+       int i, l, n;
+       char *p, **list;
+       struct strlist *slp, *nslp;
+       struct stat sb;
+
+       lf = el_line(el);
+
+       /* Try to find to begin and end of the word that we have to comple. */
+       begin= lf->cursor;
+       while (begin > lf->buffer && !isspace((unsigned char)begin[-1]))
+               begin--;
+       end= lf->cursor;
+       while (end < lf->lastchar && !isspace((unsigned char)end[0]))
+               end++;
+
+       *(const char **)&lf->cursor= end; /* XXX */
+
+       /* Copy the word to a string */
+       dirnam= stalloc(end-begin+1);
+       strncpy(dirnam, begin, end-begin);
+       dirnam[end-begin]= '\0';
+
+       /* Cut the word in two pieces: a path and a (partial) component. */
+       basenam= strrchr(dirnam, '/');
+       if (basenam)
+       {
+               basenam++;
+               p= stalloc(strlen(basenam) + 1);
+               strcpy(p, basenam);
+               *basenam= '\0';
+               basenam= p;
+       }
+       else
+       {
+               if (dirnam[0] == '~')
+                       return getlist_tilde(dirnam);
+               basenam= dirnam;
+               dirnam= "./";
+       }
+       if (baselen)
+               *baselen= strlen(basenam);
+
+       arg.type= NARG;
+       arg.narg.next= NULL;
+       arg.narg.text= dirnam;
+       arg.narg.backquote= NULL;
+       arglist.list= NULL;
+       arglist.lastp= &arglist.list;
+       expandarg(&arg, &arglist, EXP_TILDE);
+
+       INTOFF;
+       list= NULL;
+       dir= opendir(arglist.list->text);
+       if (dir)
+       {
+               slp= NULL;
+               n= 0;
+               l= strlen(basenam);
+               while(dirent= readdir(dir))
+               {
+                       if (strncmp(dirent->d_name, basenam, l) != 0)
+                               continue;
+                       if (l == 0 && dirent->d_name[0] == '.')
+                               continue;
+                       nslp= stalloc(sizeof(*nslp));
+                       nslp->next= slp;
+                       slp= nslp;
+                       slp->text= stalloc(strlen(dirent->d_name)+1);
+                       strcpy(slp->text, dirent->d_name);
+                       n++;
+                       if (n == 1 && isdir != NULL)
+                       {
+                               /* Try to findout whether this entry is a
+                                * file or a directory.
+                                */
+                               p= stalloc(strlen(arglist.list->text) +
+                                       strlen(dirent->d_name) + 1);
+                               strcpy(p, arglist.list->text);
+                               strcat(p, dirent->d_name);
+                               if (stat(p, &sb) == -1)
+                                       printf("stat '%s' failed: %s\n",
+                                               p, strerror(errno));
+                               if (stat(p, &sb) == 0 && S_ISDIR(sb.st_mode))
+                                       *isdir= 1;
+                               else
+                                       *isdir= 0;
+                       }
+               }
+               closedir(dir);
+               if (n != 0)
+               {
+                       list= stalloc((n+1)*sizeof(*list));
+                       for(i= 0; slp; i++, slp= slp->next)
+                               list[i]= slp->text;
+                       if (i != n)
+                               error("complete'make_list: i != n");
+                       list[i]= NULL;
+                       qsort(list, n, sizeof(*list), vstrcmp);
+               }
+       }
+       INTON;
+       return list;
+}
+
+static char **getlist_tilde(char *prefix)
+{
+       printf("should ~-complete '%s'\n", prefix);
+       return NULL;
+}
+
+static int vstrcmp(const void *v1, const void *v2)
+{
+       return strcmp(*(char **)v1, *(char **)v2);
+}
+
+#define MAXCOLS 40
+#define SEPWIDTH 4
+
+static void print_list(char **list)
+{
+       struct
+       {
+               int cols;
+               int start[MAXCOLS+1];
+               int width[MAXCOLS];
+       } best, next;
+       int e, i, j, l, n, o, cols, maxw, width;
+       int linewidth= 80;
+
+       /* Count the number of entries. */
+       for (n= 0; list[n]; n++)
+               ;       /* do nothing */
+       if (n == 0)
+               error("complete'print_list: n= 0");
+
+       /* Try to maximize the number of columns */
+       for (cols= 1; cols<= MAXCOLS; cols++)
+       {
+               next.cols= cols;
+
+               o= 0;
+               width= 0;
+               for(j= 0; j<cols; j++)
+               {
+                       next.start[j]= o;
+
+                       /* Number of entries in this column. */
+                       e= (n-o)/(cols-j);
+                       if ((n-o)%(cols-j))
+                               e++;
+
+                       maxw= 0;
+                       for (i= 0; i<e; i++)
+                       {
+                               l= strlen(list[o+i]);
+                               if (l < 6)
+                                       l= 6;
+                               l += SEPWIDTH;
+                               if (l > maxw)
+                                       maxw= l;
+                       }
+                       next.width[j]= maxw;
+                       width += maxw;
+                       o += e;
+               }
+               next.start[j]= o;
+               if (cols > 1 && width-SEPWIDTH>linewidth)
+                       break;
+               best= next;
+       }
+       cols= best.cols;
+       e= best.start[1];
+       printf("\n");
+       for(i= 0; i<e; i++)
+       {
+               for (j= 0; j<cols; j++)
+               {
+                       if (best.start[j]+i == best.start[j+1])
+                               continue;
+                       if (j < cols-1)
+                       {
+                               printf("%-*s", best.width[j],
+                                       list[best.start[j]+i]);
+                       }
+                       else
+                       {
+                               printf("%s", list[best.start[j]+i]);
+                       }
+               }
+               if (i < e-1)
+                       printf("\n");
+       }
+       fflush(stdout);
+}
+
+static int install_extra(EditLine *el, char **list, int baselen, int isdir)
+{
+       int l;
+       char *p, **lp;
+
+       l= strlen(list[0]);
+       for (lp= &list[1]; *lp; lp++)
+       {
+               while(l>0)
+               {
+                       if (strncmp(list[0], *lp, l) != 0)
+                               l--;
+                       else
+                               break;
+               }
+       }
+       if (l > baselen || list[1] == NULL)
+       {
+               p= stalloc(l-baselen+2);
+               strncpy(p, list[0]+baselen, l-baselen);
+               if (list[1] == NULL)
+               {
+                       p[l-baselen]= isdir ? '/' : ' ';
+                       p[l-baselen+1]= '\0';
+                       l++;
+               }
+               else
+                       p[l-baselen]= '\0';
+               if (el_insertstr(el, p) == -1)
+                       return -1;
+       }
+       return l;
+}
+
+/*
+ * $PchId: complete.c,v 1.2 2006/04/10 14:35:53 philip Exp $
+ */
diff --git a/commands/ash/complete.h b/commands/ash/complete.h
new file mode 100644 (file)
index 0000000..af859f9
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+complete.h
+
+Created:       July 1995 by Philip Homburg <philip@cs.vu.nl>
+*/
+
+unsigned char complete(EditLine *el, int ch);
+unsigned char complete_list(EditLine *el, int ch);
+unsigned char complete_or_list(EditLine *el, int ch);
+unsigned char complete_expand(EditLine *el, int ch);
+
+/*
+ * $PchId: complete.h,v 1.1 2001/05/17 07:12:05 philip Exp $
+ */
diff --git a/commands/ash/dirent.c b/commands/ash/dirent.c
deleted file mode 100755 (executable)
index 521fcc6..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*-
- * Copyright (c) 1991 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.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)dirent.c   5.1 (Berkeley) 3/7/91";
-#endif /* not lint */
-
-#include "shell.h"     /* definitions for pointer, NULL, DIRENT, and BSD */
-
-#if ! DIRENT
-
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-
-#ifndef S_ISDIR                                /* macro to test for directory file */
-#define        S_ISDIR(mode)           (((mode) & S_IFMT) == S_IFDIR)
-#endif
-
-#ifdef BSD
-
-#ifdef __STDC__
-int stat(char *, struct stat *);
-#else
-int stat();
-#endif
-
-
-/*
- * The BSD opendir routine doesn't check that what is being opened is a
- * directory, so we have to include the check in a wrapper routine.
- */
-
-#undef opendir
-
-DIR *
-myopendir(dirname)
-       char *dirname;                  /* name of directory */
-       {
-       struct stat statb;
-
-       if (stat(dirname, &statb) != 0 || ! S_ISDIR(statb.st_mode)) {
-               errno = ENOTDIR;
-               return NULL;            /* not a directory */
-       }
-       return opendir(dirname);
-}
-
-#else /* not BSD */
-
-/*
- * Dirent routines for old style file systems.
- */
-
-#ifdef __STDC__
-pointer malloc(unsigned);
-void free(pointer);
-int open(char *, int, ...);
-int close(int);
-int fstat(int, struct stat *);
-#else
-pointer malloc();
-void free();
-int open();
-int close();
-int fstat();
-#endif
-
-
-DIR *
-opendir(dirname)
-       char            *dirname;       /* name of directory */
-       {
-       register DIR    *dirp;          /* -> malloc'ed storage */
-       register int    fd;             /* file descriptor for read */
-       struct stat     statb;          /* result of fstat() */
-
-#ifdef O_NDELAY
-       fd = open(dirname, O_RDONLY|O_NDELAY);
-#else
-       fd = open(dirname, O_RDONLY);
-#endif
-       if (fd < 0)
-               return NULL;            /* errno set by open() */
-
-       if (fstat(fd, &statb) != 0 || !S_ISDIR(statb.st_mode)) {
-               (void)close(fd);
-               errno = ENOTDIR;
-               return NULL;            /* not a directory */
-       }
-
-       if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
-               (void)close(fd);
-               errno = ENOMEM;
-               return NULL;            /* not enough memory */
-       }
-
-       dirp->dd_fd = fd;
-       dirp->dd_nleft = 0;             /* refill needed */
-
-       return dirp;
-}
-
-
-
-int
-closedir(dirp)
-       register DIR *dirp;             /* stream from opendir() */
-       {
-       register int fd;
-
-       if (dirp == NULL) {
-               errno = EFAULT;
-               return -1;                      /* invalid pointer */
-       }
-
-       fd = dirp->dd_fd;
-       free((pointer)dirp);
-       return close(fd);
-}
-
-
-
-struct dirent *
-readdir(dirp)
-       register DIR *dirp;             /* stream from opendir() */
-       {
-       register struct direct *dp;
-       register char *p, *q;
-       register int i;
-
-       do {
-               if ((dirp->dd_nleft -= sizeof (struct direct)) < 0) {
-                       if ((i = read(dirp->dd_fd,
-                                          (char *)dirp->dd_buf,
-                                          DIRBUFENT*sizeof(struct direct))) <= 0) {
-                               if (i == 0)
-                                       errno = 0;      /* unnecessary */
-                               return NULL;            /* EOF or error */
-                       }
-                       dirp->dd_loc = dirp->dd_buf;
-                       dirp->dd_nleft = i - sizeof (struct direct);
-               }
-               dp = dirp->dd_loc++;
-       } while (dp->d_ino == 0);
-       dirp->dd_entry.d_ino = dp->d_ino;
-
-       /* now copy the name, nul terminating it */
-       p = dp->d_name;
-       q = dirp->dd_entry.d_name;
-       i = DIRSIZ;
-       while (--i >= 0 && *p != '\0')
-               *q++ = *p++;
-       *q = '\0';
-       return &dirp->dd_entry;
-}
-
-#endif /* BSD */
-#endif /* DIRENT */
diff --git a/commands/ash/errmsg.c b/commands/ash/errmsg.c
new file mode 100644 (file)
index 0000000..2a0303b
--- /dev/null
@@ -0,0 +1,127 @@
+/*-
+ * Copyright (c) 1991, 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)errmsg.c   8.1 (Berkeley) 5/31/93";
+#endif /* not lint */
+
+#include "shell.h"
+#include "output.h"
+#include "errmsg.h"
+#include <errno.h>
+
+
+#define ALL (E_OPEN|E_CREAT|E_EXEC)
+
+
+struct errname {
+       short errcode;          /* error number */
+       short action;           /* operation which encountered the error */
+       char *msg;              /* text describing the error */
+};
+
+
+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",
+/*    EMFILE, ALL,     "too many open files", */
+       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
+};
+
+
+/*
+ * 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.
+ */
+
+char *
+errmsg(e, 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;
+}
diff --git a/commands/ash/errmsg.h b/commands/ash/errmsg.h
new file mode 100644 (file)
index 0000000..03cb605
--- /dev/null
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 1991, 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.
+ *
+ *     @(#)errmsg.h    8.1 (Berkeley) 5/31/93
+ */
+
+#define E_OPEN 01
+#define E_CREAT 02
+#define E_EXEC 04
+
+#ifdef __STDC__
+char *errmsg(int, int);
+#else
+char *errmsg();
+#endif
index af4275e4bbfbf7012f196f69b93ddf569d0e4b9f..a24807e4483d0a01f0479c712d29baebff72ffce 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)error.c    5.1 (Berkeley) 3/7/91";
+#if 0
+static char sccsid[] = "@(#)error.c    8.2 (Berkeley) 5/4/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/error.c,v 1.25 2004/04/06 20:06:51 markm Exp $");
+*/
 
 /*
  * Errors and exceptions.
@@ -47,14 +49,14 @@ static char sccsid[] = "@(#)error.c 5.1 (Berkeley) 3/7/91";
 #include "options.h"
 #include "output.h"
 #include "error.h"
-#include <sys/types.h>
+#include "nodes.h" /* show.h needs nodes.h */
+#include "show.h"
+#include "trap.h"
 #include <signal.h>
-#ifdef __STDC__
-#include "stdarg.h"
-#else
-#include <varargs.h>   
-#endif
+#include <stdlib.h>
+#include <unistd.h>
 #include <errno.h>
+#include <sys/types.h>
 
 
 /*
@@ -62,12 +64,14 @@ static char sccsid[] = "@(#)error.c 5.1 (Berkeley) 3/7/91";
  */
 
 struct jmploc *handler;
-int exception;
-volatile int suppressint;
-volatile int intpending;
+volatile sig_atomic_t exception;
+volatile sig_atomic_t suppressint;
+volatile sig_atomic_t intpending;
 char *commandname;
 
 
+static void exverror(int, const char *, va_list) __printf0like(2, 0);
+
 /*
  * 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
@@ -75,7 +79,8 @@ char *commandname;
  */
 
 void
-exraise(e) {
+exraise(int e)
+{
        if (handler == NULL)
                abort();
        exception = e;
@@ -87,69 +92,63 @@ exraise(e) {
  * 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.)
+ * are held using the INTOFF macro.  If SIGINTs are not suppressed and
+ * the shell is not a root shell, then we want to be terminated if we
+ * get here, as if we were terminated directly by a SIGINT.  Arrange for
+ * this here.
  */
 
 void
-onint() {
-       if (suppressint) {
+onint(void)
+{
+       sigset_t sigset;
+
+       /*
+        * The !in_dotrap here is safe.  The only way we can arrive here
+        * with in_dotrap set is that a trap handler set SIGINT to SIG_DFL
+        * and killed itself.
+        */
+
+       if (suppressint && !in_dotrap) {
                intpending++;
                return;
        }
        intpending = 0;
-#ifdef BSD
-       sigsetmask(0);
+       sigemptyset(&sigset);
+       sigprocmask(SIG_SETMASK, &sigset, NULL);
+
+       /*
+        * This doesn't seem to be needed, since main() emits a newline.
+        */
+#if 0
+       if (tcgetpgrp(0) == getpid())   
+               write(STDERR_FILENO, "\n", 1);
 #endif
        if (rootshell && iflag)
                exraise(EXINT);
-       else
-               _exit(128 + SIGINT);
-}
-
-
-
-void
-error2(a, b)
-       char *a, *b;
-       {
-       error("%s: %s", a, b);
+       else {
+               signal(SIGINT, SIG_DFL);
+               kill(getpid(), SIGINT);
+       }
 }
 
 
 /*
- * Error is called to raise the error exception.  If the first argument
+ * 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.
  */
-
-#ifdef __STDC__
-void
-error(char *msg, ...) {
-#else
-void
-error(va_alist)
-       va_dcl
-       {
-       char *msg;
-#endif
-       va_list ap;
-
+static void
+exverror(int cond, const char *msg, va_list ap)
+{
        CLEAR_PENDING_INT;
        INTOFF;
-#ifdef __STDC__
-       va_start(ap, msg);
-#else
-       va_start(ap);
-       msg = va_arg(ap, char *);
-#endif
+
 #if DEBUG
        if (msg)
-               TRACE(("error(\"%s\") pid=%d\n", msg, getpid()));
+               TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
        else
-               TRACE(("error(NULL) pid=%d\n", getpid()));
+               TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
 #endif
        if (msg) {
                if (commandname)
@@ -157,96 +156,30 @@ error(va_alist)
                doformat(&errout, msg, ap);
                out2c('\n');
        }
-       va_end(ap);
        flushall();
-       exraise(EXERROR);
+       exraise(cond);
 }
 
 
-#ifdef notdef  /* These strange error messages only confuse. -- kjb */
-/*
- * Table of error messages.
- */
+void
+error(const char *msg, ...)
+{
+       va_list ap;
+       va_start(ap, msg);
+       exverror(EXERROR, msg, ap);
+       va_end(ap);
+}
 
-struct errname {
-       short errcode;          /* error number */
-       short action;           /* operation which encountered the error */
-       char *msg;              /* text describing the error */
-};
-
-
-#define ALL (E_OPEN|E_CREAT|E_EXEC)
-
-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",
-       ENOEXEC, ALL,   "not an executable",
-       EISDIR, ALL,    "is a directory",
-/*    EMFILE, ALL,     "too many open files", */
-       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
-};
 
+void
+exerror(int cond, const char *msg, ...)
+{
+       va_list ap;
+       va_start(ap, msg);
+       exverror(cond, msg, ap);
+       va_end(ap);
+}
 
 /*
- * Return a string describing an error.  The returned string may be a
- * pointer to a static buffer that will be overwritten on the next call.
- * Action describes the operation that got the error.
+ * $PchId: error.c,v 1.5 2006/04/10 14:36:23 philip Exp $
  */
-
-char *
-errmsg(e, action) {
-       const struct errname *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;
-}
-#endif
index 4cd22507a65903155f40ed0cb48be010b9c76ddf..6597d9038db7e71f9968622c4637ffed7177a187 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)error.h     5.1 (Berkeley) 3/7/91
+ *     @(#)error.h     8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/error.h,v 1.17 2004/04/06 20:06:51 markm 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
+ * contains a code identifying the exception.  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.
  */
 
 #include <setjmp.h>
+#include <signal.h>
 
 struct jmploc {
        jmp_buf loc;
 };
 
 extern struct jmploc *handler;
-extern int exception;
+extern volatile sig_atomic_t 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 */
 
 
 /*
@@ -77,32 +67,21 @@ extern int exception;
  * more fun than worrying about efficiency and portability. :-))
  */
 
-extern volatile int suppressint;
-extern volatile int intpending;
-extern char *commandname;      /* name of command--printed on error */
+extern volatile sig_atomic_t suppressint;
+extern volatile sig_atomic_t intpending;
 
 #define INTOFF suppressint++
-#define INTON if (--suppressint == 0 && intpending) onint(); else
+#define INTON { if (--suppressint == 0 && intpending) onint(); }
 #define FORCEINTON {suppressint = 0; if (intpending) onint();}
 #define CLEAR_PENDING_INT intpending = 0
 #define int_pending() intpending
 
-#ifdef __STDC__
+#define __printf0like(a,b)
+
 void exraise(int);
 void onint(void);
-void error2(char *, char *);
-void error(char *, ...);
-char *errmsg(int, int);
-#else
-void exraise();
-void onint();
-void error2();
-void error();
-char *errmsg();
-#endif
-
-/* Errmsg uses confusingly different messages.  Prefer strerror().  -- kjb */
-#define errmsg(errno, action)  strerror(errno)
+void error(const char *, ...) __printf0like(1, 2);
+void exerror(int, const char *, ...) __printf0like(2, 3);
 
 
 /*
@@ -111,6 +90,12 @@ char *errmsg();
  */
 
 #ifdef BSD
+#ifndef __minix
 #define setjmp(jmploc) _setjmp(jmploc)
 #define longjmp(jmploc, val)   _longjmp(jmploc, val)
 #endif
+#endif
+
+/*
+ * $PchId: error.h,v 1.5 2006/04/10 14:36:43 philip Exp $
+ */
index 388a8000db4a8a5d90f54c51dde056dadd911574..02c4da1f6d8093274b9a093a678e1c243f69e421 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * 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.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)eval.c     5.3 (Berkeley) 4/12/91";
+#if 0
+static char sccsid[] = "@(#)eval.c     8.9 (Berkeley) 6/8/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/eval.c,v 1.42 2004/04/06 20:06:51 markm Exp $");
+*/
+
+#ifndef NO_PATHS_H
+#include <paths.h>
+#endif
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h> /* For WIFSIGNALED(status) */
+#include <errno.h>
 
 /*
  * Evaluate a command.
@@ -59,22 +70,21 @@ static char sccsid[] = "@(#)eval.c  5.3 (Berkeley) 4/12/91";
 #include "var.h"
 #include "memalloc.h"
 #include "error.h"
+#include "show.h"
 #include "mystring.h"
-#include <sys/types.h>
-#include <signal.h>
+#if !defined(NO_HISTORY) && !defined(EDITLINE)
+#include "myhistedit.h"
+#endif
 
+#ifndef _PATH_STDPATH
+#define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin:"
+#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 */
 
-
-/* reasons for skipping commands (see comment on breakcmd routine) */
-#define SKIPBREAK 1
-#define SKIPCONT 2
-#define SKIPFUNC 3
-
 MKINIT int evalskip;           /* set if we are skipping commands */
 STATIC int skipcount;          /* number of levels to skip */
 MKINIT int loopnest;           /* current loop nesting level */
@@ -87,7 +97,6 @@ int exitstatus;                       /* exit status of last command */
 int oexitstatus;               /* saved exit status */
 
 
-#ifdef __STDC__
 STATIC void evalloop(union node *);
 STATIC void evalfor(union node *);
 STATIC void evalcase(union node *, int);
@@ -96,17 +105,6 @@ STATIC void expredir(union node *);
 STATIC void evalpipe(union node *);
 STATIC void evalcommand(union node *, int, struct backcmd *);
 STATIC void prehash(union node *);
-#else
-STATIC void evalloop();
-STATIC void evalfor();
-STATIC void evalcase();
-STATIC void evalsubshell();
-STATIC void expredir();
-STATIC void evalpipe();
-STATIC void evalcommand();
-STATIC void prehash();
-#endif
-
 
 
 /*
@@ -130,11 +128,11 @@ SHELLPROC {
 
 
 /*
- * The eval commmand.
+ * The eval command.
  */
 
-evalcmd(argc, argv)  
-       char **argv; 
+int
+evalcmd(int argc, char **argv)
 {
         char *p;
         char *concat;
@@ -166,9 +164,8 @@ evalcmd(argc, argv)
  */
 
 void
-evalstring(s)
-       char *s;
-       {
+evalstring(char *s)
+{
        union node *n;
        struct stackmark smark;
 
@@ -190,14 +187,17 @@ evalstring(s)
  */
 
 void
-evaltree(n, flags)
-       union node *n;
-       {
+evaltree(union node *n, int flags)
+{
        if (n == NULL) {
                TRACE(("evaltree(NULL) called\n"));
-               return;
+               exitstatus = 0;
+               goto out;
        }
-       TRACE(("evaltree(0x%x: %d) called\n", (int)n, n->type));
+#if !defined(NO_HISTORY) && !defined(EDITLINE)
+       displayhist = 1;        /* show history substitutions done with fc */
+#endif
+       TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
        switch (n->type) {
        case NSEMI:
                evaltree(n->nbinary.ch1, 0);
@@ -207,8 +207,9 @@ evaltree(n, flags)
                break;
        case NAND:
                evaltree(n->nbinary.ch1, EV_TESTED);
-               if (evalskip || exitstatus != 0)
+               if (evalskip || exitstatus != 0) {
                        goto out;
+               }
                evaltree(n->nbinary.ch2, flags);
                break;
        case NOR:
@@ -230,19 +231,15 @@ evaltree(n, flags)
                evalsubshell(n, flags);
                break;
        case NIF: {
-               int status = 0; 
-
                evaltree(n->nif.test, EV_TESTED);
                if (evalskip)
                        goto out;
-               if (exitstatus == 0) {
+               if (exitstatus == 0)
                        evaltree(n->nif.ifpart, flags);
-                       status = exitstatus;
-               } else if (n->nif.elsepart) {
+               else if (n->nif.elsepart)
                        evaltree(n->nif.elsepart, flags);
-                       status = exitstatus;
-               }
-               exitstatus = status;
+               else
+                       exitstatus = 0;
                break;
        }
        case NWHILE:
@@ -259,6 +256,11 @@ evaltree(n, flags)
                defun(n->narg.text, n->narg.next);
                exitstatus = 0;
                break;
+       case NNOT:
+               evaltree(n->nnot.com, EV_TESTED);
+               exitstatus = !exitstatus;
+               break;
+
        case NPIPE:
                evalpipe(n);
                break;
@@ -273,18 +275,16 @@ evaltree(n, flags)
 out:
        if (pendingsigs)
                dotrap();
-       if ((flags & EV_EXIT) || (eflag && exitstatus
-         && !(flags & EV_TESTED) && (n->type == NCMD ||
-         n->type == NSUBSHELL))) {
+       if ((flags & EV_EXIT) || (eflag && exitstatus 
+           && !(flags & EV_TESTED) && (n->type == NCMD || 
+           n->type == NSUBSHELL)))
                exitshell(exitstatus);
-       }
 }
 
 
 STATIC void
-evalloop(n)
-       union node *n;
-       {
+evalloop(union node *n)
+{
        int status;
 
        loopnest++;
@@ -319,9 +319,8 @@ skipping:     if (evalskip == SKIPCONT && --skipcount <= 0) {
 
 
 STATIC void
-evalfor(n)
-       union node *n;
-       {
+evalfor(union node *n)
+{
        struct arglist arglist;
        union node *argp;
        struct strlist *sp;
@@ -331,7 +330,7 @@ evalfor(n)
        arglist.lastp = &arglist.list;
        for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
                oexitstatus = exitstatus;
-               expandarg(argp, &arglist, 1);
+               expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
                if (evalskip)
                        goto out;
        }
@@ -360,9 +359,8 @@ out:
 
 
 STATIC void
-evalcase(n, flags)
-       union node *n;
-       {
+evalcase(union node *n, int flags)
+{
        union node *cp;
        union node *patp;
        struct arglist arglist;
@@ -370,8 +368,8 @@ evalcase(n, flags)
 
        setstackmark(&smark);
        arglist.lastp = &arglist.list;
-        oexitstatus = exitstatus;
-       expandarg(n->ncase.expr, &arglist, 0);
+       oexitstatus = exitstatus;
+       expandarg(n->ncase.expr, &arglist, EXP_TILDE);
        for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
                for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
                        if (casematch(patp, arglist.list->text)) {
@@ -393,9 +391,8 @@ out:
  */
 
 STATIC void
-evalsubshell(n, flags)
-       union node *n;
-       {
+evalsubshell(union node *n, int flags)
+{
        struct job *jp;
        int backgnd = (n->type == NBACKGND);
 
@@ -409,7 +406,7 @@ evalsubshell(n, flags)
        }
        if (! backgnd) {
                INTOFF;
-               exitstatus = waitforjob(jp);
+               exitstatus = waitforjob(jp, (int *)NULL);
                INTON;
        }
 }
@@ -421,20 +418,30 @@ evalsubshell(n, flags)
  */
 
 STATIC void
-expredir(n)
-       union node *n;
-       {
-       register union node *redir;
+expredir(union node *n)
+{
+       union node *redir;
 
        for (redir = n ; redir ; redir = redir->nfile.next) {
+               struct arglist fn;
+               fn.lastp = &fn.list;
                oexitstatus = exitstatus;
-               if (redir->type == NFROM
-                || redir->type == NTO
-                || redir->type == NAPPEND) {
-                       struct arglist fn;
-                       fn.lastp = &fn.list;
-                       expandarg(redir->nfile.fname, &fn, 0);
+               switch (redir->type) {
+               case NFROM:
+               case NTO:
+               case NFROMTO:
+               case NAPPEND:
+               case NCLOBBER:
+                       expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
                        redir->nfile.expfname = fn.list->text;
+                       break;
+               case NFROMFD:
+               case NTOFD:
+                       if (redir->ndup.vname) {
+                               expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
+                               fixredir(redir, fn.list->text, 1);
+                       }
+                       break;
                }
        }
 }
@@ -449,16 +456,15 @@ expredir(n)
  */
 
 STATIC void
-evalpipe(n)
-       union node *n;
-       {
+evalpipe(union node *n)
+{
        struct job *jp;
        struct nodelist *lp;
        int pipelen;
        int prevfd;
        int pip[2];
 
-       TRACE(("evalpipe(0x%x) called\n", (int)n));
+       TRACE(("evalpipe(0x%lx) called\n", (long)n));
        pipelen = 0;
        for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
                pipelen++;
@@ -471,21 +477,20 @@ evalpipe(n)
                if (lp->next) {
                        if (pipe(pip) < 0) {
                                close(prevfd);
-                               error("Pipe call failed");
+                               error("Pipe call failed: %s", strerror(errno));
                        }
                }
                if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
                        INTON;
                        if (prevfd > 0) {
-                               close(0);
-                               copyfd(prevfd, 0);
+                               dup2(prevfd, 0);
                                close(prevfd);
                        }
                        if (pip[1] >= 0) {
-                               close(pip[0]);
+                               if (!(prevfd >= 0 && pip[0] == 0))
+                                       close(pip[0]);
                                if (pip[1] != 1) {
-                                       close(1);
-                                       copyfd(pip[1], 1);
+                                       dup2(pip[1], 1);
                                        close(pip[1]);
                                }
                        }
@@ -499,7 +504,7 @@ evalpipe(n)
        INTON;
        if (n->npipe.backgnd == 0) {
                INTOFF;
-               exitstatus = waitforjob(jp);
+               exitstatus = waitforjob(jp, (int *)NULL);
                TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
                INTON;
        }
@@ -515,10 +520,8 @@ evalpipe(n)
  */
 
 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 */
@@ -529,21 +532,22 @@ evalbackcmd(n, result)
        result->nleft = 0;
        result->jp = NULL;
        if (n == NULL) {
-               /* `` */
-       } else
+               exitstatus = 0;
+               goto out;
+       }
        if (n->type == NCMD) {
-                exitstatus = oexitstatus;
+               exitstatus = oexitstatus;
                evalcommand(n, EV_BACKCMD, result);
        } else {
+               exitstatus = 0;
                if (pipe(pip) < 0)
-                       error("Pipe call failed");
+                       error("Pipe call failed: %s", strerror(errno));
                jp = makejob(n, 1);
                if (forkshell(jp, n, FORK_NOJOB) == 0) {
                        FORCEINTON;
                        close(pip[0]);
                        if (pip[1] != 1) {
-                               close(1);
-                               copyfd(pip[1], 1);
+                               dup2(pip[1], 1);
                                close(pip[1]);
                        }
                        evaltree(n, EV_EXIT);
@@ -552,8 +556,9 @@ evalbackcmd(n, result)
                result->fd = pip[0];
                result->jp = jp;
        }
+out:
        popstackmark(&smark);
-       TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
+       TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n",
                result->fd, result->buf, result->nleft, result->jp));
 }
 
@@ -564,10 +569,8 @@ evalbackcmd(n, result)
  */
 
 STATIC void
-evalcommand(cmd, flags, backcmd)
-       union node *cmd;
-       struct backcmd *backcmd;
-       {
+evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
+{
        struct stackmark smark;
        union node *argp;
        struct arglist arglist;
@@ -577,7 +580,6 @@ evalcommand(cmd, flags, backcmd)
        char **envp;
        int varflag;
        struct strlist *sp;
-       register char *p;
        int mode;
        int pip[2];
        struct cmdentry cmdentry;
@@ -589,27 +591,38 @@ evalcommand(cmd, flags, backcmd)
        struct localvar *volatile savelocalvars;
        volatile int e;
        char *lastarg;
+       int realstatus;
+       int do_clearcmdentry;
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &argv;
+       (void) &argc;
+       (void) &lastarg;
+       (void) &flags;
+       (void) &do_clearcmdentry;
+#endif
 
        /* First expand the arguments. */
-       TRACE(("evalcommand(0x%x, %d) called\n", (int)cmd, flags));
+       TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
        setstackmark(&smark);
        arglist.lastp = &arglist.list;
        varlist.lastp = &varlist.list;
        varflag = 1;
-        oexitstatus = exitstatus;
+       do_clearcmdentry = 0;
+       oexitstatus = exitstatus;
        exitstatus = 0;
        for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
-               p = argp->narg.text;
+               char *p = argp->narg.text;
                if (varflag && is_name(*p)) {
                        do {
                                p++;
                        } while (is_in_name(*p));
                        if (*p == '=') {
-                               expandarg(argp, &varlist, 0);
+                               expandarg(argp, &varlist, EXP_VARTILDE);
                                continue;
                        }
                }
-               expandarg(argp, &arglist, 1);
+               expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
                varflag = 0;
        }
        *arglist.lastp = NULL;
@@ -619,8 +632,11 @@ evalcommand(cmd, flags, backcmd)
        for (sp = arglist.list ; sp ; sp = sp->next)
                argc++;
        argv = stalloc(sizeof (char *) * (argc + 1));
-       for (sp = arglist.list ; sp ; sp = sp->next)
+
+       for (sp = arglist.list ; sp ; sp = sp->next) {
+               TRACE(("evalcommand arg: %s\n", sp->text));
                *argv++ = sp->text;
+       }
        *argv = NULL;
        lastarg = NULL;
        if (iflag && funcnest == 0 && argc > 0)
@@ -628,7 +644,7 @@ evalcommand(cmd, flags, backcmd)
        argv -= argc;
 
        /* Print the command if xflag is set. */
-       if (xflag == 1) {
+       if (xflag) {
                outc('+', &errout);
                for (sp = varlist.list ; sp ; sp = sp->next) {
                        outc(' ', &errout);
@@ -647,11 +663,42 @@ evalcommand(cmd, flags, backcmd)
                cmdentry.cmdtype = CMDBUILTIN;
                cmdentry.u.index = BLTINCMD;
        } else {
-               find_command(argv[0], &cmdentry, 1);
+               static const char PATH[] = "PATH=";
+               char *path = pathval();
+
+               /*
+                * Modify the command lookup path, if a PATH= assignment
+                * is present
+                */
+               for (sp = varlist.list ; sp ; sp = sp->next)
+                       if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) {
+                               path = sp->text + sizeof(PATH) - 1;
+                               /* 
+                                * On `PATH=... command`, we need to make
+                                * sure that the command isn't using the
+                                * non-updated hash table of the outer PATH
+                                * setting and we need to make sure that 
+                                * the hash table isn't filled with items
+                                * from the temporary setting.
+                                *
+                                * It would be better to forbit using and 
+                                * updating the table while this command
+                                * runs, by the command finding mechanism
+                                * is heavily integrated with hash handling,
+                                * so we just delete the hash before and after
+                                * the command runs. Partly deleting like
+                                * changepatch() does doesn't seem worth the
+                                * bookinging effort, since most such runs add
+                                * directories in front of the new PATH.
+                                */
+                               clearcmdentry(0);
+                               do_clearcmdentry = 1;
+                       }
+
+               find_command(argv[0], &cmdentry, 1, path);
                if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
-                       exitstatus = 2;
+                       exitstatus = 127;
                        flushout(&errout);
-                       popstackmark(&smark);
                        return;
                }
                /* implement the bltin builtin here */
@@ -662,9 +709,8 @@ evalcommand(cmd, flags, backcmd)
                                        break;
                                if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
                                        outfmt(&errout, "%s: not found\n", *argv);
-                                       exitstatus = 2;
+                                       exitstatus = 127;
                                        flushout(&errout);
-                                       popstackmark(&smark);
                                        return;
                                }
                                if (cmdentry.u.index != BLTINCMD)
@@ -675,17 +721,21 @@ evalcommand(cmd, flags, backcmd)
 
        /* Fork off a child process if necessary. */
        if (cmd->ncmd.backgnd
-        || cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0
-        || (flags & EV_BACKCMD) != 0
+        || (cmdentry.cmdtype == CMDNORMAL
+           && ((flags & EV_EXIT) == 0 || Tflag))
+        || ((flags & EV_BACKCMD) != 0
            && (cmdentry.cmdtype != CMDBUILTIN
+                || cmdentry.u.index == CDCMD
                 || cmdentry.u.index == DOTCMD
-                || cmdentry.u.index == EVALCMD)) {
+                || cmdentry.u.index == EVALCMD))
+        || (cmdentry.cmdtype == CMDBUILTIN &&
+           cmdentry.u.index == COMMANDCMD)) {
                jp = makejob(cmd, 1);
                mode = cmd->ncmd.backgnd;
                if (flags & EV_BACKCMD) {
                        mode = FORK_NOJOB;
                        if (pipe(pip) < 0)
-                               error("Pipe call failed");
+                               error("Pipe call failed: %s", strerror(errno));
                }
                if (forkshell(jp, cmd, mode) != 0)
                        goto parent;    /* at end of routine */
@@ -693,8 +743,7 @@ evalcommand(cmd, flags, backcmd)
                        FORCEINTON;
                        close(pip[0]);
                        if (pip[1] != 1) {
-                               close(1);
-                               copyfd(pip[1], 1);
+                               dup2(pip[1], 1);
                                close(pip[1]);
                        }
                }
@@ -704,10 +753,13 @@ evalcommand(cmd, flags, backcmd)
        /* This is the child process if a fork occurred. */
        /* Execute the command. */
        if (cmdentry.cmdtype == CMDFUNCTION) {
+#if DEBUG
                trputs("Shell function:  ");  trargs(argv);
+#endif
                redirect(cmd->ncmd.redirect, REDIR_PUSH);
                saveparam = shellparam;
                shellparam.malloc = 0;
+               shellparam.reset = 1;
                shellparam.nparam = argc - 1;
                shellparam.p = argv + 1;
                shellparam.optnext = NULL;
@@ -752,7 +804,9 @@ evalcommand(cmd, flags, backcmd)
                if (flags & EV_EXIT)
                        exitshell(exitstatus);
        } else if (cmdentry.cmdtype == CMDBUILTIN) {
+#if DEBUG
                trputs("builtin command:  ");  trargs(argv);
+#endif
                mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
                if (flags == EV_BACKCMD) {
                        memout.nleft = 0;
@@ -777,6 +831,7 @@ evalcommand(cmd, flags, backcmd)
                exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
                flushall();
 cmddone:
+               cmdenviron = NULL;
                out1 = &output;
                out2 = &errout;
                freestdout();
@@ -788,10 +843,15 @@ cmddone:
                }
                handler = savehandler;
                if (e != -1) {
-                       if (e != EXERROR || cmdentry.u.index == BLTINCMD
-                                              || cmdentry.u.index == DOTCMD
-                                              || cmdentry.u.index == EVALCMD
-                                              || cmdentry.u.index == EXECCMD)
+                       if ((e != EXERROR && e != EXEXEC)
+                          || cmdentry.u.index == BLTINCMD
+                          || cmdentry.u.index == DOTCMD
+                          || cmdentry.u.index == EVALCMD
+#ifndef NO_HISTORY
+                          || cmdentry.u.index == HISTCMD
+#endif
+                          || cmdentry.u.index == EXECCMD
+                          || cmdentry.u.index == COMMANDCMD)
                                exraise(e);
                        FORCEINTON;
                }
@@ -803,19 +863,15 @@ cmddone:
                        memout.buf = NULL;
                }
        } else {
+#if DEBUG
                trputs("normal command:  ");  trargs(argv);
+#endif
                clearredir();
                redirect(cmd->ncmd.redirect, 0);
-               if (varlist.list) {
-                       p = stalloc(strlen(pathval()) + 1);
-                       scopy(pathval(), p);
-               } else {
-                       p = pathval();
-               }
                for (sp = varlist.list ; sp ; sp = sp->next)
                        setvareq(sp->text, VEXPORT|VSTACK);
                envp = environment();
-               shellexec(argv, envp, p, cmdentry.u.index);
+               shellexec(argv, envp, pathval(), cmdentry.u.index);
                /*NOTREACHED*/
        }
        goto out;
@@ -823,8 +879,12 @@ cmddone:
 parent:        /* parent process gets here (if we forked) */
        if (mode == 0) {        /* argument to fork */
                INTOFF;
-               exitstatus = waitforjob(jp);
+               exitstatus = waitforjob(jp, &realstatus);
                INTON;
+               if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) {
+                       evalskip = SKIPBREAK;
+                       skipcount = loopnest;
+               }
        } else if (mode == 2) {
                backcmd->fd = pip[0];
                close(pip[1]);
@@ -834,6 +894,8 @@ parent:     /* parent process gets here (if we forked) */
 out:
        if (lastarg)
                setvar("_", lastarg, 0);
+       if (do_clearcmdentry)
+               clearcmdentry(0);
        popstackmark(&smark);
 }
 
@@ -847,13 +909,14 @@ out:
  */
 
 STATIC void
-prehash(n)
-       union node *n;
-       {
+prehash(union node *n)
+{
        struct cmdentry entry;
 
-       if (n->type == NCMD && goodname(n->ncmd.args->narg.text))
-               find_command(n->ncmd.args->narg.text, &entry, 0);
+       if (n->type == NCMD && n->ncmd.args)
+               if (goodname(n->ncmd.args->narg.text))
+                       find_command(n->ncmd.args->narg.text, &entry, 0,
+                                    pathval());
 }
 
 
@@ -868,8 +931,14 @@ prehash(n)
  * specified variables.
  */
 
-bltincmd(argc, argv)  char **argv; {
+int
+bltincmd(int argc __unused, char **argv __unused)
+{
        listsetvar(cmdenviron);
+       /*
+        * Preserve exitstatus of a previous possible redirection
+        * as POSIX mandates
+        */
        return exitstatus;
 }
 
@@ -885,12 +954,11 @@ bltincmd(argc, argv)  char **argv; {
  * in the standard shell so we don't make it one here.
  */
 
-breakcmd(argc, argv)  char **argv; {
-       int n;
+int
+breakcmd(int argc, char **argv)
+{
+       int n = argc > 1 ? number(argv[1]) : 1;
 
-       n = 1;
-       if (argc > 1)
-               n = number(argv[1]);
        if (n > loopnest)
                n = loopnest;
        if (n > 0) {
@@ -900,40 +968,108 @@ breakcmd(argc, argv)  char **argv; {
        return 0;
 }
 
+/*
+ * The `command' command.
+ */
+int
+commandcmd(int argc, char **argv)
+{
+       static char stdpath[] = _PATH_STDPATH;
+       struct jmploc loc, *old;
+       struct strlist *sp;
+       char *path;
+       int ch;
+
+       for (sp = cmdenviron; sp ; sp = sp->next)
+               setvareq(sp->text, VEXPORT|VSTACK);
+       path = pathval();
+
+       optind = optreset = 1;
+       opterr = 0;
+       while ((ch = getopt(argc, argv, "p")) != -1) {
+               switch (ch) {
+               case 'p':
+                       path = stdpath;
+                       break;
+               case '?':
+               default:
+                       error("unknown option: -%c", optopt);
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (argc != 0) {
+               old = handler;
+               handler = &loc;
+               if (setjmp(handler->loc) == 0)
+                       shellexec(argv, environment(), path, 0);
+               handler = old;
+               if (exception == EXEXEC)
+                       exit(exerrno);
+               exraise(exception);
+       }
+
+       /*
+        * Do nothing successfully if no command was specified;
+        * ksh also does this.
+        */
+       exit(0);
+}
+
 
 /*
  * The return command.
  */
 
-returncmd(argc, argv)  char **argv; {
-       int ret;
+int
+returncmd(int argc, char **argv)
+{
+       int ret = argc > 1 ? number(argv[1]) : oexitstatus;
 
-       ret = oexitstatus;
-       if (argc > 1)
-               ret = number(argv[1]);
        if (funcnest) {
                evalskip = SKIPFUNC;
                skipcount = 1;
+       } else {
+               /* skip the rest of the file */
+               evalskip = SKIPFILE;
+               skipcount = 1;
        }
        return ret;
 }
 
 
-truecmd(argc, argv)  char **argv; {
-       return strcmp(argv[0], "false") == 0 ? 1 : 0;
+int
+falsecmd(int argc __unused, char **argv __unused)
+{
+       return 1;
 }
 
 
-execcmd(argc, argv)  char **argv; {
+int
+truecmd(int argc __unused, char **argv __unused)
+{
+       return 0;
+}
+
+
+int
+execcmd(int argc, char **argv)
+{
        if (argc > 1) {
+               struct strlist *sp;
+
                iflag = 0;              /* exit on error */
-               setinteractive(0);
-#if JOBS
-               jflag = 0;
-               setjobctl(0);
-#endif
+               mflag = 0;
+               optschanged();
+               for (sp = cmdenviron; sp ; sp = sp->next)
+                       setvareq(sp->text, VEXPORT|VSTACK);
                shellexec(argv + 1, environment(), pathval(), 0);
 
        }
        return 0;
 }
+
+/*
+ * $PchId: eval.c,v 1.7 2006/04/10 14:46:14 philip Exp $
+ */
index 04499cb6c6307d091c20a1b8f4829ca72a1b6ff9..b8b9415b921ca0c53af2f58af06bde218666a1e9 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
@@ -33,7 +29,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)eval.h      5.2 (Berkeley) 4/12/91
+ *     @(#)eval.h      8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/eval.h,v 1.10 2004/04/06 20:06:51 markm Exp $
  */
 
 extern char *commandname;      /* currently executing command */
@@ -48,18 +45,30 @@ struct backcmd {            /* result of evalbackcmd */
        struct job *jp;         /* job structure for command */
 };
 
-
-#ifdef __STDC__
+int evalcmd(int, char **);
 void evalstring(char *);
 union node;    /* BLETCH for ansi C */
 void evaltree(union node *, int);
 void evalbackcmd(union node *, struct backcmd *);
-#else
-void evalstring();
-void evaltree();
-void evalbackcmd();
-#endif
+int bltincmd(int, char **);
+int breakcmd(int, char **);
+int returncmd(int, char **);
+int falsecmd(int, char **);
+int truecmd(int, char **);
+int execcmd(int, char **);
+int commandcmd(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
+
+/*
+ * $PchId: eval.h,v 1.3 2006/03/30 15:39:25 philip Exp $
+ */
index ad7158eb72584a054fbb60df42d566487018c760..5020819cd8a170995398677d3de918cb5407c80f 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)exec.c     5.2 (Berkeley) 3/13/91";
+#if 0
+static char sccsid[] = "@(#)exec.c     8.4 (Berkeley) 6/8/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/exec.c,v 1.24.2.1 2004/09/30 04:41:55 des Exp $");
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
 
 /*
  * When commands are first encountered, they are entered in a hash table.
@@ -64,11 +73,9 @@ static char sccsid[] = "@(#)exec.c   5.2 (Berkeley) 3/13/91";
 #include "error.h"
 #include "init.h"
 #include "mystring.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
+#include "show.h"
+#include "jobs.h"
+#include "alias.h"
 
 
 #define CMDTABLESIZE 31                /* should be prime */
@@ -87,23 +94,14 @@ struct tblentry {
 
 STATIC struct tblentry *cmdtable[CMDTABLESIZE];
 STATIC int builtinloc = -1;            /* index in path of %builtin, or -1 */
+int exerrno = 0;                       /* Last exec error */
 
 
-#ifdef __STDC__
 STATIC void tryexec(char *, char **, char **);
-STATIC void execinterp(char **, char **);
-STATIC void printentry(struct tblentry *);
-STATIC void clearcmdentry(int);
+STATIC void printentry(struct tblentry *, int);
 STATIC struct tblentry *cmdlookup(char *, int);
 STATIC void delete_cmd_entry(void);
-#else
-STATIC void tryexec();
-STATIC void execinterp();
-STATIC void printentry();
-STATIC void clearcmdentry();
-STATIC struct tblentry *cmdlookup();
-STATIC void delete_cmd_entry();
-#endif
+STATIC void addcmdentry(char *, struct cmdentry *);
 
 
 
@@ -113,10 +111,8 @@ STATIC void delete_cmd_entry();
  */
 
 void
-shellexec(argv, envp, path, index)
-       char **argv, **envp;
-       char *path;
-       {
+shellexec(char **argv, char **envp, char *path, int index)
+{
        char *cmdname;
        int e;
 
@@ -134,40 +130,37 @@ shellexec(argv, envp, path, index)
                        stunalloc(cmdname);
                }
        }
-       error2(argv[0], errmsg(e, E_EXEC));
+
+       /* Map to POSIX errors */
+       switch (e) {
+       case EACCES:
+               exerrno = 126;
+               break;
+       case ENOENT:
+               exerrno = 127;
+               break;
+       default:
+               exerrno = 2;
+               break;
+       }
+       if (e == ENOENT || e == ENOTDIR)
+               exerror(EXEXEC, "%s: not found", argv[0]);
+       exerror(EXEXEC, "%s: %s", argv[0], strerror(e));
 }
 
 
 STATIC void
-tryexec(cmd, argv, envp)
-       char *cmd;
-       char **argv;
-       char **envp;
-       {
+tryexec(char *cmd, char **argv, char **envp)
+{
        int e;
-       char *p;
 
-#ifdef SYSV
-       do {
-               execve(cmd, argv, envp);
-       } while (errno == EINTR);
-#else
        execve(cmd, argv, envp);
-#endif
-#if HASHBANG
+#if !__minix_vmd
        e = errno;
        if (e == ENOEXEC) {
                initshellproc();
                setinputfile(cmd, 0);
                commandname = arg0 = savestr(argv[0]);
-#ifndef BSD
-               pgetc(); pungetc();             /* fill up input buffer */
-               p = parsenextc;
-               if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
-                       argv[0] = cmd;
-                       execinterp(argv, envp);
-               }
-#endif
                setparam(argv + 1);
                exraise(EXSHELLPROC);
                /*NOTREACHED*/
@@ -176,88 +169,6 @@ tryexec(cmd, argv, envp)
 #endif
 }
 
-
-#if !defined(BSD) && HASHBANG
-/*
- * 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.
- */
-
-#define NEWARGS 5
-
-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;
-
-       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 !__minix
-       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:;
-       }
-#endif
-       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);
-}
-#endif
-
-
-
 /*
  * Do a path search.  The variable path (passed by reference) should be
  * set to the start of the path before the first call; padvance will update
@@ -271,11 +182,9 @@ break2:;
 char *pathopt;
 
 char *
-padvance(path, name)
-       char **path;
-       char *name;
-       {
-       register char *p, *q;
+padvance(char **path, char *name)
+{
+       char *p, *q;
        char *start;
        int len;
 
@@ -288,7 +197,7 @@ padvance(path, name)
                growstackblock();
        q = stackblock();
        if (p != start) {
-               bcopy(start, q, p - start);
+               memcpy(q, start, p - start);
                q += p - start;
                *q++ = '/';
        }
@@ -310,7 +219,9 @@ padvance(path, name)
 /*** Command hashing code ***/
 
 
-hashcmd(argc, argv)  char **argv; {
+int
+hashcmd(int argc __unused, char **argv __unused)
+{
        struct tblentry **pp;
        struct tblentry *cmdp;
        int c;
@@ -318,14 +229,6 @@ hashcmd(argc, argv)  char **argv; {
        struct cmdentry entry;
        char *name;
 
-       if (argc <= 1) {
-               for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
-                       for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
-                               printentry(cmdp);
-                       }
-               }
-               return 0;
-       }
        verbose = 0;
        while ((c = nextopt("rv")) != '\0') {
                if (c == 'r') {
@@ -334,16 +237,28 @@ hashcmd(argc, argv)  char **argv; {
                        verbose++;
                }
        }
+       if (*argptr == NULL) {
+               for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
+                       for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+                               if (cmdp->cmdtype == CMDNORMAL)
+                                       printentry(cmdp, verbose);
+                       }
+               }
+               return 0;
+       }
        while ((name = *argptr) != NULL) {
                if ((cmdp = cmdlookup(name, 0)) != NULL
                 && (cmdp->cmdtype == CMDNORMAL
-                    || cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
+                    || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
                        delete_cmd_entry();
-               find_command(name, &entry, 1);
+               find_command(name, &entry, 1, pathval());
                if (verbose) {
                        if (entry.cmdtype != CMDUNKNOWN) {      /* if no error msg */
                                cmdp = cmdlookup(name, 0);
-                               printentry(cmdp);
+                               if (cmdp != NULL)
+                                       printentry(cmdp, verbose);
+                               else
+                                       outfmt(&errout, "%s: not found\n", name);
                        }
                        flushall();
                }
@@ -354,9 +269,8 @@ hashcmd(argc, argv)  char **argv; {
 
 
 STATIC void
-printentry(cmdp)
-       struct tblentry *cmdp;
-       {
+printentry(struct tblentry *cmdp, int verbose)
+{
        int index;
        char *path;
        char *name;
@@ -373,6 +287,14 @@ printentry(cmdp)
                out1fmt("builtin %s", cmdp->cmdname);
        } else if (cmdp->cmdtype == CMDFUNCTION) {
                out1fmt("function %s", cmdp->cmdname);
+               if (verbose) {
+                       INTOFF;
+                       name = commandtext(cmdp->param.func);
+                       out1c(' ');
+                       out1str(name);
+                       ckfree(name);
+                       INTON;
+               }
 #if DEBUG
        } else {
                error("internal error: cmdtype %d", cmdp->cmdtype);
@@ -391,14 +313,11 @@ printentry(cmdp)
  */
 
 void
-find_command(name, entry, printerr)
-       char *name;
-       struct cmdentry *entry;
-       {
+find_command(char *name, struct cmdentry *entry, int printerr, char *path)
+{
        struct tblentry *cmdp;
        int index;
        int prev;
-       char *path;
        char *fullname;
        struct stat statb;
        int e;
@@ -434,7 +353,6 @@ find_command(name, entry, printerr)
                        prev = cmdp->param.index;
        }
 
-       path = pathval();
        e = ENOENT;
        index = -1;
 loop:
@@ -464,17 +382,13 @@ loop:
                        TRACE(("searchexec \"%s\": no change\n", name));
                        goto success;
                }
-               while (stat(fullname, &statb) < 0) {
-#ifdef SYSV
-                       if (errno == EINTR)
-                               continue;
-#endif
+               if (stat(fullname, &statb) < 0) {
                        if (errno != ENOENT && errno != ENOTDIR)
                                e = errno;
                        goto loop;
                }
                e = EACCES;     /* if we fail, this will be the error */
-               if ((statb.st_mode & S_IFMT) != S_IFREG)
+               if (!S_ISREG(statb.st_mode))
                        goto loop;
                if (pathopt) {          /* this is a %func directory */
                        stalloc(strlen(fullname) + 1);
@@ -484,6 +398,7 @@ loop:
                        stunalloc(fullname);
                        goto success;
                }
+#ifdef notdef
                if (statb.st_uid == geteuid()) {
                        if ((statb.st_mode & 0100) == 0)
                                goto loop;
@@ -491,23 +406,10 @@ loop:
                        if ((statb.st_mode & 010) == 0)
                                goto loop;
                } else {
-#if __minix_vmd || defined(BSD)
-                       gid_t group_list[NGROUPS_MAX];
-                       int ngroups, i;
-
-                       ngroups = getgroups(NGROUPS_MAX, group_list);
-
-                       for (i = 0; i < ngroups; i++) {
-                               if (statb.st_gid == group_list[i]) break;
-                       }
-                       if (i < ngroups) {
-                               if ((statb.st_mode & 010) == 0)
-                                       goto loop;
-                       } else
-#endif
                        if ((statb.st_mode & 01) == 0)
                                goto loop;
                }
+#endif
                TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
                INTOFF;
                cmdp = cmdlookup(name, 1);
@@ -520,8 +422,12 @@ loop:
        /* We failed.  If there was an entry for this command, delete it */
        if (cmdp)
                delete_cmd_entry();
-       if (printerr)
-               outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
+       if (printerr) {
+               if (e == ENOENT || e == ENOTDIR)
+                       outfmt(out2, "%s: not found\n", name);
+               else
+                       outfmt(out2, "%s: %s\n", name, strerror(e));
+       }
        entry->cmdtype = CMDUNKNOWN;
        return;
 
@@ -538,10 +444,9 @@ success:
  */
 
 int
-find_builtin(name)
-       char *name;
-       {
-       const register struct builtincmd *bp;
+find_builtin(char *name)
+{
+       const struct builtincmd *bp;
 
        for (bp = builtincmd ; bp->name ; bp++) {
                if (*bp->name == *name && equal(bp->name, name))
@@ -558,14 +463,15 @@ find_builtin(name)
  */
 
 void
-hashcd() {
+hashcd(void)
+{
        struct tblentry **pp;
        struct tblentry *cmdp;
 
        for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
                for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
                        if (cmdp->cmdtype == CMDNORMAL
-                        || cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)
+                        || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
                                cmdp->rehash = 1;
                }
        }
@@ -580,10 +486,9 @@ hashcd() {
  */
 
 void
-changepath(newval)
-       char *newval;
-       {
-       char *old, *new;
+changepath(const char *newval)
+{
+       const char *old, *new;
        int index;
        int firstchange;
        int bltin;
@@ -596,8 +501,8 @@ changepath(newval)
        for (;;) {
                if (*old != *new) {
                        firstchange = index;
-                       if (*old == '\0' && *new == ':'
-                        || *old == ':' && *new == '\0')
+                       if ((*old == '\0' && *new == ':')
+                        || (*old == ':' && *new == '\0'))
                                firstchange++;
                        old = new;      /* ignore subsequent differences */
                }
@@ -624,8 +529,9 @@ changepath(newval)
  * PATH which has changed.
  */
 
-STATIC void
-clearcmdentry(firstchange) {
+void
+clearcmdentry(int firstchange)
+{
        struct tblentry **tblp;
        struct tblentry **pp;
        struct tblentry *cmdp;
@@ -634,8 +540,10 @@ clearcmdentry(firstchange) {
        for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
                pp = tblp;
                while ((cmdp = *pp) != NULL) {
-                       if (cmdp->cmdtype == CMDNORMAL && cmdp->param.index >= firstchange
-                        || cmdp->cmdtype == CMDBUILTIN && builtinloc >= firstchange) {
+                       if ((cmdp->cmdtype == CMDNORMAL &&
+                            cmdp->param.index >= firstchange)
+                        || (cmdp->cmdtype == CMDBUILTIN &&
+                            builtinloc >= firstchange)) {
                                *pp = cmdp->next;
                                ckfree(cmdp);
                        } else {
@@ -652,15 +560,15 @@ clearcmdentry(firstchange) {
  */
 
 #ifdef mkinit
-MKINIT void deletefuncs();
-
+INCLUDE "exec.h"
 SHELLPROC {
        deletefuncs();
 }
 #endif
 
 void
-deletefuncs() {
+deletefuncs(void)
+{
        struct tblentry **tblp;
        struct tblentry **pp;
        struct tblentry *cmdp;
@@ -691,15 +599,14 @@ deletefuncs() {
  * entry.
  */
 
-struct tblentry **lastcmdentry;
+STATIC struct tblentry **lastcmdentry;
 
 
 STATIC struct tblentry *
-cmdlookup(name, add)
-       char *name;
-       {
+cmdlookup(char *name, int add)
+{
        int hashval;
-       register char *p;
+       char *p;
        struct tblentry *cmdp;
        struct tblentry **pp;
 
@@ -728,13 +635,13 @@ cmdlookup(name, add)
        return cmdp;
 }
 
-
 /*
  * Delete the command entry returned on the last lookup.
  */
 
 STATIC void
-delete_cmd_entry() {
+delete_cmd_entry(void)
+{
        struct tblentry *cmdp;
 
        INTOFF;
@@ -746,35 +653,14 @@ delete_cmd_entry() {
 
 
 
-#ifdef notdef
-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.
  */
 
-void
-addcmdentry(name, entry)
-       char *name;
-       struct cmdentry *entry;
-       {
+static void
+addcmdentry(char *name, struct cmdentry *entry)
+{
        struct tblentry *cmdp;
 
        INTOFF;
@@ -793,10 +679,8 @@ addcmdentry(name, entry)
  */
 
 void
-defun(name, func)
-       char *name;
-       union node *func;
-       {
+defun(char *name, union node *func)
+{
        struct cmdentry entry;
 
        INTOFF;
@@ -811,14 +695,98 @@ defun(name, func)
  * Delete a function if it exists.
  */
 
-void
-unsetfunc(name)
-       char *name;
-       {
+int
+unsetfunc(char *name)
+{
        struct tblentry *cmdp;
 
        if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
                freefunc(cmdp->param.func);
                delete_cmd_entry();
+               return (0);
        }
+       return (0);
 }
+
+/*
+ * Locate and print what a word is...
+ */
+
+int
+typecmd(int argc, char **argv)
+{
+       struct cmdentry entry;
+       struct tblentry *cmdp;
+       char **pp;
+       struct alias *ap;
+       int i;
+       int error = 0;
+       extern char *const parsekwd[];
+
+       for (i = 1; i < argc; i++) {
+               out1str(argv[i]);
+               /* First look at the keywords */
+               for (pp = (char **)parsekwd; *pp; pp++)
+                       if (**pp == *argv[i] && equal(*pp, argv[i]))
+                               break;
+
+               if (*pp) {
+                       out1str(" is a shell keyword\n");
+                       continue;
+               }
+
+               /* Then look at the aliases */
+               if ((ap = lookupalias(argv[i], 1)) != NULL) {
+                       out1fmt(" is an alias for %s\n", ap->val);
+                       continue;
+               }
+
+               /* Then check if it is a tracked alias */
+               if ((cmdp = cmdlookup(argv[i], 0)) != NULL) {
+                       entry.cmdtype = cmdp->cmdtype;
+                       entry.u = cmdp->param;
+               }
+               else {
+                       /* Finally use brute force */
+                       find_command(argv[i], &entry, 0, pathval());
+               }
+
+               switch (entry.cmdtype) {
+               case CMDNORMAL: {
+                       if (strchr(argv[i], '/') == NULL) {
+                               char *path = pathval(), *name;
+                               int j = entry.u.index;
+                               do {
+                                       name = padvance(&path, argv[i]);
+                                       stunalloc(name);
+                               } while (--j >= 0);
+                               out1fmt(" is%s %s\n",
+                                   cmdp ? " a tracked alias for" : "", name);
+                       } else {
+                               if (access(argv[i], X_OK) == 0)
+                                       out1fmt(" is %s\n", argv[i]);
+                               else
+                                       out1fmt(": %s\n", strerror(errno));
+                       }
+                       break;
+               }
+               case CMDFUNCTION:
+                       out1str(" is a shell function\n");
+                       break;
+
+               case CMDBUILTIN:
+                       out1str(" is a shell builtin\n");
+                       break;
+
+               default:
+                       out1str(": not found\n");
+                       error |= 127;
+                       break;
+               }
+       }
+       return error;
+}
+
+/*
+ * $PchId: exec.c,v 1.6 2006/04/10 14:47:03 philip Exp $
+ */
index cd333dc94d3f0c9496c30bbc97185b94cf21fd46..eef4c9533bece435aeec8b5d1528254756ba5708 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
@@ -33,7 +29,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)exec.h      5.1 (Berkeley) 3/7/91
+ *     @(#)exec.h      8.3 (Berkeley) 6/8/95
+ * $FreeBSD: src/bin/sh/exec.h,v 1.12 2004/04/06 20:06:51 markm Exp $
  */
 
 /* values of cmdtype */
@@ -53,23 +50,21 @@ struct cmdentry {
 
 
 extern char *pathopt;          /* set by padvance */
+extern int exerrno;            /* last exec error */
 
-#ifdef __STDC__
 void shellexec(char **, char **, char *, int);
 char *padvance(char **, char *);
-void find_command(char *, struct cmdentry *, int);
+int hashcmd(int, char **);
+void find_command(char *, struct cmdentry *, int, char *);
 int find_builtin(char *);
 void hashcd(void);
-void changepath(char *);
+void changepath(const char *);
+void deletefuncs(void);
 void defun(char *, union node *);
-void unsetfunc(char *);
-#else
-void shellexec();
-char *padvance();
-void find_command();
-int find_builtin();
-void hashcd();
-void changepath();
-void defun();
-void unsetfunc();
-#endif
+int unsetfunc(char *);
+int typecmd(int, char **);
+void clearcmdentry(int);
+
+/*
+ * $PchId: exec.h,v 1.5 2006/04/10 14:47:34 philip Exp $
+ */
index 28ef32ab02030ad552b355914ddaa1eb8e3df97f..a0ef6924d74c355b28b0b974a33837559468ff98 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)expand.c   5.1 (Berkeley) 3/7/91";
+#if 0
+static char sccsid[] = "@(#)expand.c   8.5 (Berkeley) 5/15/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/expand.c,v 1.46 2004/04/06 20:06:51 markm Exp $");
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
 
 /*
  * Routines to expand arguments to commands.  We have to deal with
@@ -58,13 +71,8 @@ static char sccsid[] = "@(#)expand.c 5.1 (Berkeley) 3/7/91";
 #include "memalloc.h"
 #include "error.h"
 #include "mystring.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <dirent.h>
-#if USEGETPW
-#include <pwd.h>
-#endif
+#include "arith.h"
+#include "show.h"
 
 /*
  * Structure specifying which parts of the string should be searched
@@ -79,67 +87,51 @@ struct ifsregion {
 };
 
 
-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 */
-#if UDIR || TILDE
-/*
- * Set if the last argument processed had /u/logname or ~logname expanded.
- * This variable is read by the cd command.
- */
-int didudir;
-#endif
+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 */
 
-#ifdef __STDC__
 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);
 STATIC char *evalvar(char *, int);
-STATIC int varisset(int);
-STATIC void varvalue(int, int, int);
+STATIC int varisset(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 expandmeta(struct strlist *);
+STATIC void expandmeta(struct strlist *, int);
 STATIC void expmeta(char *, char *);
 STATIC void addfname(char *);
 STATIC struct strlist *expsort(struct strlist *);
 STATIC struct strlist *msort(struct strlist *, int);
-STATIC int pmatch(char *, char *);
-#else
-STATIC void argstr();
-STATIC void expbackq();
-STATIC char *evalvar();
-STATIC int varisset();
-STATIC void varvalue();
-STATIC void recordregion();
-STATIC void ifsbreakup();
-STATIC void expandmeta();
-STATIC void expmeta();
-STATIC void addfname();
-STATIC struct strlist *expsort();
-STATIC struct strlist *msort();
-STATIC int pmatch();
-#endif
-#if UDIR || TILDE
-#ifdef __STDC__
-STATIC char *expudir(char *);
-#else
-STATIC char *expudir();
-#endif
-#endif /* UDIR || TILDE */
+STATIC int pmatch(char *, char *, int);
+STATIC char *cvtnum(int, char *);
+STATIC int collate_range_cmp(int, int);
+STATIC void expari(int);
 
+STATIC int
+collate_range_cmp(int c1, int c2)
+{
+       static char s1[2], s2[2];
 
+       s1[0] = c1;
+       s2[0] = c2;
+       return (strcoll(s1, s2));
+}
 
 /*
  * Expand shell variables and backquotes inside a here document.
+ *     union node *arg         the document
+ *     int fd;                 where to write the expanded version
  */
 
 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());
@@ -148,38 +140,39 @@ expandhere(arg, fd)
 
 /*
  * Perform variable substitution and command substitution on an argument,
- * placing the resulting list of arguments in arglist.  If full is true,
+ * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
  * perform splitting and file name expansion.  When arglist is NULL, perform
  * here document expansion.
  */
 
 void
-expandarg(arg, arglist, full)
-       union node *arg;
-       struct arglist *arglist;
-       {
+expandarg(union node *arg, struct arglist *arglist, int flag)
+{
        struct strlist *sp;
        char *p;
 
-#if UDIR || TILDE
-       didudir = 0;
-#endif
        argbackq = arg->narg.backquote;
        STARTSTACKSTR(expdest);
        ifsfirst.next = NULL;
        ifslastp = NULL;
-       argstr(arg->narg.text, full);
-       if (arglist == NULL)
+       argstr(arg->narg.text, flag);
+       if (arglist == NULL) {
                return;                 /* here document expanded */
+       }
        STPUTC('\0', expdest);
        p = grabstackstr(expdest);
        exparg.lastp = &exparg.list;
-       if (full) {
+       /*
+        * TODO - EXP_REDIR
+        */
+       if (flag & EXP_FULL) {
                ifsbreakup(p, &exparg);
                *exparg.lastp = NULL;
                exparg.lastp = &exparg.list;
-               expandmeta(exparg.list);
+               expandmeta(exparg.list, flag);
        } else {
+               if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
+                       rmescapes(p);
                sp = (struct strlist *)stalloc(sizeof (struct strlist));
                sp->text = p;
                *exparg.lastp = sp;
@@ -203,36 +196,66 @@ expandarg(arg, arglist, full)
 
 
 /*
- * Perform variable and command substitution.  If full is set, output CTLESC
- * characters to allow for further processing.  If full is not set, treat
+ * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
+ * characters to allow for further processing.  Otherwise treat
  * $@ like $* since no splitting will be performed.
  */
 
 STATIC void
-argstr(p, full)
-       register char *p;
-       {
+argstr(char *p, int flag)
+{
        char c;
+       int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);  /* do CTLESC */
+       int firsteq = 1;
 
+       if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
+               p = exptilde(p, flag);
        for (;;) {
                switch (c = *p++) {
                case '\0':
-               case CTLENDVAR:
+               case CTLENDVAR: /* ??? */
                        goto breakloop;
+               case CTLQUOTEMARK:
+                       /* "$@" syntax adherence hack */
+                       if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
+                               break;
+                       if ((flag & EXP_FULL) != 0)
+                               STPUTC(c, expdest);
+                       break;
                case CTLESC:
-                       if (full)
+                       if (quotes)
                                STPUTC(c, expdest);
                        c = *p++;
                        STPUTC(c, expdest);
                        break;
                case CTLVAR:
-                       p = evalvar(p, full);
+                       p = evalvar(p, flag);
                        break;
                case CTLBACKQ:
                case CTLBACKQ|CTLQUOTE:
-                       expbackq(argbackq->n, c & CTLQUOTE, full);
+                       expbackq(argbackq->n, c & CTLQUOTE, flag);
                        argbackq = argbackq->next;
                        break;
+               case CTLENDARI:
+                       expari(flag);
+                       break;
+               case ':':
+               case '=':
+                       /*
+                        * sort of a hack - expand tildes in variable
+                        * assignments (after the first '=' and after ':'s).
+                        */
+                       STPUTC(c, expdest);
+                       if (flag & EXP_VARTILDE && *p == '~') {
+                               if (c == '=') {
+                                       if (firsteq)
+                                               firsteq = 0;
+                                       else
+                                               break;
+                               }
+                               p = exptilde(p, flag);
+                       }
+                       break;
                default:
                        STPUTC(c, expdest);
                }
@@ -240,15 +263,159 @@ argstr(p, full)
 breakloop:;
 }
 
+STATIC char *
+exptilde(char *p, int flag)
+{
+       char c, *startp = p;
+       struct passwd *pw;
+       char *home;
+       int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
+
+       while ((c = *p) != '\0') {
+               switch(c) {
+               case CTLESC:
+                       return (startp);
+               case CTLQUOTEMARK:
+                       return (startp);
+               case ':':
+                       if (flag & EXP_VARTILDE)
+                               goto done;
+                       break;
+               case '/':
+                       goto done;
+               }
+               p++;
+       }
+done:
+       *p = '\0';
+       if (*(startp+1) == '\0') {
+               if ((home = lookupvar("HOME")) == NULL)
+                       goto lose;
+       } else {
+               if ((pw = getpwnam(startp+1)) == NULL)
+                       goto lose;
+               home = pw->pw_dir;
+       }
+       if (*home == '\0')
+               goto lose;
+       *p = c;
+       while ((c = *home++) != '\0') {
+               if (quotes && SQSYNTAX[(int)c] == CCTL)
+                       STPUTC(CTLESC, expdest);
+               STPUTC(c, expdest);
+       }
+       return (p);
+lose:
+       *p = c;
+       return (startp);
+}
+
+
+STATIC void 
+removerecordregions(int endoff)
+{
+       if (ifslastp == NULL)
+               return;
+
+       if (ifsfirst.endoff > endoff) {
+               while (ifsfirst.next != NULL) {
+                       struct ifsregion *ifsp;
+                       INTOFF;
+                       ifsp = ifsfirst.next->next;
+                       ckfree(ifsfirst.next);
+                       ifsfirst.next = ifsp;
+                       INTON;
+               }
+               if (ifsfirst.begoff > endoff)
+                       ifslastp = NULL;
+               else {
+                       ifslastp = &ifsfirst;
+                       ifsfirst.endoff = endoff;
+               }
+               return;
+       }
+       
+       ifslastp = &ifsfirst;
+       while (ifslastp->next && ifslastp->next->begoff < endoff)
+               ifslastp=ifslastp->next;
+       while (ifslastp->next != NULL) {
+               struct ifsregion *ifsp;
+               INTOFF;
+               ifsp = ifslastp->next->next;
+               ckfree(ifslastp->next);
+               ifslastp->next = ifsp;
+               INTON;
+       }
+       if (ifslastp->endoff > endoff)
+               ifslastp->endoff = endoff;
+}
+
+/*
+ * Expand arithmetic expression.  Backup to start of expression,
+ * evaluate, place result in (backed up) result, adjust string position.
+ */
+STATIC void
+expari(int flag)
+{
+       char *p, *start;
+       int result;
+       int begoff;
+       int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
+       int quoted;
+
+
+       /*
+        * This routine is slightly over-complicated for
+        * efficiency.  First we make sure there is
+        * enough space for the result, which may be bigger
+        * than the expression if we add exponentiation.  Next we
+        * scan backwards looking for the start of arithmetic.  If the
+        * next previous character is a CTLESC character, then we
+        * have to rescan starting from the beginning since CTLESC
+        * characters have to be processed left to right.
+        */
+#if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10
+#error "integers with more than 10 digits are not supported"
+#endif
+       CHECKSTRSPACE(12 - 2, expdest);
+       USTPUTC('\0', expdest);
+       start = stackblock();
+       p = expdest - 2;
+       while (p >= start && *p != CTLARI)
+               --p;
+       if (p < start || *p != CTLARI)
+               error("missing CTLARI (shouldn't happen)");
+       if (p > start && *(p - 1) == CTLESC)
+               for (p = start; *p != CTLARI; p++)
+                       if (*p == CTLESC)
+                               p++;
+
+       if (p[1] == '"')
+               quoted=1;
+       else
+               quoted=0;
+       begoff = p - start;
+       removerecordregions(begoff);
+       if (quotes)
+               rmescapes(p+2);
+       result = arith(p+2);
+       fmtstr(p, 12, "%d", result);
+       while (*p++)
+               ;
+       if (quoted == 0)
+               recordregion(begoff, p - 1 - start, 0);
+       result = expdest - p + 1;
+       STADJUST(-result, expdest);
+}
+
 
 /*
  * Expand stuff in backwards quotes.
  */
 
 STATIC void
-expbackq(cmd, quoted, full)
-       union node *cmd;
-       {
+expbackq(union node *cmd, int quoted, int flag)
+{
        struct backcmd in;
        int i;
        char buf[128];
@@ -260,12 +427,14 @@ expbackq(cmd, quoted, full)
        int startloc = dest - stackblock();
        char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
        int saveherefd;
+       int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
+       int nnl;
 
        INTOFF;
        saveifs = ifsfirst;
        savelastp = ifslastp;
        saveargbackq = argbackq;
-       saveherefd = herefd;      
+       saveherefd = herefd;
        herefd = -1;
        p = grabstackstr(dest);
        evalbackcmd(cmd, &in);
@@ -277,6 +446,8 @@ expbackq(cmd, quoted, full)
 
        p = in.buf;
        lastc = '\0';
+       nnl = 0;
+       /* Don't copy trailing newlines */
        for (;;) {
                if (--in.nleft < 0) {
                        if (in.fd < 0)
@@ -290,20 +461,26 @@ expbackq(cmd, quoted, full)
                }
                lastc = *p++;
                if (lastc != '\0') {
-                       if (full && syntax[lastc] == CCTL)
+                       if (quotes && syntax[(int)lastc] == CCTL)
                                STPUTC(CTLESC, dest);
-                       STPUTC(lastc, dest);
+                       if (lastc == '\n') {
+                               nnl++;
+                       } else {
+                               while (nnl > 0) {
+                                       nnl--;
+                                       STPUTC('\n', dest);
+                               }
+                               STPUTC(lastc, dest);
+                       }
                }
        }
-       if (lastc == '\n') {
-               STUNPUTC(dest);
-       }
+
        if (in.fd >= 0)
                close(in.fd);
        if (in.buf)
                ckfree(in.buf);
        if (in.jp)
-               exitstatus = waitforjob(in.jp);
+               exitstatus = waitforjob(in.jp, (int *)NULL);
        if (quoted == 0)
                recordregion(startloc, dest - stackblock(), 0);
        TRACE(("evalbackq: size=%d: \"%.*s\"\n",
@@ -316,26 +493,150 @@ expbackq(cmd, quoted, full)
 
 
 
+STATIC int
+subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
+  int varflags)
+{
+       char *startp;
+       char *loc = NULL;
+       char *q;
+       int c = 0;
+       int saveherefd = herefd;
+       struct nodelist *saveargbackq = argbackq;
+       int amount;
+
+       herefd = -1;
+       argstr(p, 0);
+       STACKSTRNUL(expdest);
+       herefd = saveherefd;
+       argbackq = saveargbackq;
+       startp = stackblock() + startloc;
+       if (str == NULL)
+           str = stackblock() + strloc;
+
+       switch (subtype) {
+       case VSASSIGN:
+               setvar(str, startp, 0);
+               amount = startp - expdest;
+               STADJUST(amount, expdest);
+               varflags &= ~VSNUL;
+               if (c != 0)
+                       *loc = c;
+               return 1;
+
+       case VSQUESTION:
+               if (*p != CTLENDVAR) {
+                       outfmt(&errout, "%s\n", startp);
+                       error((char *)NULL);
+               }
+               error("%.*s: parameter %snot set", (int)(p - str - 1),
+                     str, (varflags & VSNUL) ? "null or "
+                                             : nullstr);
+               return 0;
+
+       case VSTRIMLEFT:
+               for (loc = startp; loc < str; loc++) {
+                       c = *loc;
+                       *loc = '\0';
+                       if (patmatch(str, startp, varflags & VSQUOTE)) {
+                               *loc = c;
+                               goto recordleft;
+                       }
+                       *loc = c;
+                       if ((varflags & VSQUOTE) && *loc == CTLESC)
+                               loc++;
+               }
+               return 0;
+
+       case VSTRIMLEFTMAX:
+               for (loc = str - 1; loc >= startp;) {
+                       c = *loc;
+                       *loc = '\0';
+                       if (patmatch(str, startp, varflags & VSQUOTE)) {
+                               *loc = c;
+                               goto recordleft;
+                       }
+                       *loc = c;
+                       loc--;
+                       if ((varflags & VSQUOTE) && loc > startp &&
+                           *(loc - 1) == CTLESC) {
+                               for (q = startp; q < loc; q++)
+                                       if (*q == CTLESC)
+                                               q++;
+                               if (q > loc)
+                                       loc--;
+                       }
+               }
+               return 0;
+
+       case VSTRIMRIGHT:
+               for (loc = str - 1; loc >= startp;) {
+                       if (patmatch(str, loc, varflags & VSQUOTE)) {
+                               amount = loc - expdest;
+                               STADJUST(amount, expdest);
+                               return 1;
+                       }
+                       loc--;
+                       if ((varflags & VSQUOTE) && loc > startp &&
+                           *(loc - 1) == CTLESC) { 
+                               for (q = startp; q < loc; q++)
+                                       if (*q == CTLESC)
+                                               q++;
+                               if (q > loc)
+                                       loc--;
+                       }
+               }
+               return 0;
+
+       case VSTRIMRIGHTMAX:
+               for (loc = startp; loc < str - 1; loc++) {
+                       if (patmatch(str, loc, varflags & VSQUOTE)) {
+                               amount = loc - expdest;
+                               STADJUST(amount, expdest);
+                               return 1;
+                       }
+                       if ((varflags & VSQUOTE) && *loc == CTLESC)
+                               loc++;
+               }
+               return 0;
+
+
+       default:
+               abort();
+       }
+
+recordleft:
+       amount = ((str - 1) - (loc - startp)) - expdest;
+       STADJUST(amount, expdest);
+       while (loc != str - 1)
+               *startp++ = *loc++;
+       return 1;
+}
+
+
 /*
  * Expand a variable, and return a pointer to the next character in the
  * input string.
  */
 
 STATIC char *
-evalvar(p, full)
-       char *p;
-       {
+evalvar(char *p, int flag)
+{
        int subtype;
-       int flags;
+       int varflags;
        char *var;
        char *val;
+       int patloc;
        int c;
        int set;
        int special;
        int startloc;
+       int varlen;
+       int easy;
+       int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
 
-       flags = *p++;
-       subtype = flags & VSTYPE;
+       varflags = *p++;
+       subtype = varflags & VSTYPE;
        var = p;
        special = 0;
        if (! is_name(*p))
@@ -343,72 +644,139 @@ evalvar(p, full)
        p = strchr(p, '=') + 1;
 again: /* jump here after setting a variable with ${var=text} */
        if (special) {
-               set = varisset(*var);
+               set = varisset(var, varflags & VSNUL);
                val = NULL;
        } else {
-               val = lookupvar(var);
-               if (val == NULL || (flags & VSNUL) && val[0] == '\0') {
+               val = bltinlookup(var, 1);
+               if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
                        val = NULL;
                        set = 0;
                } else
                        set = 1;
        }
+       varlen = 0;
        startloc = expdest - stackblock();
+       if (!set && uflag) {
+               switch (subtype) {
+               case VSNORMAL:
+               case VSTRIMLEFT:
+               case VSTRIMLEFTMAX:
+               case VSTRIMRIGHT:
+               case VSTRIMRIGHTMAX:
+               case VSLENGTH:
+                       error("%.*s: parameter not set", (int)(p - var - 1),
+                           var);
+               }
+       }
        if (set && subtype != VSPLUS) {
                /* insert the value of the variable */
                if (special) {
-                       varvalue(*var, flags & VSQUOTE, full);
+                       varvalue(var, varflags & VSQUOTE, flag & EXP_FULL);
+                       if (subtype == VSLENGTH) {
+                               varlen = expdest - stackblock() - startloc;
+                               STADJUST(-varlen, expdest);
+                       }
                } else {
-                       char const *syntax = (flags & VSQUOTE)? DQSYNTAX : BASESYNTAX;
+                       char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
+                                                                 : BASESYNTAX;
+
+                       if (subtype == VSLENGTH) {
+                               for (;*val; val++)
+                                       varlen++;
+                       }
+                       else {
+                               while (*val) {
+                                       if (quotes &&
+                                           syntax[(int)*val] == CCTL)
+                                               STPUTC(CTLESC, expdest);
+                                       STPUTC(*val++, expdest);
+                               }
 
-                       while (*val) {
-                               if (full && syntax[*val] == CCTL)
-                                       STPUTC(CTLESC, expdest);
-                               STPUTC(*val++, expdest);
                        }
                }
        }
+
        if (subtype == VSPLUS)
                set = ! set;
-       if (((flags & VSQUOTE) == 0 || (*var == '@' && shellparam.nparam != 1))
-        && (set || subtype == VSNORMAL))
-               recordregion(startloc, expdest - stackblock(), flags & VSQUOTE);
-       if (! set && subtype != VSNORMAL) {
-               if (subtype == VSPLUS || subtype == VSMINUS) {
-                       argstr(p, full);
-               } else {
-                       char *startp;
-                       int saveherefd = herefd;
-                       herefd = -1;
-                       argstr(p, 0);
-                       STACKSTRNUL(expdest);
-                       herefd = saveherefd;
-                       startp = stackblock() + startloc;
-                       if (subtype == VSASSIGN) {
-                               setvar(var, startp, 0);
-                               STADJUST(startp - expdest, expdest);
-                               flags &=~ VSNUL;
+
+       easy = ((varflags & VSQUOTE) == 0 ||
+               (*var == '@' && shellparam.nparam != 1));
+
+
+       switch (subtype) {
+       case VSLENGTH:
+               expdest = cvtnum(varlen, expdest);
+               goto record;
+
+       case VSNORMAL:
+               if (!easy)
+                       break;
+record:
+               recordregion(startloc, expdest - stackblock(),
+                            varflags & VSQUOTE);
+               break;
+
+       case VSPLUS:
+       case VSMINUS:
+               if (!set) {
+                       argstr(p, flag);
+                       break;
+               }
+               if (easy)
+                       goto record;
+               break;
+
+       case VSTRIMLEFT:
+       case VSTRIMLEFTMAX:
+       case VSTRIMRIGHT:
+       case VSTRIMRIGHTMAX:
+               if (!set)
+                       break;
+               /*
+                * Terminate the string and start recording the pattern
+                * right after it
+                */
+               STPUTC('\0', expdest);
+               patloc = expdest - stackblock();
+               if (subevalvar(p, NULL, patloc, subtype,
+                              startloc, varflags) == 0) {
+                       int amount = (expdest - stackblock() - patloc) + 1;
+                       STADJUST(-amount, expdest);
+               }
+               /* Remove any recorded regions beyond start of variable */
+               removerecordregions(startloc);
+               goto record;
+
+       case VSASSIGN:
+       case VSQUESTION:
+               if (!set) {
+                       if (subevalvar(p, var, 0, subtype, startloc, varflags)) {
+                               varflags &= ~VSNUL;
+                               /* 
+                                * Remove any recorded regions beyond 
+                                * start of variable 
+                                */
+                               removerecordregions(startloc);
                                goto again;
                        }
-                       /* subtype == VSQUESTION */
-                       if (*p != CTLENDVAR) {
-                               outfmt(&errout, "%s\n", startp);
-                               error((char *)NULL);
-                       }
-                       error("%.*s: parameter %snot set", p - var - 1,
-                               var, (flags & VSNUL)? "null or " : nullstr);
+                       break;
                }
+               if (easy)
+                       goto record;
+               break;
+
+       default:
+               abort();
        }
+
        if (subtype != VSNORMAL) {      /* skip to end of alternative */
                int nesting = 1;
                for (;;) {
                        if ((c = *p++) == CTLESC)
                                p++;
                        else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
-                               if (set) {
-                                       if (argbackq != NULL)
-                                               argbackq = argbackq->next;
-                               }
+                               if (set)
+                                       argbackq = argbackq->next;
                        } else if (c == CTLVAR) {
                                if ((*p++ & VSTYPE) != VSNORMAL)
                                        nesting++;
@@ -428,23 +796,37 @@ again: /* jump here after setting a variable with ${var=text} */
  */
 
 STATIC int
-varisset(name)
-       char name;
-       {
-       char **ap;
+varisset(char *name, int nulok)
+{
 
-       if (name == '!') {
-               if (backgndpid == -1)
-                       return 0;
-       } else if (name == '@' || name == '*') {
+       if (*name == '!')
+               return backgndpid != -1;
+       else if (*name == '@' || *name == '*') {
                if (*shellparam.p == NULL)
                        return 0;
-       } else if ((unsigned)(name -= '1') <= '9' - '1') {
-               ap = shellparam.p;
-               do {
-                       if (*ap++ == NULL)
-                               return 0;
-               } while (--name >= 0);
+
+               if (nulok) {
+                       char **av;
+
+                       for (av = shellparam.p; *av; av++)
+                               if (**av != '\0')
+                                       return 1;
+                       return 0;
+               }
+       } else if (is_digit(*name)) {
+               char *ap;
+               int num = atoi(name);
+
+               if (num > shellparam.nparam)
+                       return 0;
+
+               if (num == 0)
+                       ap = arg0;
+               else
+                       ap = shellparam.p[num - 1];
+
+               if (nulok && (ap == NULL || *ap == '\0'))
+                       return 0;
        }
        return 1;
 }
@@ -456,11 +838,9 @@ varisset(name)
  */
 
 STATIC void
-varvalue(name, quoted, allow_split)
-       char name;
-       {
+varvalue(char *name, int quoted, int allow_split)
+{
        int num;
-       char temp[32];
        char *p;
        int i;
        extern int oexitstatus;
@@ -468,7 +848,22 @@ varvalue(name, quoted, allow_split)
        char **ap;
        char const *syntax;
 
-       switch (name) {
+#define STRTODEST(p) \
+       do {\
+       if (allow_split) { \
+               syntax = quoted? DQSYNTAX : BASESYNTAX; \
+               while (*p) { \
+                       if (syntax[(int)*p] == CCTL) \
+                               STPUTC(CTLESC, expdest); \
+                       STPUTC(*p++, expdest); \
+               } \
+       } else \
+               while (*p) \
+                       STPUTC(*p++, expdest); \
+       } while (0)
+
+
+       switch (*name) {
        case '$':
                num = rootpid;
                goto numvar;
@@ -481,59 +876,46 @@ varvalue(name, quoted, allow_split)
        case '!':
                num = backgndpid;
 numvar:
-               p = temp + 31;
-               temp[31] = '\0';
-               do {
-                       *--p = num % 10 + '0';
-               } while ((num /= 10) != 0);
-               while (*p)
-                       STPUTC(*p++, expdest);
+               expdest = cvtnum(num, expdest);
                break;
        case '-':
-               for (i = 0 ; optchar[i] ; i++) {
-                       if (optval[i])
-                               STPUTC(optchar[i], expdest);
+               for (i = 0 ; i < NOPTS ; i++) {
+                       if (optlist[i].val)
+                               STPUTC(optlist[i].letter, expdest);
                }
                break;
        case '@':
-               if (allow_split) {
-                       sep = '\0';
-                       goto allargs;
+               if (allow_split && quoted) {
+                       for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
+                               STRTODEST(p);
+                               if (*ap)
+                                       STPUTC('\0', expdest);
+                       }
+                       break;
                }
-               /* fall through */                      
+               /* FALLTHROUGH */
        case '*':
-               sep = ' ';
-allargs:
-               /* Only emit CTLESC if we will do further processing,
-                  i.e. if allow_split is set.  */
-               syntax = quoted && allow_split ? DQSYNTAX : BASESYNTAX;
+               if (ifsset() != 0)
+                       sep = ifsval()[0];
+               else
+                       sep = ' ';
                for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
-                       /* should insert CTLESC characters */
-                       while (*p) {
-                               if (syntax[*p] == CCTL)
-                                       STPUTC(CTLESC, expdest);
-                               STPUTC(*p++, expdest);
-                       }
-                       if (*ap)
+                       STRTODEST(p);
+                       if (*ap && sep)
                                STPUTC(sep, expdest);
                }
                break;
        case '0':
                p = arg0;
-string:
-               /* Only emit CTLESC if we will do further processing,
-                  i.e. if allow_split is set.  */
-               syntax = quoted && allow_split ? DQSYNTAX : BASESYNTAX;
-               while (*p) {
-                       if (syntax[*p] == CCTL)
-                               STPUTC(CTLESC, expdest);
-                       STPUTC(*p++, expdest);
-               }
+               STRTODEST(p);
                break;
        default:
-               if ((unsigned)(name -= '1') <= '9' - '1') {
-                       p = shellparam.p[name];
-                       goto string;
+               if (is_digit(*name)) {
+                       num = atoi(name);
+                       if (num > 0 && num <= shellparam.nparam) {
+                               p = shellparam.p[num - 1];
+                               STRTODEST(p);
+                       }
                }
                break;
        }
@@ -547,8 +929,9 @@ string:
  */
 
 STATIC void
-recordregion(start, end, nulonly) {
-       register struct ifsregion *ifsp;
+recordregion(int start, int end, int nulonly)
+{
+       struct ifsregion *ifsp;
 
        if (ifslastp == NULL) {
                ifsp = &ifsfirst;
@@ -570,55 +953,79 @@ recordregion(start, end, nulonly) {
  * strings to the argument list.  The regions of the string to be
  * searched for IFS characters have been stored by recordregion.
  */
-
 STATIC void
-ifsbreakup(string, arglist)
-       char *string;
-       struct arglist *arglist;
-       {
+ifsbreakup(char *string, struct arglist *arglist)
+{
        struct ifsregion *ifsp;
        struct strlist *sp;
        char *start;
-       register char *p;
+       char *p;
        char *q;
        char *ifs;
+       int ifsspc;
+       int nulonly;
+
 
        start = string;
+       ifsspc = 0;
+       nulonly = 0;
        if (ifslastp != NULL) {
                ifsp = &ifsfirst;
                do {
                        p = string + ifsp->begoff;
-                       ifs = ifsp->nulonly? nullstr : ifsval();
+                       nulonly = ifsp->nulonly;
+                       ifs = nulonly ? nullstr : 
+                               ( ifsset() ? ifsval() : " \t\n" );
+                       ifsspc = 0;
                        while (p < string + ifsp->endoff) {
                                q = p;
                                if (*p == CTLESC)
                                        p++;
-                               if (strchr(ifs, *p++)) {
-                                       if (q > start || *ifs != ' ') {
-                                               *q = '\0';
-                                               sp = (struct strlist *)stalloc(sizeof *sp);
-                                               sp->text = start;
-                                               *arglist->lastp = sp;
-                                               arglist->lastp = &sp->next;
+                               if (strchr(ifs, *p)) {
+                                       if (!nulonly)
+                                               ifsspc = (strchr(" \t\n", *p) != NULL);
+                                       /* Ignore IFS whitespace at start */
+                                       if (q == start && ifsspc) {
+                                               p++;
+                                               start = p;
+                                               continue;
                                        }
-                                       if (*ifs == ' ') {
+                                       *q = '\0';
+                                       sp = (struct strlist *)stalloc(sizeof *sp);
+                                       sp->text = start;
+                                       *arglist->lastp = sp;
+                                       arglist->lastp = &sp->next;
+                                       p++;
+                                       if (!nulonly) {
                                                for (;;) {
-                                                       if (p >= string + ifsp->endoff)
+                                                       if (p >= string + ifsp->endoff) {
                                                                break;
+                                                       }
                                                        q = p;
                                                        if (*p == CTLESC)
                                                                p++;
-                                                       if (strchr(ifs, *p++) == NULL) {
+                                                       if (strchr(ifs, *p) == NULL ) {
                                                                p = q;
                                                                break;
-                                                       }
+                                                       } else if (strchr(" \t\n",*p) == NULL) {
+                                                               if (ifsspc) {
+                                                                       p++;
+                                                                       ifsspc = 0;
+                                                               } else {
+                                                                       p = q;
+                                                                       break;
+                                                               }
+                                                       } else
+                                                               p++;
                                                }
                                        }
                                        start = p;
-                               }
+                               } else
+                                       p++;
                        }
                } while ((ifsp = ifsp->next) != NULL);
-               if (*start || (*ifs != ' ' && start > string)) {
+               if (*start || (!ifsspc && start > string && 
+                       (nulonly || 1))) {
                        sp = (struct strlist *)stalloc(sizeof *sp);
                        sp->text = start;
                        *arglist->lastp = sp;
@@ -639,30 +1046,22 @@ ifsbreakup(string, arglist)
  * should be escapes.  The results are stored in the list exparg.
  */
 
-char *expdir;
+STATIC char *expdir;
 
 
 STATIC void
-expandmeta(str)
-       struct strlist *str;
-       {
+expandmeta(struct strlist *str, int flag __unused)
+{
        char *p;
        struct strlist **savelastp;
        struct strlist *sp;
        char c;
+       /* TODO - EXP_REDIR */
 
        while (str) {
                if (fflag)
                        goto nometa;
                p = str->text;
-#if UDIR
-               if (p[0] == '/' && p[1] == 'u' && p[2] == '/')
-                       str->text = p = expudir(p);
-#endif
-#if TILDE
-               if (p[0] == '~')
-                       str->text = p = expudir(p);
-#endif
                for (;;) {                      /* fast check for meta chars */
                        if ((c = *p++) == '\0')
                                goto nometa;
@@ -671,22 +1070,23 @@ expandmeta(str)
                }
                savelastp = exparg.lastp;
                INTOFF;
-               if (expdir == NULL)
-               {
+               if (expdir == NULL) {
                        int i = strlen(str->text);
                        expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
                }
+
                expmeta(expdir, str->text);
                ckfree(expdir);
                expdir = NULL;
                INTON;
                if (exparg.lastp == savelastp) {
-                       if (! zflag) {
+                       /*
+                        * no matches
+                        */
 nometa:
-                               *exparg.lastp = str;
-                               rmescapes(str->text);
-                               exparg.lastp = &str->next;
-                       }
+                       *exparg.lastp = str;
+                       rmescapes(str->text);
+                       exparg.lastp = &str->next;
                } else {
                        *exparg.lastp = NULL;
                        *savelastp = sp = expsort(*savelastp);
@@ -699,114 +1099,14 @@ nometa:
 }
 
 
-#if UDIR || TILDE
-/*
- * UDIR: Expand /u/username into the home directory for the specified user.
- * TILDE: Expand ~username into the home directory for the specified user.
- * We hope not to use the getpw stuff here, because then we would have to load
- * in stdio and who knows what else.  With networked password files there is
- * no choice alas.
- */
-
-#define MAXLOGNAME 32
-#define MAXPWLINE 128
-
-char *pfgets();
-
-
-STATIC char *
-expudir(path)
-       char *path;
-       {
-       register char *p, *q, *r;
-       char name[MAXLOGNAME];
-       char line[MAXPWLINE];
-       int i;
-#if USEGETPW
-       struct passwd *pw;
-#endif
-
-       r = path;                               /* result on failure */
-       p = r + (*r == '~' ? 1 : 3);    /* the 1 skips "~", 3 skips "/u/" */
-       q = name;
-       while (*p && *p != '/') {
-               if (q >= name + MAXLOGNAME - 1)
-                       return r;               /* fail, name too long */
-               *q++ = *p++;
-       }
-       *q = '\0';
-
-#if TILDE
-       if (*name == 0 && *r == '~') {
-               /* null name, use $HOME */
-               if ((q = lookupvar("HOME")) == NULL)
-                       return r;               /* fail, home not set */
-               i = strlen(q);
-               r = stalloc(i + strlen(p) + 1);
-               scopy(q, r);
-               scopy(p, r + i);
-               TRACE(("expudir converts %s to %s\n", path, r));
-               didudir = 1;
-               path = r;
-               return r;
-       }
-#endif
-#if !USEGETPW  /* can do without the bloat */
-       setinputfile("/etc/passwd", 1);
-       q = line + strlen(name);
-       while (pfgets(line, MAXPWLINE) != NULL) {
-               if (line[0] == name[0] && prefix(name, line) && *q == ':') {
-                       /* skip to start of home directory */
-                       i = 4;
-                       do {
-                               while (*++q && *q != ':');
-                       } while (--i > 0);
-                       if (*q == '\0')
-                               break;          /* fail, corrupted /etc/passwd */
-                       q++;
-                       for (r = q ; *r && *r != '\n' && *r != ':' ; r++);
-                       *r = '\0';              /* nul terminate home directory */
-                       i = r - q;              /* i = strlen(q) */
-                       r = stalloc(i + strlen(p) + 1);
-                       scopy(q, r);
-                       scopy(p, r + i);
-                       TRACE(("expudir converts %s to %s\n", path, r));
-                       didudir = 1;
-                       path = r;               /* succeed */
-                       break;
-               }
-       }
-       popfile();
-#else
-       if ((pw = getpwnam(name)) != NULL) {
-               /* user exists */
-               q = pw->pw_dir;
-               i = strlen(q);
-               r = stalloc(i + strlen(p) + 1);
-               scopy(q, r);
-               scopy(p, r + i);
-               TRACE(("expudir converts %s to %s\n", path, r));
-               didudir = 1;
-               path = r;
-       }
-       endpwent();
-#endif /* USEGETPW */
-
-       return r;
-}
-#endif
-
-
 /*
  * Do metacharacter (i.e. *, ?, [...]) expansion.
  */
 
 STATIC void
-expmeta(enddir, name)
-       char *enddir;
-       char *name;
-       {
-       register char *p;
+expmeta(char *enddir, char *name)
+{
+       char *p;
        char *q;
        char *start;
        char *endname;
@@ -824,9 +1124,11 @@ expmeta(enddir, name)
                        metaflag = 1;
                else if (*p == '[') {
                        q = p + 1;
-                       if (*q == '!')
+                       if (*q == '!' || *q == '^')
                                q++;
                        for (;;) {
+                               while (*q == CTLQUOTEMARK)
+                                       q++;
                                if (*q == CTLESC)
                                        q++;
                                if (*q == '/' || *q == '\0')
@@ -840,6 +1142,8 @@ expmeta(enddir, name)
                        metaflag = 1;
                } else if (*p == '\0')
                        break;
+               else if (*p == CTLQUOTEMARK)
+                       continue;
                else if (*p == CTLESC)
                        p++;
                if (*p == '/') {
@@ -852,6 +1156,8 @@ expmeta(enddir, name)
                if (enddir != expdir)
                        metaflag++;
                for (p = name ; ; p++) {
+                       if (*p == CTLQUOTEMARK)
+                               continue;
                        if (*p == CTLESC)
                                p++;
                        *enddir++ = *p;
@@ -866,6 +1172,8 @@ expmeta(enddir, name)
        if (start != name) {
                p = name;
                while (p < start) {
+                       while (*p == CTLQUOTEMARK)
+                               p++;
                        if (*p == CTLESC)
                                p++;
                        *enddir++ = *p++;
@@ -890,18 +1198,25 @@ expmeta(enddir, name)
                *endname++ = '\0';
        }
        matchdot = 0;
-       if (start[0] == '.' || start[0] == CTLESC && start[1] == '.')
+       p = start;
+       while (*p == CTLQUOTEMARK)
+               p++;
+       if (*p == CTLESC)
+               p++;
+       if (*p == '.')
                matchdot++;
        while (! int_pending() && (dp = readdir(dirp)) != NULL) {
                if (dp->d_name[0] == '.' && ! matchdot)
                        continue;
-               if (patmatch(start, dp->d_name)) {
+               if (patmatch(start, dp->d_name, 0)) {
                        if (atend) {
                                scopy(dp->d_name, enddir);
                                addfname(expdir);
                        } else {
                                char *q;
-                               for (p = enddir, q = dp->d_name ; *p++ = *q++ ;);
+                               for (p = enddir, q = dp->d_name;
+                                    (*p++ = *q++) != '\0';)
+                                       continue;
                                p[-1] = '/';
                                expmeta(p, endname);
                        }
@@ -918,9 +1233,8 @@ expmeta(enddir, name)
  */
 
 STATIC void
-addfname(name)
-       char *name;
-       {
+addfname(char *name)
+{
        char *p;
        struct strlist *sp;
 
@@ -940,9 +1254,8 @@ addfname(name)
  */
 
 STATIC struct strlist *
-expsort(str)
-       struct strlist *str;
-       {
+expsort(struct strlist *str)
+{
        int len;
        struct strlist *sp;
 
@@ -954,17 +1267,16 @@ expsort(str)
 
 
 STATIC struct strlist *
-msort(list, len)
-       struct strlist *list;
-       {
-       struct strlist *p, *q;
+msort(struct strlist *list, int len)
+{
+       struct strlist *p, *q = NULL;
        struct strlist **lpp;
        int half;
        int n;
 
        if (len <= 1)
                return list;
-       half = len >> 1;      
+       half = len >> 1;
        p = list;
        for (n = half ; --n >= 0 ; ) {
                q = p;
@@ -1001,24 +1313,22 @@ msort(list, len)
  */
 
 int
-patmatch(pattern, string)
-       char *pattern;
-       char *string;
-       {
+patmatch(char *pattern, char *string, int squoted)
+{
+#ifdef notdef
        if (pattern[0] == '!' && pattern[1] == '!')
                return 1 - pmatch(pattern + 2, string);
        else
-               return pmatch(pattern, string);
+#endif
+               return pmatch(pattern, string, squoted);
 }
 
 
 STATIC int
-pmatch(pattern, string)
-       char *pattern;
-       char *string;
-       {
-       register char *p, *q;
-       register char c;
+pmatch(char *pattern, char *string, int squoted)
+{
+       char *p, *q;
+       char c;
 
        p = pattern;
        q = string;
@@ -1027,25 +1337,41 @@ pmatch(pattern, string)
                case '\0':
                        goto breakloop;
                case CTLESC:
+                       if (squoted && *q == CTLESC)
+                               q++;
                        if (*q++ != *p++)
                                return 0;
                        break;
+               case CTLQUOTEMARK:
+                       continue;
                case '?':
+                       if (squoted && *q == CTLESC)
+                               q++;
                        if (*q++ == '\0')
                                return 0;
                        break;
                case '*':
                        c = *p;
-                       if (c != CTLESC && c != '?' && c != '*' && c != '[') {
+                       while (c == CTLQUOTEMARK || c == '*')
+                               c = *++p;
+                       if (c != CTLESC &&  c != CTLQUOTEMARK &&
+                           c != '?' && c != '*' && c != '[') {
                                while (*q != c) {
+                                       if (squoted && *q == CTLESC &&
+                                           q[1] == c)
+                                               break;
                                        if (*q == '\0')
                                                return 0;
+                                       if (squoted && *q == CTLESC)
+                                               q++;
                                        q++;
                                }
                        }
                        do {
-                               if (pmatch(p, q))
+                               if (pmatch(p, q, squoted))
                                        return 1;
+                               if (squoted && *q == CTLESC)
+                                       q++;
                        } while (*q++ != '\0');
                        return 0;
                case '[': {
@@ -1054,9 +1380,11 @@ pmatch(pattern, string)
                        char chr;
 
                        endp = p;
-                       if (*endp == '!')
+                       if (*endp == '!' || *endp == '^')
                                endp++;
                        for (;;) {
+                               while (*endp == CTLQUOTEMARK)
+                                       endp++;
                                if (*endp == '\0')
                                        goto dft;               /* no matching ] */
                                if (*endp == CTLESC)
@@ -1065,21 +1393,31 @@ pmatch(pattern, string)
                                        break;
                        }
                        invert = 0;
-                       if (*p == '!') {
+                       if (*p == '!' || *p == '^') {
                                invert++;
                                p++;
                        }
                        found = 0;
                        chr = *q++;
+                       if (squoted && chr == CTLESC)
+                               chr = *q++;
+                       if (chr == '\0')
+                               return 0;
                        c = *p++;
                        do {
+                               if (c == CTLQUOTEMARK)
+                                       continue;
                                if (c == CTLESC)
                                        c = *p++;
                                if (*p == '-' && p[1] != ']') {
                                        p++;
+                                       while (*p == CTLQUOTEMARK)
+                                               p++;
                                        if (*p == CTLESC)
                                                p++;
-                                       if (chr >= c && chr <= *p)
+                                       if (   collate_range_cmp(chr, c) >= 0
+                                           && collate_range_cmp(chr, *p) <= 0
+                                          )
                                                found = 1;
                                        p++;
                                } else {
@@ -1091,7 +1429,9 @@ pmatch(pattern, string)
                                return 0;
                        break;
                }
-dft:       default:
+dft:           default:
+                       if (squoted && *q == CTLESC)
+                               q++;
                        if (*q++ != c)
                                return 0;
                        break;
@@ -1110,18 +1450,21 @@ breakloop:
  */
 
 void
-rmescapes(str)
-       char *str;
-       {
-       register char *p, *q;
+rmescapes(char *str)
+{
+       char *p, *q;
 
        p = str;
-       while (*p != CTLESC) {
+       while (*p != CTLESC && *p != CTLQUOTEMARK) {
                if (*p++ == '\0')
                        return;
        }
        q = p;
        while (*p) {
+               if (*p == CTLQUOTEMARK) {
+                       p++;
+                       continue;
+               }
                if (*p == CTLESC)
                        p++;
                *q++ = *p++;
@@ -1136,10 +1479,8 @@ rmescapes(str)
  */
 
 int
-casematch(pattern, val)
-       union node *pattern;
-       char *val;
-       {
+casematch(union node *pattern, char *val)
+{
        struct stackmark smark;
        int result;
        char *p;
@@ -1148,12 +1489,60 @@ casematch(pattern, val)
        argbackq = pattern->narg.backquote;
        STARTSTACKSTR(expdest);
        ifslastp = NULL;
-       /* Preserve any CTLESC characters inserted previously, so that
-          we won't expand reg exps which are inside strings.  */
-       argstr(pattern->narg.text, 1);
+       argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
        STPUTC('\0', expdest);
        p = grabstackstr(expdest);
-       result = patmatch(p, val);
+       result = patmatch(p, val, 0);
        popstackmark(&smark);
        return result;
 }
+
+/*
+ * Our own itoa().
+ */
+
+STATIC char *
+cvtnum(int num, char *buf)
+{
+       char temp[32];
+       int neg = num < 0;
+       char *p = temp + 31;
+
+       temp[31] = '\0';
+
+       do {
+               *--p = num % 10 + '0';
+       } while ((num /= 10) != 0);
+
+       if (neg)
+               *--p = '-';
+
+       while (*p)
+               STPUTC(*p++, buf);
+       return buf;
+}
+
+/*
+ * Do most of the work for wordexp(3).
+ */
+
+int
+wordexpcmd(int argc, char **argv)
+{
+       size_t len;
+       int i;
+
+       out1fmt("%08x", argc - 1);
+       for (i = 1, len = 0; i < argc; i++)
+               len += strlen(argv[i]);
+       out1fmt("%08x", (int)len);
+       for (i = 1; i < argc; i++) {
+               out1str(argv[i]);
+               out1c('\0');
+       }
+        return (0);
+}
+
+/*
+ * $PchId: expand.c,v 1.6 2006/04/10 14:52:06 philip Exp $
+ */
index 65ecf8b09812d74d1d02e791cb02af7626640719..061d85f041828ab3a09438dddb1be9fc68eddceb 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
@@ -33,7 +29,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)expand.h    5.1 (Berkeley) 3/7/91
+ *     @(#)expand.h    8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/expand.h,v 1.12 2004/04/06 20:06:51 markm Exp $
  */
 
 struct strlist {
@@ -47,17 +44,24 @@ struct arglist {
        struct strlist **lastp;
 };
 
-#ifdef __STDC__
+/*
+ * 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 */
+
+
 union node;
-void expandarg(union node *, struct arglist *, int);
 void expandhere(union node *, int);
-int patmatch(char *, char *);
+void expandarg(union node *, struct arglist *, int);
+int patmatch(char *, char *, int);
 void rmescapes(char *);
 int casematch(union node *, char *);
-#else
-void expandarg();
-void expandhere();
-int patmatch();
-void rmescapes();
-int casematch();
-#endif
+int wordexpcmd(int, char **);
+
+/*
+ * $PchId: expand.h,v 1.4 2006/03/30 14:50:52 philip Exp $
+ */
index 0c6c4d3baa492690f0bb7945b9181dc00d0aab4b..0e701e5cb357b4e05c4a63394b1b94763e861b6b 100755 (executable)
@@ -1,5 +1,5 @@
-# Copyright (c) 1991 The Regents of the University of California.
-# All rights reserved.
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
 #
 # This code is derived from software contributed to Berkeley by
 # Kenneth Almquist.
 # 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.
@@ -32,7 +28,8 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-#      @(#)cmv 5.1 (Berkeley) 3/7/91
+#      @(#)cmv 8.2 (Berkeley) 5/4/95
+# $FreeBSD: src/bin/sh/funcs/cmv,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 # Conditional move--don't replace an existing file.
 
@@ -47,3 +44,6 @@ cmv() {
        fi
        /bin/mv "$1" "$2"
 }
+
+#
+# $PchId: cmv,v 1.2 2006/03/29 10:43:18 philip Exp $
index a31d2312354c08d046a571d76633a16653c7e30f..337c70945e32e05bc959ff74713bd6014f9ef7c8 100755 (executable)
@@ -1,5 +1,5 @@
-# Copyright (c) 1991 The Regents of the University of California.
-# All rights reserved.
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
 #
 # This code is derived from software contributed to Berkeley by
 # Kenneth Almquist.
 # 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.
@@ -32,7 +28,8 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-#      @(#)dirs        5.1 (Berkeley) 3/7/91
+#      @(#)dirs        8.2 (Berkeley) 5/4/95
+# $FreeBSD: src/bin/sh/funcs/dirs,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 # pushd, popd, and dirs --- written by Chris Bertin
 # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
@@ -71,3 +68,6 @@ dirs () {
        echo "`pwd` $DSTACK"
        return 0
 }
+
+#
+# $PchId: dirs,v 1.2 2006/03/29 10:43:18 philip Exp $
index 9e643183f4bc69e199bb5ad2bb967c52c28f2c64..3c858ca20b20132bb23ea3a266f981ae5ce52210 100755 (executable)
@@ -1,5 +1,5 @@
-# Copyright (c) 1991 The Regents of the University of California.
-# All rights reserved.
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
 #
 # This code is derived from software contributed to Berkeley by
 # Kenneth Almquist.
 # 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.
@@ -32,7 +28,8 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-#      @(#)kill        5.1 (Berkeley) 3/7/91
+#      @(#)kill        8.2 (Berkeley) 5/4/95
+# $FreeBSD: src/bin/sh/funcs/kill,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 # Convert job names to process ids and then run /bin/kill.
 
@@ -47,3 +44,6 @@ kill() {
        done
        /bin/kill $args
 }
+
+#
+# $PchId: kill,v 1.2 2006/03/29 10:43:18 philip Exp $
index 6e24b437cccc5c3f6a9cce32aa84eb97bdc11087..d4720ed1bbad67b0d1bcc5c57c1d43d9bd2fa961 100755 (executable)
@@ -1,5 +1,5 @@
-# Copyright (c) 1991 The Regents of the University of California.
-# All rights reserved.
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
 #
 # This code is derived from software contributed to Berkeley by
 # Kenneth Almquist.
 # 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.
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-#      @(#)login       5.1 (Berkeley) 3/7/91
+#      @(#)login       8.2 (Berkeley) 5/4/95
+# $FreeBSD: src/bin/sh/funcs/login,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 # replaces the login builtin in the BSD shell
 login () exec login "$@"
+
+#
+# $PchId: login,v 1.2 2006/03/29 10:43:18 philip Exp $
index 7980ff54d06e3e8b887dccbafd6b60e75833d10b..c2ab4fd18783b273268b07f76dbb4d2ac6236d4f 100755 (executable)
@@ -1,5 +1,5 @@
-# Copyright (c) 1991 The Regents of the University of California.
-# All rights reserved.
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
 #
 # This code is derived from software contributed to Berkeley by
 # Kenneth Almquist.
 # 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.
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-#      @(#)newgrp      5.1 (Berkeley) 3/7/91
+#      @(#)newgrp      8.2 (Berkeley) 5/4/95
+# $FreeBSD: src/bin/sh/funcs/newgrp,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 newgrp() exec newgrp "$@"
+
+#
+# $PchId: newgrp,v 1.2 2006/03/29 10:43:18 philip Exp $
index 4cecba9ee4c5b0a8e71ab96fbfc210b05374921f..a2654e573d73893d075c4fbd38f076f3bb84ef91 100755 (executable)
@@ -1,5 +1,5 @@
-# Copyright (c) 1991 The Regents of the University of California.
-# All rights reserved.
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
 #
 # This code is derived from software contributed to Berkeley by
 # Kenneth Almquist.
 # 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.
@@ -32,7 +28,8 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-#      @(#)popd        5.1 (Berkeley) 3/7/91
+#      @(#)popd        8.2 (Berkeley) 5/4/95
+# $FreeBSD: src/bin/sh/funcs/popd,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 # pushd, popd, and dirs --- written by Chris Bertin
 # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
@@ -71,3 +68,6 @@ dirs () {
        echo "`pwd` $DSTACK"
        return 0
 }
+
+#
+# $PchId: popd,v 1.2 2006/03/29 10:43:18 philip Exp $
index 4e8c48cf662b9d323de2e15811e0141c2802e12c..799bef4ee46d60a55760fe8a6122757f77bd3a4e 100755 (executable)
@@ -1,5 +1,5 @@
-# Copyright (c) 1991 The Regents of the University of California.
-# All rights reserved.
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
 #
 # This code is derived from software contributed to Berkeley by
 # Kenneth Almquist.
 # 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.
@@ -32,7 +28,8 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-#      @(#)pushd       5.1 (Berkeley) 3/7/91
+#      @(#)pushd       8.2 (Berkeley) 5/4/95
+# $FreeBSD: src/bin/sh/funcs/pushd,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 # pushd, popd, and dirs --- written by Chris Bertin
 # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
@@ -71,3 +68,6 @@ dirs () {
        echo "`pwd` $DSTACK"
        return 0
 }
+
+#
+# $PchId: pushd,v 1.2 2006/03/29 10:43:18 philip Exp $
index 6c4e5795dee25d67c72f5b77496257513c8c650d..3d354e1e49d128191221f49e9dbdb76d062199d3 100755 (executable)
@@ -1,5 +1,5 @@
-# Copyright (c) 1991 The Regents of the University of California.
-# All rights reserved.
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
 #
 # This code is derived from software contributed to Berkeley by
 # Kenneth Almquist.
 # 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.
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-#      @(#)suspend     5.1 (Berkeley) 3/7/91
+#      @(#)suspend     8.2 (Berkeley) 5/4/95
+# $FreeBSD: src/bin/sh/funcs/suspend,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 suspend() {
        local -
        set +j
        kill -TSTP 0
 }
+
+#
+# $PchId: suspend,v 1.2 2006/03/29 10:43:18 philip Exp $
diff --git a/commands/ash/histedit.c b/commands/ash/histedit.c
new file mode 100644 (file)
index 0000000..1e6ed1a
--- /dev/null
@@ -0,0 +1,533 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/histedit.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
+*/
+
+#include <limits.h>
+#ifndef NO_PATHS_H
+#include <paths.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+/*
+ * Editline and history functions (and glue).
+ */
+#include "shell.h"
+#include "parser.h"
+#include "var.h"
+#include "options.h"
+#include "main.h"
+#include "output.h"
+#include "mystring.h"
+#include "builtins.h"
+#if !defined(NO_HISTORY) && !defined(EDITLINE)
+#include "myhistedit.h"
+#include "complete.h"
+#include "error.h"
+#include "eval.h"
+#include "memalloc.h"
+
+#define MAXHISTLOOPS   4       /* max recursions through fc */
+#define DEFEDITOR      "ed"    /* default editor *should* be $EDITOR */
+
+History *hist; /* history cookie */
+EditLine *el;  /* editline cookie */
+int displayhist;
+static FILE *el_in, *el_out, *el_err;
+
+STATIC char *fc_replace(const char *, char *, char *);
+STATIC int not_fcnumber(char *);
+STATIC int str_to_event(char *, int);
+
+/*
+ * Set history and editing status.  Called whenever the status may
+ * have changed (figures out what to do).
+ */
+void
+histedit(void)
+{
+
+#define editing (Eflag || Vflag)
+
+       if (iflag) {
+               if (!hist) {
+                       /*
+                        * turn history on
+                        */
+                       INTOFF;
+                       hist = history_init();
+                       INTON;
+
+                       if (hist != NULL)
+                               sethistsize(histsizeval());
+                       else
+                               out2str("sh: can't initialize history\n");
+               }
+               if (editing && !el && isatty(0)) { /* && isatty(2) ??? */
+                       /*
+                        * turn editing on
+                        */
+                       INTOFF;
+                       if (el_in == NULL)
+                               el_in = fdopen(0, "r");
+                       if (el_err == NULL)
+                               el_err = fdopen(1, "w");
+                       if (el_out == NULL)
+                               el_out = fdopen(2, "w");
+                       if (el_in == NULL || el_err == NULL || el_out == NULL)
+                               goto bad;
+                       el = el_init(arg0, el_in, el_out, el_err);
+                       if (el != NULL) {
+                               if (hist)
+                                       el_set(el, EL_HIST, history, hist);
+                               el_set(el, EL_PROMPT, getprompt);
+                       } else {
+bad:
+                               out2str("sh: can't initialize editing\n");
+                       }
+                       INTON;
+               } else if (!editing && el) {
+                       INTOFF;
+                       el_end(el);
+                       el = NULL;
+                       INTON;
+               }
+               if (el) {
+                       if (Vflag)
+                               el_set(el, EL_EDITOR, "vi");
+                       else if (Eflag)
+                               el_set(el, EL_EDITOR, "emacs");
+                       el_set(el, EL_ADDFN, "ed-do-complete",
+                               "Complete Argument", complete);
+                       el_set(el, EL_ADDFN, "ed-list-complete",
+                               "List Argument Completions", complete_list);
+                       el_set(el, EL_ADDFN, "ed-maybe-complete",
+                               "Complete Argument Or List Completions",
+                               complete_or_list);
+                       el_set(el, EL_ADDFN, "ed-expand",
+                               "Expand Completions", complete_expand);
+                       el_set(el, EL_BIND, "^I", "ed-maybe-complete", NULL);
+                       el_set(el, EL_BIND, "-a", "=", "ed-list-complete",
+                               NULL);
+                       el_set(el, EL_BIND, "-a", "\\\\", "ed-do-complete",
+                               NULL);
+                       el_set(el, EL_BIND, "-a", "*", "ed-expand",
+                               NULL);
+                       el_source(el, NULL);
+               }
+       } else {
+               INTOFF;
+               if (el) {       /* no editing if not interactive */
+                       el_end(el);
+                       el = NULL;
+               }
+               if (hist) {
+                       history_end(hist);
+                       hist = NULL;
+               }
+               INTON;
+       }
+}
+
+
+void
+sethistsize(hs)
+       const char *hs;
+{
+       int histsize;
+       HistEvent he;
+
+       if (hist != NULL) {
+               if (hs == NULL || *hs == '\0' ||
+                  (histsize = atoi(hs)) < 0)
+                       histsize = 100;
+               history(hist, &he, H_EVENT, histsize);
+       }
+}
+
+int
+histcmd(int argc, char **argv)
+{
+       int ch;
+       char *editor = NULL;
+       HistEvent he;
+       int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
+       int i, retval;
+       char *firststr, *laststr;
+       int first, last, direction;
+       char *pat = NULL, *repl;
+       static int active = 0;
+       struct jmploc jmploc;
+       struct jmploc *volatile savehandler;
+       char editfile[PATH_MAX];
+       FILE *efp;
+       int oldhistnum;
+#ifdef __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &editor;
+       (void) &lflg;
+       (void) &nflg;
+       (void) &rflg;
+       (void) &sflg;
+       (void) &firststr;
+       (void) &laststr;
+       (void) &pat;
+       (void) &repl;
+       (void) &efp;
+       (void) &argc;
+       (void) &argv;
+#endif
+
+       if (hist == NULL)
+               error("history not active");
+
+       if (argc == 1)
+               error("missing history argument");
+
+       optreset = 1; optind = 1; /* initialize getopt */
+       opterr = 0;
+       while (not_fcnumber(argv[optind]) &&
+             (ch = getopt(argc, argv, ":e:lnrs")) != -1)
+               switch ((char)ch) {
+               case 'e':
+                       editor = optarg;
+                       break;
+               case 'l':
+                       lflg = 1;
+                       break;
+               case 'n':
+                       nflg = 1;
+                       break;
+               case 'r':
+                       rflg = 1;
+                       break;
+               case 's':
+                       sflg = 1;
+                       break;
+               case ':':
+                       error("option -%c expects argument", optopt);
+               case '?':
+               default:
+                       error("unknown option: -%c", optopt);
+               }
+       argc -= optind, argv += optind;
+
+       /*
+        * If executing...
+        */
+       if (lflg == 0 || editor || sflg) {
+               lflg = 0;       /* ignore */
+               editfile[0] = '\0';
+               /*
+                * Catch interrupts to reset active counter and
+                * cleanup temp files.
+                */
+               if (setjmp(jmploc.loc)) {
+                       active = 0;
+                       if (*editfile)
+                               unlink(editfile);
+                       handler = savehandler;
+                       longjmp(handler->loc, 1);
+               }
+               savehandler = handler;
+               handler = &jmploc;
+               if (++active > MAXHISTLOOPS) {
+                       active = 0;
+                       displayhist = 0;
+                       error("called recursively too many times");
+               }
+               /*
+                * Set editor.
+                */
+               if (sflg == 0) {
+                       if (editor == NULL &&
+                           (editor = bltinlookup("FCEDIT", 1)) == NULL &&
+                           (editor = bltinlookup("EDITOR", 1)) == NULL)
+                               editor = DEFEDITOR;
+                       if (editor[0] == '-' && editor[1] == '\0') {
+                               sflg = 1;       /* no edit */
+                               editor = NULL;
+                       }
+               }
+       }
+
+       /*
+        * If executing, parse [old=new] now
+        */
+       if (lflg == 0 && argc > 0 &&
+            ((repl = strchr(argv[0], '=')) != NULL)) {
+               pat = argv[0];
+               *repl++ = '\0';
+               argc--, argv++;
+       }
+       /*
+        * determine [first] and [last]
+        */
+       switch (argc) {
+       case 0:
+               firststr = lflg ? "-16" : "-1";
+               laststr = "-1";
+               break;
+       case 1:
+               firststr = argv[0];
+               laststr = lflg ? "-1" : argv[0];
+               break;
+       case 2:
+               firststr = argv[0];
+               laststr = argv[1];
+               break;
+       default:
+               error("too many args");
+       }
+       /*
+        * Turn into event numbers.
+        */
+       first = str_to_event(firststr, 0);
+       last = str_to_event(laststr, 1);
+
+       if (rflg) {
+               i = last;
+               last = first;
+               first = i;
+       }
+       /*
+        * XXX - this should not depend on the event numbers
+        * always increasing.  Add sequence numbers or offset
+        * to the history element in next (diskbased) release.
+        */
+       direction = first < last ? H_PREV : H_NEXT;
+
+       /*
+        * If editing, grab a temp file.
+        */
+       if (editor) {
+               int fd;
+               INTOFF;         /* easier */
+               sprintf(editfile, "%s/_shXXXXXX", _PATH_TMP);
+               if ((fd = mkstemp(editfile)) < 0)
+                       error("can't create temporary file %s", editfile);
+               if ((efp = fdopen(fd, "w")) == NULL) {
+                       close(fd);
+                       error("can't allocate stdio buffer for temp");
+               }
+       }
+
+       /*
+        * Loop through selected history events.  If listing or executing,
+        * do it now.  Otherwise, put into temp file and call the editor
+        * after.
+        *
+        * The history interface needs rethinking, as the following
+        * convolutions will demonstrate.
+        */
+       history(hist, &he, H_FIRST);
+       retval = history(hist, &he, H_NEXT_EVENT, first);
+       for (;retval != -1; retval = history(hist, &he, direction)) {
+               if (lflg) {
+                       if (!nflg)
+                               out1fmt("%5d ", he.num);
+                       out1str(he.str);
+               } else {
+                       char *s = pat ?
+                          fc_replace(he.str, pat, repl) : (char *)he.str;
+
+                       if (sflg) {
+                               if (displayhist) {
+                                       out2str(s);
+                               }
+                               evalstring(s);
+                               if (displayhist && hist) {
+                                       /*
+                                        *  XXX what about recursive and
+                                        *  relative histnums.
+                                        */
+                                       oldhistnum = he.num;
+                                       history(hist, &he, H_ENTER, s);
+                                       /*
+                                        * XXX H_ENTER moves the internal
+                                        * cursor, set it back to the current
+                                        * entry.
+                                        */
+                                       retval = history(hist, &he,
+                                           H_NEXT_EVENT, oldhistnum);
+                               }
+                       } else
+                               fputs(s, efp);
+               }
+               /*
+                * At end?  (if we were to loose last, we'd sure be
+                * messed up).
+                */
+               if (he.num == last)
+                       break;
+       }
+       if (editor) {
+               char *editcmd;
+
+               fclose(efp);
+               editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
+               sprintf(editcmd, "%s %s", editor, editfile);
+               evalstring(editcmd);    /* XXX - should use no JC command */
+               INTON;
+               readcmdfile(editfile);  /* XXX - should read back - quick tst */
+               unlink(editfile);
+       }
+
+       if (lflg == 0 && active > 0)
+               --active;
+       if (displayhist)
+               displayhist = 0;
+       return 0;
+}
+
+STATIC char *
+fc_replace(const char *s, char *p, char *r)
+{
+       char *dest;
+       int plen = strlen(p);
+
+       STARTSTACKSTR(dest);
+       while (*s) {
+               if (*s == *p && strncmp(s, p, plen) == 0) {
+                       while (*r)
+                               STPUTC(*r++, dest);
+                       s += plen;
+                       *p = '\0';      /* so no more matches */
+               } else
+                       STPUTC(*s++, dest);
+       }
+       STACKSTRNUL(dest);
+       dest = grabstackstr(dest);
+
+       return (dest);
+}
+
+STATIC int
+not_fcnumber(char *s)
+{
+       if (s == NULL)
+               return (0);
+       if (*s == '-')
+               s++;
+       return (!is_number(s));
+}
+
+STATIC int
+str_to_event(char *str, int last)
+{
+       HistEvent he;
+       char *s = str;
+       int relative = 0;
+       int i, retval;
+
+       retval = history(hist, &he, H_FIRST);
+       switch (*s) {
+       case '-':
+               relative = 1;
+               /*FALLTHROUGH*/
+       case '+':
+               s++;
+       }
+       if (is_number(s)) {
+               i = atoi(s);
+               if (relative) {
+                       while (retval != -1 && i--) {
+                               retval = history(hist, &he, H_NEXT);
+                       }
+                       if (retval == -1)
+                               retval = history(hist, &he, H_LAST);
+               } else {
+                       retval = history(hist, &he, H_NEXT_EVENT, i);
+                       if (retval == -1) {
+                               /*
+                                * the notion of first and last is
+                                * backwards to that of the history package
+                                */
+                               retval = history(hist, &he, last ? H_FIRST : H_LAST);
+                       }
+               }
+               if (retval == -1)
+                       error("history number %s not found (internal error)",
+                              str);
+       } else {
+               /*
+                * pattern
+                */
+               retval = history(hist, &he, H_PREV_STR, str);
+               if (retval == -1)
+                       error("history pattern not found: %s", str);
+       }
+       return (he.num);
+}
+
+int
+bindcmd(int argc, char **argv)
+{
+
+       if (el == NULL)
+               error("line editing is disabled");
+       return (el_parse(el, argc, argv));
+}
+
+#else
+#include "error.h"
+
+int
+histcmd(int argc, char **argv)
+{
+
+       error("not compiled with history support");
+       /*NOTREACHED*/
+       return (0);
+}
+
+int
+bindcmd(int argc, char **argv)
+{
+
+       error("not compiled with line editing support");
+       return (0);
+}
+#endif /* !NO_HISTORY && !EDITLINE */
+
+/*
+ * $PchId: histedit.c,v 1.6 2006/04/10 14:52:58 philip Exp $
+ */
index 51efdb4b482e5df82c72c7943bcf119a5c23a7a8..0cfb9c4ca7433da74dcaf6e33a551456bac67dcb 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)init.h      5.1 (Berkeley) 3/7/91
+ *     @(#)init.h      8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/init.h,v 1.8 2004/04/06 20:06:51 markm Exp $
  */
 
-#ifdef __STDC__
 void init(void);
 void reset(void);
 void initshellproc(void);
-#else
-void init();
-void reset();
-void initshellproc();
-#endif
+
+/*
+ * $PchId: init.h,v 1.3 2006/03/30 14:31:06 philip Exp $
+ */
index 1ed7e0174c091ba16e2b25536d5963eda010239b..c44b4a87c5b8f7e5f6a4e4984881d9740fbe5784 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)input.c    5.4 (Berkeley) 7/1/91";
+#if 0
+static char sccsid[] = "@(#)input.c    8.3 (Berkeley) 6/9/95";
+#endif
 #endif /* not lint */
-
 /*
- * This file implements the input routines used by the parser.
- */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/input.c,v 1.22 2004/04/06 20:06:51 markm Exp $");
+*/
 
 #include <sys/types.h>
 #include <stdio.h>     /* defines BUFSIZ */
-#include "shell.h"
 #include <fcntl.h>
 #include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * This file implements the input routines used by the parser.
+ */
+
+#include "shell.h"
+#include "redir.h"
 #include "syntax.h"
 #include "input.h"
 #include "output.h"
+#include "options.h"
 #include "memalloc.h"
 #include "error.h"
+#include "alias.h"
+#include "parser.h"
+#ifdef EDITLINE
+#ifdef __minix_vmd
+#include <readline/readline.h>
+#else
+/* What about other systems? */
+#endif
+#else
+#include "myhistedit.h"
+#endif
+#include "redir.h"
+#include "trap.h"
+
+static void popstring(void);
 
 #define EOF_NLEFT -99          /* value of parsenleft when EOF pushed back */
 
+MKINIT
+struct strpush {
+       struct strpush *prev;   /* preceding string on stack */
+       char *prevstring;
+       int prevnleft;
+       int prevlleft;
+       struct alias *ap;       /* if push was associated with an alias */
+};
 
 /*
  * The parsefile structure pointed to by the global variable parsefile
@@ -63,36 +94,34 @@ static char sccsid[] = "@(#)input.c 5.4 (Berkeley) 7/1/91";
 
 MKINIT
 struct parsefile {
+       struct parsefile *prev; /* preceding file on stack */
        int linno;              /* current line */
        int fd;                 /* file descriptor (or -1 if string) */
-       int nleft;              /* number of chars left in buffer */
+       int nleft;              /* number of chars left in this line */
+       int lleft;              /* number of lines left in this buffer */
        char *nextc;            /* next char in buffer */
-       struct parsefile *prev; /* preceding file on stack */
        char *buf;              /* input buffer */
+       struct strpush *strpush; /* for pushing strings at this level */
+       struct strpush basestrpush; /* so pushing one is fast */
 };
 
 
 int plinno = 1;                        /* input line number */
 MKINIT int parsenleft;         /* copy of parsefile->nleft */
+MKINIT int parselleft;         /* copy of parsefile->lleft */
 char *parsenextc;              /* copy of parsefile->nextc */
 MKINIT struct parsefile basepf;        /* top level input file */
 char basebuf[BUFSIZ];          /* buffer for top level input file */
-struct parsefile *parsefile = &basepf; /* current input file */
-char *pushedstring;            /* copy of parsenextc when text pushed back */
-int pushednleft;               /* copy of parsenleft when text pushed back */
+STATIC struct parsefile *parsefile = &basepf;  /* current input file */
+int init_editline = 0;         /* editline library initialized? */
+int whichprompt;               /* -1 == PSE, 1 == PS1, 2 == PS2 */
 
-#if READLINE
-char *readline __P((const char *prompt));
-char *r_use_prompt = NULL;     /* the prompt to use with readline */
+#ifndef EDITLINE
+EditLine *el;                  /* cookie for editline package */
 #endif
 
-#ifdef __STDC__
 STATIC void pushfile(void);
-#else
-STATIC void pushfile();
-#endif
-
-
+static int preadfd(void);
 
 #ifdef mkinit
 INCLUDE "input.h"
@@ -106,7 +135,7 @@ INIT {
 
 RESET {
        if (exception != EXSHELLPROC)
-               parsenleft = 0;            /* clear input buffer */
+               parselleft = parsenleft = 0;    /* clear input buffer */
        popallfiles();
 }
 
@@ -121,10 +150,9 @@ SHELLPROC {
  */
 
 char *
-pfgets(line, len)
-       char *line;
-       {
-       register char *p = line;
+pfgets(char *line, int len)
+{
+       char *p = line;
        int nleft = len;
        int c;
 
@@ -151,64 +179,74 @@ pfgets(line, len)
  */
 
 int
-pgetc() {
+pgetc(void)
+{
        return pgetc_macro();
 }
 
 
-/*
- * Refill the input buffer and return the next input character:
- *
- * 1) If a string was pushed back on the input, switch back to the regular
- *    buffer.
- * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
- *    from a string so we can't refill the buffer, return EOF.
- * 3) Call read to read in the characters.
- * 4) Delete all nul characters from the buffer.
- */
+static int
+preadfd(void)
+{
+       int nr;
+       parsenextc = parsefile->buf;
 
-int
-preadbuffer() {
-       register char *p, *q;
-       register int i;
-
-       if (pushedstring) {
-               parsenextc = pushedstring;
-               pushedstring = NULL;
-               parsenleft = pushednleft;
-               if (--parsenleft >= 0)
-                       return *parsenextc++;
+#if !defined(NO_HISTORY) && !defined(EDITLINE)
+       if (el != NULL && gotwinch) {
+               gotwinch = 0;
+               el_resize(el);
        }
-       if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
-               return PEOF;
-       flushout(&output);
-       flushout(&errout);
-#if READLINE
-    /* Use the readline() call if a prompt is to be printed (interactive). */
-    if (r_use_prompt != NULL) {
-       char *prompt;
-       char *line;
-
-       p = parsenextc = parsefile->buf;
-
-       prompt = r_use_prompt;
-       r_use_prompt = NULL;
-
-       if ((line = readline(prompt)) == NULL) {
-                parsenleft = EOF_NLEFT;
-                return PEOF;
-       }
-       strcpy(p, line);
-       free(line);
-       i = strlen(p);
-       p[i++] = '\n';
-    } else {
 #endif
 retry:
-       p = parsenextc = parsefile->buf;
-       i = read(parsefile->fd, p, BUFSIZ);
-       if (i <= 0) {
-                if (i < 0) {
+#ifndef NO_HISTORY
+#ifdef EDITLINE
+       if (parsefile->fd == 0) {
+               static const char *rl_cp= NULL;
+               static size_t rl_off= 0;
+
+               if (!rl_cp)
+               {
+                       rl_cp = readline(getprompt(NULL));
+                       if (rl_cp == NULL)
+                               nr = 0;
+               }
+               if (rl_cp)
+               {
+                       nr= strlen(rl_cp+rl_off);
+                       if (nr >= BUFSIZ-1)
+                       {
+                               nr= BUFSIZ-1;
+                               (void) memcpy(parsenextc, rl_cp+rl_off, nr);
+                               rl_off += nr;
+                       }
+                       else
+                       {
+                               (void) memcpy(parsenextc, rl_cp+rl_off, nr);
+                               parsenextc[nr++]= '\n';
+                               free(rl_cp);
+                               rl_cp= NULL;
+                               rl_off= 0;
+                       }
+               }
+       } else
+#else /* !EDITLINE */
+       if (parsefile->fd == 0 && el) {
+               const char *rl_cp;
+
+               rl_cp = el_gets(el, &nr);
+               if (rl_cp == NULL)
+                       nr = 0;
+               else {
+                       /* XXX - BUFSIZE should redesign so not necessary */
+                       (void) strcpy(parsenextc, rl_cp);
+               }
+       } else
+#endif /* !EDITLINE */
+#endif
+               nr = read(parsefile->fd, parsenextc, BUFSIZ - 1);
+
+       if (nr <= 0) {
+                if (nr < 0) {
                         if (errno == EINTR)
                                 goto retry;
 #ifdef EWOULDBLOCK
@@ -222,64 +260,164 @@ retry:
                                         }
                                 }
                         }
-#endif
+#endif /* EWOULDBLOCK */
                 }
-                parsenleft = EOF_NLEFT;
-                return PEOF;
+                nr = -1;
        }
-#if READLINE
-    }
-#endif
-       parsenleft = i - 1;
+       return nr;
+}
+
+/*
+ * Refill the input buffer and return the next input character:
+ *
+ * 1) If a string was pushed back on the input, pop it;
+ * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
+ *    from a string so we can't refill the buffer, return EOF.
+ * 3) If there is more in this buffer, use it else call read to fill it.
+ * 4) Process input up to the next newline, deleting nul characters.
+ */
+
+int
+preadbuffer(void)
+{
+       char *p, *q;
+       int more;
+       int something;
+       char savec;
+
+       if (parsefile->strpush) {
+               popstring();
+               if (--parsenleft >= 0)
+                       return (*parsenextc++);
+       }
+       if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
+               return PEOF;
+       flushout(&output);
+       flushout(&errout);
+
+again:
+       if (parselleft <= 0) {
+               if ((parselleft = preadfd()) == -1) {
+                       parselleft = parsenleft = EOF_NLEFT;
+                       return PEOF;
+               }
+       }
+
+       q = p = parsenextc;
 
        /* delete nul characters */
-       for (;;) {
-               if (*p++ == '\0')
+       something = 0;
+       for (more = 1; more;) {
+               switch (*p) {
+               case '\0':
+                       p++;    /* Skip nul */
+                       goto check;
+
+               case '\t':
+               case ' ':
+                       break;
+
+               case '\n':
+                       parsenleft = q - parsenextc;
+                       more = 0; /* Stop processing here */
+                       break;
+
+               default:
+                       something = 1;
                        break;
-               if (--i <= 0)
-                       return *parsenextc++;           /* no nul characters */
+               }
+
+               *q++ = *p++;
+check:
+               if (--parselleft <= 0) {
+                       parsenleft = q - parsenextc - 1;
+                       if (parsenleft < 0)
+                               goto again;
+                       *q = '\0';
+                       more = 0;
+               }
+       }
+
+       savec = *q;
+       *q = '\0';
+
+#if !defined(NO_HISTORY) && !defined(EDITLINE)
+       if (parsefile->fd == 0 && hist && something) {
+               HistEvent he;
+               INTOFF;
+               history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
+                   parsenextc);
+               INTON;
        }
-       q = p - 1;
-       while (--i > 0) {
-               if (*p != '\0')
-                       *q++ = *p;
-               p++;
+#endif
+
+       if (vflag) {
+               out2str(parsenextc);
+               flushout(out2);
        }
-       if (q == parsefile->buf)
-               goto retry;                     /* buffer contained nothing but nuls */
-       parsenleft = q - parsefile->buf - 1;
+
+       *q = savec;
+
        return *parsenextc++;
 }
 
-
 /*
  * Undo the last call to pgetc.  Only one character may be pushed back.
  * PEOF may be pushed back.
  */
 
 void
-pungetc() {
+pungetc(void)
+{
        parsenleft++;
        parsenextc--;
 }
 
-
 /*
- * Push a string back onto the input.  This code doesn't work if the user
- * tries to push back more than one string at once.
+ * Push a string back onto the input at this current parsefile level.
+ * We handle aliases this way.
  */
-
 void
-ppushback(string, length)
-       char *string;
-       {
-       pushedstring = parsenextc;
-       pushednleft = parsenleft;
-       parsenextc = string;
-       parsenleft = length;
+pushstring(char *s, int len, void *ap)
+{
+       struct strpush *sp;
+
+       INTOFF;
+/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
+       if (parsefile->strpush) {
+               sp = ckmalloc(sizeof (struct strpush));
+               sp->prev = parsefile->strpush;
+               parsefile->strpush = sp;
+       } else
+               sp = parsefile->strpush = &(parsefile->basestrpush);
+       sp->prevstring = parsenextc;
+       sp->prevnleft = parsenleft;
+       sp->prevlleft = parselleft;
+       sp->ap = (struct alias *)ap;
+       if (ap)
+               ((struct alias *)ap)->flag |= ALIASINUSE;
+       parsenextc = s;
+       parsenleft = len;
+       INTON;
 }
 
+static void
+popstring(void)
+{
+       struct strpush *sp = parsefile->strpush;
 
+       INTOFF;
+       parsenextc = sp->prevstring;
+       parsenleft = sp->prevnleft;
+       parselleft = sp->prevlleft;
+/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
+       if (sp->ap)
+               sp->ap->flag &= ~ALIASINUSE;
+       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
@@ -287,17 +425,16 @@ ppushback(string, length)
  */
 
 void
-setinputfile(fname, push)
-       char *fname;
-       {
+setinputfile(char *fname, int push)
+{
        int fd;
        int fd2;
 
        INTOFF;
        if ((fd = open(fname, O_RDONLY)) < 0)
-               error("Can't open %s", fname);
+               error("Can't open %s: %s", fname, strerror(errno));
        if (fd < 10) {
-               fd2 = copyfd(fd, 10);
+               fd2 = fcntl(fd, F_DUPFD, 10);
                close(fd);
                if (fd2 < 0)
                        error("Out of file descriptors");
@@ -314,8 +451,9 @@ setinputfile(fname, push)
  */
 
 void
-setinputfd(fd, push) {
-       (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+setinputfd(int fd, int push)
+{
+       (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
        if (push) {
                pushfile();
                parsefile->buf = ckmalloc(BUFSIZ);
@@ -325,7 +463,7 @@ setinputfd(fd, push) {
        parsefile->fd = fd;
        if (parsefile->buf == NULL)
                parsefile->buf = ckmalloc(BUFSIZ);
-       parsenleft = 0;
+       parselleft = parsenleft = 0;
        plinno = 1;
 }
 
@@ -335,14 +473,13 @@ setinputfd(fd, push) {
  */
 
 void
-setinputstring(string, push)
-       char *string;
-       {
+setinputstring(char *string, int push)
+{
        INTOFF;
        if (push)
                pushfile();
        parsenextc = string;
-       parsenleft = strlen(string);
+       parselleft = parsenleft = strlen(string);
        parsefile->buf = NULL;
        plinno = 1;
        INTON;
@@ -356,21 +493,26 @@ setinputstring(string, push)
  */
 
 STATIC void
-pushfile() {
+pushfile(void)
+{
        struct parsefile *pf;
 
        parsefile->nleft = parsenleft;
+       parsefile->lleft = parselleft;
        parsefile->nextc = parsenextc;
        parsefile->linno = plinno;
        pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
        pf->prev = parsefile;
        pf->fd = -1;
+       pf->strpush = NULL;
+       pf->basestrpush.prev = NULL;
        parsefile = pf;
 }
 
 
 void
-popfile() {
+popfile(void)
+{
        struct parsefile *pf = parsefile;
 
        INTOFF;
@@ -378,9 +520,12 @@ popfile() {
                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;
@@ -392,7 +537,8 @@ popfile() {
  */
 
 void
-popallfiles() {
+popallfiles(void)
+{
        while (parsefile != &basepf)
                popfile();
 }
@@ -405,10 +551,15 @@ popallfiles() {
  */
 
 void
-closescript() {
+closescript(void)
+{
        popallfiles();
        if (parsefile->fd > 0) {
                close(parsefile->fd);
                parsefile->fd = 0;
        }
 }
+
+/*
+ * $PchId: input.c,v 1.6 2006/05/23 12:00:32 philip Exp $
+ */
index 656bb2930312b0f707b886806929255963e6006b..97267b513c2c4f770a85cd67fad89b98f1112405 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
@@ -33,7 +29,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)input.h     5.1 (Berkeley) 3/7/91
+ *     @(#)input.h     8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/input.h,v 1.9 2004/04/06 20:06:51 markm Exp $
  */
 
 /* PEOF (the end of file marker) is defined in syntax.h */
 extern int plinno;
 extern int parsenleft;         /* number of characters left in input buffer */
 extern char *parsenextc;       /* next character in input buffer */
+extern int init_editline;      /* 0 == not setup, 1 == OK, -1 == failed */
 
-
-#ifdef __STDC__
 char *pfgets(char *, int);
 int pgetc(void);
 int preadbuffer(void);
 void pungetc(void);
-void ppushback(char *, int);
+void pushstring(char *, int, void *);
 void setinputfile(char *, int);
 void setinputfd(int, int);
 void setinputstring(char *, int);
 void popfile(void);
 void popallfiles(void);
 void closescript(void);
-#else
-char *pfgets();
-int pgetc();
-int preadbuffer();
-void pungetc();
-void ppushback();
-void setinputfile();
-void setinputfd();
-void setinputstring();
-void popfile();
-void popallfiles();
-void closescript();
-#endif
 
 #define pgetc_macro()  (--parsenleft >= 0? *parsenextc++ : preadbuffer())
 
-#if READLINE
-/* The variable "r_use_prompt" indicates the prompt to use with readline,
- * *and* that readline may only be used if non-NULL.
+/*
+ * $PchId: input.h,v 1.3 2006/03/30 13:49:37 philip Exp $
  */
-extern char *r_use_prompt;
-#endif
index ae9c5038cecb162784e4bbf93a678c76de19025a..792ffe7e46643dcc3fcf7437a29231871e5cc24e 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)jobs.c     5.1 (Berkeley) 3/7/91";
+#if 0
+static char sccsid[] = "@(#)jobs.c     8.5 (Berkeley) 5/4/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/jobs.c,v 1.67 2004/04/06 20:06:51 markm Exp $");
+*/
 
 #include "shell.h"
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#ifndef NO_PATHS_H
+#include <paths.h>
+#endif
+#include <unistd.h>
+#include <stdlib.h>
+#ifdef POSIX
+#include <signal.h>
+#include <sys/wait.h>
+#elif defined(BSD)
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#include <sys/ioctl.h>
+
 #if JOBS
-#include "sgtty.h"
+#include <termios.h>
 #undef CEOF                    /* syntax.h redefines this */
 #endif
+#include "redir.h"
+#include "show.h"
 #include "main.h"
 #include "parser.h"
 #include "nodes.h"
 #include "jobs.h"
 #include "options.h"
 #include "trap.h"
-#include "signames.h"
 #include "syntax.h"
 #include "input.h"
 #include "output.h"
 #include "memalloc.h"
 #include "error.h"
 #include "mystring.h"
-#include "redir.h"
-#include <sys/types.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <errno.h>
-#ifdef BSD
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#endif
-#if POSIX
-#include <sys/wait.h>
-#endif
+#include "builtins.h"
 
+#ifdef __minix
+/* #define NO_KILLPG */
+#endif
 
+#ifndef _PATH_TTY
+#define _PATH_TTY "/dev/tty"
+#endif
+#ifndef _PATH_DEVNULL
+#define _PATH_DEVNULL "/dev/null"
+#endif
 
-struct job *jobtab;            /* array of jobs */
-int njobs;                     /* size of array */
+STATIC struct job *jobtab;     /* array of jobs */
+STATIC int njobs;              /* size of array */
 MKINIT pid_t backgndpid = -1;  /* pid of last background process */
 #if JOBS
-int initialpgrp;               /* pgrp of shell on invocation */
-pid_t curjob;                  /* current job */
+STATIC struct job *jobmru;     /* most recently used job list */
+STATIC pid_t initialpgrp;      /* pgrp of shell on invocation */
+#endif
+int in_waitcmd = 0;            /* are we in waitcmd()? */
+int in_dowait = 0;             /* are we in dowait()? */
+volatile sig_atomic_t breakwaitcmd = 0;        /* should wait be terminated? */
+static int ttyfd = -1;
+
+#ifndef WCOREDUMP
+#define WCOREDUMP(s)   ((s) & 0x80)
 #endif
 
-#ifdef __STDC__
+#if JOBS
 STATIC void restartjob(struct job *);
-STATIC struct job *getjob(char *);
+#endif
 STATIC void freejob(struct job *);
-STATIC int procrunning(int);
-STATIC int dowait(int, struct job *);
-STATIC int waitproc(int, int *);
-STATIC char *commandtext(union node *);
-#else
-STATIC void restartjob();
-STATIC struct job *getjob();
-STATIC void freejob();
-STATIC int procrunning();
-STATIC int dowait();
-STATIC int waitproc();
-STATIC char *commandtext();
+STATIC struct job *getjob(char *);
+STATIC pid_t dowait(int, struct job *);
+STATIC pid_t waitproc(int, int *);
+STATIC void cmdtxt(union node *);
+STATIC void cmdputs(char *);
+#if JOBS
+STATIC void setcurjob(struct job *);
+STATIC void deljob(struct job *);
+STATIC struct job *getcurjob(struct job *);
 #endif
+STATIC void showjob(struct job *, pid_t, int, int);
 
+#ifdef NO_KILLPG
+static int killpg(pid_t,int);
+#endif
 
-#if JOBS
 /*
  * Turn job control on and off.
- *
- * Note:  This code assumes that the third arg to ioctl is a character
- * pointer, which is true on Berkeley systems but not System V.  Since
- * System V doesn't have job control yet, this isn't a problem now.
  */
 
 MKINIT int jobctl;
 
+#if JOBS
 void
-setjobctl(on) {
-       int ldisc;
+setjobctl(int on)
+{
+       int i;
 
        if (on == jobctl || rootshell == 0)
                return;
        if (on) {
+               if (ttyfd != -1)
+                       close(ttyfd);
+               if ((ttyfd = open(_PATH_TTY, O_RDWR)) < 0) {
+                       i = 0;
+                       while (i <= 2 && !isatty(i))
+                               i++;
+                       if (i > 2 || (ttyfd = fcntl(i, F_DUPFD, 10)) < 0)
+                               goto out;
+               }
+               if (ttyfd < 10) {
+                       /*
+                        * Keep our TTY file descriptor out of the way of
+                        * the user's redirections.
+                        */
+                       if ((i = fcntl(ttyfd, F_DUPFD, 10)) < 0) {
+                               close(ttyfd);
+                               ttyfd = -1;
+                               goto out;
+                       }
+                       close(ttyfd);
+                       ttyfd = i;
+               }
+               if (fcntl(ttyfd, F_SETFD, FD_CLOEXEC) < 0) {
+                       close(ttyfd);
+                       ttyfd = -1;
+                       goto out;
+               }
                do { /* while we are in the background */
-                       if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
-                               out2str("ash: can't access tty; job control turned off\n");
-                               jflag = 0;
+                       initialpgrp = tcgetpgrp(ttyfd);
+                       if (initialpgrp < 0) {
+out:                           out2str("sh: can't access tty; job control turned off\n");
+                               mflag = 0;
                                return;
                        }
                        if (initialpgrp == -1)
-                               initialpgrp = getpgrp(0);
-                       else if (initialpgrp != getpgrp(0)) {
-                               killpg(initialpgrp, SIGTTIN);
+                               initialpgrp = getpgrp();
+                       else if (initialpgrp != getpgrp()) {
+                               killpg(0, SIGTTIN);
                                continue;
                        }
                } while (0);
-               if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
-                       out2str("ash: need new tty driver to run job control; job control turned off\n");
-                       jflag = 0;
-                       return;
-               }
                setsignal(SIGTSTP);
                setsignal(SIGTTOU);
-               setpgrp(0, rootpid);
-               ioctl(2, TIOCSPGRP, (char *)&rootpid);
+               setsignal(SIGTTIN);
+               setpgid(0, rootpid);
+               tcsetpgrp(ttyfd, rootpid);
        } else { /* turning job control off */
-               setpgrp(0, initialpgrp);
-               ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
+               setpgid(0, initialpgrp);
+               tcsetpgrp(ttyfd, initialpgrp);
+               close(ttyfd);
+               ttyfd = -1;
                setsignal(SIGTSTP);
                setsignal(SIGTTOU);
+               setsignal(SIGTTIN);
        }
        jobctl = on;
 }
@@ -153,6 +205,8 @@ setjobctl(on) {
 
 
 #ifdef mkinit
+INCLUDE <sys/types.h>
+INCLUDE <stdlib.h>
 
 SHELLPROC {
        backgndpid = -1;
@@ -166,50 +220,66 @@ SHELLPROC {
 
 
 #if JOBS
-fgcmd(argc, argv)  char **argv; {
+int
+fgcmd(int argc __unused, char **argv)
+{
        struct job *jp;
-       int pgrp;
+       pid_t pgrp;
        int status;
 
        jp = getjob(argv[1]);
        if (jp->jobctl == 0)
                error("job not created under job control");
+       out1str(jp->ps[0].cmd);
+       out1c('\n');
+       flushout(&output);
        pgrp = jp->ps[0].pid;
-       ioctl(2, TIOCSPGRP, (char *)&pgrp);
+       tcsetpgrp(ttyfd, pgrp);
        restartjob(jp);
+       jp->foreground = 1;
        INTOFF;
-       status = waitforjob(jp);
+       status = waitforjob(jp, (int *)NULL);
        INTON;
        return status;
 }
 
 
-bgcmd(argc, argv)  char **argv; {
+int
+bgcmd(int argc, char **argv)
+{
+       char s[64];
        struct job *jp;
 
        do {
                jp = getjob(*++argv);
                if (jp->jobctl == 0)
                        error("job not created under job control");
+               if (jp->state == JOBDONE)
+                       continue;
                restartjob(jp);
+               jp->foreground = 0;
+               fmtstr(s, 64, "[%td] ", jp - jobtab + 1);
+               out1str(s);
+               out1str(jp->ps[0].cmd);
+               out1c('\n');
        } while (--argc > 1);
        return 0;
 }
 
 
 STATIC void
-restartjob(jp)
-       struct job *jp;
-       {
+restartjob(struct job *jp)
+{
        struct procstat *ps;
        int i;
 
        if (jp->state == JOBDONE)
                return;
+       setcurjob(jp);
        INTOFF;
        killpg(jp->ps[0].pid, SIGCONT);
        for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
-               if ((ps->status & 0377) == 0177) {
+               if (WIFSTOPPED(ps->status)) {
                        ps->status = -1;
                        jp->state = 0;
                }
@@ -220,11 +290,121 @@ restartjob(jp)
 
 
 int
-jobscmd(argc, argv)  char **argv; {
-       showjobs(0);
-       return 0;
+jobscmd(int argc, char *argv[])
+{
+       char *id;
+       int ch, sformat, lformat;
+
+       optind = optreset = 1;
+       opterr = 0;
+       sformat = lformat = 0;
+       while ((ch = getopt(argc, argv, "ls")) != -1) {
+               switch (ch) {
+               case 'l':
+                       lformat = 1;
+                       break;
+               case 's':
+                       sformat = 1;
+                       break;
+               case '?':
+               default:
+                       error("unknown option: -%c", optopt);
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (argc == 0)
+               showjobs(0, sformat, lformat);
+       else
+               while ((id = *argv++) != NULL)
+                       showjob(getjob(id), 0, sformat, lformat);
+
+       return (0);
 }
 
+STATIC void
+showjob(struct job *jp, pid_t pid, int sformat, int lformat)
+{
+       char s[64];
+       struct procstat *ps;
+       struct job *j;
+       int col, curr, i, jobno, prev, procno;
+       char c;
+
+       procno = jp->nprocs;
+       jobno = jp - jobtab + 1;
+       curr = prev = 0;
+#if JOBS
+       if ((j = getcurjob(NULL)) != NULL) {
+               curr = j - jobtab + 1;
+               if ((j = getcurjob(j)) != NULL)
+                       prev = j - jobtab + 1;
+       }
+#endif
+       for (ps = jp->ps ; ; ps++) {    /* for each process */
+               if (sformat) {
+                       out1fmt("%d\n", (int)ps->pid);
+                       goto skip;
+               }
+               if (!lformat && ps != jp->ps && pid == 0)
+                       goto skip;
+               if (pid != 0 && pid != ps->pid)
+                       goto skip;
+               if (jobno == curr && ps == jp->ps)
+                       c = '+';
+               else if (jobno == prev && ps == jp->ps)
+                       c = '-';
+               else
+                       c = ' ';
+               if (ps == jp->ps)
+                       fmtstr(s, 64, "[%d] %c ", jobno, c);
+               else
+                       fmtstr(s, 64, "    %c ", c);
+               out1str(s);
+               col = strlen(s);
+               if (lformat) {
+                       fmtstr(s, 64, "%d ", (int)ps->pid);
+                       out1str(s);
+                       col += strlen(s);
+               }
+               s[0] = '\0';
+               if (ps != jp->ps) {
+                       *s = '\0';
+               } else if (ps->status == -1) {
+                       strcpy(s, "Running");
+               } else if (WIFEXITED(ps->status)) {
+                       if (WEXITSTATUS(ps->status) == 0)
+                               strcpy(s, "Done");
+                       else
+                               fmtstr(s, 64, "Done (%d)",
+                                   WEXITSTATUS(ps->status));
+               } else {
+#if JOBS
+                       if (WIFSTOPPED(ps->status)) 
+                               i = WSTOPSIG(ps->status);
+                       else
+#endif
+                               i = WTERMSIG(ps->status);
+                       if ((i & 0x7F) < _NSIG && strsiglist(i & 0x7F))
+                               scopy(strsiglist(i & 0x7F), s);
+                       else
+                               fmtstr(s, 64, "Signal %d", i & 0x7F);
+                       if (WCOREDUMP(ps->status))
+                               strcat(s, " (core dumped)");
+               }
+               out1str(s);
+               col += strlen(s);
+               do {
+                       out1c(' ');
+                       col++;
+               } while (col < 30);
+               out1str(ps->cmd);
+               out1c('\n');
+skip:          if (--procno <= 0)
+                       break;
+       }
+}
 
 /*
  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
@@ -236,14 +416,10 @@ jobscmd(argc, argv)  char **argv; {
  */
 
 void
-showjobs(change) {
+showjobs(int change, int sformat, int lformat)
+{
        int jobno;
-       int procno;
-       int i;
        struct job *jp;
-       struct procstat *ps;
-       int col;
-       char s[64];
 
        TRACE(("showjobs(%d) called\n", change));
        while (dowait(0, (struct job *)NULL) > 0);
@@ -256,43 +432,7 @@ showjobs(change) {
                }
                if (change && ! jp->changed)
                        continue;
-               procno = jp->nprocs;
-               for (ps = jp->ps ; ; ps++) {    /* for each process */
-                       if (ps == jp->ps)
-                               fmtstr(s, 64, "[%d] %d ", jobno, ps->pid);
-                       else
-                               fmtstr(s, 64, "    %d ", ps->pid);
-                       out1str(s);
-                       col = strlen(s);
-                       s[0] = '\0';
-                       if (ps->status == -1) {
-                               /* don't print anything */
-                       } else if ((ps->status & 0xFF) == 0) {
-                               fmtstr(s, 64, "Exit %d", ps->status >> 8);
-                       } else {
-                               i = ps->status;
-#if JOBS
-                               if ((i & 0xFF) == 0177)
-                                       i >>= 8;
-#endif
-                               if ((i & 0x7F) <= MAXSIG && sigmesg[i & 0x7F])
-                                       scopy(sigmesg[i & 0x7F], s);
-                               else
-                                       fmtstr(s, 64, "Signal %d", i & 0x7F);
-                               if (i & 0x80)
-                                       strcat(s, " (core dumped)");
-                       }
-                       out1str(s);
-                       col += strlen(s);
-                       do {
-                               out1c(' ');
-                               col++;
-                       } while (col < 30);
-                       out1str(ps->cmd);
-                       out1c('\n');
-                       if (--procno <= 0)
-                               break;
-               }
+               showjob(jp, 0, sformat, lformat);
                jp->changed = 0;
                if (jp->state == JOBDONE) {
                        freejob(jp);
@@ -306,9 +446,8 @@ showjobs(change) {
  */
 
 STATIC void
-freejob(jp)
-       struct job *jp;
-       {
+freejob(struct job *jp)
+{
        struct procstat *ps;
        int i;
 
@@ -321,8 +460,7 @@ freejob(jp)
                ckfree(jp->ps);
        jp->used = 0;
 #if JOBS
-       if (curjob == jp - jobtab + 1)
-               curjob = 0;
+       deljob(jp);
 #endif
        INTON;
 }
@@ -330,9 +468,10 @@ freejob(jp)
 
 
 int
-waitcmd(argc, argv)  char **argv; {
+waitcmd(int argc, char **argv)
+{
        struct job *job;
-       int status;
+       int status, retval;
        struct job *jp;
 
        if (argc > 1) {
@@ -340,44 +479,57 @@ waitcmd(argc, argv)  char **argv; {
        } else {
                job = NULL;
        }
-       for (;;) {      /* loop until process terminated or stopped */
+
+       /*
+        * Loop until a process is terminated or stopped, or a SIGINT is
+        * received.
+        */
+
+       in_waitcmd++;
+       do {
                if (job != NULL) {
                        if (job->state) {
                                status = job->ps[job->nprocs - 1].status;
-                               if ((status & 0xFF) == 0)
-                                       status = status >> 8 & 0xFF;
+                               if (WIFEXITED(status))
+                                       retval = WEXITSTATUS(status);
 #if JOBS
-                               else if ((status & 0xFF) == 0177)
-                                       status = (status >> 8 & 0x7F) + 128;
+                               else if (WIFSTOPPED(status))
+                                       retval = WSTOPSIG(status) + 128;
 #endif
                                else
-                                       status = (status & 0x7F) + 128;
+                                       retval = WTERMSIG(status) + 128;
                                if (! iflag)
                                        freejob(job);
-                               return status;
+                               in_waitcmd--;
+                               return retval;
                        }
                } else {
                        for (jp = jobtab ; ; jp++) {
                                if (jp >= jobtab + njobs) {     /* no running procs */
+                                       in_waitcmd--;
                                        return 0;
                                }
                                if (jp->used && jp->state == 0)
                                        break;
                        }
                }
-               dowait(1, (struct job *)NULL);
-       }
+       } while (dowait(1, (struct job *)NULL) != -1);
+       in_waitcmd--;
+
+       return 0;
 }
 
 
 
-jobidcmd(argc, argv)  char **argv; {
+int
+jobidcmd(int argc __unused, char **argv)
+{
        struct job *jp;
        int i;
 
        jp = getjob(argv[1]);
        for (i = 0 ; i < jp->nprocs ; ) {
-               out1fmt("%d", jp->ps[i].pid);
+               out1fmt("%d", (int)jp->ps[i].pid);
                out1c(++i < jp->nprocs? ' ' : '\n');
        }
        return 0;
@@ -390,20 +542,18 @@ jobidcmd(argc, argv)  char **argv; {
  */
 
 STATIC struct job *
-getjob(name)
-       char *name;
-       {
+getjob(char *name)
+{
        int jobno;
-       register struct job *jp;
-       int pid;
+       struct job *found, *jp;
+       pid_t pid;
        int i;
 
        if (name == NULL) {
 #if JOBS
-currentjob:
-               if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
+currentjob:    if ((jp = getcurjob(NULL)) == NULL)
                        error("No current job");
-               return &jobtab[jobno - 1];
+               return (jp);
 #else
                error("No current job");
 #endif
@@ -416,9 +566,28 @@ currentjob:
 #if JOBS
                } else if (name[1] == '%' && name[2] == '\0') {
                        goto currentjob;
+               } else if (name[1] == '+' && name[2] == '\0') {
+                       goto currentjob;
+               } else if (name[1] == '-' && name[2] == '\0') {
+                       if ((jp = getcurjob(NULL)) == NULL ||
+                           (jp = getcurjob(jp)) == NULL)
+                               error("No previous job");
+                       return (jp);
 #endif
+               } else if (name[1] == '?') {
+                       found = NULL;
+                       for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
+                               if (jp->used && jp->nprocs > 0
+                                && strstr(jp->ps[0].cmd, name + 2) != NULL) {
+                                       if (found)
+                                               error("%s: ambiguous", name);
+                                       found = jp;
+                               }
+                       }
+                       if (found != NULL)
+                               return (found);
                } else {
-                       register struct job *found = NULL;
+                       found = NULL;
                        for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
                                if (jp->used && jp->nprocs > 0
                                 && prefix(name + 1, jp->ps[0].cmd)) {
@@ -431,7 +600,7 @@ currentjob:
                                return found;
                }
        } else if (is_number(name)) {
-               pid = number(name);
+               pid = (pid_t)number(name);
                for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
                        if (jp->used && jp->nprocs > 0
                         && jp->ps[jp->nprocs - 1].pid == pid)
@@ -439,6 +608,8 @@ currentjob:
                }
        }
        error("No such job: %s", name);
+       /*NOTREACHED*/
+       return NULL;
 }
 
 
@@ -448,9 +619,8 @@ currentjob:
  */
 
 struct job *
-makejob(node, nprocs)
-       union node *node;
-       {
+makejob(union node *node __unused, int nprocs)
+{
        int i;
        struct job *jp;
 
@@ -459,14 +629,25 @@ makejob(node, nprocs)
                        INTOFF;
                        if (njobs == 0) {
                                jobtab = ckmalloc(4 * sizeof jobtab[0]);
+#if JOBS
+                               jobmru = NULL;
+#endif
                        } else {
                                jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
-                               bcopy(jobtab, jp, njobs * sizeof jp[0]);
-                               for (i= 0; i<njobs; i++)
-                               {
-                                       if (jobtab[i].ps == &jobtab[i].ps0)
-                                               jp[i].ps= &jp[i].ps0;
-                               }
+                               memcpy(jp, jobtab, njobs * sizeof jp[0]);
+#if JOBS
+                               /* Relocate `next' pointers and list head */
+                               if (jobmru != NULL)
+                                       jobmru = &jp[jobmru - jobtab];
+                               for (i = 0; i < njobs; i++)
+                                       if (jp[i].next != NULL)
+                                               jp[i].next = &jp[jp[i].next -
+                                                   jobtab];
+#endif
+                               /* Relocate `ps' pointers */
+                               for (i = 0; i < njobs; i++)
+                                       if (jp[i].ps == &jobtab[i].ps0)
+                                               jp[i].ps = &jp[i].ps0;
                                ckfree(jobtab);
                                jobtab = jp;
                        }
@@ -483,8 +664,10 @@ makejob(node, nprocs)
        jp->used = 1;
        jp->changed = 0;
        jp->nprocs = 0;
+       jp->foreground = 0;
 #if JOBS
        jp->jobctl = jobctl;
+       jp->next = NULL;
 #endif
        if (nprocs > 1) {
                jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
@@ -492,10 +675,70 @@ makejob(node, nprocs)
                jp->ps = &jp->ps0;
        }
        INTON;
-       TRACE(("makejob(0x%x, %d) returns %%%d\n", (int)node, nprocs, jp - jobtab + 1));
+       TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
+           jp - jobtab + 1));
        return jp;
-}      
+}
 
+#if JOBS
+STATIC void
+setcurjob(struct job *cj)
+{
+       struct job *jp, *prev;
+
+       for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
+               if (jp == cj) {
+                       if (prev != NULL)
+                               prev->next = jp->next;
+                       else
+                               jobmru = jp->next;
+                       jp->next = jobmru;
+                       jobmru = cj;
+                       return;
+               }
+       }
+       cj->next = jobmru;
+       jobmru = cj;
+}
+
+STATIC void
+deljob(struct job *j)
+{
+       struct job *jp, *prev;
+
+       for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
+               if (jp == j) {
+                       if (prev != NULL)
+                               prev->next = jp->next;
+                       else
+                               jobmru = jp->next;
+                       return;
+               }
+       }
+}
+
+/*
+ * Return the most recently used job that isn't `nj', and preferably one
+ * that is stopped.
+ */
+STATIC struct job *
+getcurjob(struct job *nj)
+{
+       struct job *jp;
+
+       /* Try to find a stopped one.. */
+       for (jp = jobmru; jp != NULL; jp = jp->next)
+               if (jp->used && jp != nj && jp->state == JOBSTOPPED)
+                       return (jp);
+       /* Otherwise the most recently used job that isn't `nj' */
+       for (jp = jobmru; jp != NULL; jp = jp->next)
+               if (jp->used && jp != nj)
+                       return (jp);
+
+       return (NULL);
+}
+
+#endif
 
 /*
  * Fork of a subshell.  If we are doing job control, give the subshell its
@@ -512,73 +755,76 @@ makejob(node, nprocs)
  * in a pipeline).
  */
 
-int
-forkshell(jp, n, mode)
-       union node *n;
-       struct job *jp;
-       {
-       int pid;
-       int pgrp;
+pid_t
+forkshell(struct job *jp, union node *n, int mode)
+{
+       pid_t pid;
+       pid_t pgrp;
 
-       TRACE(("forkshell(%%%d, 0x%x, %d) called\n", jp - jobtab, (int)n, mode));
+       TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
+           mode));
        INTOFF;
+       flushall();
        pid = fork();
        if (pid == -1) {
                TRACE(("Fork failed, errno=%d\n", errno));
                INTON;
-               error("Cannot fork");
+               error("Cannot fork: %s", strerror(errno));
        }
        if (pid == 0) {
                struct job *p;
                int wasroot;
                int i;
 
-               TRACE(("Child shell %d\n", getpid()));
+               TRACE(("Child shell %d\n", (int)getpid()));
                wasroot = rootshell;
                rootshell = 0;
-               for (i = njobs, p = jobtab ; --i >= 0 ; p++)
-                       if (p->used)
-                               freejob(p);
                closescript();
                INTON;
                clear_traps();
 #if JOBS
                jobctl = 0;             /* do job control only in root shell */
-               if (wasroot && mode != FORK_NOJOB && jflag) {
+               if (wasroot && mode != FORK_NOJOB && mflag) {
                        if (jp == NULL || jp->nprocs == 0)
                                pgrp = getpid();
                        else
                                pgrp = jp->ps[0].pid;
-                       setpgrp(0, pgrp);
-                       if (mode == FORK_FG) {
+                       if (setpgid(0, pgrp) == 0 && mode == FORK_FG) {
                                /*** this causes superfluous TIOCSPGRPS ***/
-                               if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
-                                       error("TIOCSPGRP failed, errno=%d\n", errno);
+                               if (tcsetpgrp(ttyfd, pgrp) < 0)
+                                       error("tcsetpgrp failed, errno=%d", errno);
                        }
                        setsignal(SIGTSTP);
                        setsignal(SIGTTOU);
                } else if (mode == FORK_BG) {
                        ignoresig(SIGINT);
                        ignoresig(SIGQUIT);
-                       if ((jp == NULL || jp->nprocs == 0)
-                           && ! fd0_redirected_p ()) {
+                       if ((jp == NULL || jp->nprocs == 0) &&
+                           ! fd0_redirected_p ()) {
                                close(0);
-                               if (open("/dev/null", O_RDONLY) != 0)
-                                       error("Can't open /dev/null");
+                               if (open(_PATH_DEVNULL, O_RDONLY) != 0)
+                                       error("Can't open %s: %s",
+                                           _PATH_DEVNULL, strerror(errno));
                        }
                }
 #else
                if (mode == FORK_BG) {
                        ignoresig(SIGINT);
                        ignoresig(SIGQUIT);
-                       if ((jp == NULL || jp->nprocs == 0)
-                           && ! fd0_redirected_p ()) {
+                       if ((jp == NULL || jp->nprocs == 0) &&
+                           ! fd0_redirected_p ()) {
                                close(0);
-                               if (open("/dev/null", O_RDONLY) != 0)
-                                       error("Can't open /dev/null");
+                               if (open(_PATH_DEVNULL, O_RDONLY) != 0)
+                                       error("Can't open %s: %s", 
+                                           _PATH_DEVNULL, strerror(errno));
                        }
                }
 #endif
+               INTOFF;
+               for (i = njobs, p = jobtab ; --i >= 0 ; p++)
+                       if (p->used)
+                               freejob(p);
+               INTON;
                if (wasroot && iflag) {
                        setsignal(SIGINT);
                        setsignal(SIGQUIT);
@@ -586,13 +832,13 @@ forkshell(jp, n, mode)
                }
                return pid;
        }
-       if (rootshell && mode != FORK_NOJOB && jflag) {
+       if (rootshell && mode != FORK_NOJOB && mflag) {
                if (jp == NULL || jp->nprocs == 0)
                        pgrp = pid;
                else
                        pgrp = jp->ps[0].pid;
 #if JOBS
-               setpgrp(pid, pgrp);
+               setpgid(pid, pgrp);
 #endif
        }
        if (mode == FORK_BG)
@@ -604,9 +850,13 @@ forkshell(jp, n, mode)
                ps->cmd = nullstr;
                if (iflag && rootshell && n)
                        ps->cmd = commandtext(n);
+               jp->foreground = mode == FORK_FG;
+#if JOBS
+               setcurjob(jp);
+#endif
        }
        INTON;
-       TRACE(("In parent shell:  child = %d\n", pid));
+       TRACE(("In parent shell:  child = %d\n", (int)pid));
        return pid;
 }
 
@@ -623,7 +873,7 @@ forkshell(jp, n, mode)
  * the interactive program catches interrupts, the user doesn't want
  * these interrupts to also abort the loop.  The approach we take here
  * is to have the shell ignore interrupt signals while waiting for a
- * forground process to terminate, and then send itself an interrupt
+ * foreground process to terminate, and then send itself an interrupt
  * signal if the child process was terminated by an interrupt signal.
  * Unfortunately, some programs want to do a bit of cleanup and then
  * exit on interrupt; unless these processes terminate themselves by
@@ -632,41 +882,47 @@ forkshell(jp, n, mode)
  */
 
 int
-waitforjob(jp)
-       register struct job *jp;
-       {
+waitforjob(struct job *jp, int *origstatus)
+{
 #if JOBS
-       int mypgrp = getpgrp(0);
+       pid_t mypgrp = getpgrp();
 #endif
        int status;
        int st;
 
        INTOFF;
        TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
-       while (jp->state == 0 && dowait(1, jp) != -1) ;
+       while (jp->state == 0)
+               if (dowait(1, jp) == -1)
+                       dotrap();
 #if JOBS
        if (jp->jobctl) {
-               if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
-                       error("TIOCSPGRP failed, errno=%d\n", errno);
+               if (tcsetpgrp(ttyfd, mypgrp) < 0)
+                       error("tcsetpgrp failed, errno=%d\n", errno);
        }
        if (jp->state == JOBSTOPPED)
-               curjob = jp - jobtab + 1;
+               setcurjob(jp);
 #endif
        status = jp->ps[jp->nprocs - 1].status;
+       if (origstatus != NULL)
+               *origstatus = status;
        /* convert to 8 bits */
-       if ((status & 0xFF) == 0)
-               st = status >> 8 & 0xFF;
+       if (WIFEXITED(status))
+               st = WEXITSTATUS(status);
 #if JOBS
-       else if ((status & 0xFF) == 0177)
-               st = (status >> 8 & 0x7F) + 128;
+       else if (WIFSTOPPED(status))
+               st = WSTOPSIG(status) + 128;
 #endif
        else
-               st = (status & 0x7F) + 128;
+               st = WTERMSIG(status) + 128;
        if (! JOBS || jp->state == JOBDONE)
                freejob(jp);
-       CLEAR_PENDING_INT;
-       if ((status & 0x7F) == SIGINT)
-               kill(getpid(), SIGINT);
+       if (int_pending()) {
+               if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
+                       kill(getpid(), SIGINT);
+               else
+                       CLEAR_PENDING_INT;
+       }
        INTON;
        return st;
 }
@@ -677,25 +933,31 @@ waitforjob(jp)
  * Wait for a process to terminate.
  */
 
-STATIC int
-dowait(block, job)
-       struct job *job;
-       {
-       int pid;
-       int status;
+STATIC pid_t
+dowait(int block, struct job *job)
+{
+       pid_t pid;
+       int status, core;
        struct procstat *sp;
        struct job *jp;
        struct job *thisjob;
        int done;
        int stopped;
-       int core;
+       int sig;
+       int i;
 
+       in_dowait++;
        TRACE(("dowait(%d) called\n", block));
        do {
                pid = waitproc(block, &status);
-               TRACE(("wait returns %d, status=%d, errno=%d\n",
-                               pid, status, errno));
-       } while (pid == -1 && errno == EINTR);
+               TRACE(("wait returns %d, status=%d\n", (int)pid, status));
+       } while ((pid == -1 && errno == EINTR && breakwaitcmd == 0) ||
+                (pid > 0 && WIFSTOPPED(status) && !iflag));
+       in_dowait--;
+       if (breakwaitcmd != 0) {
+               breakwaitcmd = 0;
+               return -1;
+       }
        if (pid <= 0)
                return pid;
        INTOFF;
@@ -708,13 +970,15 @@ dowait(block, job)
                                if (sp->pid == -1)
                                        continue;
                                if (sp->pid == pid) {
-                                       TRACE(("Changin status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
+                                       TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
+                                                  (int)pid, sp->status,
+                                                  status));
                                        sp->status = status;
                                        thisjob = jp;
                                }
                                if (sp->status == -1)
                                        stopped = 0;
-                               else if ((sp->status & 0377) == 0177)
+                               else if (WIFSTOPPED(sp->status))
                                        done = 0;
                        }
                        if (stopped) {          /* stopped or done */
@@ -723,8 +987,8 @@ dowait(block, job)
                                        TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
                                        jp->state = state;
 #if JOBS
-                                       if (done && curjob == jp - jobtab + 1)
-                                               curjob = 0;             /* no current job */
+                                       if (done)
+                                               deljob(jp);
 #endif
                                }
                        }
@@ -732,32 +996,34 @@ dowait(block, job)
        }
        INTON;
        if (! rootshell || ! iflag || (job && thisjob == job)) {
+               core = WCOREDUMP(status);
 #if JOBS
-               if ((status & 0xFF) == 0177)
-                       status >>= 8;
-#endif
-               core = status & 0x80;
-               status &= 0x7F;
-               if (status != 0 && status != SIGINT && status != SIGPIPE) {
-                       if (thisjob != job)
-                               outfmt(out2, "%d: ", pid);
-#if JOBS
-                       if (status == SIGTSTP && rootshell && iflag)
-                               outfmt(out2, "%%%d ", job - jobtab + 1);
+               if (WIFSTOPPED(status))
+                       sig = WSTOPSIG(status);
+               else
 #endif
-                       if (status <= MAXSIG && sigmesg[status])
-                               out2str(sigmesg[status]);
+               {
+                       if (WIFEXITED(status))
+                               sig = 0;
                        else
-                               outfmt(out2, "Signal %d", status);
-                       if (core)
-                               out2str(" - core dumped");
-                       out2c('\n');
-                       flushout(&errout);
-               } else {
-                       TRACE(("Not printing status: status=%d\n", status));
+                               sig = WTERMSIG(status);
+               }
+               if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
+                       if (!mflag ||
+                           (thisjob->foreground && !WIFSTOPPED(status))) {
+                               i = WTERMSIG(status);
+                               if ((i & 0x7F) < _NSIG && strsiglist(i & 0x7F))
+                                       out1str(strsiglist(i & 0x7F));
+                               else
+                                       out1fmt("Signal %d", i & 0x7F);
+                               if (core)
+                                       out1str(" (core dumped)");
+                               out1c('\n');
+                       } else
+                               showjob(thisjob, pid, 0, 0);
                }
        } else {
-               TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
+               TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job));
                if (thisjob)
                        thisjob->changed = 1;
        }
@@ -770,80 +1036,58 @@ dowait(block, job)
  * Do a wait system call.  If job control is compiled in, we accept
  * stopped processes.  If block is zero, we return a value of zero
  * rather than blocking.
- *
- * System V doesn't have a non-blocking wait system call.  It does
- * have a SIGCLD signal that is sent to a process when one of it's
- * children dies.  The obvious way to use SIGCLD would be to install
- * a handler for SIGCLD which simply bumped a counter when a SIGCLD
- * was received, and have waitproc bump another counter when it got
- * the status of a process.  Waitproc would then know that a wait
- * system call would not block if the two counters were different.
- * This approach doesn't work because if a process has children that
- * have not been waited for, System V will send it a SIGCLD when it
- * installs a signal handler for SIGCLD.  What this means is that when
- * a child exits, the shell will be sent SIGCLD signals continuously
- * until is runs out of stack space, unless it does a wait call before
- * restoring the signal handler.  The code below takes advantage of
- * this (mis)feature by installing a signal handler for SIGCLD and
- * then checking to see whether it was called.  If there are any
- * children to be waited for, it will be.
- *
- * If neither SYSV nor BSD is defined, we don't implement nonblocking
- * waits at all.  In this case, the user will not be informed when
- * a background process until the next time she runs a real program
- * (as opposed to running a builtin command or just typing return),
- * and the jobs command may give out of date information.
  */
+STATIC pid_t
+waitproc(int block, int *status)
+{
+#if POSIX
+       int flags;
 
-#ifdef SYSV
-STATIC int gotsigchild;
-
-STATIC int onsigchild() {
-       gotsigchild = 1;
-}
-#endif
-
-
-STATIC int
-waitproc(block, status)
-       int *status;
-       {
-#ifdef BSD
+#if JOBS
+       flags = ((rootshell && is_interactive) ? WUNTRACED : 0);
+#else
+       flags = 0;
+#endif /* JOBS */
+       return waitpid(-1, status, (block == 0 ? WNOHANG : 0) | flags);
+#else /* !POSIX */
+       /* Assume BSD */
        int flags;
 
 #if JOBS
        flags = WUNTRACED;
 #else
        flags = 0;
-#endif
+#endif /* JOBS */
        if (block == 0)
                flags |= WNOHANG;
-       return wait3((union wait *)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 POSIX
-       return waitpid(-1, status, block == 0 ? WNOHANG : 0);
-#else
-       if (block == 0)
-               return 0;
-       return wait(status);
-#endif
-#endif
-#endif
+       return wait3(status, flags, (struct rusage *)NULL);
+#endif /* POSIX */
 }
 
+/*
+ * return 1 if there are stopped jobs, otherwise 0
+ */
+int job_warning = 0;
+int
+stoppedjobs(void)
+{
+       int jobno;
+       struct job *jp;
+
+       if (job_warning)
+               return (0);
+       for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
+               if (jp->used == 0)
+                       continue;
+               if (jp->state == JOBSTOPPED) {
+                       out2str("You have stopped jobs.\n");
+                       job_warning = 2;
+                       return (1);
+               }
+       }
 
+       return (0);
+}
 
 /*
  * Return a string identifying a command (to be printed by the
@@ -852,16 +1096,15 @@ waitproc(block, status)
 
 STATIC char *cmdnextc;
 STATIC int cmdnleft;
-STATIC void cmdtxt(), cmdputs();
+#define MAXCMDTEXT     200
 
-STATIC char *
-commandtext(n)
-       union node *n;
-       {
+char *
+commandtext(union node *n)
+{
        char *name;
 
-       cmdnextc = name = ckmalloc(50);
-       cmdnleft = 50 - 4;
+       cmdnextc = name = ckmalloc(MAXCMDTEXT);
+       cmdnleft = MAXCMDTEXT - 4;
        cmdtxt(n);
        *cmdnextc = '\0';
        return name;
@@ -869,17 +1112,16 @@ commandtext(n)
 
 
 STATIC void
-cmdtxt(n)
-       union node *n;
-       {
+cmdtxt(union node *n)
+{
        union node *np;
        struct nodelist *lp;
        char *p;
        int i;
        char s[2];
 
-       if (n == NULL) return;
-
+       if (n == NULL)
+               return;
        switch (n->type) {
        case NSEMI:
                cmdtxt(n->nbinary.ch1);
@@ -964,8 +1206,12 @@ until:
                p = ">>";  i = 1;  goto redir;
        case NTOFD:
                p = ">&";  i = 1;  goto redir;
+       case NCLOBBER:
+               p = ">|"; i = 1; goto redir;
        case NFROM:
                p = "<";  i = 0;  goto redir;
+       case NFROMTO:
+               p = "<>";  i = 0;  goto redir;
        case NFROMFD:
                p = "<&";  i = 0;  goto redir;
 redir:
@@ -976,7 +1222,10 @@ redir:
                }
                cmdputs(p);
                if (n->type == NTOFD || n->type == NFROMFD) {
-                       s[0] = n->ndup.dupfd + '0';
+                       if (n->ndup.dupfd >= 0)
+                               s[0] = n->ndup.dupfd + '0';
+                       else
+                               s[0] = '-';
                        s[1] = '\0';
                        cmdputs(s);
                } else {
@@ -996,11 +1245,10 @@ redir:
 
 
 STATIC void
-cmdputs(s)
-       char *s;
-       {
-       register char *p, *q;
-       register char c;
+cmdputs(char *s)
+{
+       char *p, *q;
+       char c;
        int subtype = 0;
 
        if (cmdnleft <= 0)
@@ -1020,7 +1268,7 @@ cmdputs(s)
                        subtype = 0;
                } else if (c == CTLENDVAR) {
                        *q++ = '}';
-               } else if (c == CTLBACKQ | c == CTLBACKQ+CTLQUOTE)
+               } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
                        cmdnleft++;             /* ignore it */
                else
                        *q++ = c;
@@ -1033,3 +1281,16 @@ cmdputs(s)
        }
        cmdnextc = q;
 }
+
+#ifdef NO_KILLPG
+static int killpg(grp, sig)
+pid_t grp;
+int sig;
+{
+       return kill(-grp, sig);
+}
+#endif
+
+/*
+ * $PchId: jobs.c,v 1.7 2006/05/22 12:02:13 philip Exp $
+ */
index b87262fe23040511df7cdee4a64c0a5167553ec5..db436aa8bc48dba46735bc9d275aab3edec52c47 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
@@ -33,7 +29,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)jobs.h      5.1 (Berkeley) 3/7/91
+ *     @(#)jobs.h      8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/jobs.h,v 1.18 2004/04/06 20:06:51 markm Exp $
  */
 
 /* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
@@ -41,6 +38,7 @@
 #define FORK_BG 1
 #define FORK_NOJOB 2
 
+#include <signal.h>            /* for sig_atomic_t */
 
 /*
  * A job structure contains information about a job.  A job is either a
@@ -51,7 +49,7 @@
 
 struct procstat {
        pid_t pid;              /* process id */
-       short status;           /* status flags (defined above) */
+       int status;             /* status flags (defined above) */
        char *cmd;              /* text of command being run */
 };
 
@@ -64,33 +62,41 @@ struct procstat {
 struct job {
        struct procstat ps0;    /* status of process */
        struct procstat *ps;    /* status or processes when more than one */
-       pid_t nprocs;           /* number of processes */
+       short nprocs;           /* number of processes */
        pid_t 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 */
+       char foreground;        /* true if running in the foreground */
 #if JOBS
        char jobctl;            /* job running under job control */
+       struct job *next;       /* job used after this one */
 #endif
 };
 
 extern pid_t backgndpid;       /* pid of last background process */
+extern int job_warning;                /* user was warned about stopped jobs */
+extern int in_waitcmd;         /* are we in waitcmd()? */
+extern int in_dowait;          /* are we in dowait()? */
+extern volatile sig_atomic_t breakwaitcmd; /* break wait to process traps? */
 
-
-#ifdef __STDC__
 void setjobctl(int);
-void showjobs(int);
+int fgcmd(int, char **);
+int bgcmd(int, char **);
+int jobscmd(int, char **);
+void showjobs(int, int, int);
+int waitcmd(int, char **);
+int jobidcmd(int, char **);
 struct job *makejob(union node *, int);
-int forkshell(struct job *, union node *, int);
-int waitforjob(struct job *);
-#else
-void setjobctl();
-void showjobs();
-struct job *makejob();
-int forkshell();
-int waitforjob();
-#endif
+pid_t forkshell(struct job *, union node *, int);
+int waitforjob(struct job *, int *);
+int stoppedjobs(void);
+char *commandtext(union node *);
 
 #if ! JOBS
 #define setjobctl(on)  /* do nothing */
 #endif
+
+/*
+ * $PchId: jobs.h,v 1.4 2006/03/30 12:07:24 philip Exp $
+ */
index e4ee3c94451eb4ae90d2aa3d64a1118c4943972c..4de7acd21e03536cabccd0dcf74ec4c3ad5902b9 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
@@ -33,7 +33,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)machdep.h   5.1 (Berkeley) 3/7/91
+ *     @(#)machdep.h   8.2 (Berkeley) 5/4/95
  */
 
 /*
@@ -47,5 +47,9 @@ union align {
        char *cp;
 };
 
-#define ALIGN(nbytes)  ((nbytes) + sizeof(union align) - 1 &~ (sizeof(union align) - 1))
+#define ALIGN(nbytes)  (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
 #endif
+
+/*
+ * $PchId: machdep.h,v 1.2 2001/05/15 16:36:26 philip Exp $
+ */
index a90d4a0117a8cf3f78499f793e4ad44b486fec88..14bc1d91e7e51a87d8d544ba488a8e1300bfde76 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)mail.c     5.1 (Berkeley) 3/7/91";
+#if 0
+static char sccsid[] = "@(#)mail.c     8.2 (Berkeley) 5/4/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/mail.c,v 1.13 2004/04/06 20:06:51 markm Exp $");
+*/
 
 /*
  * Routines to check for mail.  (Perhaps make part of main.c?)
@@ -48,8 +50,10 @@ static char sccsid[] = "@(#)mail.c   5.1 (Berkeley) 3/7/91";
 #include "output.h"
 #include "memalloc.h"
 #include "error.h"
+#include "mail.h"
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <stdlib.h>
 
 
 #define MAXMBOXES 10
@@ -67,11 +71,12 @@ STATIC time_t mailtime[MAXMBOXES];  /* times of mailboxes */
  */
 
 void
-chkmail(silent) {
-       register int i;
+chkmail(int silent)
+{
+       int i;
        char *mpath;
        char *p;
-       register char *q;
+       char *q;
        struct stackmark smark;
        struct stat statb;
 
@@ -91,18 +96,28 @@ chkmail(silent) {
                if (q[-1] != '/')
                        abort();
                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 (!silent
-                       && statb.st_size > 0
-                       && statb.st_mtime > mailtime[i]
-                       && statb.st_mtime > statb.st_atime
-               ) {
-                       out2str(pathopt? pathopt : "You have mail");
+               if (statb.st_mtime > mailtime[i] && ! silent) {
+                       out2str(pathopt? pathopt : "you have mail");
                        out2c('\n');
                }
                mailtime[i] = statb.st_mtime;
+#else /* this is what it should do */
+               if (stat(p, &statb) < 0)
+                       statb.st_size = 0;
+               if (statb.st_size > mailtime[i] && ! silent) {
+                       out2str(pathopt? pathopt : "you have mail");
+                       out2c('\n');
+               }
+               mailtime[i] = statb.st_size;
+#endif
        }
        nmboxes = i;
        popstackmark(&smark);
 }
+
+/*
+ * $PchId: mail.c,v 1.5 2006/05/22 12:02:37 philip Exp $
+ */
index 8280791e81646bd170e5f3c20c66404a8255a1ff..4d67b0ae920ae527959aca1eec1403eafbcd77dc 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)mail.h      5.1 (Berkeley) 3/7/91
+ *     @(#)mail.h      8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/mail.h,v 1.8 2004/04/06 20:06:51 markm Exp $
  */
 
-#ifdef __STDC__
 void chkmail(int);
-#else
-void chkmail();
-#endif
+
+/*
+ * $PchId: mail.h,v 1.3 2006/03/30 11:53:44 philip Exp $
+ */
index e8200eaf2c542a67be868470fa3a419cedd77b9d..262756db4e390d4c37bc53533ab5b2342aee20e8 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1991 The Regents of the University of California.\n\
- All rights reserved.\n";
+static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)main.c     5.2 (Berkeley) 3/13/91";
+#if 0
+static char sccsid[] = "@(#)main.c     8.6 (Berkeley) 5/28/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/main.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
+*/
 
-#include <sys/types.h>
+#include <stdio.h>
 #include <signal.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <fcntl.h>
+#include <locale.h>
+#include <errno.h>
+
 #include "shell.h"
 #include "main.h"
 #include "mail.h"
@@ -54,38 +61,26 @@ static char sccsid[] = "@(#)main.c  5.2 (Berkeley) 3/13/91";
 #include "output.h"
 #include "parser.h"
 #include "nodes.h"
+#include "expand.h"
 #include "eval.h"
 #include "jobs.h"
 #include "input.h"
 #include "trap.h"
-#if ATTY
 #include "var.h"
-#endif
+#include "show.h"
 #include "memalloc.h"
 #include "error.h"
 #include "init.h"
 #include "mystring.h"
-
-#define PROFILE 0
+#include "exec.h"
+#include "cd.h"
+#include "builtins.h"
 
 int rootpid;
 int rootshell;
-STATIC union node *curcmd;
-STATIC union node *prevcmd;
-extern int errno;
-#if PROFILE
-short profile_buf[16384];
-extern int etext();
-#endif
 
-#ifdef __STDC__
 STATIC void read_profile(char *);
-char *getenv(char *);
-#else
-STATIC void read_profile();
-char *getenv();
-#endif
-
+STATIC char *find_dot_file(char *);
 
 /*
  * Main routine.  We initialize things, parse the arguments, execute
@@ -95,16 +90,15 @@ char *getenv();
  * is used to figure out how far we had gotten.
  */
 
-main(argc, argv)  char **argv; {
+int
+main(int argc, char *argv[])
+{
        struct jmploc jmploc;
        struct stackmark smark;
        volatile int state;
-       char *shinit, *home;
-       char *profile = NULL, *ashrc = NULL;
+       char *shinit;
 
-#if PROFILE
-       monitor(4, etext, profile_buf, sizeof profile_buf, 50);
-#endif
+       (void) setlocale(LC_ALL, "");
        state = 0;
        if (setjmp(jmploc.loc)) {
                /*
@@ -112,21 +106,32 @@ main(argc, argv)  char **argv; {
                 * exception EXSHELLPROC to clean up before executing
                 * the shell procedure.
                 */
-               if (exception == EXSHELLPROC) {
+               switch (exception) {
+               case EXSHELLPROC:
                        rootpid = getpid();
                        rootshell = 1;
                        minusc = NULL;
                        state = 3;
-               } else if (state == 0 || iflag == 0 || ! rootshell)
-                       exitshell(2);
+                       break;
+
+               case EXEXEC:
+                       exitstatus = exerrno;
+                       break;
+
+               case EXERROR:
+                       exitstatus = 2;
+                       break;
+
+               default:
+                       break;
+               }
+
+               if (exception != EXSHELLPROC) {
+                   if (state == 0 || iflag == 0 || ! rootshell)
+                           exitshell(exitstatus);
+               }
                reset();
-#if ATTY
-               if (exception == EXINT
-                && (! attyset() || equal(termval(), "emacs")))
-#else
-               if (exception == EXINT)
-#endif
-               {
+               if (exception == EXINT) {
                        out2c('\n');
                        flushout(&errout);
                }
@@ -151,57 +156,38 @@ main(argc, argv)  char **argv; {
        init();
        setstackmark(&smark);
        procargs(argc, argv);
-       if (eflag) eflag = 2;   /* Truly enable [ex]flag after init. */
-       if (xflag) xflag = 2;
+       if (getpwd() == NULL && iflag)
+               out2str("sh: cannot determine working directory\n");
        if (argv[0] && argv[0][0] == '-') {
                state = 1;
                read_profile("/etc/profile");
 state1:
                state = 2;
-               if ((home = getenv("HOME")) != NULL
-                   && (profile = (char *) malloc(strlen(home) + 10)) != NULL)
-               {
-                       strcpy(profile, home);
-                       strcat(profile, "/.profile");
-                       read_profile(profile);
-               } else {
+               if (privileged == 0)
                        read_profile(".profile");
-               }
-       } else if ((sflag || minusc) && (shinit = getenv("SHINIT")) != NULL) {
-               state = 2;
-               evalstring(shinit);
+               else
+                       read_profile("/etc/suid_profile");
        }
 state2:
-       if (profile != NULL) free(profile);
-
        state = 3;
-       if (!argv[0] || argv[0][0] != '-') {
-               if ((home = getenv("HOME")) != NULL
-                       && (ashrc = (char *) malloc(strlen(home) + 8)) != NULL)
-               {
-                       strcpy(ashrc, home);
-                       strcat(ashrc, "/.ashrc");
-                       read_profile(ashrc);
+       if (!privileged && iflag) {
+               if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
+                       state = 3;
+                       read_profile(shinit);
                }
        }
 state3:
-       if (ashrc != NULL) free(ashrc);
-       if (eflag) eflag = 1;   /* Init done, enable [ex]flag */
-       if (xflag) xflag = 1;
-       exitstatus = 0;         /* Init shouldn't influence initial $? */
-
        state = 4;
        if (minusc) {
                evalstring(minusc);
        }
        if (sflag || minusc == NULL) {
-state4:
+state4:        /* XXX ??? - why isn't this before the "if" statement */
                cmdloop(1);
        }
-#if PROFILE
-       monitor(0);
-#endif
        exitshell(exitstatus);
+       /*NOTREACHED*/
+       return 0;
 }
 
 
@@ -211,52 +197,49 @@ state4:
  */
 
 void
-cmdloop(top) {
+cmdloop(int top)
+{
        union node *n;
        struct stackmark smark;
        int inter;
-       int numeof;
+       int numeof = 0;
 
        TRACE(("cmdloop(%d) called\n", top));
        setstackmark(&smark);
-       numeof = 0;
        for (;;) {
                if (pendingsigs)
                        dotrap();
                inter = 0;
                if (iflag && top) {
                        inter++;
-                       showjobs(1);
+                       showjobs(1, 0, 0);
                        chkmail(0);
                        flushout(&output);
                }
                n = parsecmd(inter);
-#if DEBUG
-               /* showtree(n); */
-#endif
+               /* showtree(n); DEBUG */
                if (n == NEOF) {
-                       if (Iflag == 0 || numeof >= 50)
+                       if (!top || numeof >= 50)
                                break;
-                       out2str("\nUse \"exit\" to leave shell.\n");
+                       if (!stoppedjobs()) {
+                               if (!Iflag)
+                                       break;
+                               out2str("\nUse \"exit\" to leave shell.\n");
+                       }
                        numeof++;
                } else if (n != NULL && nflag == 0) {
-                       if (inter) {
-                               INTOFF;
-                               if (prevcmd)
-                                       freefunc(prevcmd);
-                               prevcmd = curcmd;
-                               curcmd = copyfunc(n);
-                               INTON;
-                       }
+                       job_warning = (job_warning == 2) ? 1 : 0;
+                       numeof = 0;
                        evaltree(n, 0);
-#ifdef notdef
-                       if (exitstatus)                               /*DEBUG*/
-                               outfmt(&errout, "Exit status 0x%X\n", exitstatus);
-#endif
                }
                popstackmark(&smark);
+               setstackmark(&smark);
+               if (evalskip == SKIPFILE) {
+                       evalskip = 0;
+                       break;
+               }
        }
-       popstackmark(&smark);           /* unnecessary */
+       popstackmark(&smark);
 }
 
 
@@ -266,9 +249,8 @@ cmdloop(top) {
  */
 
 STATIC void
-read_profile(name)
-       char *name;
-       {
+read_profile(char *name)
+{
        int fd;
 
        INTOFF;
@@ -288,32 +270,63 @@ read_profile(name)
  */
 
 void
-readcmdfile(name)
-       char *name;
-       {
+readcmdfile(char *name)
+{
        int fd;
 
        INTOFF;
        if ((fd = open(name, O_RDONLY)) >= 0)
                setinputfd(fd, 1);
        else
-               error("Can't open %s", name);
+               error("Can't open %s: %s", name, strerror(errno));
        INTON;
        cmdloop(0);
        popfile();
 }
 
 
+
 /*
- * Take commands from a file.  To be compatable we should do a path
- * search for the file, but a path search doesn't make any sense.
+ * Take commands from a file.  To be compatible we should do a path
+ * search for the file, which is necessary to find sub-commands.
  */
 
-dotcmd(argc, argv)  char **argv; {
+
+STATIC char *
+find_dot_file(char *basename)
+{
+       static char localname[FILENAME_MAX+1];
+       char *fullname;
+       char *path = pathval();
+       struct stat statb;
+
+       /* don't try this for absolute or relative paths */
+       if( strchr(basename, '/'))
+               return basename;
+
+       while ((fullname = padvance(&path, basename)) != NULL) {
+               strcpy(localname, fullname);
+               stunalloc(fullname);
+               if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode))
+                       return localname;
+       }
+       return basename;
+}
+
+int
+dotcmd(int argc, char **argv)
+{
+       struct strlist *sp;
        exitstatus = 0;
+
+       for (sp = cmdenviron; sp ; sp = sp->next)
+               setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
+
        if (argc >= 2) {                /* That's what SVR2 does */
-               setinputfile(argv[1], 1);
-               commandname = argv[1];
+               char *fullname = find_dot_file(argv[1]);
+
+               setinputfile(fullname, 1);
+               commandname = fullname;
                cmdloop(0);
                popfile();
        }
@@ -321,40 +334,22 @@ dotcmd(argc, argv)  char **argv; {
 }
 
 
-exitcmd(argc, argv)  char **argv; {
+int
+exitcmd(int argc, char **argv)
+{
        extern int oexitstatus;
+
+       if (stoppedjobs())
+               return 0;
        if (argc > 1)
                exitstatus = number(argv[1]);
        else
                exitstatus = oexitstatus;
        exitshell(exitstatus);
+       /*NOTREACHED*/
+       return 0;
 }
 
-
-lccmd(argc, argv)  char **argv; {
-       if (argc > 1) {
-               defun(argv[1], prevcmd);
-               return 0;
-       } else {
-               INTOFF;
-               freefunc(curcmd);
-               curcmd = prevcmd;
-               prevcmd = NULL;
-               INTON;
-               evaltree(curcmd, 0);
-               return exitstatus;
-       }
-}
-
-
-
-#ifdef notdef
 /*
- * Should never be called.
+ * $PchId: main.c,v 1.5 2006/05/22 12:03:02 philip Exp $
  */
-
-void
-exit(exitstatus) {
-       _exit(exitstatus);
-}
-#endif
index c5fda20ce0b815612e36581967a2fedc8dc7bffc..55ab91b7a1d12b8cc4ea4b9487905526e8ac1aff 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)main.h      5.1 (Berkeley) 3/7/91
+ *     @(#)main.h      8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/main.h,v 1.8 2004/04/06 20:06:51 markm Exp $
  */
 
 extern int rootpid;    /* pid of main shell */
 extern int rootshell;  /* true if we aren't a child of the main shell */
 
-#ifdef __STDC__
 void readcmdfile(char *);
 void cmdloop(int);
-#else
-void readcmdfile();
-void cmdloop();
-#endif
+int dotcmd(int, char **);
+int exitcmd(int, char **);
+
+/*
+ * $PchId: main.h,v 1.3 2006/03/30 11:43:59 philip Exp $
+ */
index 31fcd3a3a3d04e3c12cdd4e9322660485b17cccb..8f567cce945c3c9c1fee82ee760a8190e392c4b5 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)memalloc.c 5.2 (Berkeley) 3/13/91";
+#if 0
+static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/memalloc.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
+*/
 
 #include "shell.h"
 #include "output.h"
+#include "machdep.h"
 #include "memalloc.h"
 #include "error.h"
-#include "machdep.h"
 #include "mystring.h"
+#include "expand.h"
+#include <stdlib.h>
+#include <unistd.h>
 
 /*
  * Like malloc, but returns an error when out of space.
  */
 
 pointer
-ckmalloc(nbytes) {
-       register pointer p;
-       pointer malloc();
+ckmalloc(int nbytes)
+{
+       pointer p;
 
        if ((p = malloc(nbytes)) == NULL)
                error("Out of space");
@@ -65,11 +70,8 @@ ckmalloc(nbytes) {
  */
 
 pointer
-ckrealloc(p, nbytes)
-       register pointer p;
-       {
-       pointer realloc();
-
+ckrealloc(pointer p, int nbytes)
+{
        if ((p = realloc(p, nbytes)) == NULL)
                error("Out of space");
        return p;
@@ -81,10 +83,9 @@ ckrealloc(p, nbytes)
  */
 
 char *
-savestr(s)
-       char *s;
-       {
-       register char *p;
+savestr(char *s)
+{
+       char *p;
 
        p = ckmalloc(strlen(s) + 1);
        scopy(s, p);
@@ -97,47 +98,56 @@ savestr(s)
  * 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.
+ * The size 496 was chosen because with 16-byte alignment the total size
+ * for the allocated block is 512.
  */
 
-#define MINSIZE 504            /* minimum size of a block */
+#define MINSIZE 496            /* minimum size of a block. */
 
 
 struct stack_block {
        struct stack_block *prev;
-       char space[MINSIZE];
+       /* Data follows */
 };
+#define SPACE(sp)      ((char*)(sp) + ALIGN(sizeof(struct stack_block)))
 
-struct stack_block stackbase;
-struct stack_block *stackp = &stackbase;
-char *stacknxt = stackbase.space;
-int stacknleft = MINSIZE;
+STATIC struct stack_block *stackp;
+STATIC struct stackmark *markp;
+char *stacknxt;
+int stacknleft;
 int sstrnleft;
 int herefd = -1;
 
 
+static void
+stnewblock(int nbytes)
+{
+       struct stack_block *sp;
+       int allocsize;
+
+       if (nbytes < MINSIZE)
+               nbytes = MINSIZE;
+
+       allocsize = ALIGN(sizeof(struct stack_block)) + ALIGN(nbytes);
+
+       INTOFF;
+       sp = ckmalloc(allocsize);
+       sp->prev = stackp;
+       stacknxt = SPACE(sp);
+       stacknleft = allocsize - (stacknxt - (char*)sp);
+       stackp = sp;
+       INTON;
+}
+
 
 pointer
-stalloc(nbytes) {
-       register char *p;
+stalloc(int nbytes)
+{
+       char *p;
 
        nbytes = ALIGN(nbytes);
-       if (nbytes > stacknleft) {
-               int blocksize;
-               struct stack_block *sp;
-
-               blocksize = nbytes;
-               if (blocksize < MINSIZE)
-                       blocksize = MINSIZE;
-               INTOFF;
-               sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
-               sp->prev = stackp;
-               stacknxt = sp->space;
-               stacknleft = blocksize;
-               stackp = sp;
-               INTON;
-       }
+       if (nbytes > stacknleft)
+               stnewblock(nbytes);
        p = stacknxt;
        stacknxt += nbytes;
        stacknleft -= nbytes;
@@ -146,11 +156,10 @@ stalloc(nbytes) {
 
 
 void
-stunalloc(p)
-       pointer p;
-       {
+stunalloc(pointer p)
+{
        if (p == NULL) {                /*DEBUG */
-               write(2, "stunalloc\n", 10);
+               write(STDERR_FILENO, "stunalloc\n", 10);
                abort();
        }
        stacknleft += stacknxt - (char *)p;
@@ -160,22 +169,23 @@ stunalloc(p)
 
 
 void
-setstackmark(mark)
-       struct stackmark *mark;
-       {
+setstackmark(struct stackmark *mark)
+{
        mark->stackp = stackp;
        mark->stacknxt = stacknxt;
        mark->stacknleft = stacknleft;
+       mark->marknext = markp;
+       markp = mark;
 }
 
 
 void
-popstackmark(mark)
-       struct stackmark *mark;
-       {
+popstackmark(struct stackmark *mark)
+{
        struct stack_block *sp;
 
        INTOFF;
+       markp = mark->marknext;
        while (stackp != mark->stackp) {
                sp = stackp;
                stackp = sp->prev;
@@ -198,35 +208,56 @@ popstackmark(mark)
  */
 
 void
-growstackblock() {
+growstackblock(void)
+{
        char *p;
-       int newlen = stacknleft * 2 + 100;
-       char *oldspace = stacknxt;
-       int oldlen = stacknleft;
+       int newlen;
+       char *oldspace;
+       int oldlen;
        struct stack_block *sp;
+       struct stack_block *oldstackp;
+       struct stackmark *xmark;
 
-       if (stacknxt == stackp->space && stackp != &stackbase) {
+       newlen = (stacknleft == 0) ? MINSIZE : stacknleft * 2 + 100;
+       newlen = ALIGN(newlen);
+       oldspace = stacknxt;
+       oldlen = stacknleft;
+
+       if (stackp != NULL && stacknxt == SPACE(stackp)) {
                INTOFF;
-               sp = stackp;
-               stackp = sp->prev;
-               sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
+               oldstackp = stackp;
+               stackp = oldstackp->prev;
+               sp = ckrealloc((pointer)oldstackp, newlen);
                sp->prev = stackp;
                stackp = sp;
-               stacknxt = sp->space;
-               stacknleft = newlen;
+               stacknxt = SPACE(sp);
+               stacknleft = newlen - (stacknxt - (char*)sp);
+
+               /*
+                * Stack marks pointing to the start of the old block
+                * must be relocated to point to the new block
+                */
+               xmark = markp;
+               while (xmark != NULL && xmark->stackp == oldstackp) {
+                       xmark->stackp = stackp;
+                       xmark->stacknxt = stacknxt;
+                       xmark->stacknleft = stacknleft;
+                       xmark = xmark->marknext;
+               }
                INTON;
        } else {
                p = stalloc(newlen);
-               bcopy(oldspace, p, oldlen);
-               stacknxt = p;                   /* free the space */
-               stacknleft += newlen;           /* we just allocated */
+               if (oldlen != 0)
+                       memcpy(p, oldspace, oldlen);
+               stunalloc(p);
        }
 }
 
 
 
 void
-grabstackblock(len) {
+grabstackblock(int len)
+{
        len = ALIGN(len);
        stacknxt += len;
        stacknleft -= len;
@@ -254,8 +285,11 @@ grabstackblock(len) {
 
 
 char *
-growstackstr() {
-       int len = stackblocksize();
+growstackstr(void)
+{
+       int len;
+
+       len = stackblocksize();
        if (herefd >= 0 && len >= 1024) {
                xwrite(herefd, stackblock(), len);
                sstrnleft = len - 1;
@@ -272,8 +306,11 @@ growstackstr() {
  */
 
 char *
-makestrspace() {
-       int len = stackblocksize() - sstrnleft;
+makestrspace(void)
+{
+       int len;
+
+       len = stackblocksize() - sstrnleft;
        growstackblock();
        sstrnleft = stackblocksize() - len;
        return stackblock() + len;
@@ -282,11 +319,13 @@ makestrspace() {
 
 
 void
-ungrabstackstr(s, p)
-       char *s;
-       char *p;
-       {
+ungrabstackstr(char *s, char *p)
+{
        stacknleft += stacknxt - s;
        stacknxt = s;
        sstrnleft = stacknleft - (p - s);
 }
+
+/*
+ * $PchId: memalloc.c,v 1.5 2006/05/22 12:03:26 philip Exp $
+ */
index 4c663ae20158abff1478d47511e8d32dcb91fd38..f3c9138f08f276592a0770f53874e89dd64d3289 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)memalloc.h  5.1 (Berkeley) 3/7/91
+ *     @(#)memalloc.h  8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/memalloc.h,v 1.9 2004/04/06 20:06:51 markm Exp $
  */
 
 struct stackmark {
        struct stack_block *stackp;
        char *stacknxt;
        int stacknleft;
+        struct stackmark *marknext;
 };
 
 
@@ -48,10 +46,8 @@ extern int stacknleft;
 extern int sstrnleft;
 extern int herefd;
 
-#ifdef __STDC__
 pointer ckmalloc(int);
 pointer ckrealloc(pointer, int);
-void free(pointer);            /* defined in C library */
 char *savestr(char *);
 pointer stalloc(int);
 void stunalloc(pointer);
@@ -62,21 +58,6 @@ void grabstackblock(int);
 char *growstackstr(void);
 char *makestrspace(void);
 void ungrabstackstr(char *, char *);
-#else
-pointer ckmalloc();
-pointer ckrealloc();
-void free();           /* defined in C library */
-char *savestr();
-pointer stalloc();
-void stunalloc();
-void setstackmark();
-void popstackmark();
-void growstackblock();
-void grabstackblock();
-char *growstackstr();
-char *makestrspace();
-void ungrabstackstr();
-#endif
 
 
 
@@ -84,7 +65,7 @@ void ungrabstackstr();
 #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(); else
+#define CHECKSTRSPACE(n, p)    { if (sstrnleft < n) p = makestrspace(); }
 #define USTPUTC(c, p)  (--sstrnleft, *p++ = (c))
 #define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
 #define STUNPUTC(p)    (++sstrnleft, --p)
@@ -93,3 +74,7 @@ void ungrabstackstr();
 #define grabstackstr(p)        stalloc(stackblocksize() - sstrnleft)
 
 #define ckfree(p)      free((pointer)(p))
+
+/*
+ * $PchId: memalloc.h,v 1.3 2006/03/30 11:39:41 philip Exp $
+ */
index f8345b4a6583df695e7df3fd3feb4ea380e32511..86f05788d64cf2e96d5d064954fceb97acb09a2e 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)miscbltin.c        5.2 (Berkeley) 3/13/91";
+#if 0
+static char sccsid[] = "@(#)miscbltin.c        8.4 (Berkeley) 5/4/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/miscbltin.c,v 1.30 2004/04/06 20:06:51 markm Exp $");
+*/
 
 /*
- * Miscelaneous builtins.
+ * Miscellaneous builtins.
  */
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+
 #include "shell.h"
 #include "options.h"
 #include "var.h"
@@ -49,38 +64,71 @@ static char sccsid[] = "@(#)miscbltin.c     5.2 (Berkeley) 3/13/91";
 #include "memalloc.h"
 #include "error.h"
 #include "mystring.h"
+#include "builtins.h"
 
 #undef eflag
 
-extern char **argptr;          /* argument list for builtin command */
-
-
 /*
- * The read builtin.  The -e option causes backslashes to escape the
- * following character.
+ * The read builtin.  The -r option causes backslashes to be treated like
+ * ordinary characters.
  *
  * This uses unbuffered input, which may be avoidable in some cases.
  */
 
-readcmd(argc, argv)  char **argv; {
+int
+readcmd(int argc __unused, char **argv __unused)
+{
        char **ap;
        int backslash;
        char c;
-       int eflag;
+       int rflag;
        char *prompt;
        char *ifs;
        char *p;
        int startword;
        int status;
        int i;
+       struct timeval tv;
+       char *tvptr;
+#ifndef __minix_vmd
+       fd_set ifds;
+#endif
+       struct termios told, tnew;
+       int tsaved;
 
-       eflag = 0;
+       rflag = 0;
        prompt = NULL;
-       while ((i = nextopt("ep:")) != '\0') {
-               if (i == 'p')
-                       prompt = optarg;
-               else
-                       eflag = 1;
+       tv.tv_sec = -1;
+       tv.tv_usec = 0;
+       while ((i = nextopt("erp:t:")) != '\0') {
+               switch(i) {
+               case 'p':
+                       prompt = shoptarg;
+                       break;
+               case 'e':
+                       break;
+               case 'r':
+                       rflag = 1;
+                       break;
+               case 't':
+                       tv.tv_sec = strtol(shoptarg, &tvptr, 0);
+                       if (tvptr == shoptarg)
+                               error("timeout value");
+                       switch(*tvptr) {
+                       case 0:
+                       case 's':
+                               break;
+                       case 'h':
+                               tv.tv_sec *= 60;
+                               /* FALLTHROUGH */
+                       case 'm':
+                               tv.tv_sec *= 60;
+                               break;
+                       default:
+                               error("timeout unit");
+                       }
+                       break;
+               }
        }
        if (prompt && isatty(0)) {
                out2str(prompt);
@@ -90,12 +138,45 @@ readcmd(argc, argv)  char **argv; {
                error("arg count");
        if ((ifs = bltinlookup("IFS", 1)) == NULL)
                ifs = nullstr;
+
+       if (tv.tv_sec >= 0) {
+#ifdef __minix
+               abort();
+#else
+               /*
+                * See if we can disable input processing; this will
+                * not give the desired result if we are in a pipeline
+                * and someone upstream is still in line-by-line mode.
+                */
+               tsaved = 0;
+               if (tcgetattr(0, &told) == 0) {
+                       memcpy(&tnew, &told, sizeof(told));
+                       cfmakeraw(&tnew);
+                       tcsetattr(0, TCSANOW, &tnew);
+                       tsaved = 1;
+               }
+               /*
+                * Wait for something to become available.
+                */
+               FD_ZERO(&ifds);
+               FD_SET(0, &ifds);
+               status = select(1, &ifds, NULL, NULL, &tv);
+               if (tsaved)
+                       tcsetattr(0, TCSANOW, &told);
+               /*
+                * If there's nothing ready, return an error.
+                */
+               if (status <= 0)
+                       return(1);
+#endif
+       }
+
        status = 0;
        startword = 1;
        backslash = 0;
        STARTSTACKSTR(p);
        for (;;) {
-               if (read(0, &c, 1) != 1) {
+               if (read(STDIN_FILENO, &c, 1) != 1) {
                        status = 1;
                        break;
                }
@@ -107,7 +188,7 @@ readcmd(argc, argv)  char **argv; {
                                STPUTC(c, p);
                        continue;
                }
-               if (eflag && c == '\\') {
+               if (!rflag && c == '\\') {
                        backslash++;
                        continue;
                }
@@ -118,7 +199,7 @@ readcmd(argc, argv)  char **argv; {
                }
                startword = 0;
                if (backslash && c == '\\') {
-                       if (read(0, &c, 1) != 1) {
+                       if (read(STDIN_FILENO, &c, 1) != 1) {
                                status = 1;
                                break;
                        }
@@ -142,25 +223,274 @@ readcmd(argc, argv)  char **argv; {
 
 
 
-umaskcmd(argc, argv)  char **argv; {
+int
+umaskcmd(int argc __unused, char **argv)
+{
+       char *ap;
        int mask;
-       char *p;
        int i;
+       int symbolic_mode = 0;
+
+       while ((i = nextopt("S")) != '\0') {
+               symbolic_mode = 1;
+       }
+
+       INTOFF;
+       mask = umask(0);
+       umask(mask);
+       INTON;
+
+       if ((ap = *argptr) == NULL) {
+               if (symbolic_mode) {
+                       char u[4], g[4], o[4];
+
+                       i = 0;
+                       if ((mask & S_IRUSR) == 0)
+                               u[i++] = 'r';
+                       if ((mask & S_IWUSR) == 0)
+                               u[i++] = 'w';
+                       if ((mask & S_IXUSR) == 0)
+                               u[i++] = 'x';
+                       u[i] = '\0';
+
+                       i = 0;
+                       if ((mask & S_IRGRP) == 0)
+                               g[i++] = 'r';
+                       if ((mask & S_IWGRP) == 0)
+                               g[i++] = 'w';
+                       if ((mask & S_IXGRP) == 0)
+                               g[i++] = 'x';
+                       g[i] = '\0';
+
+                       i = 0;
+                       if ((mask & S_IROTH) == 0)
+                               o[i++] = 'r';
+                       if ((mask & S_IWOTH) == 0)
+                               o[i++] = 'w';
+                       if ((mask & S_IXOTH) == 0)
+                               o[i++] = 'x';
+                       o[i] = '\0';
+
+                       out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
+               } else {
+                       out1fmt("%.4o\n", mask);
+               }
+       } else {
+               if (isdigit(*ap)) {
+                       mask = 0;
+                       do {
+                               if (*ap >= '8' || *ap < '0')
+                                       error("Illegal number: %s", argv[1]);
+                               mask = (mask << 3) + (*ap - '0');
+                       } while (*++ap != '\0');
+                       umask(mask);
+               } else {
+                       void *set;
+                       if ((set = setmode (ap)) == 0)
+                               error("Illegal number: %s", ap);
+
+                       mask = getmode (set, ~mask & 0777);
+                       umask(~mask & 0777);
+                       free(set);
+               }
+       }
+       return 0;
+}
 
-       if ((p = argv[1]) == NULL) {
-               INTOFF;
-               mask = umask(0);
-               umask(mask);
-               INTON;
-               out1fmt("%.4o\n", mask);        /* %#o might be better */
+#ifdef __minix
+struct rlimit
+{
+        unsigned long  rlim_cur;       /* current (soft) limit */
+       unsigned long  rlim_max;        /* maximum value for rlim_cur */
+};
+#define RLIM_INFINITY   (((unsigned long)1 << 31) - 1)
+
+int getrlimit (int, struct rlimit *);
+int setrlimit (int, const struct rlimit *);
+
+int getrlimit(resource, rlp)
+int resource;
+struct rlimit *rlp;
+{
+       errno= ENOSYS;
+       return -1;
+}
+int setrlimit(resource, rlp)
+int resource;
+const struct rlimit *rlp;
+{
+       errno= ENOSYS;
+       return -1;
+}
+#endif
+
+/*
+ * ulimit builtin
+ *
+ * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
+ * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
+ * ash by J.T. Conklin.
+ *
+ * Public domain.
+ */
+
+struct limits {
+       const char *name;
+       const char *units;
+       int     cmd;
+       int     factor; /* multiply by to get rlim_{cur,max} values */
+       char    option;
+};
+
+static const struct limits limits[] = {
+#ifdef RLIMIT_CPU
+       { "cpu time",           "seconds",      RLIMIT_CPU,        1, 't' },
+#endif
+#ifdef RLIMIT_FSIZE
+       { "file size",          "512-blocks",   RLIMIT_FSIZE,    512, 'f' },
+#endif
+#ifdef RLIMIT_DATA
+       { "data seg size",      "kbytes",       RLIMIT_DATA,    1024, 'd' },
+#endif
+#ifdef RLIMIT_STACK
+       { "stack size",         "kbytes",       RLIMIT_STACK,   1024, 's' },
+#endif
+#ifdef  RLIMIT_CORE
+       { "core file size",     "512-blocks",   RLIMIT_CORE,     512, 'c' },
+#endif
+#ifdef RLIMIT_RSS
+       { "max memory size",    "kbytes",       RLIMIT_RSS,     1024, 'm' },
+#endif
+#ifdef RLIMIT_MEMLOCK
+       { "locked memory",      "kbytes",       RLIMIT_MEMLOCK, 1024, 'l' },
+#endif
+#ifdef RLIMIT_NPROC
+       { "max user processes", (char *)0,      RLIMIT_NPROC,      1, 'u' },
+#endif
+#ifdef RLIMIT_NOFILE
+       { "open files",         (char *)0,      RLIMIT_NOFILE,     1, 'n' },
+#endif
+#ifdef RLIMIT_VMEM
+       { "virtual mem size",   "kbytes",       RLIMIT_VMEM,    1024, 'v' },
+#endif
+#ifdef RLIMIT_SWAP
+       { "swap limit",         "kbytes",       RLIMIT_SWAP,    1024, 'w' },
+#endif
+#ifdef RLIMIT_SBSIZE
+       { "sbsize",             "bytes",        RLIMIT_SBSIZE,     1, 'b' },
+#endif
+       { (char *) 0,           (char *)0,      0,                 0, '\0' }
+};
+
+int
+ulimitcmd(int argc __unused, char **argv __unused)
+{
+       int     c;
+       intmax_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;
+
+       what = 'f';
+       while ((optc = nextopt("HSatfdsmcnuvlb")) != '\0')
+               switch (optc) {
+               case 'H':
+                       how = HARD;
+                       break;
+               case 'S':
+                       how = SOFT;
+                       break;
+               case 'a':
+                       all = 1;
+                       break;
+               default:
+                       what = optc;
+               }
+
+       for (l = limits; l->name && l->option != what; l++)
+               ;
+       if (!l->name)
+               error("internal error (%c)", what);
+
+       set = *argptr ? 1 : 0;
+       if (set) {
+               char *p = *argptr;
+
+               if (all || argptr[1])
+                       error("too many arguments");
+               if (strcmp(p, "unlimited") == 0)
+                       val = RLIM_INFINITY;
+               else {
+                       val = 0;
+
+                       while ((c = *p++) >= '0' && c <= '9')
+                       {
+                               val = (val * 10) + (long)(c - '0');
+                               if (val < 0)
+                                       break;
+                       }
+                       if (c)
+                               error("bad number");
+                       val *= l->factor;
+               }
+       }
+       if (all) {
+               for (l = limits; l->name; l++) { 
+                       char optbuf[40];
+                       if (getrlimit(l->cmd, &limit) < 0)
+                               error("can't get limit: %s", strerror(errno));
+                       if (how & SOFT)
+                               val = limit.rlim_cur;
+                       else if (how & HARD)
+                               val = limit.rlim_max;
+
+                       if (l->units)
+                               snprintf(optbuf, sizeof(optbuf),
+                                       "(%s, -%c) ", l->units, l->option);
+                       else
+                               snprintf(optbuf, sizeof(optbuf),
+                                       "(-%c) ", l->option);
+                       out1fmt("%-18s %18s ", l->name, optbuf);
+                       if (val == RLIM_INFINITY)
+                               out1fmt("unlimited\n");
+                       else
+                       {
+                               val /= l->factor;
+                               out1fmt("%jd\n", (intmax_t)val);
+                       }
+               }
+               return 0;
+       }
+
+       if (getrlimit(l->cmd, &limit) < 0)
+               error("can't get limit: %s", strerror(errno));
+       if (set) {
+               if (how & SOFT)
+                       limit.rlim_cur = val;
+               if (how & HARD)
+                       limit.rlim_max = val;
+               if (setrlimit(l->cmd, &limit) < 0)
+                       error("bad limit: %s", strerror(errno));
        } else {
-               mask = 0;
-               do {
-                       if ((unsigned)(i = *p - '0') >= 8)
-                               error("Illegal number: %s", argv[1]);
-                       mask = (mask << 3) + i;
-               } while (*++p != '\0');
-               umask(mask);
+               if (how & SOFT)
+                       val = limit.rlim_cur;
+               else if (how & HARD)
+                       val = limit.rlim_max;
+
+               if (val == RLIM_INFINITY)
+                       out1fmt("unlimited\n");
+               else
+               {
+                       val /= l->factor;
+                       out1fmt("%jd\n", (intmax_t)val);
+               }
        }
        return 0;
 }
+
+/*
+ * $PchId: miscbltin.c,v 1.7 2006/05/23 11:59:08 philip Exp $
+ */
index e729cdaf72feb510c033359195efbf50db6d6ba4..73109ad70c0bbaf67fcc919eadb3418601b3e484 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh -
 #
-# Copyright (c) 1991 The Regents of the University of California.
-# All rights reserved.
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
 #
 # This code is derived from software contributed to Berkeley by
 # Kenneth Almquist.
 # 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.
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-#      @(#)mkbuiltins  5.2 (Berkeley) 3/8/91
+#      @(#)mkbuiltins  8.2 (Berkeley) 5/4/95
+# $FreeBSD: src/bin/sh/mkbuiltins,v 1.13 2004/04/06 20:06:51 markm Exp $
 
-# All calls to awk removed, because Minix bawk is deficient.  (kjb)
-
-if [ $# != 2 ]
-then
-       echo "USAGE: $0 shell.h builtins"
-       exit 1
+#temp=`/usr/bin/mktemp -t ka`
+temp=/tmp/mkb$$
+havehist=1
+if [ "X$1" = "X-h" ]; then
+       havehist=0
+       shift
 fi
-SHL=$1
-BLTINS=$2
-
-temp=/tmp/ka$$
-exec > builtins.c
+havejobs=0
+if [ "X$1" = "X-j" ]; then
+       havejobs=0
+       shift
+elif grep '^#define[    ]*JOBS[         ]*1' $2 > /dev/null
+then   havejobs=1
+fi
+objdir=$1
+exec > ${objdir}/builtins.c
 cat <<\!
 /*
  * This file was generated by the mkbuiltins program.
  */
 
+#include <stdlib.h>
 #include "shell.h"
 #include "builtins.h"
 
 !
-if grep '^#define JOBS[         ]*1' $SHL > /dev/null
-then
-       # Job control.
-       sed -e '/^#/d
-               s/      / /g
-               s/ #.*//
-               /^ *$/d
-               s/-j//' $BLTINS > $temp
-else
-       # No job control.
-       sed -e '/^#/d
-               s/      / /g
-               s/ #.*//
-               /^ *$/d
-               /-j/d' $BLTINS > $temp
-fi
-sed -e 's/ .*//
-       s/\(.*\)/int \1();/' $temp
+awk '/^[^#]/ {if(('$havejobs' || $2 != "-j") && ('$havehist' || $2 != "-h")) \
+    print $0}' $3 | sed 's/-[hj]//' > $temp
+#awk '{        printf "int %s();\n", $1}' $temp
 echo '
-int (*const builtinfunc[])() = {'
-sed -e 's/ .*//
-       s/\(.*\)/       \1,/' $temp
+int (*const builtinfunc[]) (int, char **) = {'
+awk '/^[^#]/ { printf "\t%s,\n", $1}' $temp
 echo '};
 
 const struct builtincmd builtincmd[] = {'
-i=0
-while read line
-do
-       set -$- $line
-       shift
-       for fun
-       do
-               echo "  \"$fun\", $i,"
-       done
-       i=`expr $i + 1`
-done < $temp
-echo ' NULL, 0
+awk '{ for (i = 2 ; i <= NF ; i++) {
+               printf "\t{ \"%s\", %d },\n",  $i, NR-1
+       }}' $temp
+echo ' { NULL, 0 }
 };'
 
-exec > builtins.h
+exec > ${objdir}/builtins.h
 cat <<\!
 /*
  * This file was generated by the mkbuiltins program.
  */
 
-#include <sys/cdefs.h>
 !
-i=0
 tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ < $temp |
-       while read line
-       do
-               set -$- $line
-               echo "#define $1 $i"
-               i=`expr $i + 1`
-       done
+       awk '{  printf "#define %s %d\n", $1, NR-1}'
 echo '
 struct builtincmd {
       char *name;
       int code;
 };
 
-extern int (*const builtinfunc[])();
+extern int (*const builtinfunc[]) (int, char **);
 extern const struct builtincmd builtincmd[];'
+awk '{ printf "int %s (int, char **);\n", $1 }' < $temp
 rm -f $temp
+
+#
+# $PchId: mkbuiltins,v 1.6 2006/05/22 12:42:58 philip Exp $
index c27cbbdf9763f9b7883f97b7f7a146074c563d41..dfb6829abf1ce197725f19e532aba2cabbce9ce4 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1991 The Regents of the University of California.\n\
- All rights reserved.\n";
+static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)mkinit.c   5.3 (Berkeley) 3/13/91";
+#if 0
+static char sccsid[] = "@(#)mkinit.c   8.2 (Berkeley) 5/4/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/mkinit.c,v 1.17 2004/04/06 20:06:51 markm Exp $");
+*/
 
 /*
  * This program scans all the source files for code to handle various
  * special events and combines this code into one file.  This (allegedly)
  * improves the structure of the program since there is no need for
  * anyone outside of a module to know that that module performs special
- * operations on particular events.  The command is executed iff init.c
- * is actually changed.
+ * operations on particular events.
  *
- * Usage:  mkinit command sourcefile...
+ * Usage:  mkinit sourcefile...
  */
 
 
-#include <sys/cdefs.h>
-
 #include <sys/types.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
 
+#ifdef __minix
+#define __unused
+#endif
 
 /*
  * OUTFILE is the name of the output file.  Output is initially written
- * to the file OUTTEMP, which is then moved to OUTFILE if OUTTEMP and
- * OUTFILE are different.
+ * to the file OUTTEMP, which is then moved to OUTFILE.
  */
 
 #define OUTFILE "init.c"
 #define OUTTEMP "init.c.new"
-#define OUTOBJ "init.o"
 
 
 /*
@@ -89,7 +93,7 @@ struct text {
        int nleft;
        struct block *start;
        struct block *last;
-};      
+};
 
 struct block {
        struct block *next;
@@ -105,7 +109,7 @@ struct event {
        char *name;             /* name of event (e.g. INIT) */
        char *routine;          /* name of routine called on event */
        char *comment;          /* comment describing routine */
-       struct text code;               /* code for handling event */
+       struct text code;       /* code for handling event */
 };
 
 
@@ -148,42 +152,35 @@ struct text decls;                        /* declarations */
 int amiddecls;                         /* for formatting */
 
 
-void readfile(), doevent(), doinclude(), dodecl(), output();
-void addstr(), addchar(), writetext();
+static void readfile(char *);
+static int match(char *, char *);
+static int gooddefine(char *);
+static void doevent(struct event *, FILE *, char *);
+static void doinclude(char *);
+static void dodecl(char *, FILE *);
+static void output(void);
+static void addstr(char *, struct text *);
+static void addchar(int, struct text *);
+static void writetext(struct text *, FILE *);
+static FILE *ckfopen(char *, char *);
+static void *ckmalloc(int);
+static char *savestr(char *);
+static void error(char *);
 
 #define equal(s1, s2)  (strcmp(s1, s2) == 0)
 
-FILE *ckfopen();
-char *savestr();
-void *ckmalloc __P((int));
-void error();
-
-main(argc, argv)
-       char **argv;
-       {
+int
+main(int argc __unused, char *argv[])
+{
        char **ap;
-       int fd;
-       char c;
 
-       if (argc < 2)
-               error("Usage:  mkinit command file...");
        header_files[0] = "\"shell.h\"";
        header_files[1] = "\"mystring.h\"";
-       for (ap = argv + 2 ; *ap ; ap++)
+       for (ap = argv + 1 ; *ap ; ap++)
                readfile(*ap);
        output();
-       if (file_changed()) {
-               unlink(OUTFILE);
-               link(OUTTEMP, OUTFILE);
-               unlink(OUTTEMP);
-       } else {
-               unlink(OUTTEMP);
-               if (touch(OUTOBJ))
-                       exit(0);                /* no compilation necessary */
-       }
-       printf("%s\n", argv[1]);
-       execl("/bin/sh", "sh", "-c", argv[1], (char *)0);
-       error("Can't exec shell");
+       rename(OUTTEMP, OUTFILE);
+       exit(0);
 }
 
 
@@ -191,10 +188,9 @@ main(argc, argv)
  * Parse an input file.
  */
 
-void
-readfile(fname)
-       char *fname;
-       {
+static void
+readfile(char *fname)
+{
        FILE *fp;
        char line[1024];
        struct event *ep;
@@ -215,19 +211,31 @@ readfile(fname)
                        doinclude(line);
                if (line[0] == 'M' && match("MKINIT", line))
                        dodecl(line, fp);
-               if (line[0] == '#' && gooddefine(line))
+               if (line[0] == '#' && gooddefine(line)) {
+                       char *cp;
+                       char line2[1024];
+                       static const char undef[] = "#undef ";
+
+                       strcpy(line2, line);
+                       memcpy(line2, undef, sizeof(undef) - 1);
+                       cp = line2 + sizeof(undef) - 1;
+                       while(*cp && (*cp == ' ' || *cp == '\t'))
+                               cp++;
+                       while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
+                               cp++;
+                       *cp++ = '\n'; *cp = '\0';
+                       addstr(line2, &defines);
                        addstr(line, &defines);
+               }
        }
        fclose(fp);
 }
 
 
-int
-match(name, line)
-       char *name;
-       char *line;
-       {
-       register char *p, *q;
+static int
+match(char *name, char *line)
+{
+       char *p, *q;
 
        p = name, q = line;
        while (*p) {
@@ -240,11 +248,10 @@ match(name, line)
 }
 
 
-int
-gooddefine(line)
-       char *line;
-       {
-       register char *p;
+static int
+gooddefine(char *line)
+{
+       char *p;
 
        if (! match("#define", line))
                return 0;                       /* not a define */
@@ -264,12 +271,9 @@ gooddefine(line)
 }
 
 
-void
-doevent(ep, fp, fname)
-       register struct event *ep;
-       FILE *fp;
-       char *fname;
-       {
+static void
+doevent(struct event *ep, FILE *fp, char *fname)
+{
        char line[1024];
        int indent;
        char *p;
@@ -304,13 +308,12 @@ doevent(ep, fp, fname)
 }
 
 
-void
-doinclude(line)
-       char *line;
-       {
-       register char *p;
+static void
+doinclude(char *line)
+{
+       char *p;
        char *name;
-       register char **pp;
+       char **pp;
 
        for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
        if (*p == '\0')
@@ -329,13 +332,11 @@ doinclude(line)
 }
 
 
-void
-dodecl(line1, fp)
-       char *line1;
-       FILE *fp;
-       {
+static void
+dodecl(char *line1, FILE *fp)
+{
        char line[1024];
-       register char *p, *q;
+       char *p, *q;
 
        if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
                addchar('\n', &decls);
@@ -350,7 +351,8 @@ dodecl(line1, fp)
                if (! amiddecls)
                        addchar('\n', &decls);
                q = NULL;
-               for (p = line1 + 6 ; *p != '=' && *p != '/' ; p++);
+               for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++)
+                       continue;
                if (*p == '=') {                /* eliminate initialization */
                        for (q = p ; *q && *q != ';' ; q++);
                        if (*q == '\0')
@@ -375,8 +377,9 @@ dodecl(line1, fp)
  * Write the output to the file OUTTEMP.
  */
 
-void
-output() {
+static void
+output(void)
+{
        FILE *fp;
        char **pp;
        struct event *ep;
@@ -392,7 +395,7 @@ output() {
        for (ep = event ; ep->name ; ep++) {
                fputs("\n\n\n", fp);
                fputs(ep->comment, fp);
-               fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
+               fprintf(fp, "\nvoid\n%s(void) {\n", ep->routine);
                writetext(&ep->code, fp);
                fprintf(fp, "}\n");
        }
@@ -400,62 +403,15 @@ output() {
 }
 
 
-/*
- * Return true if the new output file is different from the old one.
- */
-
-int
-file_changed() {
-       register FILE *f1, *f2;
-       register int c;
-
-       if ((f1 = fopen(OUTFILE, "r")) == NULL
-        || (f2 = fopen(OUTTEMP, "r")) == NULL)
-               return 1;
-       while ((c = getc(f1)) == getc(f2)) {
-               if (c == EOF)
-                       return 0;
-       }
-       return 1;
-}
-
-
-/*
- * Touch a file.  Returns 0 on failure, 1 on success.
- */
-
-int
-touch(file)
-       char *file;
-       {
-       int fd;
-       char c;
-
-       if ((fd = open(file, O_RDWR)) < 0)
-               return 0;
-       if (read(fd, &c, 1) != 1) {
-               close(fd);
-               return 0;
-       }
-       lseek(fd, 0L, 0);
-       write(fd, &c, 1);
-       close(fd);
-       return 1;
-}
-
-
-
 /*
  * A text structure is simply a block of text that is kept in memory.
  * Addstr appends a string to the text struct, and addchar appends a single
  * character.
  */
 
-void
-addstr(s, text)
-       register char *s;
-       register struct text *text;
-       {
+static void
+addstr(char *s, struct text *text)
+{
        while (*s) {
                if (--text->nleft < 0)
                        addchar(*s++, text);
@@ -465,10 +421,9 @@ addstr(s, text)
 }
 
 
-void
-addchar(c, text)
-       register struct text *text;
-       {
+static void
+addchar(int c, struct text *text)
+{
        struct block *bp;
 
        if (--text->nleft < 0) {
@@ -487,11 +442,9 @@ addchar(c, text)
 /*
  * Write the contents of a text structure to a file.
  */
-void
-writetext(text, fp)
-       struct text *text;
-       FILE *fp;
-       {
+static void
+writetext(struct text *text, FILE *fp)
+{
        struct block *bp;
 
        if (text->start != NULL) {
@@ -501,47 +454,47 @@ writetext(text, fp)
        }
 }
 
-FILE *
-ckfopen(file, mode)
-       char *file;
-       char *mode;
-       {
+static FILE *
+ckfopen(char *file, char *mode)
+{
        FILE *fp;
 
        if ((fp = fopen(file, mode)) == NULL) {
-               fprintf(stderr, "Can't open %s\n", file);
+               fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
                exit(2);
        }
        return fp;
 }
 
-void *
-ckmalloc(nbytes) {
-       register char *p;
-       char *malloc();
+static void *
+ckmalloc(int nbytes)
+{
+       char *p;
 
        if ((p = malloc(nbytes)) == NULL)
                error("Out of space");
        return p;
 }
 
-char *
-savestr(s)
-       char *s;
-       {
-       register char *p;
+static char *
+savestr(char *s)
+{
+       char *p;
 
        p = ckmalloc(strlen(s) + 1);
        strcpy(p, s);
        return p;
 }
 
-void
-error(msg)
-       char *msg;
-       {
+static void
+error(char *msg)
+{
        if (curfile != NULL)
                fprintf(stderr, "%s:%d: ", curfile, linno);
        fprintf(stderr, "%s\n", msg);
        exit(2);
 }
+
+/*
+ * $PchId: mkinit.c,v 1.6 2006/05/22 12:16:50 philip Exp $
+ */
index ff7d89b61078441aa3abb71d13247216bed9231d..d9582d010431128baa7287b0a7bfde09d4239804 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * SUCH DAMAGE.
  */
 
+#if 0
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1991 The Regents of the University of California.\n\
- All rights reserved.\n";
+static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)mknodes.c  5.1 (Berkeley) 3/7/91";
+static char sccsid[] = "@(#)mknodes.c  8.2 (Berkeley) 5/4/95";
 #endif /* not lint */
+#endif
+/*
+__FBSDID("$FreeBSD: src/bin/sh/mknodes.c,v 1.17 2004/04/06 20:06:51 markm Exp $");
+*/
 
 /*
  * This program reads the nodetypes file and nodes.c.pat file.  It generates
@@ -50,7 +51,10 @@ static char sccsid[] = "@(#)mknodes.c        5.1 (Berkeley) 3/7/91";
  */
 
 #include <stdio.h>
-
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
 
 #define MAXTYPES 50            /* max number of node types */
 #define MAXFIELDS 20           /* max fields in a structure */
@@ -80,31 +84,42 @@ struct str {                        /* struct representing a node structure */
 };
 
 
-int ntypes;                    /* number of node types */
-char *nodename[MAXTYPES];      /* names of the nodes */
-struct str *nodestr[MAXTYPES]; /* type of structure used by the node */
-int nstr;                      /* number of structures */
-struct str str[MAXTYPES];      /* the structures */
-struct str *curstr;            /* current structure */
-
-
-FILE *infp = stdin;
-char line[1024];
-int linno;
-char *linep;
-
+static int ntypes;                     /* number of node types */
+static char *nodename[MAXTYPES];       /* names of the nodes */
+static struct str *nodestr[MAXTYPES];  /* type of structure used by the node */
+static int nstr;                       /* number of structures */
+static struct str str[MAXTYPES];       /* the structures */
+static struct str *curstr;             /* current structure */
+static FILE *infp;
+static char line[1024];
+static int linno;
+static char *linep;
+
+#ifndef __printf0like
+#define __printf0like(a,b)
+#endif
+
+static void parsenode(void);
+static void parsefield(void);
+static void output(char *);
+static void outsizes(FILE *);
+static void outfunc(FILE *, int);
+static void indent(int, FILE *);
+static int nextfield(char *);
+static void skipbl(void);
+static int readline(void);
+static void error(const char *, ...) __printf0like(1, 2);
+static char *savestr(const char *);
 
-char *savestr();
-#define equal(s1, s2)  (strcmp(s1, s2) == 0)
 
-
-main(argc, argv)
-       char **argv;
-       {
+int
+main(int argc, char *argv[])
+{
        if (argc != 3)
-               error("usage: mknodes file\n");
+               error("usage: mknodes file");
+       infp = stdin;
        if ((infp = fopen(argv[1], "r")) == NULL)
-               error("Can't open %s", argv[1]);
+               error("Can't open %s: %s", argv[1], strerror(errno));
        while (readline()) {
                if (line[0] == ' ' || line[0] == '\t')
                        parsefield();
@@ -112,12 +127,14 @@ main(argc, argv)
                        parsenode();
        }
        output(argv[2]);
-       return 0;
+       exit(0);
 }
 
 
 
-parsenode() {
+static void
+parsenode(void)
+{
        char name[BUFLEN];
        char tag[BUFLEN];
        struct str *sp;
@@ -131,7 +148,7 @@ parsenode() {
                error("Garbage at end of line");
        nodename[ntypes] = savestr(name);
        for (sp = str ; sp < str + nstr ; sp++) {
-               if (equal(sp->tag, tag))
+               if (strcmp(sp->tag, tag) == 0)
                        break;
        }
        if (sp >= str + nstr) {
@@ -145,7 +162,9 @@ parsenode() {
 }
 
 
-parsefield() {
+static void
+parsefield(void)
+{
        char name[BUFLEN];
        char type[BUFLEN];
        char decl[2 * BUFLEN];
@@ -159,21 +178,21 @@ parsefield() {
                error("No field type");
        fp = &curstr->field[curstr->nfields];
        fp->name = savestr(name);
-       if (equal(type, "nodeptr")) {
+       if (strcmp(type, "nodeptr") == 0) {
                fp->type = T_NODE;
                sprintf(decl, "union node *%s", name);
-       } else if (equal(type, "nodelist")) {
+       } else if (strcmp(type, "nodelist") == 0) {
                fp->type = T_NODELIST;
                sprintf(decl, "struct nodelist *%s", name);
-       } else if (equal(type, "string")) {
+       } else if (strcmp(type, "string") == 0) {
                fp->type = T_STRING;
                sprintf(decl, "char *%s", name);
-       } else if (equal(type, "int")) {
+       } else if (strcmp(type, "int") == 0) {
                fp->type = T_INT;
                sprintf(decl, "int %s", name);
-       } else if (equal(type, "other")) {
+       } else if (strcmp(type, "other") == 0) {
                fp->type = T_OTHER;
-       } else if (equal(type, "temp")) {
+       } else if (strcmp(type, "temp") == 0) {
                fp->type = T_TEMP;
        } else {
                error("Unknown type %s", type);
@@ -196,9 +215,9 @@ char writer[] = "\
  */\n\
 \n";
 
-output(file)
-       char *file;
-       {
+static void
+output(char *file)
+{
        FILE *hfile;
        FILE *cfile;
        FILE *patfile;
@@ -208,9 +227,9 @@ output(file)
        char *p;
 
        if ((patfile = fopen(file, "r")) == NULL)
-               error("Can't open %s", file);
+               error("Can't open %s: %s", file, strerror(errno));
        if ((hfile = fopen("nodes.h", "w")) == NULL)
-               error("Can't create nodes.h");
+               error("Can't create nodes.h: %s", strerror(errno));
        if ((cfile = fopen("nodes.c", "w")) == NULL)
                error("Can't create nodes.c");
        fputs(writer, hfile);
@@ -234,22 +253,17 @@ output(file)
        fputs("\tstruct nodelist *next;\n", hfile);
        fputs("\tunion node *n;\n", hfile);
        fputs("};\n\n\n", hfile);
-       fputs("#ifdef __STDC__\n", hfile);
        fputs("union node *copyfunc(union node *);\n", hfile);
        fputs("void freefunc(union node *);\n", hfile);
-       fputs("#else\n", hfile);
-       fputs("union node *copyfunc();\n", hfile);
-       fputs("void freefunc();\n", hfile);
-       fputs("#endif\n", hfile);
 
        fputs(writer, cfile);
        while (fgets(line, sizeof line, patfile) != NULL) {
                for (p = line ; *p == ' ' || *p == '\t' ; p++);
-               if (equal(p, "%SIZES\n"))
+               if (strcmp(p, "%SIZES\n") == 0)
                        outsizes(cfile);
-               else if (equal(p, "%CALCSIZE\n"))
+               else if (strcmp(p, "%CALCSIZE\n") == 0)
                        outfunc(cfile, 1);
-               else if (equal(p, "%COPY\n"))
+               else if (strcmp(p, "%COPY\n") == 0)
                        outfunc(cfile, 0);
                else
                        fputs(line, cfile);
@@ -258,9 +272,9 @@ output(file)
 
 
 
-outsizes(cfile)
-       FILE *cfile;
-       {
+static void
+outsizes(FILE *cfile)
+{
        int i;
 
        fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes);
@@ -271,9 +285,9 @@ outsizes(cfile)
 }
 
 
-outfunc(cfile, calcsize)
-       FILE *cfile;
-       {
+static void
+outfunc(FILE *cfile, int calcsize)
+{
        struct str *sp;
        struct field *fp;
        int i;
@@ -287,8 +301,7 @@ outfunc(cfile, calcsize)
                fputs("      funcblocksize += nodesize[n->type];\n", cfile);
        else {
                fputs("      new = funcblock;\n", cfile);
-               fputs("      *(char **)&funcblock += nodesize[n->type];\n", 
-                                                                       cfile);
+               fputs("      funcblock = (char *)funcblock + nodesize[n->type];\n", cfile);
        }
        fputs("      switch (n->type) {\n", cfile);
        for (sp = str ; sp < &str[nstr] ; sp++) {
@@ -351,9 +364,9 @@ outfunc(cfile, calcsize)
 }
 
 
-indent(amount, fp)
-       FILE *fp;
-       {
+static void
+indent(int amount, FILE *fp)
+{
        while (amount >= 8) {
                putc('\t', fp);
                amount -= 8;
@@ -364,11 +377,10 @@ indent(amount, fp)
 }
 
 
-int
-nextfield(buf)
-       char *buf;
-       {
-       register char *p, *q;
+static int
+nextfield(char *buf)
+{
+       char *p, *q;
 
        p = linep;
        while (*p == ' ' || *p == '\t')
@@ -382,15 +394,18 @@ nextfield(buf)
 }
 
 
-skipbl() {
+static void
+skipbl(void)
+{
        while (*linep == ' ' || *linep == '\t')
                linep++;
 }
 
 
-int
-readline() {
-       register char *p;
+static int
+readline(void)
+{
+       char *p;
 
        if (fgets(line, 1024, infp) == NULL)
                return 0;
@@ -407,26 +422,34 @@ readline() {
 
 
 
-error(msg, a1, a2, a3, a4, a5, a6)
-       char *msg;
-       {
-       fprintf(stderr, "line %d: ", linno);
-       fprintf(stderr, msg, a1, a2, a3, a4, a5, a6);
-       putc('\n', stderr);
+static void
+error(const char *msg, ...)
+{
+       va_list va;
+       va_start(va, msg);
+
+       (void) fprintf(stderr, "line %d: ", linno);
+       (void) vfprintf(stderr, msg, va);
+       (void) fputc('\n', stderr);
+
+       va_end(va);
+
        exit(2);
 }
 
 
 
-char *
-savestr(s)
-       char *s;
-       {
-       register char *p;
-       char *malloc();
+static char *
+savestr(const char *s)
+{
+       char *p;
 
        if ((p = malloc(strlen(s) + 1)) == NULL)
                error("Out of space");
-       strcpy(p, s);
+       (void) strcpy(p, s);
        return p;
 }
+
+/*
+ * $PchId: mknodes.c,v 1.6 2006/05/23 12:05:14 philip Exp $
+ */
index 640fcfd142b14fc4034b75d09776be87e911dfb5..bbead25e189da81260df39e811dd0dc49813af0a 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1991 The Regents of the University of California.\n\
- All rights reserved.\n";
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)mksignames.c       5.1 (Berkeley) 3/7/91";
+static char sccsid[] = "@(#)mksignames.c       8.1 (Berkeley) 5/31/93";
 #endif /* not lint */
 
 /*
  * This program generates the signames.h and signames.c files.
  */
-#include <sys/types.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <signal.h>
 
-
+int main(int argc, char *argv[]);
 
 struct sig {
        int signo;              /* signal number */
@@ -198,3 +198,7 @@ main(argc, argv)  char **argv; {
        fprintf(cfile, "};\n");
        exit(0);
 }
+
+/*
+ * $PchId: mksignames.c,v 1.2 2001/05/14 19:22:26 philip Exp $
+ */
index 5b26fc004ddcbb040a01ce1f50faa75b1e8ccda3..71aadd55739deb3a12b69ac428e9ec7f535cac1e 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * SUCH DAMAGE.
  */
 
+#if 0
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1991 The Regents of the University of California.\n\
- All rights reserved.\n";
+static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)mksyntax.c 5.2 (Berkeley) 3/8/91";
+static char sccsid[] = "@(#)mksyntax.c 8.2 (Berkeley) 5/4/95";
 #endif /* not lint */
+#endif
+/*
+__FBSDID("$FreeBSD: src/bin/sh/mksyntax.c,v 1.23 2004/04/06 20:06:51 markm Exp $");
+*/
 
 /*
  * This program creates syntax.h and syntax.c.
  */
 
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include "parser.h"
 
+#ifdef __minix
+#define __unused
+#endif
 
 struct synclass {
        char *name;
@@ -59,19 +65,21 @@ struct synclass {
 
 /* Syntax classes */
 struct synclass synclass[] = {
-       "CWORD",                "character is nothing special",
-       "CNL",          "newline character",
-       "CBACK",                "a backslash character",
-       "CSQUOTE",      "single quote",
-       "CDQUOTE",      "double quote",
-       "CENDQUOTE",    "a terminating quote",
-       "CBQUOTE",      "backwards single quote",
-       "CVAR",         "a dollar sign",
-       "CENDVAR",      "a '}' character",
-       "CEOF",         "end of file",
-       "CCTL",         "like CWORD, except it must be escaped",
-       "CSPCL",                "these terminate a word",
-       NULL, NULL
+       { "CWORD",      "character is nothing special" },
+       { "CNL",        "newline character" },
+       { "CBACK",      "a backslash character" },
+       { "CSQUOTE",    "single quote" },
+       { "CDQUOTE",    "double quote" },
+       { "CENDQUOTE",  "a terminating quote" },
+       { "CBQUOTE",    "backwards single quote" },
+       { "CVAR",       "a dollar sign" },
+       { "CENDVAR",    "a '}' character" },
+       { "CLP",        "a left paren in arithmetic" },
+       { "CRP",        "a right paren in arithmetic" },
+       { "CEOF",       "end of file" },
+       { "CCTL",       "like CWORD, except it must be escaped" },
+       { "CSPCL",      "these terminate a word" },
+       { NULL,         NULL }
 };
 
 
@@ -80,31 +88,39 @@ struct synclass synclass[] = {
  * you may have to change the definition of the is_in_name macro.
  */
 struct synclass is_entry[] = {
-       "ISDIGIT",      "a digit",
-       "ISUPPER",      "an upper case letter",
-       "ISLOWER",      "a lower case letter",
-       "ISUNDER",      "an underscore",
-       "ISSPECL",      "the name of a special parameter",
-       NULL, NULL,
+       { "ISDIGIT",    "a digit" },
+       { "ISUPPER",    "an upper case letter" },
+       { "ISLOWER",    "a lower case letter" },
+       { "ISUNDER",    "an underscore" },
+       { "ISSPECL",    "the name of a special parameter" },
+       { NULL,         NULL }
 };
 
-char writer[] = "\
+static char writer[] = "\
 /*\n\
  * This file was generated by the mksyntax program.\n\
  */\n\
 \n";
 
 
-FILE *cfile;
-FILE *hfile;
-char *syntax[513];
-int base;
-int size;              /* number of values which a char variable can have */
-int nbits;             /* number of bits in a character */
-int digit_contig;      /* true if digits are contiguous */
-
-
-main() {
+static FILE *cfile;
+static FILE *hfile;
+static char *syntax[513];
+static int base;
+static int size;       /* number of values which a char variable can have */
+static int nbits;      /* number of bits in a character */
+static int digit_contig;/* true if digits are contiguous */
+
+static void filltable(char *);
+static void init(void);
+static void add(char *, char *);
+static void print(char *);
+static void output_type_macros(void);
+static void digit_convert(void);
+
+int
+main(int argc __unused, char **argv __unused)
+{
        char c;
        char d;
        int sign;
@@ -136,7 +152,9 @@ main() {
                if (d == c)
                        break;
        }
+#if 0
        printf("%s %d bit chars\n", sign? "signed" : "unsigned", nbits);
+#endif
        if (nbits > 9) {
                fputs("Characters can't have more than 9 bits\n", stderr);
                exit(2);
@@ -151,14 +169,14 @@ main() {
                        digit_contig = 0;
        }
 
-       fputs("#include <sys/cdefs.h>\n", hfile);
+       fputs("#include <ctype.h>\n", hfile);
 
        /* Generate the #define statements in the header file */
        fputs("/* Syntax classes */\n", hfile);
        for (i = 0 ; synclass[i].name ; i++) {
                sprintf(buf, "#define %s %d", synclass[i].name, i);
                fputs(buf, hfile);
-               for (pos = strlen(buf) ; pos < 32 ; pos = pos + 8 &~ 07)
+               for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
                        putc('\t', hfile);
                fprintf(hfile, "/* %s */\n", synclass[i].comment);
        }
@@ -167,7 +185,7 @@ main() {
        for (i = 0 ; is_entry[i].name ; i++) {
                sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i);
                fputs(buf, hfile);
-               for (pos = strlen(buf) ; pos < 32 ; pos = pos + 8 &~ 07)
+               for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
                        putc('\t', hfile);
                fprintf(hfile, "/* %s */\n", is_entry[i].comment);
        }
@@ -178,6 +196,7 @@ main() {
        fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile);
        fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile);
        fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile);
+       fputs("#define ARISYNTAX (arisyntax + SYNBASE)\n", hfile);
        putc('\n', hfile);
        output_type_macros();           /* is_digit, etc. */
        putc('\n', hfile);
@@ -204,14 +223,28 @@ main() {
        add("`", "CBQUOTE");
        add("$", "CVAR");
        add("}", "CENDVAR");
-       add("!*?[=", "CCTL");
+       /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
+       add("!*?[=~:/-", "CCTL");
        print("dqsyntax");
        init();
        fputs("\n/* syntax table used when in single quotes */\n", cfile);
        add("\n", "CNL");
        add("'", "CENDQUOTE");
-       add("!*?[=", "CCTL");
+       /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
+       add("!*?[=~:/-", "CCTL");
        print("sqsyntax");
+       init();
+       fputs("\n/* syntax table used when in arithmetic */\n", cfile);
+       add("\n", "CNL");
+       add("\\", "CBACK");
+       add("`", "CBQUOTE");
+       add("'", "CSQUOTE");
+       add("\"", "CDQUOTE");
+       add("$", "CVAR");
+       add("}", "CENDVAR");
+       add("(", "CLP");
+       add(")", "CRP");
+       print("arisyntax");
        filltable("0");
        fputs("\n/* character classification table */\n", cfile);
        add("0123456789", "ISDIGIT");
@@ -231,9 +264,9 @@ main() {
  * Clear the syntax table.
  */
 
-filltable(dftval)
-       char *dftval;
-       {
+static void
+filltable(char *dftval)
+{
        int i;
 
        for (i = 0 ; i < size ; i++)
@@ -245,7 +278,9 @@ filltable(dftval)
  * Initialize the syntax table with default values.
  */
 
-init() {
+static void
+init(void)
+{
        filltable("CWORD");
        syntax[0] = "CEOF";
        syntax[base + CTLESC] = "CCTL";
@@ -253,6 +288,9 @@ init() {
        syntax[base + CTLENDVAR] = "CCTL";
        syntax[base + CTLBACKQ] = "CCTL";
        syntax[base + CTLBACKQ + CTLQUOTE] = "CCTL";
+       syntax[base + CTLARI] = "CCTL";
+       syntax[base + CTLENDARI] = "CCTL";
+       syntax[base + CTLQUOTEMARK] = "CCTL";
 }
 
 
@@ -260,9 +298,9 @@ init() {
  * Add entries to the syntax table.
  */
 
-add(p, type)
-       char *p, *type;
-       {
+static void
+add(char *p, char *type)
+{
        while (*p)
                syntax[*p++ + base] = type;
 }
@@ -273,9 +311,9 @@ add(p, type)
  * Output the syntax table.
  */
 
-print(name)
-       char *name;
-       {
+static void
+print(char *name)
+{
        int i;
        int col;
 
@@ -306,16 +344,18 @@ print(name)
  * contiguous, we can test for them quickly.
  */
 
-char *macro[] = {
+static char *macro[] = {
        "#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)",
-       "#define is_alpha(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER))",
-       "#define is_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER))",
-       "#define is_in_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER|ISDIGIT))",
+       "#define is_alpha(c)\t((c) != PEOF && ((c) < CTLESC || (c) > CTLQUOTEMARK) && isalpha((unsigned char) (c)))",
+       "#define is_name(c)\t((c) != PEOF && ((c) < CTLESC || (c) > CTLQUOTEMARK) && ((c) == '_' || isalpha((unsigned char) (c))))",
+       "#define is_in_name(c)\t((c) != PEOF && ((c) < CTLESC || (c) > CTLQUOTEMARK) && ((c) == '_' || isalnum((unsigned char) (c))))",
        "#define is_special(c)\t((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))",
        NULL
 };
 
-output_type_macros() {
+static void
+output_type_macros(void)
+{
        char **pp;
 
        if (digit_contig)
@@ -334,7 +374,9 @@ output_type_macros() {
  * Output digit conversion table (if digits are not contiguous).
  */
 
-digit_convert() {
+static void
+digit_convert(void)
+{
        int maxdigit;
        static char digit[] = "0123456789";
        char *p;
@@ -350,7 +392,11 @@ digit_convert() {
                for (p = digit ; *p && *p != i ; p++);
                if (*p == '\0')
                        p = digit;
-               fprintf(cfile, "      %d,\n", p - digit);
+               fprintf(cfile, "      %d,\n", (int)(p - digit));
        }
        fputs("};\n", cfile);
 }
+
+/*
+ * $PchId: mksyntax.c,v 1.7 2006/05/23 12:04:27 philip Exp $
+ */
index a9c33985cb3d9afef726492e2613e78bc736935e..e529902b4b4a7fdd0a52d6eac8b1f44544837224 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh -
 #
-# Copyright (c) 1991 The Regents of the University of California.
-# All rights reserved.
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
 #
 # This code is derived from software contributed to Berkeley by
 # Kenneth Almquist.
 # 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.
@@ -34,7 +30,8 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-#      @(#)mktokens    5.1 (Berkeley) 3/7/91
+#      @(#)mktokens    8.1 (Berkeley) 5/31/93
+# $FreeBSD: src/bin/sh/mktokens,v 1.9 2004/04/06 20:06:51 markm Exp $
 
 # All calls to awk removed, because Minix bawk is deficient.  (kjb)
 
@@ -42,7 +39,9 @@
 # token marks the end of a list.  The third column is the name to print in
 # error messages.
 
-cat > /tmp/ka$$ <<\!
+#temp=`/usr/bin/mktemp -t ka`
+temp=/tmp/mkt$$
+cat > $temp <<\!
 TEOF   1       end of file
 TNL    0       newline
 TSEMI  0       ";"
@@ -70,16 +69,17 @@ TBEGIN      0       "{"
 TEND   1       "}"
 TCASE  0       "case"
 TESAC  1       "esac"
+TNOT   0       "!"
 !
-nl=`wc -l /tmp/ka$$`
-exec > token.def
+nl=`wc -l $temp`
+exec > token.h
 i=0
 while read line
 do
        set -$- $line
        echo "#define $1 $i"
        i=`expr $i + 1`
-done </tmp/ka$$
+done <$temp
 echo '
 /* Array indicating which tokens mark the end of a list */
 const char tokendlist[] = {'
@@ -87,18 +87,18 @@ while read line
 do
        set -$- $line
        echo "  $2,"
-done </tmp/ka$$
+done <$temp
 echo '};
 
-char *const tokname[] = {'
+const char *const tokname[] = {'
 sed -e 's/"/\\"/g' \
     -e 's/[^    ]*[     ][      ]*[^    ]*[     ][      ]*\(.*\)/      "\1",/' \
-    /tmp/ka$$
+    $temp
 echo '};
 '
 i=0
 go=
-sed 's/"//g' /tmp/ka$$ |
+sed 's/"//g' $temp |
        while read line
        do
                set -$- $line
@@ -106,7 +106,7 @@ sed 's/"//g' /tmp/ka$$ |
                then
                        echo "#define KWDOFFSET $i"
                        echo
-                       echo "char *const parsekwd[] = {"
+                       echo "const char *const parsekwd[] = {"
                        go=true
                fi
                if [ "$go" ]
@@ -118,4 +118,7 @@ sed 's/"//g' /tmp/ka$$ |
 echo ' 0
 };'
 
-rm /tmp/ka$$
+rm $temp
+
+#
+# $PchId: mktokens,v 1.5 2006/05/22 12:43:35 philip Exp $
diff --git a/commands/ash/myhistedit.h b/commands/ash/myhistedit.h
new file mode 100644 (file)
index 0000000..f6e295b
--- /dev/null
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 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.
+ *
+ *     @(#)myhistedit.h        8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/myhistedit.h,v 1.10 2004/04/06 20:06:51 markm Exp $
+ */
+
+#include <histedit.h>
+
+extern History *hist;
+extern EditLine *el;
+extern int displayhist;
+
+void histedit(void);
+void sethistsize(const char *);
+int histcmd(int, char **);
+int bindcmd(int, char **);
+
+/* From libedit */
+void  re_goto_bottom(EditLine *);
+
+/*
+ * $PchId: myhistedit.h,v 1.5 2006/03/29 15:55:18 philip Exp $
+ */
+
index 42635cf1279bf892286b304519289d98ec7ef356..7957c333a77b59a21c62c537593edf5706ad1328 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)mystring.c 5.1 (Berkeley) 3/7/91";
+#if 0
+static char sccsid[] = "@(#)mystring.c 8.2 (Berkeley) 5/4/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/mystring.c,v 1.13 2004/04/06 20:06:51 markm Exp $");
+*/
 
 /*
  * String functions.
@@ -44,12 +46,11 @@ static char sccsid[] = "@(#)mystring.c      5.1 (Berkeley) 3/7/91";
  *     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.
- *     strchr(s, c)            Find first occurance of c in s.
- *     bcopy(from, to, n)      Copy a block of memory.
  *     number(s)               Convert a string of digits to an integer.
  *     is_number(s)            Return true if s is a string of digits.
  */
 
+#include <stdlib.h>
 #include "shell.h"
 #include "syntax.h"
 #include "error.h"
@@ -58,6 +59,14 @@ static char sccsid[] = "@(#)mystring.c       5.1 (Berkeley) 3/7/91";
 
 char nullstr[1];               /* zero length string */
 
+/*
+ * equal - #defined in mystring.h
+ */
+
+/*
+ * scopy - #defined in mystring.h
+ */
+
 
 /*
  * scopyn - copy a string from "from" to "to", truncating the string
@@ -66,11 +75,8 @@ char nullstr[1];             /* zero length string */
  */
 
 void
-scopyn(from, to, size)
-       register char const *from;
-       register char *to;
-       register int size;
-       {
+scopyn(const char *from, char *to, int size)
+{
 
        while (--size > 0) {
                if ((*to++ = *from++) == '\0')
@@ -80,59 +86,13 @@ scopyn(from, to, size)
 }
 
 
-/*
- * strchr - find first occurrence of a character in a string.
- */
-
-#ifndef SYS5
-char *
-mystrchr(s, charwanted)
-       char const *s;
-       register char charwanted;
-       {
-       register char const *scan;
-
-       /*
-        * The odd placement of the two tests is so NUL is findable.
-        */
-       for (scan = s ; *scan != charwanted ; ) /* ++ moved down for opt. */
-               if (*scan++ == '\0')
-                       return NULL;
-       return (char *)scan;
-}
-#endif
-
-
-
-/*
- * bcopy - copy bytes
- *
- * This routine was derived from code by Henry Spencer.
- */
-
-void
-mybcopy(src, dst, length)
-       pointer dst;
-       const pointer src;
-       register int length;
-       {
-       register char *d = dst;
-       register char *s = src;
-
-       while (--length >= 0)
-               *d++ = *s++;
-}
-
-
 /*
  * prefix -- see if pfx is a prefix of string.
  */
 
 int
-prefix(pfx, string)
-       register char const *pfx;
-       register char const *string;
-       {
+prefix(const char *pfx, const char *string)
+{
        while (*pfx) {
                if (*pfx++ != *string++)
                        return 0;
@@ -147,12 +107,10 @@ prefix(pfx, string)
  */
 
 int
-number(s)
-       const char *s;
-       {
-
+number(const char *s)
+{
        if (! is_number(s))
-               error2("Illegal number", (char *)s);
+               error("Illegal number: %s", (char *)s);
        return atoi(s);
 }
 
@@ -163,12 +121,15 @@ number(s)
  */
 
 int
-is_number(p)
-       register const char *p;
-       {
+is_number(const char *p)
+{
        do {
                if (! is_digit(*p))
                        return 0;
        } while (*++p != '\0');
        return 1;
 }
+
+/*
+ * $PchId: mystring.c,v 1.4 2006/05/22 12:21:53 philip Exp $
+ */
index 6eaa1df0be9023b2e94de5521ba85d5638b53276..9e9939cd0efb28ccda95954c4e2e2b80bf41f0d3 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)mystring.h  5.1 (Berkeley) 3/7/91
+ *     @(#)mystring.h  8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/mystring.h,v 1.8 2004/04/06 20:06:51 markm Exp $
  */
 
-#ifndef SYSV
-#define strchr mystrchr
-#endif
+#include <string.h>
 
-#ifdef __STDC__
 void scopyn(const char *, char *, int);
-char *strchr(const char *, int);
-void mybcopy(const pointer, pointer, int);
 int prefix(const char *, const char *);
 int number(const char *);
 int is_number(const char *);
-int strcmp(const char *, const char *);        /* from C library */
-char *strcpy(char *, const char *);    /* from C library */
-int strlen(const char *);              /* from C library */
-char *strcat(char *, const char *);    /* from C library */
-char *strerror(int);                   /* from C library */
-#else
-void scopyn();
-char *strchr();
-void mybcopy();
-int prefix();
-int number();
-int is_number();
-int strcmp();
-char *strcpy();
-int strlen();
-char *strcat();
-char *strerror();
-#endif
 
 #define equal(s1, s2)  (strcmp(s1, s2) == 0)
 #define scopy(s1, s2)  ((void)strcpy(s2, s1))
-#define bcopy(src, dst, n)     mybcopy((pointer)(src), (pointer)(dst), n)
+
+/*
+ * $PchId: mystring.h,v 1.3 2006/03/29 15:49:08 philip Exp $
+ */
index 5193a295dd8e6fd7458c2b6a7bc2368cd1c73a78..fb867053e06b0face215daf6b9ae6a71e6b01ca0 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)nodes.c.pat 5.2 (Berkeley) 3/8/91
+ *     @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/nodes.c.pat,v 1.15 2004/04/06 20:06:51 markm Exp $
  */
 
+#include <stdlib.h>
 /*
  * Routine for dealing with parsed shell commands.
  */
 #include "shell.h"
 #include "nodes.h"
 #include "memalloc.h"
-#include "machdep.h"
 #include "mystring.h"
 
-
-int funcblocksize;             /* size of structures in function */
-int funcstringsize;            /* size of strings in node */
-#ifdef __STDC__
-pointer funcblock;             /* block to allocate function from */
-#else
-char *funcblock;               /* block to allocate function from */
+#ifndef __minix
+#include <sys/param.h>
 #endif
-char *funcstring;              /* block to allocate strings from */
+#include "machdep.h"
+
+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 */
 
 %SIZES
 
 
-#ifdef __STDC__
 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 *);
-#else
-STATIC void calcsize();
-STATIC void sizenodelist();
-STATIC union node *copynode();
-STATIC struct nodelist *copynodelist();
-STATIC char *nodesavestr();
-#endif
 
 
 
@@ -80,86 +69,81 @@ STATIC char *nodesavestr();
  */
 
 union node *
-copyfunc(n)
-      union node *n;
-      {
-      if (n == NULL)
-           return NULL;
-      funcblocksize = 0;
-      funcstringsize = 0;
-      calcsize(n);
-      funcblock = ckmalloc(funcblocksize + funcstringsize);
-      funcstring = (char *)funcblock + funcblocksize;
-      return copynode(n);
+copyfunc(union node *n)
+{
+       if (n == NULL)
+               return NULL;
+       funcblocksize = 0;
+       funcstringsize = 0;
+       calcsize(n);
+       funcblock = ckmalloc(funcblocksize + funcstringsize);
+       funcstring = (char *)funcblock + funcblocksize;
+       return copynode(n);
 }
 
 
 
 STATIC void
-calcsize(n)
-      union node *n;
-      {
-      %CALCSIZE
+calcsize(union node *n)
+{
+       %CALCSIZE
 }
 
 
 
 STATIC void
-sizenodelist(lp)
-      struct nodelist *lp;
-      {
-      while (lp) {
-           funcblocksize += ALIGN(sizeof (struct nodelist));
-           calcsize(lp->n);
-           lp = lp->next;
-      }
+sizenodelist(struct nodelist *lp)
+{
+       while (lp) {
+               funcblocksize += ALIGN(sizeof(struct nodelist));
+               calcsize(lp->n);
+               lp = lp->next;
+       }
 }
 
 
 
 STATIC union node *
-copynode(n)
-      union node *n;
-      {
-      union node *new;
+copynode(union node *n)
+{
+       union node *new;
 
-      %COPY
-      return new;
+       %COPY
+       return new;
 }
 
 
 STATIC struct nodelist *
-copynodelist(lp)
-      struct nodelist *lp;
-      {
-      struct nodelist *start;
-      struct nodelist **lpp;
-
-      lpp = &start;
-      while (lp) {
-           *lpp = funcblock;
-           *(char **)&funcblock += ALIGN(sizeof (struct nodelist));
-           (*lpp)->n = copynode(lp->n);
-           lp = lp->next;
-           lpp = &(*lpp)->next;
-      }
-      *lpp = NULL;
-      return start;
+copynodelist(struct nodelist *lp)
+{
+       struct nodelist *start;
+       struct nodelist **lpp;
+
+       lpp = &start;
+       while (lp) {
+               *lpp = funcblock;
+               funcblock = (char *)funcblock + ALIGN(sizeof(struct nodelist));
+               (*lpp)->n = copynode(lp->n);
+               lp = lp->next;
+               lpp = &(*lpp)->next;
+       }
+       *lpp = NULL;
+       return start;
 }
 
 
 
 STATIC char *
-nodesavestr(s)
-      char *s;
-      {
-      register char *p = s;
-      register char *q = funcstring;
-      char *rtn = funcstring;
-
-      while (*q++ = *p++);
-      funcstring = q;
-      return rtn;
+nodesavestr(char *s)
+{
+       char *p = s;
+       char *q = funcstring;
+       char   *rtn = funcstring;
+
+       while ((*q++ = *p++) != '\0')
+               continue;
+       funcstring = q;
+       return rtn;
 }
 
 
@@ -169,9 +153,12 @@ nodesavestr(s)
  */
 
 void
-freefunc(n)
-      union node *n;
-      {
-      if (n)
-           ckfree(n);
+freefunc(union node *n)
+{
+       if (n)
+               ckfree(n);
 }
+
+/*
+ * $PchId: nodes.c.pat,v 1.5 2006/05/22 12:43:57 philip Exp $
+ */
index b7c680c7ec8a8d19275b7a9fe1d74647f283982a..2c25c1d33753c2fa5807a9dc377e28d5a8a9d1cf 100755 (executable)
@@ -1,7 +1,6 @@
-#!/bin/sh -
 #
-# Copyright (c) 1991 The Regents of the University of California.
-# All rights reserved.
+# Copyright (c) 1991, 1993
+#      The Regents of the University of California.  All rights reserved.
 #
 # This code is derived from software contributed to Berkeley by
 # Kenneth Almquist.
 # 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.
@@ -34,7 +29,8 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-#      @(#)nodetypes   5.1 (Berkeley) 3/7/91
+#      @(#)nodetypes   8.2 (Berkeley) 5/4/95
+# $FreeBSD: src/bin/sh/nodetypes,v 1.9 2004/04/06 20:06:51 markm Exp $
 
 # This file describes the nodes used in parse trees.  Unindented lines
 # contain a node type followed by a structure tag.  Subsequent indented
@@ -118,7 +114,9 @@ NARG narg                   # represents a word
 
 NTO nfile                      # fd> fname
 NFROM nfile                    # fd< fname
+NFROMTO nfile                  # fd<> fname
 NAPPEND nfile                  # fd>> fname
+NCLOBBER nfile                 # fd>| fname
        type      int
        next      nodeptr               # next redirection in list
        fd        int                   # file descriptor being redirected
@@ -131,6 +129,8 @@ NFROMFD ndup                        # fd>&dupfd
        next      nodeptr               # next redirection in list
        fd        int                   # file descriptor being redirected
        dupfd     int                   # file descriptor to duplicate
+       vname     nodeptr               # file name if fd>&$var
+
 
 NHERE nhere                    # fd<<\!
 NXHERE nhere                   # fd<<!
@@ -138,3 +138,10 @@ NXHERE nhere                       # fd<<!
        next      nodeptr               # next redirection in list
        fd        int                   # file descriptor being redirected
        doc       nodeptr               # input to command (NARG node)
+
+NNOT nnot                      # ! command  (actually pipeline)
+       type    int
+       com     nodeptr
+
+#
+# $PchId: nodetypes,v 1.3 2006/03/29 15:43:35 philip Exp $
index 6d854ba1e6c09ca4d53017ab6f1d4f88010375ec..6109f1a993bce5d75025dc3deed0e2a81b0a1fdf 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)options.c  5.2 (Berkeley) 3/13/91";
+#if 0
+static char sccsid[] = "@(#)options.c  8.2 (Berkeley) 5/4/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/options.c,v 1.21 2004/04/06 20:06:51 markm Exp $");
+*/
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
 
 #include "shell.h"
 #define DEFINE_OPTIONS
@@ -52,25 +58,24 @@ static char sccsid[] = "@(#)options.c       5.2 (Berkeley) 3/13/91";
 #include "memalloc.h"
 #include "error.h"
 #include "mystring.h"
+#include "builtins.h"
+#if !defined(NO_HISTORY) && !defined(EDITLINE)
+#include "myhistedit.h"
+#endif
 
 char *arg0;                    /* value of $0 */
 struct shparam shellparam;     /* current positional parameters */
 char **argptr;                 /* argument list for builtin commands */
-char *optarg;                  /* set by nextopt (like getopt) */
+char *shoptarg;                        /* set by nextopt (like getopt) */
 char *optptr;                  /* used by nextopt */
-int editable;                  /* isatty(0) && isatty(1) */
 
 char *minusc;                  /* argument to -c option */
 
 
-#ifdef __STDC__
 STATIC void options(int);
+STATIC void minus_o(char *, int);
 STATIC void setoption(int, int);
-#else
-STATIC void options();
-STATIC void setoption();
-#endif
-
+STATIC int getopts(char *, char *, char **, char ***, char **);
 
 
 /*
@@ -78,46 +83,55 @@ STATIC void setoption();
  */
 
 void
-procargs(argc, argv)
-       char **argv;
-       {
-       char *p;
+procargs(int argc, char **argv)
+{
+       int i;
 
        argptr = argv;
        if (argc > 0)
                argptr++;
-       for (p = optval ; p < optval + sizeof optval - 1 ; p++)
-               *p = 2;
+       for (i = 0; i < NOPTS; i++)
+               optlist[i].val = 2;
+       privileged = (getuid() != geteuid() || getgid() != getegid());
        options(1);
        if (*argptr == NULL && minusc == NULL)
                sflag = 1;
-       editable = (isatty(0) && isatty(1));
-       if (iflag == 2 && sflag == 1 && editable)
+       if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
                iflag = 1;
-       if (jflag == 2)
-               jflag = iflag;
-       for (p = optval ; p < optval + sizeof optval - 1 ; p++)
-               if (*p == 2)
-                       *p = 0;
+       if (mflag == 2)
+               mflag = iflag;
+       for (i = 0; i < NOPTS; i++)
+               if (optlist[i].val == 2)
+                       optlist[i].val = 0;
        arg0 = argv[0];
-       if (sflag == 0) {
-               arg0 = *argptr++;
-               if (minusc == NULL) {
-                       commandname = arg0;
-                       setinputfile(commandname, 0);
-               }
+       if (sflag == 0 && minusc == NULL) {
+               commandname = arg0 = *argptr++;
+               setinputfile(commandname, 0);
        }
+       /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
+       if (argptr && minusc && *argptr)
+               arg0 = *argptr++;
+
        shellparam.p = argptr;
+       shellparam.reset = 1;
        /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
        while (*argptr) {
                shellparam.nparam++;
                argptr++;
        }
-       setinteractive(iflag);
-       setjobctl(jflag);
+       optschanged();
 }
 
 
+void
+optschanged(void)
+{
+       setinteractive(iflag);
+#if !defined(NO_HISTORY) && !defined(EDITLINE)
+       histedit();
+#endif
+       setjobctl(mflag);
+}
 
 /*
  * Process shell options.  The global variable argptr contains a pointer
@@ -125,8 +139,9 @@ procargs(argc, argv)
  */
 
 STATIC void
-options(cmdline) {
-       register char *p;
+options(int cmdline)
+{
+       char *p;
        int val;
        int c;
 
@@ -136,14 +151,14 @@ options(cmdline) {
                argptr++;
                if ((c = *p++) == '-') {
                        val = 1;
-                        if (p[0] == '\0' || p[0] == '-' && p[1] == '\0') {
+                        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);
+                                               setparam(argptr);
                                 }
                                break;    /* "-" or  "--" terminates options */
                        }
@@ -166,26 +181,79 @@ options(cmdline) {
 #ifdef NOHACK
                                break;
 #endif
+                       } else if (c == 'o') {
+                               minus_o(*argptr, val);
+                               if (*argptr)
+                                       argptr++;
                        } else {
+                               if (c == 'p' && !val && privileged) {
+                                       (void) setuid(getuid());
+                                       (void) setgid(getgid());
+                               }
                                setoption(c, val);
                        }
                }
-               if (! cmdline)
-                       break;
        }
 }
 
-
 STATIC void
-setoption(flag, val)
-       char flag;
-       int val;
-       {
-       register char *p;
+minus_o(char *name, int val)
+{
+       int doneset, i;
+
+       if (name == NULL) {
+               if (val) {
+                       /* "Pretty" output. */
+                       out1str("Current option settings\n");
+                       for (i = 0; i < NOPTS; i++)
+                               out1fmt("%-16s%s\n", optlist[i].name,
+                                       optlist[i].val ? "on" : "off");
+               } else {
+                       /* Output suitable for re-input to shell. */
+                       for (doneset = i = 0; i < NOPTS; i++)
+                               if (optlist[i].val) {
+                                       if (!doneset) {
+                                               out1str("set");
+                                               doneset = 1;
+                                       }
+                                       out1fmt(" -o %s", optlist[i].name);
+                               }
+                       if (doneset)
+                               out1c('\n');
+               }
+       } else {
+               for (i = 0; i < NOPTS; i++)
+                       if (equal(name, optlist[i].name)) {
+                               if (!val && privileged && equal(name, "privileged")) {
+                                       (void) setuid(getuid());
+                                       (void) setgid(getgid());
+                               }
+                               setoption(optlist[i].letter, val);
+                               return;
+                       }
+               error("Illegal option -o %s", name);
+       }
+}
+
 
-       if ((p = strchr(optchar, flag)) == NULL)
-               error("Illegal option -%c", flag);
-       optval[p - optchar] = val;
+STATIC void
+setoption(int flag, int val)
+{
+       int i;
+
+       for (i = 0; i < NOPTS; i++)
+               if (optlist[i].letter == flag) {
+                       optlist[i].val = val;
+                       if (val) {
+                               /* #%$ hack for ksh semantics */
+                               if (flag == 'V')
+                                       Eflag = 0;
+                               else if (flag == 'E')
+                                       Vflag = 0;
+                       }
+                       return;
+               }
+       error("Illegal option -%c", flag);
 }
 
 
@@ -194,10 +262,12 @@ setoption(flag, val)
 INCLUDE "options.h"
 
 SHELLPROC {
-       char *p;
+       int i;
+
+       for (i = 0; i < NOPTS; i++)
+               optlist[i].val = 0;
+       optschanged();
 
-       for (p = optval ; p < optval + sizeof optval ; p++)
-               *p = 0;
 }
 #endif
 
@@ -207,9 +277,8 @@ SHELLPROC {
  */
 
 void
-setparam(argv)
-       char **argv;
-       {
+setparam(char **argv)
+{
        char **newparam;
        char **ap;
        int nparam;
@@ -233,9 +302,8 @@ setparam(argv)
  */
 
 void
-freeparam(param)
-       struct shparam *param;
-       {
+freeparam(struct shparam *param)
+{
        char **ap;
 
        if (param->malloc) {
@@ -251,7 +319,9 @@ freeparam(param)
  * The shift builtin command.
  */
 
-shiftcmd(argc, argv)  char **argv; {
+int
+shiftcmd(int argc, char **argv)
+{
        int n;
        char **ap1, **ap2;
 
@@ -259,7 +329,7 @@ shiftcmd(argc, argv)  char **argv; {
        if (argc > 1)
                n = number(argv[1]);
        if (n > shellparam.nparam)
-               n = shellparam.nparam;
+               error("can't shift that many");
        INTOFF;
        shellparam.nparam -= n;
        for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
@@ -279,13 +349,14 @@ shiftcmd(argc, argv)  char **argv; {
  * The set command builtin.
  */
 
-setcmd(argc, argv)  char **argv; {
+int
+setcmd(int argc, char **argv)
+{
        if (argc == 1)
                return showvarscmd(argc, argv);
        INTOFF;
        options(0);
-       setinteractive(iflag);
-       setjobctl(jflag);
+       optschanged();
        if (*argptr != NULL) {
                setparam(argptr);
        }
@@ -294,6 +365,15 @@ setcmd(argc, argv)  char **argv; {
 }
 
 
+void
+getoptsreset(const char *value)
+{
+       if (number(value) == 1) {
+               shellparam.optnext = NULL;
+               shellparam.reset = 1;
+       }
+}
+
 /*
  * The getopts builtin.  Shellparam.optnext points to the next argument
  * to be processed.  Shellparam.optptr points to the next character to
@@ -301,63 +381,127 @@ setcmd(argc, argv)  char **argv; {
  * then it's the first time getopts has been called.
  */
 
-getoptscmd(argc, argv)  char **argv; {
-       register char *p, *q;
-       char c;
-       char s[10];
-
-       if (argc != 3)
-               error("Usage: getopts optstring var");
-       if (shellparam.optnext == NULL) {
-               shellparam.optnext = shellparam.p;
+int
+getoptscmd(int argc, char **argv)
+{
+       char **optbase = NULL;
+
+       if (argc < 3)
+               error("usage: getopts optstring var [arg]");
+       else if (argc == 3)
+               optbase = shellparam.p;
+       else
+               optbase = &argv[3];
+
+       if (shellparam.reset == 1) {
+               shellparam.optnext = optbase;
                shellparam.optptr = NULL;
+               shellparam.reset = 0;
        }
-       if ((p = shellparam.optptr) == NULL || *p == '\0') {
-               p = *shellparam.optnext;
+
+       return getopts(argv[1], argv[2], optbase, &shellparam.optnext,
+                      &shellparam.optptr);
+}
+
+STATIC int
+getopts(char *optstr, char *optvar, char **optfirst, char ***optnext,
+    char **optptr)
+{
+       char *p, *q;
+       char c = '?';
+       int done = 0;
+       int ind = 0;
+       int err = 0;
+       char s[10];
+
+       if ((p = *optptr) == NULL || *p == '\0') {
+               /* Current word is done, advance */
+               if (*optnext == NULL)
+                       return 1;
+               p = **optnext;
                if (p == NULL || *p != '-' || *++p == '\0') {
 atend:
-                       fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1);
-                       setvar("OPTIND", s, 0);
-                       shellparam.optnext = NULL;
-                       return 1;
+                       ind = *optnext - optfirst + 1;
+                       *optnext = NULL;
+                       p = NULL;
+                       done = 1;
+                       goto out;
                }
-               shellparam.optnext++;
+               (*optnext)++;
                if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
                        goto atend;
        }
+
        c = *p++;
-       for (q = argv[1] ; *q != c ; ) {
+       for (q = optstr; *q != c; ) {
                if (*q == '\0') {
-                       out1fmt("Illegal option -%c\n", c);
+                       if (optstr[0] == ':') {
+                               s[0] = c;
+                               s[1] = '\0';
+                               err |= setvarsafe("OPTARG", s, 0);
+                       }
+                       else {
+                               out1fmt("Illegal option -%c\n", c);
+                               (void) unsetvar("OPTARG");
+                       }
                        c = '?';
-                       goto out;
+                       goto bad;
                }
                if (*++q == ':')
                        q++;
        }
+
        if (*++q == ':') {
-               if (*p == '\0') {
-                       if ((p = *shellparam.optnext) == NULL) {
+               if (*p == '\0' && (p = **optnext) == NULL) {
+                       if (optstr[0] == ':') {
+                               s[0] = c;
+                               s[1] = '\0';
+                               err |= setvarsafe("OPTARG", s, 0);
+                               c = ':';
+                       }
+                       else {
                                out1fmt("No arg for -%c option\n", c);
+                               (void) unsetvar("OPTARG");
                                c = '?';
-                               goto out;
                        }
-                       shellparam.optnext++;
+                       goto bad;
                }
-               setvar("OPTARG", p, 0);
-               p = "";
+
+               if (p == **optnext)
+                       (*optnext)++;
+               setvarsafe("OPTARG", p, 0);
+               p = NULL;
        }
+       else
+               setvarsafe("OPTARG", "", 0);
+       ind = *optnext - optfirst + 1;
+       goto out;
+
+bad:
+       ind = 1;
+       *optnext = NULL;
+       p = NULL;
 out:
-       shellparam.optptr = p;
+       *optptr = p;
+       fmtstr(s, sizeof(s), "%d", ind);
+       err |= setvarsafe("OPTIND", s, VNOFUNC);
        s[0] = c;
        s[1] = '\0';
-       setvar(argv[2], s, 0);
-       fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1);
-       setvar("OPTIND", s, 0);
-       return 0;
+       err |= setvarsafe(optvar, s, 0);
+       if (err) {
+               *optnext = NULL;
+               *optptr = NULL;
+               flushall();
+               exraise(EXERROR);
+       }
+       return done;
 }
 
 /*
+ * XXX - should get rid of.  have all builtins use getopt(3).  the
+ * library getopt must have the BSD extension static variable "optreset"
+ * otherwise it can't be used within the shell safely.
+ *
  * Standard option processing (a la getopt) for builtin routines.  The
  * only argument that is passed to nextopt is the option string; the
  * other arguments are unnecessary.  It return the character, or '\0' on
@@ -365,10 +509,9 @@ out:
  */
 
 int
-nextopt(optstring)
-       char *optstring;
-       {
-       register char *p, *q;
+nextopt(char *optstring)
+{
+       char *p, *q;
        char c;
 
        if ((p = optptr) == NULL || *p == '\0') {
@@ -389,9 +532,13 @@ nextopt(optstring)
        if (*++q == ':') {
                if (*p == '\0' && (p = *argptr++) == NULL)
                        error("No arg for -%c option", c);
-               optarg = p;
+               shoptarg = p;
                p = NULL;
        }
        optptr = p;
        return c;
 }
+
+/*
+ * $PchId: options.c,v 1.5 2006/05/22 12:23:10 philip Exp $
+ */
index 7d86de33d35d594b9c20a369e2f32a5e124d24c5..27b461a880d32581f989facb9a051a723e5594a1 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)options.h   5.1 (Berkeley) 3/7/91
+ *     @(#)options.h   8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/options.h,v 1.13 2004/04/06 20:06:51 markm Exp $
  */
 
 struct shparam {
-       int nparam;     /* number of positional parameters (without $0) */
-       char malloc;    /* true if parameter list dynamicly allocated */
+       int nparam;             /* # of positional parameters (without $0) */
+       unsigned char malloc;   /* if parameter list dynamically allocated */
+       unsigned char reset;    /* if getopts has been reset */
        char **p;               /* parameter list */
-       char **optnext; /* next parameter to be processed by getopts */
-       char *optptr;   /* used by getopts */
+       char **optnext;         /* next parameter to be processed by getopts */
+       char *optptr;           /* used by getopts */
 };
 
 
 
-#define eflag optval[0]
-#define fflag optval[1]
-#define Iflag optval[2]
-#define iflag optval[3]
-#define jflag optval[4]
-#define nflag optval[5]
-#define sflag optval[6]
-#define xflag optval[7]
-#define zflag optval[8]
-#define vflag optval[9]
+#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        privileged optlist[15].val
+#define        Tflag optlist[16].val
+#define        Pflag optlist[17].val
 
-#define NOPTS  10
+#define NOPTS  18
+
+struct optent {
+       const char *name;
+       const char letter;
+       char val;
+};
 
 #ifdef DEFINE_OPTIONS
-const char optchar[NOPTS+1] = "efIijnsxzv";       /* shell flags */
-char optval[NOPTS+1];           /* values of option flags */
+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 },
+       { "privileged", 'p',    0 },
+       { "trapsasync", 'T',    0 },
+       { "physical",   'P',    0 },
+};
 #else
-extern const char optchar[NOPTS+1];
-extern char optval[NOPTS+1];
+extern struct optent optlist[NOPTS];
 #endif
 
 
@@ -72,19 +101,19 @@ 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 *optarg;           /* set by nextopt */
+extern char *shoptarg;         /* set by nextopt */
 extern char *optptr;           /* used by nextopt */
-extern int editable;           /* isatty(0) && isatty(1) */
-
 
-#ifdef __STDC__
 void procargs(int, char **);
+void optschanged(void);
 void setparam(char **);
 void freeparam(struct shparam *);
+int shiftcmd(int, char **);
+int setcmd(int, char **);
+int getoptscmd(int, char **);
 int nextopt(char *);
-#else
-void procargs();
-void setparam();
-void freeparam();
-int nextopt();
-#endif
+void getoptsreset(const char *);
+
+/*
+ * $PchId: options.h,v 1.4 2006/03/29 15:37:43 philip Exp $
+ */
index 03e48e474a4758b44be6b75a9590a65a1c6bf4af..fb89e2adea84e4da30de16e6c8469c4965f6b40e 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
@@ -35,7 +31,7 @@
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)output.c   5.1 (Berkeley) 3/7/91";
+static char sccsid[] = "@(#)output.c   8.1 (Berkeley) 5/31/93";
 #endif /* not lint */
 
 /*
@@ -55,12 +51,16 @@ static char sccsid[] = "@(#)output.c        5.1 (Berkeley) 3/7/91";
 #include "output.h"
 #include "memalloc.h"
 #include "error.h"
+#include "var.h"
 #ifdef __STDC__
 #include "stdarg.h"
 #else
 #include <varargs.h>
 #endif
 #include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
 
 
 #define OUTBUFSIZ BUFSIZ
@@ -115,27 +115,63 @@ open_mem(block, length, file)
 
 void
 out1str(p)
-       char *p;
+       const char *p;
        {
        outstr(p, out1);
 }
 
+void
+out1qstr(const char *p)
+{
+       outqstr(p, out1);
+}
+
 
 void
-out2str(p)
-       char *p;
-       {
+out2str(const char *p)
+{
        outstr(p, out2);
 }
 
 
 void
 outstr(p, file)
-       register char *p;
+       register const char *p;
        register struct output *file;
        {
        while (*p)
                outc(*p++, file);
+       if (file == out2)
+               flushout(file);
+}
+
+/* Like outstr(), but quote for re-input into the shell. */
+void
+outqstr(const char *p, struct output *file)
+{
+       char ch;
+
+       if (p[strcspn(p, "|&;<>()$`\\\"'")] == '\0' && (!ifsset() ||
+           p[strcspn(p, ifsval())] == '\0')) {
+               outstr(p, file);
+               return;
+       }
+
+       out1c('\'');
+       while ((ch = *p++) != '\0') {
+               switch (ch) {
+               case '\'':
+                       /*
+                        * Can't quote single quotes inside single quotes;
+                        * close them, write escaped single quote, open again.
+                        */
+                       outstr("'\\''", file);
+                       break;
+               default:
+                       outc(ch, file);
+               }
+       }
+       out1c('\'');
 }
 
 
@@ -208,7 +244,8 @@ freestdout() {
 
 #ifdef __STDC__
 void
-outfmt(struct output *file, char *fmt, ...) {
+outfmt(struct output *file, const char *fmt, ...)
+{
        va_list ap;
 
        va_start(ap, fmt);
@@ -218,7 +255,8 @@ outfmt(struct output *file, char *fmt, ...) {
 
 
 void
-out1fmt(char *fmt, ...) {
+out1fmt(const char *fmt, ...)
+{
        va_list ap;
 
        va_start(ap, fmt);
@@ -226,9 +264,20 @@ out1fmt(char *fmt, ...) {
        va_end(ap);
 }
 
+void
+dprintf(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       doformat(out2, fmt, ap);
+       va_end(ap);
+       flushout(out2);
+}
 
 void
-fmtstr(char *outbuf, int length, char *fmt, ...) {
+fmtstr(char *outbuf, int length, const char *fmt, ...)
+{
        va_list ap;
        struct output strout;
 
@@ -275,6 +324,19 @@ out1fmt(va_alist)
        va_end(ap);
 }
 
+void
+dprintf(va_alist)
+       va_dcl
+       {
+       va_list ap;
+       char *fmt;
+
+       va_start(ap);
+       fmt = va_arg(ap, char *);
+       doformat(out2, fmt, ap);
+       va_end(ap);
+       flushout(out2);
+}
 
 void
 fmtstr(va_alist)
@@ -325,11 +387,8 @@ static const char digit[17] = "0123456789ABCDEF";
 
 
 void
-doformat(dest, f, ap)
-       register struct output *dest;
-       register char *f;               /* format string */
-       va_list ap;
-       {
+doformat(struct output *dest, const char *f, va_list ap)
+{
        register char c;
        char temp[TEMPSIZE];
        int flushleft;
@@ -517,15 +576,6 @@ xwrite(fd, buf, nbytes)
        }
 }
 
-
 /*
- * Version of ioctl that retries after a signal is caught.
+ * $PchId: output.c,v 1.6 2006/05/22 12:46:03 philip Exp $
  */
-
-int
-xioctl(fd, request, arg) {
-       int i;
-
-       while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
-       return i;
-}
index b8b814c3e2c72e88292e2a18e17e7777efcf0e06..44b8b2a288491f9921135f2c421408b065894362 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)output.h    5.1 (Berkeley) 3/7/91
+ *     @(#)output.h    8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/output.h,v 1.13 2004/04/06 20:06:51 markm Exp $
  */
 
 #ifndef OUTPUT_INCL
 
+#include <stdarg.h>
+
 struct output {
        char *nextc;
        int nleft;
@@ -53,38 +52,27 @@ extern struct output memout;
 extern struct output *out1;
 extern struct output *out2;
 
+#ifndef __printflike
+#define __printflike(a,b)
+#endif
 
-#ifdef __STDC__
-void outstr(char *, struct output *);
-void out1str(char *);
-void out2str(char *);
-void outfmt(struct output *, char *, ...);
-void out1fmt(char *, ...);
-void fmtstr(char *, int, char *, ...);
-/* void doformat(struct output *, char *, va_list); */
-void doformat();
+void open_mem(char *, int, struct output *);
+void out1str(const char *);
+void out1qstr(const char *);
+void out2str(const char *);
+void out2qstr(const char *);
+void outstr(const char *, struct output *);
+void outqstr(const char *, struct output *);
 void emptyoutbuf(struct output *);
 void flushall(void);
 void flushout(struct output *);
 void freestdout(void);
+void outfmt(struct output *, const char *, ...) __printflike(2, 3);
+void out1fmt(const char *, ...) __printflike(1, 2);
+void dprintf(const char *, ...) __printflike(1, 2);
+void fmtstr(char *, int, const char *, ...) __printflike(3, 4);
+void doformat(struct output *, const char *, va_list) __printflike(2, 0);
 int xwrite(int, char *, int);
-int xioctl(int, int, int);
-#else
-void outstr();
-void out1str();
-void out2str();
-void outfmt();
-void out1fmt();
-void fmtstr();
-/* void doformat(); */
-void doformat();
-void emptyoutbuf();
-void flushall();
-void flushout();
-void freestdout();
-int xwrite();
-int xioctl();
-#endif
 
 #define outc(c, file)  (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c)))
 #define out1c(c)       outc(c, out1);
@@ -92,3 +80,7 @@ int xioctl();
 
 #define OUTPUT_INCL
 #endif
+
+/*
+ * $PchId: output.h,v 1.5 2006/05/23 12:04:54 philip Exp $
+ */
index 318a8a45d6d6d5c9ff7b5aa39a824fc01d854894..d837829ff99c88406533d53a9652d896410e0c51 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)parser.c   5.3 (Berkeley) 4/12/91";
+#if 0
+static char sccsid[] = "@(#)parser.c   8.7 (Berkeley) 5/16/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/parser.c,v 1.51.2.1 2005/03/03 03:43:20 obrien Exp $");
+*/
+
+#include <stdlib.h>
+#include <unistd.h>
 
 #include "shell.h"
 #include "parser.h"
 #include "nodes.h"
 #include "expand.h"    /* defines rmescapes() */
-#include "redir.h"     /* defines copyfd() */
 #include "syntax.h"
 #include "options.h"
 #include "input.h"
@@ -51,16 +55,22 @@ static char sccsid[] = "@(#)parser.c        5.3 (Berkeley) 4/12/91";
 #include "error.h"
 #include "memalloc.h"
 #include "mystring.h"
-
+#include "alias.h"
+#include "show.h"
+#include "eval.h"
+#if !defined(NO_HISTORY) && !defined(EDITLINE)
+#include "myhistedit.h"
+#endif
 
 /*
  * Shell command parser.
  */
 
-#define EOFMARKLEN 79
+#define        EOFMARKLEN      79
+#define        PROMPTLEN       128
 
 /* values returned by readtoken */
-#include "token.def"
+#include "token.h"
 
 
 
@@ -73,20 +83,22 @@ struct heredoc {
 
 
 
-struct heredoc *heredoclist;   /* list of here documents to read */
-int parsebackquote;            /* nonzero if we are inside backquotes */
-int doprompt;                  /* if set, prompt the user */
-int needprompt;                        /* true if interactive and at start of line */
-int lasttoken;                 /* last token read */
+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 */
 MKINIT int tokpushback;                /* last token pushed back */
-char *wordtext;                        /* text of last word returned by readtoken */
-int checkkwd;               /* 1 == check for kwds, 2 == also eat newlines */
-struct nodelist *backquotelist;
-union node *redirnode;
-struct heredoc *heredoc;
-int quoteflag;                 /* set if (part of) last token was quoted */
-int startlinno;                        /* line # where last token started */
+STATIC char *wordtext;         /* text of last word returned by readtoken */
+MKINIT int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
+STATIC struct nodelist *backquotelist;
+STATIC union node *redirnode;
+STATIC struct heredoc *heredoc;
+STATIC int quoteflag;          /* set if (part of) last token was quoted */
+STATIC int startlinno;         /* line # where last token started */
 
+/* XXX When 'noaliases' is set to one, no alias expansion takes place. */
+static int noaliases = 0;
 
 #define GDB_HACK 1 /* avoid local declarations which gdb can't handle */
 #ifdef GDB_HACK
@@ -95,27 +107,22 @@ static const char types[] = "}-+?=";
 #endif
 
 
-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((union node **, union node *));
-STATIC void parsefname __P((void));
-STATIC void parseheredoc __P((void));
-STATIC int readtoken __P((void));
-STATIC int readtoken1 __P((int, char const *, char *, int));
-STATIC void attyline __P((void));
-STATIC int noexpand __P((char *));
-STATIC void synexpect __P((int));
-STATIC void synerror __P((char *));
-
-#if ATTY || READLINE
-STATIC void putprompt __P((char *));
-#else /* not ATTY */
-#define putprompt(s)   out2str(s)
-#endif
-
-
+STATIC union node *list(int);
+STATIC union node *andor(void);
+STATIC union node *pipeline(void);
+STATIC union node *command(void);
+STATIC union node *simplecmd(union node **, union node *);
+STATIC union node *makename(void);
+STATIC void parsefname(void);
+STATIC void parseheredoc(void);
+STATIC int peektoken(void);
+STATIC int readtoken(void);
+STATIC int xxreadtoken(void);
+STATIC int readtoken1(int, char const *, char *, int);
+STATIC int noexpand(char *);
+STATIC void synexpect(int);
+STATIC void synerror(char *);
+STATIC void setprompt(int);
 
 
 /*
@@ -124,15 +131,21 @@ STATIC void putprompt __P((char *));
  */
 
 union node *
-parsecmd(interact) {
+parsecmd(int interact)
+{
        int t;
        extern int exitstatus;
 
+       tokpushback = 0;
        doprompt = interact;
        if (doprompt)
-               putprompt(exitstatus == 0 ? ps1val() : pseval());
+               setprompt(exitstatus == 0 || (vpse.flags & VUNSET)
+                                       ? 1 : -1);
+       else
+               setprompt(0);
        needprompt = 0;
-       if ((t = readtoken()) == TEOF)
+       t = readtoken();
+       if (t == TEOF)
                return NEOF;
        if (t == TNL)
                return NULL;
@@ -142,36 +155,48 @@ parsecmd(interact) {
 
 
 STATIC union node *
-list(nlflag) {
-       union node *n1, *n2, *n3, **pn;
-       int first;
+list(int nlflag)
+{
+       union node *n1, *n2, *n3;
+       int tok;
 
        checkkwd = 2;
        if (nlflag == 0 && tokendlist[peektoken()])
                return NULL;
-       n1 = andor();
-       for (first = 1; ; first = 0) {
-               switch (readtoken()) {
-               case TBACKGND:
-                       pn = &n1;
-                       if (!first && n1->type == NSEMI) pn = &n1->nbinary.ch2;
-                       if ((*pn)->type == NCMD || (*pn)->type == NPIPE) {
-                               (*pn)->ncmd.backgnd = 1;
-                       } else if ((*pn)->type == NREDIR) {
-                               (*pn)->type = NBACKGND;
+       n1 = NULL;
+       for (;;) {
+               n2 = andor();
+               tok = readtoken();
+               if (tok == TBACKGND) {
+                       if (n2->type == NCMD || n2->type == NPIPE) {
+                               n2->ncmd.backgnd = 1;
+                       } else if (n2->type == NREDIR) {
+                               n2->type = NBACKGND;
                        } else {
                                n3 = (union node *)stalloc(sizeof (struct nredir));
                                n3->type = NBACKGND;
-                               n3->nredir.n = *pn;
+                               n3->nredir.n = n2;
                                n3->nredir.redirect = NULL;
-                               *pn = n3;
+                               n2 = n3;
                        }
-                       goto tsemi;
+               }
+               if (n1 == NULL) {
+                       n1 = n2;
+               }
+               else {
+                       n3 = (union node *)stalloc(sizeof (struct nbinary));
+                       n3->type = NSEMI;
+                       n3->nbinary.ch1 = n1;
+                       n3->nbinary.ch2 = n2;
+                       n1 = n3;
+               }
+               switch (tok) {
+               case TBACKGND:
+               case TSEMI:
+                       tok = readtoken();
+                       /* FALLTHROUGH */
                case TNL:
-                       tokpushback++;
-                       /* fall through */
-tsemi:         case TSEMI:
-                       if (readtoken() == TNL) {
+                       if (tok == TNL) {
                                parseheredoc();
                                if (nlflag)
                                        return n1;
@@ -181,12 +206,6 @@ tsemi:             case TSEMI:
                        checkkwd = 2;
                        if (tokendlist[peektoken()])
                                return n1;
-                       n2 = andor();
-                       n3 = (union node *)stalloc(sizeof (struct nbinary));
-                       n3->type = NSEMI;
-                       n3->nbinary.ch1 = n1;
-                       n3->nbinary.ch2 = n2;
-                       n1 = n3;
                        break;
                case TEOF:
                        if (heredoclist)
@@ -206,7 +225,8 @@ tsemi:              case TSEMI:
 
 
 STATIC union node *
-andor() {
+andor(void)
+{
        union node *n1, *n2, *n3;
        int t;
 
@@ -232,10 +252,17 @@ andor() {
 
 
 STATIC union node *
-pipeline() {
-       union node *n1, *pipenode;
+pipeline(void)
+{
+       union node *n1, *n2, *pipenode;
        struct nodelist *lp, *prev;
+       int negate;
 
+       negate = 0;
+       TRACE(("pipeline: entered\n"));
+       while (readtoken() == TNOT)
+               negate = !negate;
+       tokpushback++;
        n1 = command();
        if (readtoken() == TPIPE) {
                pipenode = (union node *)stalloc(sizeof (struct npipe));
@@ -254,22 +281,31 @@ pipeline() {
                n1 = pipenode;
        }
        tokpushback++;
-       return n1;
+       if (negate) {
+               n2 = (union node *)stalloc(sizeof (struct nnot));
+               n2->type = NNOT;
+               n2->nnot.com = n1;
+               return n2;
+       } else
+               return n1;
 }
 
 
 
 STATIC union node *
-command() {
+command(void)
+{
        union node *n1, *n2;
        union node *ap, **app;
        union node *cp, **cpp;
        union node *redir, **rpp;
-       int t;
+       int t, negate = 0;
 
        checkkwd = 2;
-       redir = 0;
+       redir = NULL;
+       n1 = NULL;
        rpp = &redir;
+
        /* Check for redirection which may precede command */
        while (readtoken() == TREDIR) {
                *rpp = n2 = redirnode;
@@ -278,11 +314,18 @@ command() {
        }
        tokpushback++;
 
+       while (readtoken() == TNOT) {
+               TRACE(("command: TNOT recognized\n"));
+               negate = !negate;
+       }
+       tokpushback++;
+
        switch (readtoken()) {
        case TIF:
                n1 = (union node *)stalloc(sizeof (struct nif));
                n1->type = NIF;
-               n1->nif.test = list(0);
+               if ((n1->nif.test = list(0)) == NULL)
+                       synexpect(-1);
                if (readtoken() != TTHEN)
                        synexpect(TTHEN);
                n1->nif.ifpart = list(0);
@@ -291,7 +334,8 @@ command() {
                        n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
                        n2 = n2->nif.elsepart;
                        n2->type = NIF;
-                       n2->nif.test = list(0);
+                       if ((n2->nif.test = list(0)) == NULL)
+                               synexpect(-1);
                        if (readtoken() != TTHEN)
                                synexpect(TTHEN);
                        n2->nif.ifpart = list(0);
@@ -311,7 +355,8 @@ command() {
                int got;
                n1 = (union node *)stalloc(sizeof (struct nbinary));
                n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
-               n1->nbinary.ch1 = list(0);
+               if ((n1->nbinary.ch1 = list(0)) == NULL)
+                       synexpect(-1);
                if ((got=readtoken()) != TDO) {
 TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
                        synexpect(TDO);
@@ -340,8 +385,6 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
                        }
                        *app = NULL;
                        n1->nfor.args = ap;
-                       /* A newline or semicolon is required here to end
-                          the list.  */
                        if (lasttoken != TNL && lasttoken != TSEMI)
                                synexpect(-1);
                } else {
@@ -355,8 +398,10 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
                        n2->narg.backquote = NULL;
                        n2->narg.next = NULL;
                        n1->nfor.args = n2;
-                       /* A newline or semicolon is optional here. Anything
-                          else gets pushed back so we can read it again.  */
+                       /*
+                        * Newline or semicolon here is optional (but note
+                        * that the original Bourne shell only allowed NL).
+                        */
                        if (lasttoken != TNL && lasttoken != TSEMI)
                                tokpushback++;
                }
@@ -386,34 +431,40 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
                if (lasttoken != TWORD || ! equal(wordtext, "in"))
                        synerror("expecting \"in\"");
                cpp = &n1->ncase.cases;
-               while (checkkwd = 2, readtoken() == TWORD) {
+               noaliases = 1;  /* turn off alias expansion */
+               checkkwd = 2, readtoken();
+               while (lasttoken != TESAC) {
                        *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
                        cp->type = NCLIST;
                        app = &cp->nclist.pattern;
+                       if (lasttoken == TLP)
+                               readtoken();
                        for (;;) {
                                *app = ap = (union node *)stalloc(sizeof (struct narg));
                                ap->type = NARG;
                                ap->narg.text = wordtext;
                                ap->narg.backquote = backquotelist;
-                               if (readtoken() != TPIPE)
+                               if (checkkwd = 2, readtoken() != TPIPE)
                                        break;
                                app = &ap->narg.next;
-                               if (readtoken() != TWORD)
-                                       synexpect(TWORD);
+                               readtoken();
                        }
                        ap->narg.next = NULL;
                        if (lasttoken != TRP)
-                               synexpect(TRP);
+                               noaliases = 0, synexpect(TRP);
                        cp->nclist.body = list(0);
-                       if ((t = readtoken()) == TESAC)
-                               tokpushback++;
-                       else if (t != TENDCASE)
-                               synexpect(TENDCASE);
+
+                       checkkwd = 2;
+                       if ((t = readtoken()) != TESAC) {
+                               if (t != TENDCASE)
+                                       noaliases = 0, synexpect(TENDCASE);
+                               else
+                                       checkkwd = 2, readtoken();
+                       }
                        cpp = &cp->nclist.next;
                }
+               noaliases = 0;  /* reset alias expansion */
                *cpp = NULL;
-               if (lasttoken != TESAC)
-                       synexpect(TESAC);
                checkkwd = 1;
                break;
        case TLP:
@@ -432,14 +483,22 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
                checkkwd = 1;
                break;
        /* Handle an empty command like other simple commands.  */
-       case TNL:
        case TSEMI:
-       case TEND:
-       case TRP:
+       case TAND:
+       case TOR:
+               /*
+                * An empty command before a ; doesn't make much sense, and
+                * should certainly be disallowed in the case of `if ;'.
+                */
+               if (!redir)
+                       synexpect(-1);
+       case TNL:
        case TEOF:
        case TWORD:
+       case TRP:
                tokpushback++;
-               return simplecmd(rpp, redir);
+               n1 = simplecmd(rpp, redir);
+               goto checkneg;
        default:
                synexpect(-1);
        }
@@ -461,29 +520,47 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
                }
                n1->nredir.redirect = redir;
        }
-       return n1;
+
+checkneg:
+       if (negate) {
+               n2 = (union node *)stalloc(sizeof (struct nnot));
+               n2->type = NNOT;
+               n2->nnot.com = n1;
+               return n2;
+       }
+       else
+               return n1;
 }
 
 
 STATIC union node *
-simplecmd(rpp, redir)
-       union node **rpp, *redir;
-       {
+simplecmd(union node **rpp, union node *redir)
+{
        union node *args, **app;
        union node **orig_rpp = rpp;
-       union node *n;
+       union node *n = NULL, *n2;
+       int negate = 0;
 
-       /* If we don't have any redirections already, then we must reset
-          rpp to be the address of the local redir variable.  */
+       /* If we don't have any redirections already, then we must reset */
+       /* rpp to be the address of the local redir variable.  */
        if (redir == 0)
                rpp = &redir;
 
        args = NULL;
        app = &args;
-       /* We save the incoming value, because we need this for shell
-          functions.  There can not be a redirect or an argument between
-          the function name and the open parenthesis.  */
+       /*
+        * We save the incoming value, because we need this for shell
+        * functions.  There can not be a redirect or an argument between
+        * the function name and the open parenthesis.
+        */
        orig_rpp = rpp;
+
+       while (readtoken() == TNOT) {
+               TRACE(("command: TNOT recognized\n"));
+               negate = !negate;
+       }
+       tokpushback++;
+
        for (;;) {
                if (readtoken() == TWORD) {
                        n = (union node *)stalloc(sizeof (struct narg));
@@ -507,7 +584,7 @@ simplecmd(rpp, redir)
 #endif
                        n->type = NDEFUN;
                        n->narg.next = command();
-                       return n;
+                       goto checkneg;
                } else {
                        tokpushback++;
                        break;
@@ -520,12 +597,54 @@ simplecmd(rpp, redir)
        n->ncmd.backgnd = 0;
        n->ncmd.args = args;
        n->ncmd.redirect = redir;
+
+checkneg:
+       if (negate) {
+               n2 = (union node *)stalloc(sizeof (struct nnot));
+               n2->type = NNOT;
+               n2->nnot.com = n;
+               return n2;
+       }
+       else
+               return n;
+}
+
+STATIC union node *
+makename(void)
+{
+       union node *n;
+
+       n = (union node *)stalloc(sizeof (struct narg));
+       n->type = NARG;
+       n->narg.next = NULL;
+       n->narg.text = wordtext;
+       n->narg.backquote = backquotelist;
        return n;
 }
 
+void fixredir(union node *n, const char *text, int err)
+{
+       TRACE(("Fix redir %s %d\n", text, err));
+       if (!err)
+               n->ndup.vname = NULL;
+
+       if (is_digit(text[0]) && text[1] == '\0')
+               n->ndup.dupfd = digit_val(text[0]);
+       else if (text[0] == '-' && text[1] == '\0')
+               n->ndup.dupfd = -1;
+       else {
+
+               if (err)
+                       synerror("Bad fd number");
+               else
+                       n->ndup.vname = makename();
+       }
+}
+
 
 STATIC void
-parsefname() {
+parsefname(void)
+{
        union node *n = redirnode;
 
        if (readtoken() != TWORD)
@@ -554,23 +673,9 @@ parsefname() {
                        p->next = here;
                }
        } else if (n->type == NTOFD || n->type == NFROMFD) {
-               if (is_digit(wordtext[0]))
-                       n->ndup.dupfd = digit_val(wordtext[0]);
-               else if (wordtext[0] == '-')
-                       n->ndup.dupfd = -1;
-               else
-                       goto bad;
-               if (wordtext[1] != '\0') {
-bad:
-                       synerror("Bad fd number");
-               }
+               fixredir(n, wordtext, 0);
        } else {
-               n->nfile.fname = (union node *)stalloc(sizeof (struct narg));
-               n = n->nfile.fname;
-               n->type = NARG;
-               n->narg.next = NULL;
-               n->narg.text = wordtext;
-               n->narg.backquote = backquotelist;
+               n->nfile.fname = makename();
        }
 }
 
@@ -580,7 +685,8 @@ bad:
  */
 
 STATIC void
-parseheredoc() {
+parseheredoc(void)
+{
        struct heredoc *here;
        union node *n;
 
@@ -588,7 +694,7 @@ parseheredoc() {
                here = heredoclist;
                heredoclist = here->next;
                if (needprompt) {
-                       putprompt(ps2val());
+                       setprompt(2);
                        needprompt = 0;
                }
                readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
@@ -603,7 +709,8 @@ parseheredoc() {
 }
 
 STATIC int
-peektoken() {
+peektoken(void)
+{
        int t;
 
        t = readtoken();
@@ -611,15 +718,17 @@ peektoken() {
        return (t);
 }
 
-STATIC int xxreadtoken();
-
 STATIC int
-readtoken() {
+readtoken(void)
+{
        int t;
+       int savecheckkwd = checkkwd;
+       struct alias *ap;
 #if DEBUG
        int alreadyseen = tokpushback;
 #endif
-       
+
+       top:
        t = xxreadtoken();
 
        if (checkkwd) {
@@ -635,19 +744,29 @@ readtoken() {
                } else
                        checkkwd = 0;
                /*
-                * check for keywords
+                * check for keywords and aliases
                 */
-               if (t == TWORD && !quoteflag) {
-                       register char *const *pp;
+               if (t == TWORD && !quoteflag)
+               {
+                       const char * const *pp;
 
                        for (pp = parsekwd; *pp; pp++) {
-                               if (**pp == *wordtext && equal(*pp, wordtext)) {
+                               if (**pp == *wordtext && equal(*pp, wordtext))
+                               {
                                        lasttoken = t = pp - parsekwd + KWDOFFSET;
                                        TRACE(("keyword %s recognized\n", tokname[t]));
-                                       break;
+                                       goto out;
                                }
                        }
+                       if (noaliases == 0 &&
+                           (ap = lookupalias(wordtext, 1)) != NULL) {
+                               pushstring(ap->val, strlen(ap->val), ap);
+                               checkkwd = savecheckkwd;
+                               goto top;
+                       }
                }
+out:
+               checkkwd = (t == TNOT) ? savecheckkwd : 0;
        }
 #if DEBUG
        if (!alreadyseen)
@@ -680,15 +799,16 @@ readtoken() {
 #define RETURN(token)  return lasttoken = token
 
 STATIC int
-xxreadtoken() {
-       register c;
+xxreadtoken(void)
+{
+       int c;
 
        if (tokpushback) {
                tokpushback = 0;
                return lasttoken;
        }
        if (needprompt) {
-               putprompt(ps2val());
+               setprompt(2);
                needprompt = 0;
        }
        startlinno = plinno;
@@ -707,7 +827,9 @@ xxreadtoken() {
                        if (pgetc() == '\n') {
                                startlinno = ++plinno;
                                if (doprompt)
-                                       putprompt(ps2val());
+                                       setprompt(2);
+                               else
+                                       setprompt(0);
                                continue;
                        }
                        pungetc();
@@ -765,23 +887,37 @@ breakloop:
 #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)
-       int firstc;
-       char const *syntax;
-       char *eofmark;
-       int striptabs;
-       {
-       register c = firstc;
-       register char *out;
+readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
+{
+       int c = firstc;
+       char *out;
        int len;
        char line[EOFMARKLEN + 1];
        struct nodelist *bqlist;
        int quotef;
        int dblquote;
-       int varnest;
+       int varnest;    /* levels of variables expansion */
+       int arinest;    /* levels of arithmetic expansion */
+       int parenlevel; /* levels of parens in arithmetic */
        int oldstyle;
+       char const *prevsyntax; /* syntax before arithmetic */
+       int synentry;
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &out;
+       (void) &quotef;
+       (void) &dblquote;
+       (void) &varnest;
+       (void) &arinest;
+       (void) &parenlevel;
+       (void) &oldstyle;
+       (void) &prevsyntax;
+       (void) &syntax;
+       (void) &synentry;
+#endif
 
        startlinno = plinno;
        dblquote = 0;
@@ -790,30 +926,27 @@ readtoken1(firstc, syntax, eofmark, striptabs)
        quotef = 0;
        bqlist = NULL;
        varnest = 0;
+       arinest = 0;
+       parenlevel = 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 */
-                       switch(syntax[c]) {
+
+                       synentry = syntax[c];
+
+                       switch(synentry) {
                        case CNL:       /* '\n' */
                                if (syntax == BASESYNTAX)
                                        goto endword;   /* exit outer loop */
                                USTPUTC(c, out);
                                plinno++;
-                               if (doprompt) {
-                                       putprompt(ps2val());
-                               }
+                               if (doprompt)
+                                       setprompt(2);
+                               else
+                                       setprompt(0);
                                c = pgetc();
                                goto loop;              /* continue outer loop */
                        case CWORD:
@@ -831,31 +964,46 @@ readtoken1(firstc, syntax, eofmark, striptabs)
                                        pungetc();
                                } else if (c == '\n') {
                                        if (doprompt)
-                                               putprompt(ps2val());
+                                               setprompt(2);
+                                       else
+                                               setprompt(0);
                                } else {
-                                       if (dblquote && c != '\\' && c != '`' && c != '$'
-                                                        && (c != '"' || eofmark != NULL))
+                                       if (dblquote && c != '\\' &&
+                                           c != '`' && c != '$' &&
+                                           (c != '"' || eofmark != NULL))
                                                USTPUTC('\\', out);
                                        if (SQSYNTAX[c] == CCTL)
                                                USTPUTC(CTLESC, out);
+                                       else if (eofmark == NULL)
+                                               USTPUTC(CTLQUOTEMARK, out);
                                        USTPUTC(c, out);
                                        quotef++;
                                }
                                break;
                        case CSQUOTE:
+                               if (eofmark == NULL)
+                                       USTPUTC(CTLQUOTEMARK, out);
                                syntax = SQSYNTAX;
                                break;
                        case CDQUOTE:
+                               if (eofmark == NULL)
+                                       USTPUTC(CTLQUOTEMARK, out);
                                syntax = DQSYNTAX;
                                dblquote = 1;
                                break;
                        case CENDQUOTE:
-                               if (eofmark) {
+                               if (eofmark != NULL && arinest == 0 &&
+                                   varnest == 0) {
                                        USTPUTC(c, out);
                                } else {
-                                       syntax = BASESYNTAX;
+                                       if (arinest) {
+                                               syntax = ARISYNTAX;
+                                               dblquote = 0;
+                                       } else if (eofmark == NULL) {
+                                               syntax = BASESYNTAX;
+                                               dblquote = 0;
+                                       }
                                        quotef++;
-                                       dblquote = 0;
                                }
                                break;
                        case CVAR:      /* '$' */
@@ -869,6 +1017,35 @@ readtoken1(firstc, syntax, eofmark, striptabs)
                                        USTPUTC(c, out);
                                }
                                break;
+                       case CLP:       /* '(' in arithmetic */
+                               parenlevel++;
+                               USTPUTC(c, out);
+                               break;
+                       case CRP:       /* ')' in arithmetic */
+                               if (parenlevel > 0) {
+                                       USTPUTC(c, out);
+                                       --parenlevel;
+                               } else {
+                                       if (pgetc() == ')') {
+                                               if (--arinest == 0) {
+                                                       USTPUTC(CTLENDARI, out);
+                                                       syntax = prevsyntax;
+                                                       if (syntax == DQSYNTAX)
+                                                               dblquote = 1;
+                                                       else
+                                                               dblquote = 0;
+                                               } else
+                                                       USTPUTC(')', out);
+                                       } else {
+                                               /*
+                                                * unbalanced parens
+                                                *  (don't 2nd guess - no error)
+                                                */
+                                               pungetc();
+                                               USTPUTC(')', out);
+                                       }
+                               }
+                               break;
                        case CBQUOTE:   /* '`' */
                                PARSEBACKQOLD();
                                break;
@@ -883,6 +1060,8 @@ readtoken1(firstc, syntax, eofmark, striptabs)
                }
        }
 endword:
+       if (syntax == ARISYNTAX)
+               synerror("Missing '))'");
        if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
                synerror("Unterminated quoted string");
        if (varnest != 0) {
@@ -926,7 +1105,7 @@ checkend: {
                }
                if (c == *eofmark) {
                        if (pfgets(line, sizeof line) != NULL) {
-                               register char *p, *q;
+                               char *p, *q;
 
                                p = line;
                                for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
@@ -935,7 +1114,7 @@ checkend: {
                                        plinno++;
                                        needprompt = doprompt;
                                } else {
-                                       ppushback(line, strlen(line));
+                                       pushstring(line, strlen(line), NULL);
                                }
                        }
                }
@@ -962,6 +1141,8 @@ parseredir: {
                        np->type = NAPPEND;
                else if (c == '&')
                        np->type = NTOFD;
+               else if (c == '|')
+                       np->type = NCLOBBER;
                else {
                        np->type = NTO;
                        pungetc();
@@ -985,6 +1166,8 @@ parseredir: {
                        }
                } else if (c == '&')
                        np->type = NFROMFD;
+               else if (c == '>')
+                       np->type = NFROMTO;
                else {
                        np->type = NFROM;
                        pungetc();
@@ -1010,27 +1193,51 @@ parsesub: {
 #ifndef GDB_HACK
        static const char types[] = "}-+?=";
 #endif
+       int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
 
        c = pgetc();
        if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
                USTPUTC('$', out);
                pungetc();
-       } else if (c == '(') {  /* $(command) */
-               PARSEBACKQNEW();
+       } else if (c == '(') {  /* $(command) or $((arith)) */
+               if (pgetc() == '(') {
+                       PARSEARITH();
+               } else {
+                       pungetc();
+                       PARSEBACKQNEW();
+               }
        } else {
                USTPUTC(CTLVAR, out);
                typeloc = out - stackblock();
                USTPUTC(VSNORMAL, out);
                subtype = VSNORMAL;
                if (c == '{') {
+                       bracketed_name = 1;
                        c = pgetc();
-                       subtype = 0;
+                       if (c == '#') {
+                               if ((c = pgetc()) == '}')
+                                       c = '#';
+                               else
+                                       subtype = VSLENGTH;
+                       }
+                       else
+                               subtype = 0;
                }
                if (is_name(c)) {
                        do {
                                STPUTC(c, out);
                                c = pgetc();
                        } while (is_in_name(c));
+               } else if (is_digit(c)) {
+                       if (bracketed_name) {
+                               do {
+                                       STPUTC(c, out);
+                                       c = pgetc();
+                               } while (is_digit(c));
+                       } else {
+                               STPUTC(c, out);
+                               c = pgetc();
+                       }
                } else {
                        if (! is_special(c))
 badsub:                                synerror("Bad substitution");
@@ -1040,18 +1247,35 @@ badsub:                         synerror("Bad substitution");
                STPUTC('=', out);
                flags = 0;
                if (subtype == 0) {
-                       if (c == ':') {
+                       switch (c) {
+                       case ':':
                                flags = VSNUL;
                                c = pgetc();
+                               /*FALLTHROUGH*/
+                       default:
+                               p = strchr(types, c);
+                               if (p == NULL)
+                                       goto badsub;
+                               subtype = p - types + VSNORMAL;
+                               break;
+                       case '%':
+                       case '#':
+                               {
+                                       int cc = c;
+                                       subtype = c == '#' ? VSTRIMLEFT :
+                                                            VSTRIMRIGHT;
+                                       c = pgetc();
+                                       if (c == cc)
+                                               subtype++;
+                                       else
+                                               pungetc();
+                                       break;
+                               }
                        }
-                       p = strchr(types, c);
-                       if (p == NULL)
-                               goto badsub;
-                       subtype = p - types + VSNORMAL;
                } else {
                        pungetc();
                }
-               if (dblquote)
+               if (subtype != VSLENGTH && (dblquote || arinest))
                        flags |= VSQUOTE;
                *(stackblock() + typeloc) = subtype | flags;
                if (subtype != VSNORMAL)
@@ -1076,7 +1300,11 @@ parsebackq: {
        struct jmploc jmploc;
        struct jmploc *volatile savehandler;
        int savelen;
-       int savedoprompt;
+       int saveprompt;
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &saveprompt;
+#endif
 
        savepbq = parsebackquote;
        if (setjmp(jmploc.loc)) {
@@ -1091,65 +1319,110 @@ parsebackq: {
        savelen = out - stackblock();
        if (savelen > 0) {
                str = ckmalloc(savelen);
-               bcopy(stackblock(), str, savelen);
+               memcpy(str, stackblock(), savelen);
        }
        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.  */
-               register char *out;
-               register c;
-               int savelen;
-               char *str;
-
-               STARTSTACKSTR(out);
-               while ((c = pgetc ()) != '`') {
-                       if (c == '\\') {
-                               c = pgetc ();
-                               if (c != '\\' && c != '`' && c != '$'
-                                   && (!dblquote || c != '"'))
-                                       STPUTC('\\', out);
+        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 *out;
+                int c;
+                int savelen;
+                char *str;
+
+
+                STARTSTACKSTR(out);
+               for (;;) {
+                       if (needprompt) {
+                               setprompt(2);
+                               needprompt = 0;
                        }
-                       if (c == '\n') {
+                       switch (c = pgetc()) {
+                       case '`':
+                               goto done;
+
+                       case '\\':
+                                if ((c = pgetc()) == '\n') {
+                                       plinno++;
+                                       if (doprompt)
+                                               setprompt(2);
+                                       else
+                                               setprompt(0);
+                                       /*
+                                        * If eating a newline, avoid putting
+                                        * the newline into the new character
+                                        * stream (via the STPUTC after the
+                                        * switch).
+                                        */
+                                       continue;
+                               }
+                                if (c != '\\' && c != '`' && c != '$'
+                                    && (!dblquote || c != '"'))
+                                        STPUTC('\\', out);
+                               break;
+
+                       case '\n':
                                plinno++;
-                               if (doprompt)
-                                       putprompt(ps2val());
+                               needprompt = doprompt;
+                               break;
+
+                       case PEOF:
+                               startlinno = plinno;
+                               synerror("EOF in backquote substitution");
+                               break;
+
+                       default:
+                               break;
                        }
                        STPUTC(c, out);
-               }
-               STPUTC('\0', out);
-               savelen = out - stackblock();
-               if (savelen > 0) {
-                       str = ckmalloc(savelen);
-                       bcopy(stackblock(), str, savelen);
-               }
-               setinputstring(str, 1);
-               savedoprompt = doprompt;
-               doprompt = 0;   /* no prompts while rereading string */
-       }
+                }
+done:
+                STPUTC('\0', out);
+                savelen = out - stackblock();
+                if (savelen > 0) {
+                        str = ckmalloc(savelen);
+                        memcpy(str, stackblock(), savelen);
+                       setinputstring(str, 1);
+                }
+        }
        nlpp = &bqlist;
        while (*nlpp)
                nlpp = &(*nlpp)->next;
        *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
        (*nlpp)->next = NULL;
        parsebackquote = oldstyle;
+
+       if (oldstyle) {
+               saveprompt = doprompt;
+               doprompt = 0;
+       }
+
        n = list(0);
-       if (!oldstyle && (readtoken() != TRP))
-               synexpect(TRP);
+
+       if (oldstyle)
+               doprompt = saveprompt;
+       else {
+               if (readtoken() != TRP)
+                       synexpect(TRP);
+       }
+
        (*nlpp)->n = n;
-       /* Start reading from old file again.  */
-       if (oldstyle) {
-               popfile();
-               doprompt = savedoprompt;
+        if (oldstyle) {
+               /*
+                * Start reading from old file again, ignoring any pushed back
+                * tokens left from the backquote parsing
+                */
+                popfile();
+               tokpushback = 0;
        }
        while (stackblocksize() <= savelen)
                growstackblock();
        STARTSTACKSTR(out);
        if (str) {
-               bcopy(str, out, savelen);
+               memcpy(out, str, savelen);
                STADJUST(savelen, out);
                INTOFF;
                ckfree(str);
@@ -1158,118 +1431,68 @@ parsebackq: {
        }
        parsebackquote = savepbq;
        handler = savehandler;
-       USTPUTC(CTLBACKQ + dblquote, out);
+       if (arinest || dblquote)
+               USTPUTC(CTLBACKQ | CTLQUOTE, out);
+       else
+               USTPUTC(CTLBACKQ, out);
        if (oldstyle)
                goto parsebackq_oldreturn;
        else
                goto parsebackq_newreturn;
 }
 
-} /* end of readtoken */
-
-
-
-#ifdef mkinit
-RESET {
-       tokpushback = 0;
-}
-#endif
-
-
-#if READLINE
 /*
- * Remember a prompt for use with readline if input and output is a terminal.
+ * Parse an arithmetic expansion (indicate start of one and set state)
  */
+parsearith: {
 
-STATIC void
-putprompt(s)
-       char *s;
-       {
-       if (editable) {
-               r_use_prompt = s;
+       if (++arinest == 1) {
+               prevsyntax = syntax;
+               syntax = ARISYNTAX;
+               USTPUTC(CTLARI, out);
+               if (dblquote)
+                       USTPUTC('"',out);
+               else
+                       USTPUTC(' ',out);
        } else {
-               out2str(s);
+               /*
+                * we collapse embedded arithmetic expansion to
+                * parenthesis, which should be equivalent
+                */
+               USTPUTC('(', out);
        }
+       goto parsearith_return;
 }
-#endif
-
-#if ATTY
-/*
- * Called to process a command generated by atty.  We execute the line,
- * and catch any errors that occur so they don't propagate outside of
- * this routine.
- */
-
-STATIC void
-attyline() {
-       char line[256];
-       struct stackmark smark;
-       struct jmploc jmploc;
-       struct jmploc *volatile savehandler;
 
-       if (pfgets(line, sizeof line) == NULL)
-               return;                         /* "can't happen" */
-       if (setjmp(jmploc.loc)) {
-               if (exception == EXERROR)
-                       out2str("\033]D\n");
-               handler = savehandler;
-               longjmp(handler->loc, 1);
-       }
-       savehandler = handler;
-       handler = &jmploc;
-       setstackmark(&smark);
-       evalstring(line);
-       popstackmark(&smark);
-       handler = savehandler;
-       doprompt = 1;
-}
+} /* end of readtoken */
 
 
-/*
- * Output a prompt for atty.  We output the prompt as part of the
- * appropriate escape sequence.  
- */
 
-STATIC void
-putprompt(s)
-       char *s;
-       {
-       register char *p;
-
-       if (attyset() && ! equal(termval(), "emacs")) {
-               if (strchr(s, '\7'))
-                       out2c('\7');
-               out2str("\033]P1;");
-               for (p = s ; *p ; p++) {
-                       if ((unsigned)(*p - ' ') <= '~' - ' ')
-                               out2c(*p);
-               }
-               out2c('\n');
-       } else {
-               out2str(s);
-       }
+#ifdef mkinit
+RESET {
+       tokpushback = 0;
+       checkkwd = 0;
 }
 #endif
 
-
-
 /*
  * Returns true if the text contains nothing to expand (no dollar signs
  * or backquotes).
  */
 
 STATIC int
-noexpand(text)
-       char *text;
-       {
-       register char *p;
-       register char c;
+noexpand(char *text)
+{
+       char *p;
+       char c;
 
        p = text;
        while ((c = *p++) != '\0') {
+               if ( c == CTLQUOTEMARK)
+                       continue;
                if (c == CTLESC)
                        p++;
-               else if (BASESYNTAX[c] == CCTL)
+               else if (BASESYNTAX[(int)c] == CCTL)
                        return 0;
        }
        return 1;
@@ -1282,10 +1505,9 @@ noexpand(text)
  */
 
 int
-goodname(name)
-       char *name;
-       {
-       register char *p;
+goodname(char *name)
+{
+       char *p;
 
        p = name;
        if (! is_name(*p))
@@ -1305,7 +1527,8 @@ goodname(name)
  */
 
 STATIC void
-synexpect(token) {
+synexpect(int token)
+{
        char msg[64];
 
        if (token >= 0) {
@@ -1319,11 +1542,135 @@ synexpect(token) {
 
 
 STATIC void
-synerror(msg)
-       char *msg;
-       {
+synerror(char *msg)
+{
        if (commandname)
                outfmt(&errout, "%s: %d: ", commandname, startlinno);
        outfmt(&errout, "Syntax error: %s\n", msg);
        error((char *)NULL);
 }
+
+STATIC void
+setprompt(int which)
+{
+       whichprompt = which;
+
+#ifndef EDITLINE
+#ifndef NO_HISTORY
+       if (!el)
+#endif
+               out2str(getprompt(NULL));
+#endif /* EDITLINE */
+}
+
+/*
+ * called by editline -- any expansions to the prompt
+ *    should be added here.
+ */
+char *
+getprompt(void *unused __unused)
+{
+       static char ps[PROMPTLEN];
+       char *fmt;
+       int i, j, trim;
+
+       /*
+        * Select prompt format.
+        */
+       switch (whichprompt) {
+       case -1:
+               fmt = pseval();
+               break;
+       case 0:
+               fmt = "";
+               break;
+       case 1:
+               fmt = ps1val();
+               break;
+       case 2:
+               fmt = ps2val();
+               break;
+       default:
+               return "<internal prompt error>";
+       }
+
+       /*
+        * Format prompt string.
+        */
+       for (i = 0; (i < 127) && (*fmt != '\0'); i++, fmt++)
+               if (*fmt == '\\')
+                       switch (*++fmt) {
+
+                               /*
+                                * Hostname.
+                                *
+                                * \h specifies just the local hostname,
+                                * \H specifies fully-qualified hostname.
+                                */
+                       case 'h':
+                       case 'H':
+                               ps[i] == '\0';
+                               gethostname(&ps[i], PROMPTLEN - i);
+                               /* Skip to end of hostname. */
+                               trim = (*fmt == 'h') ? '.' : '\0';
+                               while ((ps[i+1] != '\0') && (ps[i+1] != trim))
+                                       i++;
+                               break;
+
+                               /*
+                                * Working directory.
+                                *
+                                * \W specifies just the final component,
+                                * \w specifies the entire path.
+                                */
+                       case 'W':
+                       case 'w':
+                               ps[i] == '\0';
+                               getcwd(&ps[i], PROMPTLEN - i);
+                               if (*fmt == 'W') {
+                                       /* Final path component only. */
+                                       trim = 1;
+                                       for (j = i; ps[j] != '\0'; j++)
+                                         if (ps[j] == '/')
+                                               trim = j + 1;
+                                       memmove(&ps[i], &ps[trim],
+                                           j - trim + 1);
+                               }
+                               /* Skip to end of path. */
+                               while (ps[i + 1] != '\0')
+                                       i++;
+                               break;
+
+                               /*
+                                * Superuser status.
+                                *
+                                * '$' for normal users, '#' for root.
+                                */
+                       case '$':
+                               ps[i] = (geteuid() != 0) ? '$' : '#';
+                               break;
+
+                               /*
+                                * A literal \.
+                                */
+                       case '\\':
+                               ps[i] = '\\';
+                               break;
+
+                               /*
+                                * Emit unrecognized formats verbatim.
+                                */
+                       default:
+                               ps[i++] = '\\';
+                               ps[i] = *fmt;
+                               break;
+                       }
+               else
+                       ps[i] = *fmt;
+       ps[i] = '\0';
+       return (ps);
+}
+
+/*
+ * $PchId: parser.c,v 1.5 2006/05/22 12:27:09 philip Exp $
+ */
index edb130a51b6e2cfe2167e743257347539f69b066..522902a4b0884695f68ea4bb25572b782fd82feb 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
@@ -33,7 +29,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)parser.h    5.1 (Berkeley) 3/7/91
+ *     @(#)parser.h    8.3 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/parser.h,v 1.10 2004/04/06 20:06:51 markm Exp $
  */
 
 /* control characters in argument strings */
 #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 07              /* type of variable substitution */
-#define VSNUL 040              /* colon--treat the empty string as unset */
-#define VSQUOTE 0100           /* inside double quotes--suppress splitting */
+#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 1             /* normal variable:  $var or ${var} */
-#define VSMINUS 2              /* ${var-text} */
-#define VSPLUS 3               /* ${var+text} */
-#define VSQUESTION 4           /* ${var?message} */
-#define VSASSIGN 5             /* ${var=text} */
+#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} */
 
 
 /*
  */
 extern int tokpushback;
 #define NEOF ((union node *)&tokpushback)
+extern int whichprompt;                /* 1 == PS1, 2 == PS2 */
 
 
-#ifdef __STDC__
 union node *parsecmd(int);
+void fixredir(union node *, const char *, int);
 int goodname(char *);
-#else
-union node *parsecmd();
-int goodname();
-#endif
+char *getprompt(void *);
+
+/*
+ * $PchId: parser.h,v 1.3 2006/03/29 14:33:35 philip Exp $
+ */
index 5cded98d6edf727f3fd7df56ca4a37d977250c7d..9fa35de48e6a4b4c4d7329711601b67ef1ba6b09 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)redir.c    5.1 (Berkeley) 3/7/91";
+#if 0
+static char sccsid[] = "@(#)redir.c    8.2 (Berkeley) 5/4/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/redir.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
 
 /*
  * Code for dealing with input/output redirection.
@@ -47,15 +58,10 @@ static char sccsid[] = "@(#)redir.c 5.1 (Berkeley) 3/7/91";
 #include "jobs.h"
 #include "expand.h"
 #include "redir.h"
-#include "eval.h"
 #include "output.h"
 #include "memalloc.h"
 #include "error.h"
-#include <sys/types.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
+#include "options.h"
 
 
 #define EMPTY -2               /* marks an unused slot in redirtab */
@@ -65,25 +71,21 @@ static char sccsid[] = "@(#)redir.c 5.1 (Berkeley) 3/7/91";
 MKINIT
 struct redirtab {
        struct redirtab *next;
-       short renamed[10];
+       int renamed[10];
 };
 
 
 MKINIT 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.  */
-int fd0_redirected = 0;
+/*
+ * 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;
 
-#ifdef __STDC__
-STATIC void openredirect(union node *, char *);
+STATIC void openredirect(union node *, char[10 ]);
 STATIC int openhere(union node *);
-#else
-STATIC void openredirect();
-STATIC int openhere();
-#endif
-
 
 
 /*
@@ -95,15 +97,14 @@ STATIC int openhere();
  */
 
 void
-redirect(redir, flags)
-       union node *redir;
-       int flags;
-       {
+redirect(union node *redir, int flags)
+{
        union node *n;
-       struct redirtab *sv;
+       struct redirtab *sv = NULL;
        int i;
        int fd;
-       char memory[10];                /* file descriptors to write to memory */
+       int try;
+       char memory[10];        /* file descriptors to write to memory */
 
        for (i = 10 ; --i >= 0 ; )
                memory[i] = 0;
@@ -117,21 +118,38 @@ redirect(redir, flags)
        }
        for (n = redir ; n ; n = n->nfile.next) {
                fd = n->nfile.fd;
+               try = 0;
+               if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
+                   n->ndup.dupfd == fd)
+                       continue; /* redirect from/to same file descriptor */
+
                if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
                        INTOFF;
-                       if ((i = copyfd(fd, 10)) != EMPTY) {
+again:
+                       if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
+                               switch (errno) {
+                               case EBADF:
+                                       if (!try) {
+                                               openredirect(n, memory);
+                                               try++;
+                                               goto again;
+                                       }
+                                       /* FALLTHROUGH*/
+                               default:
+                                       INTON;
+                                       error("%d: %s", fd, strerror(errno));
+                                       break;
+                               }
+                       }
+                       if (!try) {
                                sv->renamed[fd] = i;
-                               close(fd);
                        }
                        INTON;
-                       if (i == EMPTY)
-                               error("Out of file descriptors");
-               } else {
-                       close(fd);
                }
                if (fd == 0)
                        fd0_redirected++;
-               openredirect(n, memory);
+               if (!try)
+                       openredirect(n, memory);
        }
        if (memory[1])
                out1 = &memout;
@@ -141,16 +159,15 @@ redirect(redir, flags)
 
 
 STATIC void
-openredirect(redir, memory)
-       union node *redir;
-       char memory[10];
-       {
+openredirect(union node *redir, char memory[10])
+{
+       struct stat sb;
        int fd = redir->nfile.fd;
        char *fname;
        int f;
 
        /* Assume redirection succeeds. */
-       exitstatus = 0;
+       { extern int exitstatus; exitstatus = 0; }
 
        /*
         * We suppress interrupts so that we won't leave open file
@@ -163,34 +180,35 @@ openredirect(redir, memory)
        case NFROM:
                fname = redir->nfile.expfname;
                if ((f = open(fname, O_RDONLY)) < 0)
-                       error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
+                       error("cannot open %s: %s", fname, strerror(errno));
 movefd:
                if (f != fd) {
-                       copyfd(f, fd);
+                       dup2(f, fd);
                        close(f);
                }
                break;
+       case NFROMTO:
+               fname = redir->nfile.expfname;
+               if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0)
+                       error("cannot create %s: %s", fname, strerror(errno));
+               goto movefd;
        case NTO:
                fname = redir->nfile.expfname;
-#ifdef O_CREAT
+               if (Cflag && stat(fname, &sb) != -1 && S_ISREG(sb.st_mode))
+                       error("cannot create %s: %s", fname,
+                           strerror(EEXIST));
                if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
-                       error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
-#else
-               if ((f = creat(fname, 0666)) < 0)
-                       error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
-#endif
+                       error("cannot create %s: %s", fname, strerror(errno));
+               goto movefd;
+       case NCLOBBER:
+               fname = redir->nfile.expfname;
+               if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
+                       error("cannot create %s: %s", fname, strerror(errno));
                goto movefd;
        case NAPPEND:
                fname = redir->nfile.expfname;
-#ifdef O_APPEND
                if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
-                       error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
-#else
-               if ((f = open(fname, O_WRONLY)) < 0
-                && (f = creat(fname, 0666)) < 0)
-                       error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
-               lseek(f, 0L, 2);
-#endif
+                       error("cannot create %s: %s", fname, strerror(errno));
                goto movefd;
        case NTOFD:
        case NFROMFD:
@@ -198,7 +216,9 @@ movefd:
                        if (memory[redir->ndup.dupfd])
                                memory[fd] = 1;
                        else
-                               copyfd(redir->ndup.dupfd, fd);
+                               dup2(redir->ndup.dupfd, fd);
+               } else {
+                       close(fd);
                }
                break;
        case NHERE:
@@ -219,14 +239,13 @@ movefd:
  */
 
 STATIC int
-openhere(redir)
-       union node *redir;
-       {
+openhere(union node *redir)
+{
        int pip[2];
-       int len;
+       int len = 0;
 
        if (pipe(pip) < 0)
-               error("Pipe call failed");
+               error("Pipe call failed: %s", strerror(errno));
        if (redir->type == NHERE) {
                len = strlen(redir->nhere.doc->narg.text);
                if (len <= PIPESIZE) {
@@ -239,9 +258,7 @@ openhere(redir)
                signal(SIGINT, SIG_IGN);
                signal(SIGQUIT, SIG_IGN);
                signal(SIGHUP, SIG_IGN);
-#ifdef SIGTSTP
                signal(SIGTSTP, SIG_IGN);
-#endif
                signal(SIGPIPE, SIG_DFL);
                if (redir->type == NHERE)
                        xwrite(pip[1], redir->nhere.doc->narg.text, len);
@@ -261,18 +278,20 @@ out:
  */
 
 void
-popredir() {
-       register struct redirtab *rp = redirlist;
+popredir(void)
+{
+       struct redirtab *rp = redirlist;
        int i;
 
        for (i = 0 ; i < 10 ; i++) {
                if (rp->renamed[i] != EMPTY) {
-                       if (i == 0)
-                               fd0_redirected--;
-                       close(i);
+                        if (i == 0)
+                                fd0_redirected--;
                        if (rp->renamed[i] >= 0) {
-                               copyfd(rp->renamed[i], i);
+                               dup2(rp->renamed[i], i);
                                close(rp->renamed[i]);
+                       } else {
+                               close(i);
                        }
                }
        }
@@ -282,8 +301,6 @@ popredir() {
        INTON;
 }
 
-
-
 /*
  * Undo all redirections.  Called on error or interrupt.
  */
@@ -303,14 +320,21 @@ SHELLPROC {
 
 #endif
 
+/* Return true if fd 0 has already been redirected at least once.  */
+int
+fd0_redirected_p(void)
+{
+        return fd0_redirected != 0;
+}
 
 /*
  * Discard all saved file descriptors.
  */
 
 void
-clearredir() {
-       register struct redirtab *rp;
+clearredir(void)
+{
+       struct redirtab *rp;
        int i;
 
        for (rp = redirlist ; rp ; rp = rp->next) {
@@ -323,48 +347,6 @@ clearredir() {
        }
 }
 
-
-
 /*
- * Copy a file descriptor, like the F_DUPFD option of fcntl.  Returns -1
- * if the source file descriptor is closed, EMPTY if there are no unused
- * file descriptors left.
+ * $PchId: redir.c,v 1.5 2006/05/22 12:27:37 philip Exp $
  */
-
-int
-copyfd(from, to) {
-#ifdef F_DUPFD
-       int newfd;
-
-       newfd = fcntl(from, F_DUPFD, to);
-       if (newfd < 0 && errno == EMFILE)
-               return EMPTY;
-       return newfd;
-#else
-       char toclose[32];
-       int i;
-       int newfd;
-       int e;
-
-       for (i = 0 ; i < to ; i++)
-               toclose[i] = 0;
-       INTOFF;
-       while ((newfd = dup(from)) >= 0 && newfd < to)
-               toclose[newfd] = 1;
-       e = errno;
-       for (i = 0 ; i < to ; i++) {
-               if (toclose[i])
-                       close(i);
-       }
-       INTON;
-       if (newfd < 0 && e == EMFILE)
-               return EMPTY;
-       return newfd;
-#endif
-}
-
-/* Return true if fd 0 has already been redirected at least once.  */
-int
-fd0_redirected_p () {
-       return fd0_redirected != 0;
-}
index 85ba6d12a870108ef9c28d29a7d74a4b5bf3ffd1..9b665d06f92e329d92e14e74bd2a9acc8a679b8b 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)redir.h     5.1 (Berkeley) 3/7/91
+ *     @(#)redir.h     8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/redir.h,v 1.10 2004/04/06 20:06:51 markm 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 */
 
-#ifdef __STDC__
 union node;
 void redirect(union node *, int);
 void popredir(void);
-void clearredir(void);
-int copyfd(int, int);
 int fd0_redirected_p(void);
-#else
-void redirect();
-void popredir();
-void clearredir();
-int copyfd();
-int fd0_redirected_p();
-#endif
+void clearredir(void);
+
+
+/*
+ * $PchId: redir.h,v 1.3 2006/03/29 14:13:34 philip Exp $
+ */
diff --git a/commands/ash/setmode.c b/commands/ash/setmode.c
new file mode 100644 (file)
index 0000000..d80c00b
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Dave Borman at Cray Research, Inc.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setmode.c  8.2 (Berkeley) 3/25/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#ifdef SETMODE_DEBUG
+#include <stdio.h>
+#endif
+
+#include "shell.h"
+
+#ifndef S_ISTXT
+#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 */
+
+typedef struct bitcmd {
+       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
+
+static BITCMD  *addcmd (BITCMD *, int, int, int, unsigned int);
+static int      compress_mode (BITCMD *);
+#ifdef SETMODE_DEBUG
+static void     dumpmode __P((BITCMD *));
+#endif
+
+/*
+ * Given the old mode and an array of bitcmd structures, apply the operations
+ * described in the bitcmd structures to the old mode, and return the new mode.
+ * Note that there is no '=' command; a strict assignment is just a '-' (clear
+ * bits) followed by a '+' (set bits).
+ */
+mode_t
+getmode(bbox, omode)
+       void *bbox;
+       mode_t omode;
+{
+       register BITCMD *set;
+       register mode_t clrval, newmode, value;
+
+       set = (BITCMD *)bbox;
+       newmode = omode;
+       for (value = 0;; set++)
+               switch(set->cmd) {
+               /*
+                * When copying the user, group or other bits around, we "know"
+                * where the bits are in the mode so that we can do shifts to
+                * copy them around.  If we don't use shifts, it gets real
+                * grundgy with lots of single bit checks and bit sets.
+                */
+               case 'u':
+                       value = (newmode & S_IRWXU) >> 6;
+                       goto common;
+
+               case 'g':
+                       value = (newmode & S_IRWXG) >> 3;
+                       goto common;
+
+               case 'o':
+                       value = newmode & S_IRWXO;
+common:                        if (set->cmd2 & CMD2_CLR) {
+                               clrval =
+                                   (set->cmd2 & CMD2_SET) ?  S_IRWXO : value;
+                               if (set->cmd2 & CMD2_UBITS)
+                                       newmode &= ~((clrval<<6) & set->bits);
+                               if (set->cmd2 & CMD2_GBITS)
+                                       newmode &= ~((clrval<<3) & set->bits);
+                               if (set->cmd2 & CMD2_OBITS)
+                                       newmode &= ~(clrval & set->bits);
+                       }
+                       if (set->cmd2 & CMD2_SET) {
+                               if (set->cmd2 & CMD2_UBITS)
+                                       newmode |= (value<<6) & set->bits;
+                               if (set->cmd2 & CMD2_GBITS)
+                                       newmode |= (value<<3) & set->bits;
+                               if (set->cmd2 & CMD2_OBITS)
+                                       newmode |= value & set->bits;
+                       }
+                       break;
+
+               case '+':
+                       newmode |= set->bits;
+                       break;
+
+               case '-':
+                       newmode &= ~set->bits;
+                       break;
+
+               case 'X':
+                       if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
+                               newmode |= set->bits;
+                       break;
+
+               case '\0':
+               default:
+#ifdef SETMODE_DEBUG
+                       (void)printf("getmode:%04o -> %04o\n", omode, newmode);
+#endif
+                       return (newmode);
+               }
+}
+
+#define        ADDCMD(a, b, c, d)                                              \
+       if (set >= endset) {                                            \
+               register BITCMD *newset;                                \
+               setlen += SET_LEN_INCR;                                 \
+               newset = realloc(saveset, sizeof(BITCMD) * setlen);     \
+               if (!saveset)                                           \
+                       return (NULL);                                  \
+               set = newset + (set - saveset);                         \
+               saveset = newset;                                       \
+               endset = newset + (setlen - 2);                         \
+       }                                                               \
+       set = addcmd(set, (a), (b), (c), (d))
+
+#define        STANDARD_BITS   (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
+
+void *
+setmode(p)
+       register char *p;
+{
+       register int perm, who;
+       register char op;
+       BITCMD *set, *saveset, *endset;
+       sigset_t sigset, sigoset;
+       mode_t mask;
+       int equalopdone, permXbits, setlen;
+
+       if (!*p)
+               return (NULL);
+
+       /*
+        * Get a copy of the mask for the permissions that are mask relative.
+        * Flip the bits, we want what's not set.  Since it's possible that
+        * the caller is opening files inside a signal handler, protect them
+        * as best we can.
+        */
+       sigfillset(&sigset);
+        (void)sigprocmask(SIG_BLOCK, &sigset, &sigoset);
+       (void)umask(mask = umask(0));
+       mask = ~mask;
+        (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
+
+       setlen = SET_LEN + 2;
+       
+       if ((set = malloc((unsigned int)(sizeof(BITCMD) * setlen))) == NULL)
+               return (NULL);
+       saveset = set;
+       endset = set + (setlen - 2);
+
+       /*
+        * If an absolute number, get it and return; disallow non-octal digits
+        * or illegal bits.
+        */
+       if (isdigit(*p)) {
+               perm = (mode_t)strtol(p, NULL, 8);
+               if (perm & ~(STANDARD_BITS|S_ISTXT)) {
+                       free(saveset);
+                       return (NULL);
+               }
+               while (*++p)
+                       if (*p < '0' || *p > '7') {
+                               free(saveset);
+                               return (NULL);
+                       }
+               ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
+               return (saveset);
+       }
+
+       /*
+        * Build list of structures to set/clear/copy bits as described by
+        * each clause of the symbolic mode.
+        */
+       for (;;) {
+               /* First, find out which bits might be modified. */
+               for (who = 0;; ++p) {
+                       switch (*p) {
+                       case 'a':
+                               who |= STANDARD_BITS;
+                               break;
+                       case 'u':
+                               who |= S_ISUID|S_IRWXU;
+                               break;
+                       case 'g':
+                               who |= S_ISGID|S_IRWXG;
+                               break;
+                       case 'o':
+                               who |= S_IRWXO;
+                               break;
+                       default:
+                               goto getop;
+                       }
+               }
+
+getop:         if ((op = *p++) != '+' && op != '-' && op != '=') {
+                       free(saveset);
+                       return (NULL);
+               }
+               if (op == '=')
+                       equalopdone = 0;
+
+               who &= ~S_ISTXT;
+               for (perm = 0, permXbits = 0;; ++p) {
+                       switch (*p) {
+                       case 'r':
+                               perm |= S_IRUSR|S_IRGRP|S_IROTH;
+                               break;
+                       case 's':
+                               /* If only "other" bits ignore set-id. */
+                               if (who & ~S_IRWXO)
+                                       perm |= S_ISUID|S_ISGID;
+                               break;
+                       case 't':
+                               /* If only "other" bits ignore sticky. */
+                               if (who & ~S_IRWXO) {
+                                       who |= S_ISTXT;
+                                       perm |= S_ISTXT;
+                               }
+                               break;
+                       case 'w':
+                               perm |= S_IWUSR|S_IWGRP|S_IWOTH;
+                               break;
+                       case 'X':
+                               permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
+                               break;
+                       case 'x':
+                               perm |= S_IXUSR|S_IXGRP|S_IXOTH;
+                               break;
+                       case 'u':
+                       case 'g':
+                       case 'o':
+                               /*
+                                * When ever we hit 'u', 'g', or 'o', we have
+                                * to flush out any partial mode that we have,
+                                * and then do the copying of the mode bits.
+                                */
+                               if (perm) {
+                                       ADDCMD(op, who, perm, mask);
+                                       perm = 0;
+                               }
+                               if (op == '=')
+                                       equalopdone = 1;
+                               if (op == '+' && permXbits) {
+                                       ADDCMD('X', who, permXbits, mask);
+                                       permXbits = 0;
+                               }
+                               ADDCMD(*p, who, op, mask);
+                               break;
+
+                       default:
+                               /*
+                                * Add any permissions that we haven't already
+                                * done.
+                                */
+                               if (perm || (op == '=' && !equalopdone)) {
+                                       if (op == '=')
+                                               equalopdone = 1;
+                                       ADDCMD(op, who, perm, mask);
+                                       perm = 0;
+                               }
+                               if (permXbits) {
+                                       ADDCMD('X', who, permXbits, mask);
+                                       permXbits = 0;
+                               }
+                               goto apply;
+                       }
+               }
+
+apply:         if (!*p)
+                       break;
+               if (*p != ',')
+                       goto getop;
+               ++p;
+       }
+       set->cmd = 0;
+#ifdef SETMODE_DEBUG
+       (void)printf("Before compress_mode()\n");
+       dumpmode(saveset);
+#endif
+       compress_mode(saveset);
+#ifdef SETMODE_DEBUG
+       (void)printf("After compress_mode()\n");
+       dumpmode(saveset);
+#endif
+       return (saveset);
+}
+
+static BITCMD *
+addcmd(set, op, who, oparg, mask)
+       BITCMD *set;
+       register int oparg, who;
+       register int op;
+       unsigned int mask;
+{
+       switch (op) {
+       case '=':
+               set->cmd = '-';
+               set->bits = who ? who : STANDARD_BITS;
+               set++;
+
+               op = '+';
+               /* FALLTHROUGH */
+       case '+':
+       case '-':
+       case 'X':
+               set->cmd = op;
+               set->bits = (who ? who : mask) & oparg;
+               break;
+
+       case 'u':
+       case 'g':
+       case 'o':
+               set->cmd = op;
+               if (who) {
+                       set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
+                                   ((who & S_IRGRP) ? CMD2_GBITS : 0) |
+                                   ((who & S_IROTH) ? CMD2_OBITS : 0);
+                       set->bits = ~0;
+               } else {
+                       set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
+                       set->bits = mask;
+               }
+       
+               if (oparg == '+')
+                       set->cmd2 |= CMD2_SET;
+               else if (oparg == '-')
+                       set->cmd2 |= CMD2_CLR;
+               else if (oparg == '=')
+                       set->cmd2 |= CMD2_SET|CMD2_CLR;
+               break;
+       }
+       return (set + 1);
+}
+
+#ifdef SETMODE_DEBUG
+static void
+dumpmode(set)
+       register BITCMD *set;
+{
+       for (; set->cmd; ++set)
+               (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
+                   set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
+                   set->cmd2 & CMD2_CLR ? " CLR" : "",
+                   set->cmd2 & CMD2_SET ? " SET" : "",
+                   set->cmd2 & CMD2_UBITS ? " UBITS" : "",
+                   set->cmd2 & CMD2_GBITS ? " GBITS" : "",
+                   set->cmd2 & CMD2_OBITS ? " OBITS" : "");
+}
+#endif
+
+/*
+ * 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 
+ * compacted, but it's not worth the effort.
+ */
+static int
+compress_mode(set)
+       register BITCMD *set;
+{
+       register BITCMD *nset;
+       register int setbits, clrbits, Xbits, op;
+
+       for (nset = set;;) {
+               /* Copy over any 'u', 'g' and 'o' commands. */
+               while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
+                       *set++ = *nset++;
+                       if (!op)
+                               return;
+               }
+
+               for (setbits = clrbits = Xbits = 0;; nset++) {
+                       if ((op = nset->cmd) == '-') {
+                               clrbits |= nset->bits;
+                               setbits &= ~nset->bits;
+                               Xbits &= ~nset->bits;
+                       } else if (op == '+') {
+                               setbits |= nset->bits;
+                               clrbits &= ~nset->bits;
+                               Xbits &= ~nset->bits;
+                       } else if (op == 'X')
+                               Xbits |= nset->bits & ~setbits;
+                       else
+                               break;
+               }
+               if (clrbits) {
+                       set->cmd = '-';
+                       set->cmd2 = 0;
+                       set->bits = clrbits;
+                       set++;
+               }
+               if (setbits) {
+                       set->cmd = '+';
+                       set->cmd2 = 0;
+                       set->bits = setbits;
+                       set++;
+               }
+               if (Xbits) {
+                       set->cmd = 'X';
+                       set->cmd2 = 0;
+                       set->bits = Xbits;
+                       set++;
+               }
+       }
+}
+
+/*
+ * $PchId: setmode.c,v 1.3 2006/05/23 11:57:34 philip Exp $
+ */
index 04d59f5a1e8d20a03b0453c4b291e6e7ab77b864..5767b66ee990c52662af48f15163c9dacdc883b9 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)shell.h     5.4 (Berkeley) 4/12/91
+ *     @(#)shell.h     8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/shell.h,v 1.17 2004/04/06 20:06:51 markm Exp $
  */
 
+#include <sys/types.h> /* for mode_t */
+
 /*
  * The follow should be set to reflect the type of system you have:
  *     JOBS -> 1 if you have Berkeley job control, 0 otherwise.
- *     SYMLINKS -> 1 if your system includes symbolic links, 0 otherwise.
- *     DIRENT -> 1 if your system has the SVR3 directory(3X) routines.
- *     UDIR -> 1 if you want the shell to simulate the /u directory.
  *     TILDE -> 1 if you want the shell to expand ~logname.
  *     USEGETPW -> 1 if getpwnam() must be used to look up a name.
- *     ATTY -> 1 to include code for atty(1).
- *     SHORTNAMES -> 1 if your linker cannot handle long names.
  *     READLINE -> 1 if line editing by readline() should be enabled.
  *     define BSD if you are running 4.2 BSD or later.
  *     define SYSV if you are running under System V.
  * a quit signal will generate a core dump.
  */
 
-
-#define JOBS     0
-
-/* Set SYMLINKS to 0 by request of Giovanni Falzoni, who wrote the
- * symlink patches for Minix; email to minix-devel-l of thu 3 nov.
- */
-
-#if 0
-#define SYMLINKS  defined(S_ISLNK)
-#else
-#define SYMLINKS  0
+#ifndef JOBS
+#define        JOBS 1
 #endif
-
-#define DIRENT   1
-#define UDIR     0
-#define TILDE    1
-#define USEGETPW  0
-#define ATTY     0
-#define READLINE  1
-#define HASHBANG  0
-/* #define BSD */
-#define POSIX    1
-#define DEBUG    0
-
-#ifdef __STDC__
-typedef void *pointer;
-#ifndef NULL
-#define NULL (void *)0
+#ifndef BSD
+#define BSD 1
 #endif
-#else /* not __STDC__ */
-typedef char *pointer;
-#ifndef NULL
-#define NULL 0
+#ifndef DEBUG
+#define DEBUG 0
 #endif
-#endif /*  not __STDC__ */
-#define STATIC /* empty */
-#define MKINIT /* empty */
+#define POSIX 1
 
-#include <sys/cdefs.h>
-#include <sys/types.h>
+/*
+ * Type of used arithmetics. SUSv3 requires us to have at least signed long.
+ */
+typedef long arith_t;
+#define        ARITH_FORMAT_STR  "%ld"
+#define        atoarith_t(arg)  strtol(arg, NULL, 0)
+#define        strtoarith_t(nptr, endptr, base)  strtol(nptr, endptr, base)
 
-extern char nullstr[1];                /* null string */
+typedef void *pointer;
+#define STATIC  static
+#define MKINIT  /* empty */
 
+extern char nullstr[1];                /* null string */
 
 #if DEBUG
-#define TRACE(param)   trace param
+#define TRACE(param)  sh_trace param
 #else
 #define TRACE(param)
 #endif
+
+#ifdef __minix
+#define __unused
+
+typedef long quad_t;           /* XXX */
+typedef unsigned long u_quad_t;        /* XXX */
+#endif
+
+mode_t getmode(void *, int /* mode_t */);
+void *setmode(char *);
+
+/*
+ * $PchId: shell.h,v 1.7 2006/05/22 12:47:00 philip Exp $
+ */
index 0860ab667b7675c767cea612ea35e1bf07296bfe..1b848927e831590cd68acdc4058fcabc57b2175b 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)show.c     5.2 (Berkeley) 4/12/91";
+#if 0
+static char sccsid[] = "@(#)show.c     8.3 (Berkeley) 5/4/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/show.c,v 1.21 2004/04/06 20:06:51 markm Exp $");
+*/
 
+#include <fcntl.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
 #include <errno.h>
+
 #include "shell.h"
 #include "parser.h"
 #include "nodes.h"
 #include "mystring.h"
-
+#include "show.h"
 
 #if DEBUG
-static shtree(), shcmd(), sharg(), indent();
-
-
-showtree(n)
-       union node *n;
-       {
+static void trputc(int c);
+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 showtree(union node *n);
+
+
+static void
+showtree(union node *n)
+{
        trputs("showtree called\n");
        shtree(n, 1, NULL, stdout);
 }
 
 
-static
-shtree(n, ind, pfx, fp)
-       union node *n;
-       char *pfx;
-       FILE *fp;
-       {
+static void
+shtree(union node *n, int ind, char *pfx, FILE *fp)
+{
        struct nodelist *lp;
        char *s;
 
+       if (n == NULL)
+               return;
+
        indent(ind, pfx, fp);
        switch(n->type) {
        case NSEMI:
@@ -109,11 +121,9 @@ binop:
 
 
 
-static
-shcmd(cmd, fp)
-       union node *cmd;
-       FILE *fp;
-       {
+static void
+shcmd(union node *cmd, FILE *fp)
+{
        union node *np;
        int first;
        char *s;
@@ -133,14 +143,20 @@ shcmd(cmd, fp)
                        case NTO:       s = ">";  dftfd = 1; break;
                        case NAPPEND:   s = ">>"; dftfd = 1; break;
                        case NTOFD:     s = ">&"; dftfd = 1; break;
+                       case NCLOBBER:  s = ">|"; dftfd = 1; break;
                        case NFROM:     s = "<";  dftfd = 0; break;
+                       case NFROMTO:   s = "<>"; dftfd = 0; break;
                        case NFROMFD:   s = "<&"; dftfd = 0; break;
+                       default:        s = "*error*"; dftfd = 0; break;
                }
                if (np->nfile.fd != dftfd)
                        fprintf(fp, "%d", np->nfile.fd);
                fputs(s, fp);
                if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
-                       fprintf(fp, "%d", np->ndup.dupfd);
+                       if (np->ndup.dupfd >= 0)
+                               fprintf(fp, "%d", np->ndup.dupfd);
+                       else
+                               fprintf(fp, "-");
                } else {
                        sharg(np->nfile.fname, fp);
                }
@@ -150,11 +166,9 @@ shcmd(cmd, fp)
 
 
 
-static
-sharg(arg, fp)
-       union node *arg;
-       FILE *fp;
-       {
+static void
+sharg(union node *arg, FILE *fp)
+{
        char *p;
        struct nodelist *bqlist;
        int subtype;
@@ -174,10 +188,15 @@ sharg(arg, fp)
                        putc('$', fp);
                        putc('{', fp);
                        subtype = *++p;
+                       if (subtype == VSLENGTH)
+                               putc('#', fp);
+
                        while (*p != '=')
                                putc(*p++, fp);
+
                        if (subtype & VSNUL)
                                putc(':', fp);
+
                        switch (subtype & VSTYPE) {
                        case VSNORMAL:
                                putc('}', fp);
@@ -194,6 +213,22 @@ sharg(arg, fp)
                        case VSASSIGN:
                                putc('=', fp);
                                break;
+                       case VSTRIMLEFT:
+                               putc('#', fp);
+                               break;
+                       case VSTRIMLEFTMAX:
+                               putc('#', fp);
+                               putc('#', fp);
+                               break;
+                       case VSTRIMRIGHT:
+                               putc('%', fp);
+                               break;
+                       case VSTRIMRIGHTMAX:
+                               putc('%', fp);
+                               putc('%', fp);
+                               break;
+                       case VSLENGTH:
+                               break;
                        default:
                                printf("<subtype %d>", subtype);
                        }
@@ -216,11 +251,9 @@ sharg(arg, fp)
 }
 
 
-static
-indent(amount, pfx, fp)
-       char *pfx;
-       FILE *fp;
-       {
+static void
+indent(int amount, char *pfx, FILE *fp)
+{
        int i;
 
        for (i = 0 ; i < amount ; i++) {
@@ -229,8 +262,6 @@ indent(amount, pfx, fp)
                putc('\t', fp);
        }
 }
-#endif
-
 
 
 /*
@@ -247,52 +278,48 @@ int debug = 0;
 #endif
 
 
-trputc(c) {
-#if DEBUG
+static void
+trputc(int c)
+{
        if (tracefile == NULL)
                return;
        putc(c, tracefile);
        if (c == '\n')
                fflush(tracefile);
-#endif
 }
 
 
-trace(fmt, a1, a2, a3, a4, a5, a6, a7, a8)
-       char *fmt;
-       {
-#if DEBUG
-       int e = errno;
-       if (tracefile == NULL)
-               return;
-       fprintf(tracefile, fmt, a1, a2, a3, a4, a5, a6, a7, a8);
-       if (strchr(fmt, '\n'))
-               fflush(tracefile);
-       errno = e;
-#endif
+void
+sh_trace(const char *fmt, ...)
+{
+       va_list va;
+       va_start(va, fmt);
+       if (tracefile != NULL) {
+               (void) vfprintf(tracefile, fmt, va);
+               if (strchr(fmt, '\n'))
+                       (void) fflush(tracefile);
+       }
+       va_end(va);
 }
 
 
-trputs(s)
-       char *s;
-       {
-#if DEBUG
+void
+trputs(char *s)
+{
        if (tracefile == NULL)
                return;
        fputs(s, tracefile);
        if (strchr(s, '\n'))
                fflush(tracefile);
-#endif
 }
 
 
-trstring(s)
-       char *s;
-       {
-       register char *p;
+static void
+trstring(char *s)
+{
+       char *p;
        char c;
 
-#if DEBUG
        if (tracefile == NULL)
                return;
        putc('"', tracefile);
@@ -324,14 +351,12 @@ backslash:          putc('\\', tracefile);
                }
        }
        putc('"', tracefile);
-#endif
 }
 
 
-trargs(ap)
-       char **ap;
-       {
-#if DEBUG
+void
+trargs(char **ap)
+{
        if (tracefile == NULL)
                return;
        while (*ap) {
@@ -342,36 +367,43 @@ trargs(ap)
                        putc('\n', tracefile);
        }
        fflush(tracefile);
-#endif
 }
 
 
-opentrace() {
+void
+opentrace(void)
+{
        char s[100];
-       char *p;
-       char *getenv();
        int flags;
 
-#if DEBUG
        if (!debug)
                return;
-       if ((p = getenv("HOME")) == NULL) {
-               if (getuid() == 0)
-                       p = "/";
-               else
-                       p = "/tmp";
+#ifdef not_this_way
+       {
+               char *p;
+               if ((p = getenv("HOME")) == NULL) {
+                       if (geteuid() == 0)
+                               p = "/";
+                       else
+                               p = "/tmp";
+               }
+               scopy(p, s);
+               strcat(s, "/trace");
        }
-       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);
+               fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
                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
 }
+#endif /* DEBUG */
+
+/*
+ * $PchId: show.c,v 1.6 2006/05/22 12:27:51 philip Exp $
+ */
diff --git a/commands/ash/show.h b/commands/ash/show.h
new file mode 100644 (file)
index 0000000..59cb3e7
--- /dev/null
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 1995
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 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.
+ *
+ *     @(#)show.h      1.1 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/show.h,v 1.11 2004/04/06 20:06:51 markm Exp $
+ */
+
+#ifdef DEBUG
+void sh_trace(const char *, ...);
+void trargs(char **);
+void trputs(char *);
+void opentrace(void);
+#endif
+
+/*
+ * $PchId: show.h,v 1.4 2006/03/29 13:28:45 philip Exp $
+ */
diff --git a/commands/ash/sys/cdefs.h b/commands/ash/sys/cdefs.h
deleted file mode 100755 (executable)
index 0c49919..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*     Replacement for something BSD has in sys/cdefs.h. */
-
-#ifndef _ASH_SYS_CDEFS
-#define _ASH_SYS_CDEFS
-
-#if __STDC__
-#define        __P(params)                     params
-#else
-#define        __P(params)                     ()
-#endif
-
-/*     Probably in sys/types.h. */
-typedef void (*sig_t) __P(( int ));
-
-#endif /* _ASH_SYS_CDEFS */
diff --git a/commands/ash/test/malloc.c b/commands/ash/test/malloc.c
deleted file mode 100755 (executable)
index c54d716..0000000
+++ /dev/null
@@ -1,1298 +0,0 @@
-
-/**********************************************************/
-/*
-/*              This was file READ_ME
-/*
-/**********************************************************/
-
-/*
-       PROGRAM
-               malloc(), free(), realloc()
-       AUTHOR
-               Dick Grune, Free University, Amsterdam
-               Modified by Ceriel Jacobs, Free University, Amsterdam,
-               to make it faster
-       VERSION
-               $Header$
-       DESCRIPTION
-       This is an independent rewrite of the malloc/free package; it is
-       fast and efficient.  Free blocks are kept in doubly linked lists,
-       list N holding blocks with sizes between 2**N and 2**(N+1)-1.
-       Consequently neither malloc nor free have to do any searching:
-       the cost of a call of malloc() (or free()) is constant, however
-       many blocks you have got.
-       
-       If you switch on the NON_STANDARD macro (see param.h) every block
-       costs 2 pointers overhead (otherwise it's 4).
-*/
-/*
-       There is an organisational problem here: during devellopment
-       I want the package divided into modules, which implies external
-       names for the communication.  The only external names I want in
-       the finished product are malloc, realloc and free.  This requires
-       some hanky-panky.
-*/
-
-
-/**********************************************************/
-/*
-/*              This was file size_type.h
-/*
-/**********************************************************/
-
-#if    _EM_WSIZE == _EM_PSIZE
-typedef unsigned int size_type;
-#elif  _EM_LSIZE == _EM_PSIZE
-typedef unsigned long size_type;
-#else
-#error funny pointer size
-#endif
-#include       <stdlib.h>
-#include       <stdio.h>
-
-
-/**********************************************************/
-/*
-/*              This was file param.h
-/*
-/**********************************************************/
-
-/* $Header$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-
-#      undef   NON_STANDARD    /*      If defined, the contents of a block
-                                       will NOT be left undisturbed after it
-                                       is freed, as opposed to what it says
-                                       in the manual (malloc(2)).
-                                       Setting this option reduces the memory
-                                       overhead considerably.  I personally
-                                       consider the specified behaviour an
-                                       artefact of the original
-                                       implementation.
-                               */
-
-#      define  ASSERT          /*      If defined, some inexpensive tests
-                                       will be made to ensure the
-                                       correctness of some sensitive data.
-                                       It often turns an uncontrolled crash
-                                       into a controlled one.
-                               */
-
-#      define  CHECK           /*      If defined, extensive and expensive
-                                       tests will be done, inculding a
-                                       checksum on the mallinks (chunk
-                                       information blocks).  The resulting
-                                       information will be printed on a file
-                                       called mal.out .
-                                       Additionally a function
-                                               maldump(n) int n;
-                                       will be defined, which will dump
-                                       pertinent info in pseudo-readable
-                                       form; it aborts afterwards if n != 0.
-                               */
-
-#      undef   EXTERN          /*      If defined, all static names will
-                                       become extern, which is a help in
-                                       using adb(1) or prof(1)
-                               */
-
-#      define  STORE           /*      If defined, separate free lists will
-                                       be kept of chunks with small sizes,
-                                       to speed things up a little.
-                               */
-
-#      undef SYSTEM            /*      If defined, the system module is used.
-                                       Otherwise, "sbrk" is called directly.
-                               */
-
-#define        ALIGNMENT       8       
-                               /* alignment common to all types */
-#define        LOG_MIN_SIZE    3
-#define        LOG_MAX_SIZE    24
-
-
-/**********************************************************/
-/*
-/*              This was file impl.h
-/*
-/**********************************************************/
-
-/* $Header$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-/*     This file essentially describes how the mallink info block
-       is implemented.
-*/
-
-#define        MIN_SIZE        (1<<LOG_MIN_SIZE)
-#define        MAX_FLIST       (LOG_MAX_SIZE - LOG_MIN_SIZE)
-#if ALIGNMENT != 4 && ALIGNMENT != 8 && ALIGNMENT != 16
-#error ALIGNMENT must be 4, 8 or 16
-#elif ALIGNMENT % _EM_LSIZE
-/* since calloc() does it's initialization in longs */
-#error ALIGNMENT must be a multiple of the long size
-#endif
-#define align(n)       (((n) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
-
-union _inf {
-       union _inf *ptr;
-       size_type ui;
-};
-
-typedef union _inf mallink;
-#define        MAL_NULL        ((mallink *)0)
-
-/*     Access macros; only these macros know where to find values.
-       They are also lvalues.
-*/
-#ifndef        NON_STANDARD
-#define        OFF_SET 0
-#else  /* def NON_STANDARD */
-#define        OFF_SET 2
-#endif /* NON_STANDARD */
-
-#define        _log_prev_of(ml)        ((ml)[-1+OFF_SET]).ptr
-#define        _log_next_of(ml)        ((ml)[-2+OFF_SET]).ptr
-#define        _phys_prev_of(ml)       ((ml)[-3+OFF_SET]).ptr
-#define        _this_size_of(ml)       ((ml)[-4+OFF_SET]).ui
-#ifndef        CHECK
-#define        N_WORDS                 4
-#else  /* ifdef        CHECK */
-#define        _checksum_of(ml)        ((ml)[-5+OFF_SET]).ui
-#define        _print_of(ml)           ((ml)[-6+OFF_SET]).ui
-#define        _mark_of(ml)            ((ml)[-7+OFF_SET]).ui
-#define        N_WORDS                 7
-#endif /* CHECK */
-
-#define        mallink_size()          (size_t) \
-       align((N_WORDS - OFF_SET) * sizeof (mallink))
-
-#ifdef CHECK
-#define        set_mark(ml,e)          (_mark_of(ml) = (e))
-#define        mark_of(ml)             (_mark_of(ml))
-
-#define        set_checksum(ml,e)      (_checksum_of(ml) = (e))
-#define        checksum_of(ml)         (_checksum_of(ml))
-#endif /* CHECK */
-
-#define new_mallink(ml)                ( _log_prev_of(ml) = 0, \
-                                 _log_next_of(ml) = 0, \
-                                 _phys_prev_of(ml) = 0, \
-                                 _this_size_of(ml) = 0 )
-
-#define        block_of_mallink(ml)    ((void *)ml)
-#define        mallink_of_block(addr)  ((mallink *)addr)
-
-#define        public  extern
-#define        publicdata      extern
-#ifndef        EXTERN
-#define        private static
-#define        privatedata     static
-#else  /* def  EXTERN */
-#define        private extern
-#define        privatedata
-#endif /* EXTERN */
-
-#ifdef ASSERT
-private m_assert(const char *fn, int ln);
-#define        assert(b)               (!(b) ? m_assert(__FILE__, __LINE__) : 0)
-#else  /* ndef ASSERT */
-#define        assert(b)               0
-#endif /* ASSERT */
-
-
-/**********************************************************/
-/*
-/*              This was file check.h
-/*
-/**********************************************************/
-
-/* $Header$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-#ifdef CHECK
-
-private check_mallinks(const char *s), calc_checksum(mallink *ml);
-private check_work_empty(const char *s);
-private started_working_on(mallink *ml), stopped_working_on(mallink *ml);
-
-#else  /* ifndef       CHECK */
-
-#define        maldump(n)              abort()
-#define        check_mallinks(s)       0
-#define        calc_checksum(ml)       0
-#define        started_working_on(ml)  0
-#define        stopped_working_on(ml)  0
-#define        check_work_empty(s)     0
-
-#endif /* CHECK */
-
-
-/**********************************************************/
-/*
-/*              This was file log.h
-/*
-/**********************************************************/
-
-/* $Header$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-/*     Algorithms to manipulate the doubly-linked lists of free
-       chunks.
-*/
-
-private link_free_chunk(mallink *ml), unlink_free_chunk(mallink *ml);
-private mallink *first_present(int class);
-private mallink *search_free_list(int class, size_t n);
-
-#ifdef STORE
-#define in_store(ml)           ((size_type)_phys_prev_of(ml) & STORE_BIT)
-#define set_store(ml, e) \
-       (_phys_prev_of(ml) = (mallink *) \
-               ((e) ? (size_type) _phys_prev_of(ml) | STORE_BIT : \
-                      (size_type) _phys_prev_of(ml) & ~STORE_BIT))
-#endif
-#define        set_log_prev(ml,e)      (_log_prev_of(ml) = (e))
-#define        log_prev_of(ml)         (mallink *) (_log_prev_of(ml))
-
-#define        set_log_next(ml,e)      (_log_next_of(ml) = (e))
-#define        log_next_of(ml)         (mallink *) (_log_next_of(ml))
-
-
-
-/**********************************************************/
-/*
-/*              This was file phys.h
-/*
-/**********************************************************/
-
-/* $Header$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-/*     Algorithms to manipulate the doubly-linked list of physical
-       chunks.
-*/
-privatedata mallink *ml_last;
-
-#define FREE_BIT               01
-#ifdef STORE
-#define STORE_BIT              02
-#define BITS                   (FREE_BIT|STORE_BIT)
-#else
-#define BITS                   (FREE_BIT)
-#endif
-
-#define __bits(ml)             ((int)((size_type)_phys_prev_of(ml) & BITS))
-#define        __free_of(ml)           ((int)((size_type)_phys_prev_of(ml) & FREE_BIT))
-#define __phys_prev_of(ml)     ((mallink *)((size_type)_phys_prev_of(ml) & ~BITS))
-#define prev_size_of(ml)       ((char *)(ml) - \
-                                (char *)__phys_prev_of(ml) - \
-                                mallink_size() \
-                               )
-#define        set_phys_prev(ml,e) \
-       (_phys_prev_of(ml) = (mallink *) ((char *)e + __bits(ml)))
-
-#ifdef CHECK
-private Error(const char *fmt, const char *s, mallink *ml);
-#define        phys_prev_of(ml)        (mallink *) \
-       (first_mallink(ml) ? \
-               (char *)Error("phys_prev_of first_mallink %p", "somewhere", ml) : \
-               (char *)__phys_prev_of(ml) \
-       )
-#else  /* ndef CHECK */
-#define        phys_prev_of(ml)        __phys_prev_of(ml)
-#endif /* CHECK */
-
-#define        first_mallink(ml)       (int) (__phys_prev_of(ml) == 0)
-#define        last_mallink(ml)        (int) ((ml) == ml_last)
-
-/*     There is an ambiguity in the semantics of phys_next_of: sometimes
-       one wants it to return MAL_NULL if there is no next chunk, at
-       other times one wants the address of the virtual chunk at the
-       end of memory.  The present version returns the address of the
-       (virtual) chunk and relies on the user to test last_mallink(ml)
-       first.
-*/
-#define size_of(ml)            (_this_size_of(ml) - mallink_size())
-#define        set_phys_next(ml,e) \
-       (_this_size_of(ml) = (size_type)((char *)(e) - (char *)(ml)))
-#define        phys_next_of(ml)        (mallink *) ((char *)(ml) + _this_size_of(ml))
-
-#define        set_free(ml,e) \
-       (_phys_prev_of(ml) = (mallink *) \
-               ((e) ? (size_type) _phys_prev_of(ml) | FREE_BIT : \
-                      (size_type) _phys_prev_of(ml) & ~FREE_BIT))
-#define        free_of(ml)             (__free_of(ml))
-
-#define coalesce_forw(ml,nxt)  ( unlink_free_chunk(nxt), \
-                                 combine_chunks((ml), (nxt)))
-
-#define coalesce_backw(ml,prv) ( unlink_free_chunk(prv), \
-                                 stopped_working_on(ml), \
-                                 combine_chunks((prv), (ml)), \
-                                 started_working_on(prv))
-
-#ifdef CHECK
-#define        set_print(ml,e)         (_print_of(ml) = (e))
-#define        print_of(ml)            (_print_of(ml))
-#endif /* CHECK */
-
-private truncate(mallink *ml, size_t size);
-private combine_chunks(register mallink *ml1, register mallink *ml2);
-private mallink *create_chunk(void *p, size_t n);
-
-
-/**********************************************************/
-/*
-/*              This was file mal.c
-/*
-/**********************************************************/
-
-/* $Header$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-#include       <limits.h>
-#include       <stdlib.h>
-
-/*     Malloc space is traversed by N doubly-linked lists of chunks, each
-       containing a couple of house-keeping data addressed as a
-       'mallink' and a piece of useful space, called the block.
-       The N lists are accessed through their starting pointers in
-       free_list[].  Free_list[n] points to a list of chunks between
-       2**(n+LOG_MIN_SIZE) and 2**(n+LOG_MIN_SIZE+1)-1, which means
-       that the smallest chunk is 2**LOG_MIN_SIZE (== MIN_SIZE).
-*/
-
-#ifdef SYSTEM
-#include       <system.h>
-#define SBRK   sys_break
-#else
-#define SBRK   _sbrk
-#define        ILL_BREAK               (void *)(-1)    /* funny failure value */
-#endif
-extern void *SBRK(int incr);
-#ifdef STORE
-#define        MAX_STORE       32
-private do_free(mallink *ml), sell_out(void);
-privatedata mallink *store[MAX_STORE];
-#endif /* STORE */
-
-void *privious_free= (void *)-1;
-void *
-malloc(register size_t n)
-{check_mallinks("malloc entry");{
-       register mallink *ml;
-       register int min_class;
-       void *tmp;
-
-{ static int reent= 0; if (!reent) { reent++; printf("malloc\n"); reent--; } }
-privious_free= (void *)-1;
-       if (n == 0) {
-               return NULL;
-       }
-       if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
-#ifdef STORE
-       if (n <= MAX_STORE*MIN_SIZE)    {
-               /* look in the store first */
-               register mallink **stp = &store[(n >> LOG_MIN_SIZE) - 1];
-               
-               if (ml = *stp)  {
-                       *stp = log_next_of(ml);
-                       set_store(ml, 0);
-                       check_mallinks("malloc fast exit");
-                       assert(! in_store(ml));
-                       tmp= block_of_mallink(ml);
-{ static int reent= 0; if (!reent) { reent++; printf("= 0x%x\n", tmp);reent--; } }
-                       return tmp;
-               }
-       }
-#endif /* STORE */
-
-       check_work_empty("malloc, entry");
-
-       /*      Acquire a chunk of at least size n if at all possible;
-               Try everything.
-       */
-       {
-               /*      Inline substitution of "smallest".
-               */
-               register size_t n1 = n;
-
-               assert(n1 < (1L << LOG_MAX_SIZE));
-               min_class = 0;
-
-               do {
-                       n1 >>= 1;
-                       min_class++;
-               } while (n1 >= MIN_SIZE);
-       }
-
-       if (min_class >= MAX_FLIST)
-               return NULL;            /* we don't deal in blocks that big */
-       ml = first_present(min_class);
-       if (ml == MAL_NULL)     {
-               /*      Try and extend */
-               register void *p;
-#define        GRABSIZE        4096            /* Power of 2 */
-               register size_t req =
-                       ((MIN_SIZE<<min_class)+ mallink_size() + GRABSIZE - 1) &
-                               ~(GRABSIZE-1);
-       
-               if (!ml_last)   {
-                       /* first align SBRK() */
-               
-                       p = SBRK(0);
-                       SBRK((int) (align((size_type) p) - (size_type) p));
-               }
-
-               /* SBRK takes an int; sorry ... */
-               if ((int) req < 0) {
-                       p = ILL_BREAK;
-               } else {
-                       p = SBRK((int)req);
-               }
-               if (p == ILL_BREAK) {
-                       req = n + mallink_size();
-                       if ((int) req >= 0) p = SBRK((int)req);
-               }
-               if (p == ILL_BREAK)     {
-                       /*      Now this is bad.  The system will not give us
-                               more memory.  We can only liquidate our store
-                               and hope it helps.
-                       */
-#ifdef STORE
-                       sell_out();
-                       ml = first_present(min_class);
-                       if (ml == MAL_NULL)     {
-#endif /* STORE */
-                               /* In this emergency we try to locate a suitable
-                                  chunk in the free_list just below the safe
-                                  one; some of these chunks may fit the job.
-                               */
-                               ml = search_free_list(min_class - 1, n);
-                               if (!ml)        /* really out of space */
-                                       return NULL;
-                               started_working_on(ml);
-                               unlink_free_chunk(ml);
-                               check_mallinks("suitable_chunk, forced");
-#ifdef STORE
-                       }
-                       else started_working_on(ml);
-#endif /* STORE */
-               }
-               else {
-                       assert((size_type)p == align((size_type)p));
-                       ml = create_chunk(p, req);
-               }
-               check_mallinks("suitable_chunk, extended");
-       }
-       else started_working_on(ml);
-
-       /* we have a chunk */
-       set_free(ml, 0);
-       calc_checksum(ml);
-       check_mallinks("suitable_chunk, removed");
-       n += mallink_size();
-       if (n + MIN_SIZE <= size_of(ml)) {
-               truncate(ml, n);
-       }
-       stopped_working_on(ml);
-       check_mallinks("malloc exit");
-       check_work_empty("malloc exit");
-#ifdef STORE
-       assert(! in_store(ml));
-#endif
-       tmp= block_of_mallink(ml);
-{ static int reent= 0; if (!reent) { reent++; printf("= 0x%x\n", tmp);reent--; } }
-       return tmp;
-}}
-
-void
-free(void *addr)
-{check_mallinks("free entry");{
-       register mallink *ml;
-
-printf("free 0x%x\n", addr);
-if (privious_free == addr) { fflush(stdout); fflush(stderr); abort(); }
-privious_free= addr;
-       if (addr == NULL) {
-               check_mallinks("free(0) very fast exit");
-               return;
-       }
-
-       ml = mallink_of_block(addr);
-#ifdef STORE
-
-       if (free_of(ml) || in_store(ml))
-               return;                         /* user frees free block */
-       if (size_of(ml) <= MAX_STORE*MIN_SIZE)  {
-               /* return to store */
-               mallink **stp = &store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
-               
-               set_log_next(ml, *stp);
-               *stp = ml;
-               set_store(ml, 1);
-               calc_checksum(ml);
-               check_mallinks("free fast exit");
-       }
-       else    {
-               do_free(ml);
-               check_mallinks("free exit");
-       }
-}}
-
-private
-do_free(register mallink *ml)
-{{
-#endif
-
-#ifndef STORE
-       if (free_of(ml))        return;
-#endif /* STORE */
-       started_working_on(ml);
-       set_free(ml, 1);
-       calc_checksum(ml);
-       if (! last_mallink(ml)) {
-               register mallink *next = phys_next_of(ml);
-
-               if (free_of(next)) coalesce_forw(ml, next);
-       }
-
-       if (! first_mallink(ml)) {
-               register mallink *prev = phys_prev_of(ml);
-
-               if (free_of(prev)) {
-                       coalesce_backw(ml, prev);
-                       ml = prev;
-               }
-       }
-       link_free_chunk(ml);
-       stopped_working_on(ml);
-       check_work_empty("free");
-
-       /* Compile-time checks on param.h */
-       switch (0)      {
-       case MIN_SIZE < OFF_SET * sizeof(mallink):      break;
-       case 1: break;
-       /*      If this statement does not compile due to duplicate case
-               entry, the minimum size block cannot hold the links for
-               the free blocks.  Either raise LOG_MIN_SIZE or switch
-               off NON_STANDARD.
-       */
-       }
-       switch(0)       {
-       case sizeof(void *) != sizeof(size_type):       break;
-       case 1: break;
-       /*      If this statement does not compile due to duplicate
-               case entry, size_type is not defined correctly.
-               Redefine and compile again.
-       */
-       }
-}}
-
-void *
-realloc(void *addr, register size_t n)
-{check_mallinks("realloc entry");{
-       register mallink *ml, *ph_next;
-       register size_type size;
-
-printf("realloc 0x%x, %d\n", addr, n);
-       if (addr == NULL) {
-               /*      Behave like most Unix realloc's when handed a
-                       null-pointer
-               */
-               return malloc(n);
-       }
-       if (n == 0) {
-               free(addr);
-               return NULL;
-       }
-       ml = mallink_of_block(addr);
-       if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
-#ifdef STORE
-       if (in_store(ml)) {
-               register mallink *stp = store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
-               mallink *stp1 = NULL;
-               while (ml != stp)       {
-                       stp1 = stp;
-                       stp = log_next_of(stp);
-               }
-               stp = log_next_of(stp);
-               if (! stp1) store[(size_of(ml) >> LOG_MIN_SIZE) - 1] = stp;
-               else set_log_next(stp1, stp);
-               set_store(ml, 0);
-               calc_checksum(ml);
-       }
-#endif
-       if (free_of(ml)) {
-               unlink_free_chunk(ml);
-               set_free(ml, 0);                /* user reallocs free block */
-       }
-       started_working_on(ml);
-       size = size_of(ml);
-       if (    /* we can simplify the problem by adding the next chunk: */
-               n > size &&
-               !last_mallink(ml) &&
-               (ph_next = phys_next_of(ml), free_of(ph_next)) &&
-               n <= size + mallink_size() + size_of(ph_next)
-       )       {
-               /* add in the physically next chunk */
-               unlink_free_chunk(ph_next);
-               combine_chunks(ml, ph_next);
-               size = size_of(ml);
-               check_mallinks("realloc, combining");
-       }
-       if (n > size)   {               /* this didn't help */
-               void *new;
-               register char *l1, *l2 = addr;
-
-               stopped_working_on(ml);
-               if (!(new = l1 = malloc(n))) return NULL;       /* no way */
-               while (size--) *l1++ = *l2++;
-               free(addr);
-               check_work_empty("mv_realloc");
-#ifdef STORE
-               assert(! in_store(mallink_of_block(new)));
-#endif
-               return new;
-       }
-       /* it helped, but maybe too well */
-       n += mallink_size();
-       if (n + MIN_SIZE <= size_of(ml)) {
-               truncate(ml, n);
-       }
-       stopped_working_on(ml);
-       check_mallinks("realloc exit");
-       check_work_empty("realloc");
-#ifdef STORE
-       assert(! in_store(ml));
-#endif
-       return addr;
-}}
-
-void *
-calloc(size_t nmemb, size_t size)
-{check_mallinks("calloc entry");{
-       long *l1, *l2;
-       size_t n;
-
-printf("calloc\n");
-       if (size == 0) return NULL;
-       if (nmemb == 0) return NULL;
-
-       /* Check for overflow on the multiplication. The peephole-optimizer
-        * will eliminate all but one of the possibilities.
-        */
-       if (sizeof(size_t) == sizeof(int)) {
-               if (UINT_MAX / size < nmemb) return NULL;
-       } else if (sizeof(size_t) == sizeof(long)) {
-               if (ULONG_MAX / size < nmemb) return NULL;
-       } else return NULL;             /* can't happen, can it ? */
-
-       n = size * nmemb;
-       if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
-       if (n >= (1L << LOG_MAX_SIZE)) return NULL;
-       l1 = (long *) malloc(n);
-       l2 = l1 + (n / sizeof(long));   /* n is at least long aligned */
-       while ( l2 != l1 ) *--l2 = 0;
-       check_mallinks("calloc exit");
-       check_work_empty("calloc exit");
-       return (void *)l1;
-}}
-/*     Auxiliary routines */
-
-#ifdef STORE
-private
-sell_out(void) {
-       /*      Frees all block in store.
-       */
-       register mallink **stp;
-       
-       for (stp = &store[0]; stp < &store[MAX_STORE]; stp++)   {
-               register mallink *ml = *stp;
-               
-               while (ml)      {
-                       *stp = log_next_of(ml);
-                       set_store(ml, 0);
-                       do_free(ml);
-                       ml = *stp;
-               }
-       }
-
-}
-#endif /* STORE */
-
-#ifdef ASSERT
-private
-m_assert(const char *fn, int ln)
-{
-       char ch;
-       
-       while (*fn)
-               write(2, fn++, 1);
-       write(2, ": malloc assert failed in line ", 31);
-       ch = (ln / 100) + '0'; write(2, &ch, 1); ln %= 100;
-       ch = (ln / 10) + '0'; write(2, &ch, 1); ln %= 10;
-       ch = (ln / 1) + '0'; write(2, &ch, 1);
-       write(2, "\n", 1);
-       maldump(1);
-}
-#endif /* ASSERT */
-
-
-/**********************************************************/
-/*
-/*              This was file log.c
-/*
-/**********************************************************/
-
-/* $Header$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-
-/*     Logical manipulations.
-       The chunks are properly chained in the physical chain.
-*/
-
-privatedata mallink *free_list[MAX_FLIST];
-
-private
-link_free_chunk(register mallink *ml)
-{
-       /*      The free chunk ml is inserted in its proper logical
-               chain.
-       */
-       register mallink **mlp = &free_list[-1];
-       register size_type n = size_of(ml);
-       register mallink *ml1;
-
-       assert(n < (1L << LOG_MAX_SIZE));
-
-       do {
-               n >>= 1;
-               mlp++;
-       }
-       while (n >= MIN_SIZE);
-
-       ml1 = *mlp;
-       set_log_prev(ml, MAL_NULL);
-       set_log_next(ml, ml1);
-       calc_checksum(ml);
-       if (ml1) {
-               /* link backwards
-               */
-               set_log_prev(ml1, ml);
-               calc_checksum(ml1);
-       }
-       *mlp = ml;
-}
-
-private
-unlink_free_chunk(register mallink *ml)
-{
-       /*      Unlinks a free chunk from (the middle of) the
-               logical chain.
-       */
-       register mallink *next = log_next_of(ml);
-       register mallink *prev = log_prev_of(ml);
-
-       if (!prev)      {
-               /* it is the first in the chain */
-               register mallink **mlp = &free_list[-1];
-               register size_type n = size_of(ml);
-
-               assert(n < (1L << LOG_MAX_SIZE));
-               do {
-                       n >>= 1;
-                       mlp++;
-               }
-               while (n >= MIN_SIZE);
-               *mlp = next;
-       }
-       else    {
-               set_log_next(prev, next);
-               calc_checksum(prev);
-       }
-       if (next) {
-               set_log_prev(next, prev);
-               calc_checksum(next);
-       }
-}
-
-private mallink *
-search_free_list(int class, size_t n)
-{
-       /*      Searches the free_list[class] for a chunk of at least size n;
-               since it is searching a slightly undersized list,
-               such a block may not be there.
-       */
-       register mallink *ml;
-       
-       for (ml = free_list[class]; ml; ml = log_next_of(ml))
-               if (size_of(ml) >= n)
-                       return ml;
-       return MAL_NULL;                /* nothing found */
-}
-
-private mallink *
-first_present(int class)
-{
-       /*      Find the index i in free_list[] such that:
-                       i >= class && free_list[i] != MAL_NULL.
-               Return MAL_NULL if no such i exists;
-               Otherwise, return the first block of this list, after
-               unlinking it.
-       */
-       register mallink **mlp, *ml;
-
-       for (mlp = &free_list[class]; mlp < &free_list[MAX_FLIST]; mlp++) {
-               if ((ml = *mlp) != MAL_NULL)    {
-       
-                       *mlp = log_next_of(ml); /* may be MAL_NULL */
-                       if (*mlp) {
-                               /* unhook backward link
-                               */
-                               set_log_prev(*mlp, MAL_NULL);
-                               calc_checksum(*mlp);
-                       }
-                       return ml;
-               }
-       }
-       return MAL_NULL;
-}
-
-#ifdef CHECK
-private mallink *
-free_list_entry(int i) {
-       /*      To allow maldump.c access to log.c's private data.
-       */
-       return free_list[i];
-}
-#endif /* CHECK */
-
-
-/**********************************************************/
-/*
-/*              This was file phys.c
-/*
-/**********************************************************/
-
-/* $Header$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-#include       <stdlib.h>
-
-/*     Physical manipulations.
-       The blocks concerned are not in any logical chain.
-*/
-
-private mallink *
-create_chunk(void *p, size_t n)
-{
-       /*      The newly acquired piece of memory at p, of length n,
-               is turned into a free chunk, properly chained in the
-               physical chain.
-               The address of the chunk is returned.
-       */
-       register mallink *ml;
-       /*      All of malloc memory is followed by a virtual chunk, the
-               mallink of which starts mallink_size() bytes past the last
-               byte in memory.
-               Its use is prevented by testing for ml == ml_last first.
-       */
-       register mallink *last = ml_last;
-       
-       assert(!last || p == (char *)phys_next_of(last) - mallink_size());
-       ml = (mallink *)((char *)p + mallink_size());   /* bump ml */
-       new_mallink(ml);
-       started_working_on(ml);
-       set_free(ml, 1);
-       set_phys_prev(ml, last);
-       ml_last = ml;
-
-       set_phys_next(ml, (mallink *)((char *)ml + n));
-       calc_checksum(ml);
-       assert(size_of(ml) + mallink_size() == n);
-       if (last && free_of(last)) {
-               coalesce_backw(ml, last);
-               ml = last;
-       }
-       check_mallinks("create_chunk, phys. linked");
-       return ml;
-}
-
-private
-truncate(register mallink *ml, size_t size)
-{
-       /*      The chunk ml is truncated.
-               The chunk at ml is split in two.
-               The remaining part is then freed.
-       */
-       register mallink *new = (mallink *)((char *)ml + size);
-       register mallink *ph_next = phys_next_of(ml);
-
-       new_mallink(new);
-       set_free(new, 1);
-       set_phys_prev(new, ml);
-       set_phys_next(new, ph_next);
-       calc_checksum(new);
-       if (! last_mallink(ml)) {
-               set_phys_prev(ph_next, new);
-               calc_checksum(ph_next);
-               if (free_of(ph_next)) coalesce_forw(new, ph_next);
-       }
-       else    ml_last = new;
-       set_phys_next(ml, new);
-       calc_checksum(ml);
-
-       started_working_on(new);
-       link_free_chunk(new);
-       stopped_working_on(new);
-       check_mallinks("truncate");
-}
-
-private
-combine_chunks(register mallink *ml1, register mallink *ml2)
-{
-       /*      The chunks ml1 and ml2 are combined.
-       */
-       register mallink *ml3 = phys_next_of(ml2);
-
-       set_phys_next(ml1, ml3);
-       calc_checksum(ml1);
-       if (!last_mallink(ml2)) {
-               set_phys_prev(ml3, ml1);
-               calc_checksum(ml3);
-       }
-       if (ml_last == ml2)
-               ml_last = ml1;
-}
-
-
-/**********************************************************/
-/*
-/*              This was file check.c
-/*
-/**********************************************************/
-
-/* $Header$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-#include       <stdio.h>
-
-#ifdef CHECK                   /* otherwise this whole file is skipped */
-
-/* ??? check these later */
-private acquire_malout(void), check_ml_last(const char *s);
-private dump_all_mallinks(void), dump_free_list(int i);
-private dump_mallink(const char *s, mallink *ml), print_loop(mallink *ml);
-private working_on(mallink *ml);
-private size_type checksum(mallink *ml);
-static FILE *malout;
-
-private mallink *free_list_entry(int i);
-
-#define        for_free_list(i,p) \
-       for (p = free_list_entry(i); p; p = log_next_of(p))
-
-#define        for_all_mallinks(ml)    /* backwards! */ \
-       for (ml = ml_last; ml; \
-               ml = first_mallink(ml) ? MAL_NULL : phys_prev_of(ml))
-
-/* Maldump */
-
-static int pr_cnt = 0;
-
-maldump(int n) {
-       /*      Dump pertinent info in pseudo-readable format;
-               abort afterwards if n != 0.
-       */
-       static int dumping = 0;
-       int i;
-       
-       if (dumping)
-               return;
-       dumping++;
-       acquire_malout();
-       fprintf(malout,
-               ">>>>>>>>>>>>>>>> DUMP OF ALL MALLINKS <<<<<<<<<<<<<<<<");
-       fprintf(malout, "    ml_last = %p\n", ml_last);
-       if (++pr_cnt == 100) pr_cnt = 0;
-       dump_all_mallinks();
-       fprintf(malout,
-               ">>>>>>>>>>>>>>>> DUMP OF FREE_LISTS <<<<<<<<<<<<<<<<\n");
-       if (++pr_cnt == 100) pr_cnt = 0;
-       for (i = 0; i < MAX_FLIST; i++)
-               dump_free_list(i);
-       fprintf(malout,
-               ">>>>>>>>>>>>>>>> END OF DUMP <<<<<<<<<<<<<<<<\n");
-       fclose(malout);
-       dumping--;
-       if (n)
-               abort();
-}
-
-private
-acquire_malout(void)   {
-       static char buf[BUFSIZ];
-       
-       if (!malout)    {
-               malout = freopen("mal.out", "w", stderr);       
-               setbuf(malout, buf);
-       }
-}
-
-private
-dump_all_mallinks(void)        {
-       mallink *ml;
-       
-       for_all_mallinks (ml)   {
-               if (print_loop(ml))
-                       return;
-               dump_mallink((char *)0, ml);
-       }
-}
-
-private
-dump_free_list(int i)  {
-       mallink *ml = free_list_entry(i);
-       
-       if (!ml)
-               return;
-       fprintf(malout, "%2d: ", i);
-       for_free_list(i, ml)    {
-               if (print_loop(ml))
-                       return;
-               fprintf(malout, "%p ", ml);
-       }
-       fprintf(malout, "<\n");
-}
-
-private int
-print_loop(mallink *ml)        {
-       if (print_of(ml) == pr_cnt)     {
-               fprintf(malout, "... PRINT LOOP\n");
-               return 1;
-       }
-       set_print(ml, pr_cnt);
-       return 0;
-}
-
-private
-dump_mallink(const char *s, mallink *ml)       {
-       acquire_malout();
-       if (s)
-               fprintf(malout, "%s: ", s);
-       fprintf(malout, "@: %p;", ml);
-       if (ml && checksum_of(ml) != checksum(ml))
-               fprintf(malout, ">>>> CORRUPTED <<<<");
-       if (!ml)        {
-               fprintf(malout, "\n");
-               return;
-       }       
-       if (free_of(ml))        {
-               fprintf(malout, " l_p: %p;", _log_prev_of(ml));
-               fprintf(malout, " l_n: %p;", _log_next_of(ml));
-       }
-       fprintf(malout, " p_s: %p;", prev_size_of(ml));
-       fprintf(malout, " t_s: %p;", _this_size_of(ml));
-       fprintf(malout, " sz: %lu;", (unsigned long) size_of(ml));
-       fprintf(malout, " fr: %d;", free_of(ml));
-       fprintf(malout, "\n");
-}
-
-/*     Check_mallinks() checks the total data structure as accessible
-       through free_list[] and ml_last.  All check_sums should be OK,
-       except those held in the small array off_colour.  This is a
-       trick to allow to continue checking even when a few mallinks
-       are temporarily out of order.
-       Check_mallinks() tests for a lot of internal consistency.
-*/
-
-/* Some arbitrary constants */
-#define        IN_ML_LAST      93
-#define        IN_FREE_LIST    57              /* and in ml_last */
-#define        CLEAR           21
-
-#define        VRIJ            1
-#define        BEZET           2
-
-private
-check_mallinks(const char *s)  {
-       mallink *ml;
-       size_type size;
-       int i;
-       char stat;
-       
-       check_ml_last(s);
-       stat = BEZET;
-       for_all_mallinks(ml)    {
-               if (checksum_of(ml) != checksum(ml))
-                       Error("mallink info at %p corrupted", s, ml);
-               if (working_on(ml))     {
-                       stat = BEZET;
-                       continue;
-               }
-               if (    !last_mallink(ml) &&
-                       phys_prev_of(phys_next_of(ml)) != ml
-               )
-                       Error("upward chain bad at %p", s, ml);
-               if (    !first_mallink(ml) &&
-                       phys_next_of(phys_prev_of(ml)) != ml
-               )
-                       Error("downward chain bad at %p", s, ml);
-               if (free_of(ml))        {
-                       if (stat == VRIJ)
-                               Error("free mallink at %p follows free mallink",
-                                                               s, ml);
-                       stat = VRIJ;
-               }
-               else
-                       stat = BEZET;
-               set_mark(ml, IN_ML_LAST);
-       }
-       
-       for (i = 0, size = MIN_SIZE; i < MAX_FLIST; i++, size *= 2)     {
-               for_free_list(i, ml)    {
-                       if (working_on(ml))
-                               continue;
-                       if (!free_of(ml))
-                               Error("occupied mallink %p occurs in free_list", s, ml);
-                       switch (mark_of(ml))    {
-                       case IN_ML_LAST:
-                               set_mark(ml, IN_FREE_LIST);
-                               break;
-                       case IN_FREE_LIST:
-                               Error("mallink %p occurs in 2 free_lists",
-                                                               s, ml);
-                       default:
-                               Error("unknown mallink %p in free_list",
-                                                               s, ml);
-                       }
-                       if (size_of(ml) < size)
-                               Error("size of mallink %p too small", s, ml);
-                       if (size_of(ml) >= 2*size)
-                               Error("size of mallink %p too large", s, ml);
-               }
-       }
-       for_all_mallinks (ml)   {
-               if (working_on(ml))
-                       continue;
-               if (free_of(ml) && mark_of(ml) != IN_FREE_LIST)
-                       Error("free mallink %p is in no free_list", s, ml);
-               set_mark(ml, CLEAR);
-       }
-}
-
-private
-check_ml_last(const char *s)   {
-       if (ml_last && _this_size_of(ml_last) == 0)
-               Error("size of ml_last == 0, at %p", s, ml_last);
-}
-
-private size_type
-checksum(mallink *ml)  {
-       size_type sum = 0;
-       
-       if (free_of(ml))        {
-               sum += (size_type)_log_prev_of(ml);
-               sum += (size_type)_log_next_of(ml);
-       }
-       sum += (size_type)prev_size_of(ml);
-       sum += (size_type)_this_size_of(ml);
-       return sum;
-}
-
-private
-calc_checksum(mallink *ml)     {
-       set_checksum(ml, checksum(ml));
-}
-
-#define        N_COLOUR        10
-static mallink *off_colour[N_COLOUR];
-
-private
-started_working_on(mallink *ml)        {
-       int i;
-       
-       for (i = 0; i < N_COLOUR; i++)
-               if (off_colour[i] == MAL_NULL)  {
-                       off_colour[i] = ml;
-                       return;
-               }
-       Error("out of off_colour array at %p", "started_working_on", ml);
-}
-
-private
-stopped_working_on(mallink *ml)        {
-       int i;
-       
-       for (i = 0; i < N_COLOUR; i++)
-               if (off_colour[i] == ml)        {
-                       off_colour[i] = MAL_NULL;
-                       return;
-               }
-       Error("stopped working on mallink %p", "stopped_working_on", ml);
-}
-
-private int
-working_on(mallink *ml)        {
-       int i;
-       
-       for (i = 0; i < N_COLOUR; i++)
-               if (off_colour[i] == ml)
-                       return 1;
-       return 0;
-}
-
-private
-check_work_empty(const char *s)        {
-       int i;
-       int cnt = 0;
-       
-       for (i = 0; i < N_COLOUR; i++)
-               if (off_colour[i] != MAL_NULL)
-                       cnt++;
-       if (cnt != 0)
-               Error("off_colour not empty", s, MAL_NULL);
-}
-
-private int
-Error(const char *fmt, const char *s, mallink *ml)     {
-       static int already_called = 0;
-
-       if (already_called++) return 0;
-       setbuf(stdout, (char *) 0);
-       printf("%s: ", s);
-       printf(fmt, (long)ml);
-       printf("\n");
-       acquire_malout();
-       fprintf(malout, "%s: ", s);
-       fprintf(malout, fmt, (long)ml);
-       fprintf(malout, "\n");
-       fflush(stdout);
-       maldump(1);
-       return 0;                       /* to satisfy lint */
-}
-
-#endif /* CHECK */
-
index f4ec70fdf79b3e5b572094596a9a060a4f14e68e..83ce40991ad1b9524e07cd2e506dd13b5871f367 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)trap.c     5.2 (Berkeley) 4/12/91";
+#if 0
+static char sccsid[] = "@(#)trap.c     8.5 (Berkeley) 6/5/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/trap.c,v 1.29 2004/04/06 20:06:51 markm Exp $");
+*/
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
 
 #include "shell.h"
 #include "main.h"
 #include "nodes.h"     /* for other headers */
 #include "eval.h"
 #include "jobs.h"
+#include "show.h"
 #include "options.h"
 #include "syntax.h"
-#include "signames.h"
 #include "output.h"
 #include "memalloc.h"
 #include "error.h"
 #include "trap.h"
 #include "mystring.h"
-#include <sys/types.h>
-#include <signal.h>
+#if !defined(NO_HISTORY) && !defined(EDITLINE)
+#include "myhistedit.h"
+#endif
+#include "builtins.h"
+
+#ifdef __minix
+#define NO_SIGINTERRUPT
+#define NO_SYS_SIGNAME
+#define NO_SYS_SIGLIST
+
+#endif
 
+typedef void (*sig_T)(int);
 
 /*
  * Sigmode records the current value of the signal handlers for the various
@@ -64,40 +80,130 @@ static char sccsid[] = "@(#)trap.c 5.2 (Berkeley) 4/12/91";
 #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_HARD_IGN 4           /* signal is ignored permanently */
+#define S_RESET 5              /* temporary - to reset a hard ignored sig */
+
+
+MKINIT char sigmode[_NSIG];    /* current value of signal */
+int pendingsigs;               /* indicates some signal received */
+int is_interactive= -1;                /* Shell is interactive */
+int in_dotrap;                 /* do we execute in a trap handler? */
+static char *volatile trap[_NSIG];     /* trap handler commands */
+static volatile sig_atomic_t gotsig[_NSIG]; 
+                               /* indicates specified signal received */
+static int ignore_sigchld;     /* Used while handling SIGCHLD traps. */
+volatile sig_atomic_t gotwinch;
+
+static int sigstring_to_signum (char *);
+static void printsignals (void);
+static int getsigaction(int, sig_T *);
+static void onsig (int);
+#ifdef NO_SIGINTERRUPT
+static int siginterrupt (int,int);
+#endif
+static char *strsigname (int);
 
 
-extern char nullstr[1];                /* null string */
+/*
+ * Map a string to a signal number.
+ */
+static int
+sigstring_to_signum(char *sig)
+{
+
+       if (is_number(sig)) {
+               int signo;
+
+               signo = atoi(sig);
+               return ((signo >= 0 && signo < _NSIG) ? signo : (-1));
+       } else if (strcasecmp(sig, "exit") == 0) {
+               return (0);
+       } else {
+               int n;
+
+               if (strncasecmp(sig, "sig", 3) == 0)
+                       sig += 3;
+               for (n = 1; n < _NSIG; n++)
+                       if (strcasecmp(strsigname(n), sig) == 0)
+                               return (n);
+       }
+       return (-1);
+}
 
-char *trap[MAXSIG+1];          /* trap handler commands */
-MKINIT char sigmode[MAXSIG];   /* current value of signal */
-char gotsig[MAXSIG];           /* indicates specified signal received */
-int pendingsigs;                       /* indicates some signal received */
 
 /*
- * The trap builtin.
+ * Print a list of valid signal names.
  */
+static void
+printsignals(void)
+{
+       int n, outlen;
+
+       outlen = 0;
+       for (n = 1; n < _NSIG; n++) {
+               if (strsigname(n)) {
+                       out1fmt("%s", strsigname(n));
+                       outlen += strlen(strsigname(n));
+               } else {
+                       out1fmt("%d", n);
+                       outlen += 3;    /* good enough */
+               }
+               ++outlen;
+               if (outlen > 70 || n == _NSIG - 1) {
+                       out1str("\n");
+                       outlen = 0;
+               } else {
+                       out1c(' ');
+               }
+       }
+}
+
 
-trapcmd(argc, argv)  char **argv; {
+/*
+ * The trap builtin.
+ */
+int
+trapcmd(int argc, char **argv)
+{
        char *action;
-       char **ap;
        int signo;
 
        if (argc <= 1) {
-               for (signo = 0 ; signo <= MAXSIG ; signo++) {
-                       if (trap[signo] != NULL)
-                               out1fmt("%d: %s\n", signo, trap[signo]);
+               for (signo = 0 ; signo < _NSIG ; signo++) {
+                       if (trap[signo] != NULL) {
+                               if (signo == 0) {
+                                       out1fmt("trap -- '%s' %s\n",
+                                           trap[signo], "exit");
+                               } else if (strsigname(signo)) {
+                                       out1fmt("trap -- '%s' %s\n",
+                                           trap[signo], strsigname(signo));
+                               } else {
+                                       out1fmt("trap -- '%s' %d\n",
+                                           trap[signo], signo);
+                               }
+                       }
                }
                return 0;
        }
-       ap = argv + 1;
-       if (is_number(*ap))
-               action = NULL;
-       else
-               action = *ap++;
-       while (*ap) {
-               if ((signo = number(*ap)) < 0 || signo > MAXSIG)
-                       error("%s: bad trap", *ap);
+       action = NULL;
+       if (*++argv && strcmp(*argv, "--") == 0)
+               argv++;
+       if (*argv && sigstring_to_signum(*argv) == -1) {
+               if ((*argv)[0] != '-') {
+                       action = *argv;
+                       argv++;
+               } else if ((*argv)[1] == '\0') {
+                       argv++;
+               } else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') {
+                       printsignals();
+                       return 0;
+               } else {
+                       error("bad option %s", *argv);
+               }
+       }
+       while (*argv) {
+               if ((signo = sigstring_to_signum(*argv)) == -1)
+                       error("bad signal %s", *argv);
                INTOFF;
                if (action)
                        action = savestr(action);
@@ -107,22 +213,21 @@ trapcmd(argc, argv)  char **argv; {
                if (signo != 0)
                        setsignal(signo);
                INTON;
-               ap++;
+               argv++;
        }
        return 0;
 }
 
 
-
 /*
  * Clear traps on a fork.
  */
-
 void
-clear_traps() {
-       char **tp;
+clear_traps(void)
+{
+       char *volatile *tp;
 
-       for (tp = trap ; tp <= &trap[MAXSIG] ; tp++) {
+       for (tp = trap ; tp <= &trap[_NSIG - 1] ; tp++) {
                if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
                        INTOFF;
                        ckfree(*tp);
@@ -135,18 +240,16 @@ clear_traps() {
 }
 
 
-
 /*
  * Set the signal handler for the specified signal.  The routine figures
  * out what it should be set to.
  */
-
-int
-setsignal(signo) {
+void
+setsignal(int signo)
+{
        int action;
-       sig_t sigact;
+       sig_T sig, sigact = SIG_DFL;
        char *t;
-       extern void onsig();
 
        if ((t = trap[signo]) == NULL)
                action = S_DFL;
@@ -154,11 +257,10 @@ setsignal(signo) {
                action = S_CATCH;
        else
                action = S_IGN;
-       if (rootshell && action == S_DFL) {
+       if (action == S_DFL) {
                switch (signo) {
                case SIGINT:
-                       if (iflag)
-                               action = S_CATCH;
+                       action = S_CATCH;
                        break;
                case SIGQUIT:
 #if DEBUG
@@ -169,68 +271,103 @@ setsignal(signo) {
                                break;
                        }
 #endif
-                       /* FALLTHROUGH */
+                       action = S_CATCH;
+                       break;
                case SIGTERM:
-                       if (iflag)
+                       if (rootshell && iflag)
                                action = S_IGN;
                        break;
 #if JOBS
                case SIGTSTP:
                case SIGTTOU:
-                       if (jflag)
+                       if (rootshell && mflag)
                                action = S_IGN;
                        break;
+#endif
+#ifndef NO_HISTORY
+               case SIGWINCH:
+                       if (rootshell && iflag)
+                               action = S_CATCH;
+                       break;
 #endif
                }
        }
-       t = &sigmode[signo - 1];
-       if (*t == 0) {  /* current setting unknown */
+
+       t = &sigmode[signo];
+       if (*t == 0) {
                /*
-                * There is a race condition here if action is not S_IGN.
-                * A signal can be ignored that shouldn't be.
+                * current setting unknown
                 */
-               if ((int)(sigact = signal(signo, SIG_IGN)) == -1)
-                       error("Signal system call failed");
+               if (!getsigaction(signo, &sigact)) {
+                       /*
+                        * Pretend it worked; maybe we should give a warning
+                        * here, but other shells don't. We don't alter
+                        * sigmode, so that we retry every time.
+                        */
+                       return;
+               }
                if (sigact == SIG_IGN) {
-                       *t = S_HARD_IGN;
+                       if (mflag && (signo == SIGTSTP ||
+                            signo == SIGTTIN || signo == SIGTTOU)) {
+                               *t = S_IGN;     /* don't hard ignore these */
+                       } else
+                               *t = S_HARD_IGN;
                } else {
-                       *t = S_IGN;
+                       *t = S_RESET;   /* force to be set */
                }
        }
        if (*t == S_HARD_IGN || *t == action)
-               return 0;
+               return;
        switch (action) {
                case S_DFL:     sigact = SIG_DFL;       break;
                case S_CATCH:   sigact = onsig;         break;
                case S_IGN:     sigact = SIG_IGN;       break;
        }
        *t = action;
-       return (int)signal(signo, sigact);
+       sig = signal(signo, sigact);
+       if (sig != SIG_ERR && action == S_CATCH)
+               siginterrupt(signo, 1);
 }
 
 
 /*
- * Ignore a signal.
+ * Return the current setting for sig w/o changing it.
  */
+static int
+getsigaction(int signo, sig_T *sigact)
+{
+       struct sigaction sa;
+
+       if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
+               return 0;
+       *sigact = (sig_T) sa.sa_handler;
+       return 1;
+}
+
 
+/*
+ * Ignore a signal.
+ */
 void
-ignoresig(signo) {
-       if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
+ignoresig(int signo)
+{
+
+       if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) {
                signal(signo, SIG_IGN);
        }
-       sigmode[signo - 1] = S_HARD_IGN;
+       sigmode[signo] = S_HARD_IGN;
 }
 
 
 #ifdef mkinit
-INCLUDE "signames.h"
+INCLUDE <signal.h>
 INCLUDE "trap.h"
 
 SHELLPROC {
        char *sm;
 
        clear_traps();
-       for (sm = sigmode ; sm < sigmode + MAXSIG ; sm++) {
+       for (sm = sigmode ; sm < sigmode + _NSIG ; sm++) {
                if (*sm == S_IGN)
                        *sm = S_HARD_IGN;
        }
@@ -238,82 +375,119 @@ SHELLPROC {
 #endif
 
 
-
 /*
  * Signal handler.
  */
+static void
+onsig(int signo)
+{
 
-void
-onsig(signo) {
+#ifndef BSD
        signal(signo, onsig);
+#endif
        if (signo == SIGINT && trap[SIGINT] == NULL) {
                onint();
                return;
        }
-       gotsig[signo - 1] = 1;
+
+       if (signo != SIGCHLD || !ignore_sigchld)
+               gotsig[signo] = 1;
        pendingsigs++;
-}
 
+       /* If we are currently in a wait builtin, prepare to break it */
+       if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0)
+               breakwaitcmd = 1;
+       /* 
+        * If a trap is set, not ignored and not the null command, we need 
+        * to make sure traps are executed even when a child blocks signals.
+        */
+       if (Tflag &&
+           trap[signo] != NULL && 
+           ! trap[signo][0] == '\0' &&
+           ! (trap[signo][0] == ':' && trap[signo][1] == '\0'))
+               breakwaitcmd = 1;
+
+#ifndef NO_HISTORY
+       if (signo == SIGWINCH)
+               gotwinch = 1;
+#endif
+}
 
 
 /*
  * Called to execute a trap.  Perhaps we should avoid entering new trap
  * handlers while we are executing a trap handler.
  */
-
 void
-dotrap() {
+dotrap(void)
+{
        int i;
        int savestatus;
 
+       in_dotrap++;
        for (;;) {
-               for (i = 1 ; ; i++) {
-                       if (gotsig[i - 1])
+               for (i = 1; i < _NSIG; i++) {
+                       if (gotsig[i]) {
+                               gotsig[i] = 0;
+                               if (trap[i]) {
+                                       /*
+                                        * Ignore SIGCHLD to avoid infinite
+                                        * recursion if the trap action does
+                                        * a fork.
+                                        */
+                                       if (i == SIGCHLD)
+                                               ignore_sigchld++;
+                                       savestatus = exitstatus;
+                                       evalstring(trap[i]);
+                                       exitstatus = savestatus;
+                                       if (i == SIGCHLD)
+                                               ignore_sigchld--;
+                               }
                                break;
-                       if (i >= MAXSIG)
-                               goto done;
+                       }
                }
-               gotsig[i - 1] = 0;
-               savestatus=exitstatus;
-               evalstring(trap[i]);
-               exitstatus=savestatus;
+               if (i >= _NSIG)
+                       break;
        }
-done:
+       in_dotrap--;
        pendingsigs = 0;
 }
 
 
-
 /*
  * Controls whether the shell is interactive or not.
  */
-
-int is_interactive;
-
 void
-setinteractive(on) {
+setinteractive(int on)
+{
        if (on == is_interactive)
                return;
        setsignal(SIGINT);
        setsignal(SIGQUIT);
        setsignal(SIGTERM);
+#ifndef NO_HISTORY
+       setsignal(SIGWINCH);
+#endif
        is_interactive = on;
 }
 
 
-
 /*
  * Called to exit the shell.
  */
-
 void
-exitshell(status) {
+exitshell(int status)
+{
        struct jmploc loc1, loc2;
        char *p;
 
        TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
-       if (setjmp(loc1.loc))  goto l1;
-       if (setjmp(loc2.loc))  goto l2;
+       if (setjmp(loc1.loc)) {
+               goto l1;
+       }
+       if (setjmp(loc2.loc)) {
+               goto l2;
+       }
        handler = &loc1;
        if ((p = trap[0]) != NULL && *p != '\0') {
                trap[0] = NULL;
@@ -326,3 +500,85 @@ l1:   handler = &loc2;                     /* probably unnecessary */
 #endif
 l2:   _exit(status);
 }
+
+#ifdef NO_SIGINTERRUPT
+static int siginterrupt(sig, flag)
+int sig;
+int flag;
+{
+       return 0;
+}
+#endif
+
+#ifdef NO_SYS_SIGNAME
+static char *strsigname(sig)
+int sig;
+{
+       switch(sig)
+       {
+       case 0:         return "Signal 0";      /*  0 */
+       case SIGHUP:    return "hup";           /*  1 */
+       case SIGINT:    return "int";           /*  2 */
+       case SIGQUIT:   return "quit";          /*  3 */
+       case SIGILL:    return "ill";           /*  4 */
+       case SIGTRAP:   return "trap";          /*  5 */
+       case SIGABRT:   return "abrt";          /*  6 */
+#ifdef __minix_vmd
+       case SIGEMT:    return "emt";           /*  7 */
+#else
+       case SIGBUS:    return "bus";           /*  7 */
+#endif
+       case SIGFPE:    return "fpe";           /*  8 */
+       case SIGKILL:   return "kill";          /*  9 */
+       case SIGUSR1:   return "usr1";          /* 10 */
+       case SIGSEGV:   return "segv";          /* 11 */
+       case SIGUSR2:   return "usr2";          /* 12 */
+       case SIGPIPE:   return "pipe";          /* 13 */
+       case SIGALRM:   return "alrm";          /* 14 */
+       case SIGTERM:   return "term";          /* 15 */
+#ifdef __minix_vmd
+       case 16:        return "Signal 16";     /* 16 */
+#else
+       case SIGEMT:    return "emt";           /* 16 */
+#endif
+       case SIGCHLD:   return "chld";          /* 17 */
+       case SIGCONT:   return "cont";          /* 18 */
+       case SIGSTOP:   return "stop";          /* 19 */
+       case SIGTSTP:   return "tstp";          /* 20 */
+       case SIGTTIN:   return "ttin";          /* 21 */
+       case SIGTTOU:   return "ttou";          /* 22 */
+       case SIGWINCH:  return "winch";         /* 23 */
+#ifdef __minix_vmd
+       case SIGFPEMU:  return "fpemu";         /* 30 */
+#endif
+       default:        return "Signal n";
+       }
+}
+#else
+static char *strsigname(sig)
+int sig;
+{
+       return sys_signame[sig];
+}
+#endif
+
+#ifdef NO_SYS_SIGLIST
+#include "signames.h"
+char *strsiglist(sig)
+int sig;
+{
+       if (sig > MAXSIG)
+               return NULL;
+       return sigmesg[sig];
+}
+#else
+char *strsiglist(sig)
+int sig;
+{
+       return sys_siglist[sig];
+}
+#endif
+
+/*
+ * $PchId: trap.c,v 1.7 2006/05/23 11:56:21 philip Exp $
+ */
index afa984cb06b173ead0131273b34e9f6c279078a7..a61672ab61a7469ecd8f7367ae1a7c0b1d0a8b05 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)trap.h      5.1 (Berkeley) 3/7/91
+ *     @(#)trap.h      8.3 (Berkeley) 6/5/95
+ * $FreeBSD: src/bin/sh/trap.h,v 1.12 2004/04/06 20:06:51 markm Exp $
  */
 
 extern int pendingsigs;
+extern int in_dotrap;
+extern int is_interactive;
+extern volatile sig_atomic_t gotwinch;
 
-#ifdef __STDC__
+int trapcmd(int, char **);
 void clear_traps(void);
-int setsignal(int);
+void setsignal(int);
 void ignoresig(int);
 void dotrap(void);
 void setinteractive(int);
 void exitshell(int);
-#else
-void clear_traps();
-int setsignal();
-void ignoresig();
-void dotrap();
-void setinteractive();
-void exitshell();
-#endif
+char *strsiglist(int);
+
+/*
+ * $PchId: trap.h,v 1.6 2006/05/22 12:48:30 philip Exp $
+ */
index f6e38d05f741b4ec6a849e076998602c4aeafe9e..82d8de1d79a292648473a9d0b713f4990b58ebeb 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)var.c      5.3 (Berkeley) 4/12/91";
+#if 0
+static char sccsid[] = "@(#)var.c      8.3 (Berkeley) 5/4/95";
+#endif
 #endif /* not lint */
+/*
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sh/var.c,v 1.26.2.1 2004/09/30 04:41:55 des Exp $");
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#ifndef NO_PATHS_H
+#include <paths.h>
+#endif
 
 /*
  * Shell variables.
  */
 
+#include <locale.h>
+
 #include "shell.h"
 #include "output.h"
 #include "expand.h"
@@ -55,7 +65,16 @@ static char sccsid[] = "@(#)var.c    5.3 (Berkeley) 4/12/91";
 #include "memalloc.h"
 #include "error.h"
 #include "mystring.h"
+#include "parser.h"
+#if !defined(NO_HISTORY) && !defined(EDITLINE)
+#include "myhistedit.h"
+#endif
+
+#include "builtins.h"
 
+#ifndef _PATH_DEFPATH
+#define _PATH_DEFPATH "/usr/bin:/bin"
+#endif
 
 #define VTABSIZE 39
 
@@ -64,48 +83,57 @@ struct varinit {
        struct var *var;
        int flags;
        char *text;
+       void (*func)(const char *);
 };
 
 
-#if ATTY
-struct var vatty;
+#ifndef NO_HISTORY
+struct var vhistsize;
 #endif
 struct var vifs;
 struct var vmail;
 struct var vmpath;
 struct var vpath;
+struct var vppid;
 struct var vps1;
 struct var vps2;
 struct var vpse;
 struct var vvers;
-#if ATTY
-struct var vterm;
-#endif
+STATIC struct var voptind;
 
-const struct varinit varinit[] = {
-#if ATTY
-       {&vatty,        VSTRFIXED|VTEXTFIXED|VUNSET,    "ATTY="},
+STATIC const struct varinit varinit[] = {
+#if !defined(NO_HISTORY) && !defined(EDITLINE)
+       { &vhistsize,   VSTRFIXED|VTEXTFIXED|VUNSET,    "HISTSIZE=",
+         sethistsize },
 #endif
-       {&vifs, VSTRFIXED|VTEXTFIXED,           "IFS= \t\n"},
-       {&vmail,        VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL="},
-       {&vmpath,       VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH="},
-       {&vpath,        VSTRFIXED|VTEXTFIXED,           "PATH=:/bin:/usr/bin"},
-       /* 
+       { &vifs,        VSTRFIXED|VTEXTFIXED,           "IFS= \t\n",
+         NULL },
+       { &vmail,       VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL=",
+         NULL },
+       { &vmpath,      VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH=",
+         NULL },
+       { &vpath,       VSTRFIXED|VTEXTFIXED,           "PATH=" _PATH_DEFPATH,
+         changepath },
+       { &vppid,       VSTRFIXED|VTEXTFIXED|VUNSET,    "PPID=",
+         NULL },
+       /*
         * vps1 depends on uid
         */
-       {&vps2, VSTRFIXED|VTEXTFIXED,           "PS2=> "},
-       {&vpse, VSTRFIXED|VTEXTFIXED,           "PSE=* "},
-#if ATTY
-       {&vterm,        VSTRFIXED|VTEXTFIXED|VUNSET,    "TERM="},
-#endif
-       {NULL,  0,                              NULL}
+       { &vps2,        VSTRFIXED|VTEXTFIXED,           "PS2=> ",
+         NULL },
+       { &vpse,        VSTRFIXED|VTEXTFIXED|VUNSET,    "PSE=",
+         NULL },
+       { &voptind,     VSTRFIXED|VTEXTFIXED,           "OPTIND=1",
+         getoptsreset },
+       { NULL, 0,                              NULL,
+         NULL }
 };
 
-struct var *vartab[VTABSIZE];
+STATIC struct var *vartab[VTABSIZE];
 
-STATIC void unsetvar __P((char *));
-STATIC struct var **hashvar __P((char *));
-STATIC int varequal __P((char *, char *));
+STATIC struct var **hashvar(char *);
+STATIC int varequal(char *, char *);
+STATIC int localevar(char *);
 
 /*
  * Initialize the varable symbol tables and import the environment
@@ -133,7 +161,9 @@ INIT {
  */
 
 void
-initvar() {
+initvar(void)
+{
+       char ppid[20];
        const struct varinit *ip;
        struct var *vp;
        struct var **vpp;
@@ -145,6 +175,7 @@ initvar() {
                        *vpp = vp;
                        vp->text = ip->text;
                        vp->flags = ip->flags;
+                       vp->func = ip->func;
                }
        }
        /*
@@ -154,20 +185,48 @@ initvar() {
                vpp = hashvar("PS1=");
                vps1.next = *vpp;
                *vpp = &vps1;
-               vps1.text = getuid() ? "PS1=$ " : "PS1=# ";
+               vps1.text = geteuid() ? "PS1=$ " : "PS1=# ";
                vps1.flags = VSTRFIXED|VTEXTFIXED;
        }
+       if ((vppid.flags & VEXPORT) == 0) {
+               fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
+               setvarsafe("PPID", ppid, 0);
+       }
 }
 
 /*
- * Set the value of a variable.  The flags argument is ored with the
+ * Safe version of setvar, returns 1 on success 0 on failure.
+ */
+
+int
+setvarsafe(char *name, char *val, int flags)
+{
+       struct jmploc jmploc;
+       struct jmploc *volatile savehandler = handler;
+       int err = 0;
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &err;
+#endif
+
+       if (setjmp(jmploc.loc))
+               err = 1;
+       else {
+               handler = &jmploc;
+               setvar(name, val, flags);
+       }
+       handler = savehandler;
+       return err;
+}
+
+/*
+ * Set the value of a variable.  The flags argument is tored with the
  * flags of the variable.  If val is NULL, the variable is unset.
  */
 
 void
-setvar(name, val, flags)
-       char *name, *val;
-       {
+setvar(char *name, char *val, int flags)
+{
        char *p, *q;
        int len;
        int namelen;
@@ -176,8 +235,9 @@ setvar(name, val, flags)
 
        isbad = 0;
        p = name;
-       if (! is_name(*p++))
+       if (! is_name(*p))
                isbad = 1;
+       p++;
        for (;;) {
                if (! is_in_name(*p)) {
                        if (*p == '\0' || *p == '=')
@@ -188,7 +248,7 @@ setvar(name, val, flags)
        }
        namelen = p - name;
        if (isbad)
-               error("%.*s: is read only", namelen, name);
+               error("%.*s: bad variable name", namelen, name);
        len = namelen + 2;              /* 2 is space for '=' and '\0' */
        if (val == NULL) {
                flags |= VUNSET;
@@ -206,7 +266,26 @@ setvar(name, val, flags)
        setvareq(nameeq, flags);
 }
 
-
+STATIC int
+localevar(char *s)
+{
+       static char *lnames[7] = {
+               "ALL", "COLLATE", "CTYPE", "MONETARY",
+               "NUMERIC", "TIME", NULL
+       };
+       char **ss;
+
+       if (*s != 'L')
+               return 0;
+       if (varequal(s + 1, "ANG"))
+               return 1;
+       if (strncmp(s + 1, "C_", 2) != 0)
+               return 0;
+       for (ss = lnames; *ss ; ss++)
+               if (varequal(s + 3, *ss))
+                       return 1;
+       return 0;
+}
 
 /*
  * Same as setvar except that the variable and value are passed in
@@ -216,28 +295,42 @@ setvar(name, val, flags)
  */
 
 void
-setvareq(s, flags)
-       char *s;
-       {
+setvareq(char *s, int flags)
+{
        struct var *vp, **vpp;
+       int len;
 
+       if (aflag)
+               flags |= VEXPORT;
        vpp = hashvar(s);
        for (vp = *vpp ; vp ; vp = vp->next) {
                if (varequal(s, vp->text)) {
                        if (vp->flags & VREADONLY) {
-                               int len = strchr(s, '=') - s;
+                               len = strchr(s, '=') - s;
                                error("%.*s: is read only", len, s);
                        }
                        INTOFF;
-                       if (vp == &vpath)
-                               changepath(s + 5);      /* 5 = strlen("PATH=") */
+
+                       if (vp->func && (flags & VNOFUNC) == 0)
+                               (*vp->func)(strchr(s, '=') + 1);
+
                        if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
                                ckfree(vp->text);
-                       vp->flags &=~ (VTEXTFIXED|VSTACK|VUNSET);
+
+                       vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
                        vp->flags |= flags;
                        vp->text = s;
+
+                       /*
+                        * We could roll this to a function, to handle it as
+                        * a regular variable function callback, but why bother?
+                        */
                        if (vp == &vmpath || (vp == &vmail && ! mpathset()))
                                chkmail(1);
+                       if ((vp->flags & VEXPORT) && localevar(s)) {
+                               putenv(s);
+                               (void) setlocale(LC_ALL, "");
+                       }
                        INTON;
                        return;
                }
@@ -247,7 +340,14 @@ setvareq(s, flags)
        vp->flags = flags;
        vp->text = s;
        vp->next = *vpp;
+       vp->func = NULL;
+       INTOFF;
        *vpp = vp;
+       if ((vp->flags & VEXPORT) && localevar(s)) {
+               putenv(s);
+               (void) setlocale(LC_ALL, "");
+       }
+       INTON;
 }
 
 
@@ -257,9 +357,8 @@ setvareq(s, flags)
  */
 
 void
-listsetvar(list)
-       struct strlist *list;
-       {
+listsetvar(struct strlist *list)
+{
        struct strlist *lp;
 
        INTOFF;
@@ -276,9 +375,8 @@ listsetvar(list)
  */
 
 char *
-lookupvar(name)
-       char *name;
-       {
+lookupvar(char *name)
+{
        struct var *v;
 
        for (v = *hashvar(name) ; v ; v = v->next) {
@@ -300,9 +398,8 @@ lookupvar(name)
  */
 
 char *
-bltinlookup(name, doall)
-       char *name;
-       {
+bltinlookup(char *name, int doall)
+{
        struct strlist *sp;
        struct var *v;
 
@@ -312,8 +409,8 @@ bltinlookup(name, doall)
        }
        for (v = *hashvar(name) ; v ; v = v->next) {
                if (varequal(v->text, name)) {
-                       if (v->flags & VUNSET
-                        || ! doall && (v->flags & VEXPORT) == 0)
+                       if ((v->flags & VUNSET)
+                        || (!doall && (v->flags & VEXPORT) == 0))
                                return NULL;
                        return strchr(v->text, '=') + 1;
                }
@@ -329,7 +426,8 @@ bltinlookup(name, doall)
  */
 
 char **
-environment() {
+environment(void)
+{
        int nenv;
        struct var **vpp;
        struct var *vp;
@@ -359,15 +457,14 @@ environment() {
  */
 
 #ifdef mkinit
-MKINIT void shprocvar();
-
 SHELLPROC {
        shprocvar();
 }
 #endif
 
 void
-shprocvar() {
+shprocvar(void)
+{
        struct var **vpp;
        struct var *vp, **prev;
 
@@ -400,14 +497,21 @@ shprocvar() {
  */
 
 int
-showvarscmd(argc, argv)  char **argv; {
+showvarscmd(int argc __unused, char **argv __unused)
+{
        struct var **vpp;
        struct var *vp;
+       const char *s;
 
        for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
                for (vp = *vpp ; vp ; vp = vp->next) {
-                       if ((vp->flags & VUNSET) == 0)
-                               out1fmt("%s\n", vp->text);
+                       if (vp->flags & VUNSET)
+                               continue;
+                       for (s = vp->text; *s != '='; s++)
+                               out1c(*s);
+                       out1c('=');
+                       out1qstr(s + 1);
+                       out1c('\n');
                }
        }
        return 0;
@@ -420,15 +524,35 @@ showvarscmd(argc, argv)  char **argv; {
  */
 
 int
-exportcmd(argc, argv)  char **argv; {
+exportcmd(int argc, char **argv)
+{
        struct var **vpp;
        struct var *vp;
        char *name;
        char *p;
+       char *cmdname;
+       int ch, values;
        int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
 
+       cmdname = argv[0];
+       optreset = optind = 1;
+       opterr = 0;
+       values = 0;
+       while ((ch = getopt(argc, argv, "p")) != -1) {
+               switch (ch) {
+               case 'p':
+                       values = 1;
+                       break;
+               case '?':
+               default:
+                       error("unknown option: -%c", optopt);
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
        listsetvar(cmdenviron);
-       if (argc > 1) {
+       if (argc != 0) {
                while ((name = *argptr++) != NULL) {
                        if ((p = strchr(name, '=')) != NULL) {
                                p++;
@@ -436,7 +560,12 @@ exportcmd(argc, argv)  char **argv; {
                                vpp = hashvar(name);
                                for (vp = *vpp ; vp ; vp = vp->next) {
                                        if (varequal(vp->text, name)) {
+
                                                vp->flags |= flag;
+                                               if ((vp->flags & VEXPORT) && localevar(vp->text)) {
+                                                       putenv(vp->text);
+                                                       (void) setlocale(LC_ALL, "");
+                                               }
                                                goto found;
                                        }
                                }
@@ -448,8 +577,16 @@ found:;
                for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
                        for (vp = *vpp ; vp ; vp = vp->next) {
                                if (vp->flags & flag) {
+                                       if (values) {
+                                               out1str(cmdname);
+                                               out1c(' ');
+                                       }
                                        for (p = vp->text ; *p != '=' ; p++)
                                                out1c(*p);
+                                       if (values && !(vp->flags & VUNSET)) {
+                                               out1c('=');
+                                               out1qstr(p + 1);
+                                       }
                                        out1c('\n');
                                }
                        }
@@ -463,7 +600,9 @@ found:;
  * The "local" command.
  */
 
-localcmd(argc, argv)  char **argv; {
+int
+localcmd(int argc __unused, char **argv __unused)
+{
        char *name;
 
        if (! in_function())
@@ -483,9 +622,8 @@ localcmd(argc, argv)  char **argv; {
  */
 
 void
-mklocal(name)
-       char *name;
-       {
+mklocal(char *name)
+{
        struct localvar *lvp;
        struct var **vpp;
        struct var *vp;
@@ -493,8 +631,8 @@ mklocal(name)
        INTOFF;
        lvp = ckmalloc(sizeof (struct localvar));
        if (name[0] == '-' && name[1] == '\0') {
-               lvp->text = ckmalloc(sizeof optval);
-               bcopy(optval, lvp->text, sizeof optval);
+               lvp->text = ckmalloc(sizeof optlist);
+               memcpy(lvp->text, optlist, sizeof optlist);
                vp = NULL;
        } else {
                vpp = hashvar(name);
@@ -527,7 +665,8 @@ mklocal(name)
  */
 
 void
-poplocalvars() {
+poplocalvars(void)
+{
        struct localvar *lvp;
        struct var *vp;
 
@@ -535,10 +674,10 @@ poplocalvars() {
                localvars = lvp->next;
                vp = lvp->vp;
                if (vp == NULL) {       /* $- saved */
-                       bcopy(lvp->text, optval, sizeof optval);
+                       memcpy(optlist, lvp->text, sizeof optlist);
                        ckfree(lvp->text);
                } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
-                       unsetvar(vp->text);
+                       (void)unsetvar(vp->text);
                } else {
                        if ((vp->flags & VTEXTFIXED) == 0)
                                ckfree(vp->text);
@@ -550,7 +689,9 @@ poplocalvars() {
 }
 
 
-setvarcmd(argc, argv)  char **argv; {
+int
+setvarcmd(int argc, char **argv)
+{
        if (argc <= 2)
                return unsetcmd(argc, argv);
        else if (argc == 3)
@@ -567,14 +708,31 @@ setvarcmd(argc, argv)  char **argv; {
  * with the same name.
  */
 
-unsetcmd(argc, argv)  char **argv; {
+int
+unsetcmd(int argc __unused, char **argv __unused)
+{
        char **ap;
-
-       for (ap = argv + 1 ; *ap ; ap++) {
-               unsetfunc(*ap);
-               unsetvar(*ap);
+       int i;
+       int flg_func = 0;
+       int flg_var = 0;
+       int ret = 0;
+
+       while ((i = nextopt("vf")) != '\0') {
+               if (i == 'f')
+                       flg_func = 1;
+               else
+                       flg_var = 1;
        }
-       return 0;
+       if (flg_func == 0 && flg_var == 0)
+               flg_var = 1;
+
+       for (ap = argptr; *ap ; ap++) {
+               if (flg_func)
+                       ret |= unsetfunc(*ap);
+               if (flg_var)
+                       ret |= unsetvar(*ap);
+       }
+       return ret;
 }
 
 
@@ -582,22 +740,25 @@ unsetcmd(argc, argv)  char **argv; {
  * Unset the specified variable.
  */
 
-STATIC void
-unsetvar(s)
-       char *s;
-       {
+int
+unsetvar(char *s)
+{
        struct var **vpp;
        struct var *vp;
 
        vpp = hashvar(s);
        for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
                if (varequal(vp->text, s)) {
+                       if (vp->flags & VREADONLY)
+                               return (1);
                        INTOFF;
-                       if (*(strchr(vp->text, '=') + 1) != '\0'
-                        || vp->flags & VREADONLY) {
+                       if (*(strchr(vp->text, '=') + 1) != '\0')
                                setvar(s, nullstr, 0);
+                       if ((vp->flags & VEXPORT) && localevar(vp->text)) {
+                               unsetenv(s);
+                               setlocale(LC_ALL, "");
                        }
-                       vp->flags &=VEXPORT;
+                       vp->flags &= ~VEXPORT;
                        vp->flags |= VUNSET;
                        if ((vp->flags & VSTRFIXED) == 0) {
                                if ((vp->flags & VTEXTFIXED) == 0)
@@ -606,9 +767,11 @@ unsetvar(s)
                                ckfree(vp);
                        }
                        INTON;
-                       return;
+                       return (0);
                }
        }
+
+       return (0);
 }
 
 
@@ -618,14 +781,13 @@ unsetvar(s)
  */
 
 STATIC struct var **
-hashvar(p)
-       register char *p;
-       {
+hashvar(char *p)
+{
        unsigned int hashval;
 
-       hashval = *p << 4;
+       hashval = ((unsigned char) *p) << 4;
        while (*p && *p != '=')
-               hashval += *p++;
+               hashval += (unsigned char) *p++;
        return &vartab[hashval % VTABSIZE];
 }
 
@@ -638,9 +800,8 @@ hashvar(p)
  */
 
 STATIC int
-varequal(p, q)
-       register char *p, *q;
-       {
+varequal(char *p, char *q)
+{
        while (*p == *q++) {
                if (*p++ == '=')
                        return 1;
@@ -649,3 +810,7 @@ varequal(p, q)
                return 1;
        return 0;
 }
+
+/*
+ * $PchId: var.c,v 1.5 2006/05/22 12:28:49 philip Exp $
+ */
index 70a36065feaff32f92a6f817b21936ce827a317b..afa62565a7516857c35fffd2ee5f58c4a326ca08 100755 (executable)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  * 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.
@@ -33,7 +29,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)var.h       5.1 (Berkeley) 3/7/91
+ *     @(#)var.h       8.2 (Berkeley) 5/4/95
+ * $FreeBSD: src/bin/sh/var.h,v 1.12 2004/04/06 20:06:51 markm Exp $
  */
 
 /*
  */
 
 /* flags */
-#define VEXPORT                01      /* variable is exported */
-#define VREADONLY      02      /* variable cannot be modified */
-#define VSTRFIXED      04      /* variable struct is staticly allocated */
-#define VTEXTFIXED     010     /* text is staticly allocated */
-#define VSTACK         020     /* text is allocated on the stack */
-#define VUNSET         040     /* the variable is not set */
+#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 */
+       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 */
+       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 */
 };
 
 
 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 vppid;
 extern struct var vps1;
 extern struct var vps2;
 extern struct var vpse;
-#if ATTY
-extern struct var vterm;
+#ifndef NO_HISTORY
+extern struct var vhistsize;
 #endif
 
 /*
@@ -87,43 +86,39 @@ extern struct var vterm;
  */
 
 #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 pseval()       (vpse.text + 4)
-#if ATTY
-#define termval()      (vterm.text + 5)
+#define optindval()    (voptind.text + 7)
+#ifndef NO_HISTORY
+#define histsizeval()  (vhistsize.text + 9)
 #endif
 
-#if ATTY
-#define attyset()      ((vatty.flags & VUNSET) == 0)
-#endif
 #define mpathset()     ((vmpath.flags & VUNSET) == 0)
 
-
-#ifdef __STDC__
-void initvar();
+void initvar(void);
 void setvar(char *, char *, int);
 void setvareq(char *, int);
 struct strlist;
 void listsetvar(struct strlist *);
 char *lookupvar(char *);
 char *bltinlookup(char *, int);
-char **environment();
+char **environment(void);
+void shprocvar(void);
 int showvarscmd(int, char **);
+int exportcmd(int, char **);
+int localcmd(int, char **);
 void mklocal(char *);
 void poplocalvars(void);
-#else
-void initvar();
-void setvar();
-void setvareq();
-void listsetvar();
-char *lookupvar();
-char *bltinlookup();
-char **environment();
-int showvarscmd();
-void mklocal();
-void poplocalvars();
-#endif
+int setvarcmd(int, char **);
+int unsetcmd(int, char **);
+int unsetvar(char *);
+int setvarsafe(char *, char *, int);
+
+/*
+ * $PchId: var.h,v 1.4 2006/03/29 12:04:45 philip Exp $
+ */