# 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 $? $@
/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
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 $@
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 \
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 $
-# @(#)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
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
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 $
--- /dev/null
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 $
+ */
--- /dev/null
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 $
+ */
--- /dev/null
+/*-
+ * 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 $
+ */
--- /dev/null
+%{
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 $
+ */
--- /dev/null
+/*
+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 $
+ */
--- /dev/null
+%{
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 $
+ */
+/*-
+ * 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 $
+ */
+/*-
+ * 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 $
+ */
*/
-#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
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 */
#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;
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++;
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)
}
-int
+static int
expr_is_false(val)
struct value *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:
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;
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;
}
-int
+static int
lookup_op(name, table)
char *name;
char *const*table;
# 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[];
* 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
};
sed -e '/^[^#]/!d
s/[ ][ ]*/ /g
s/^[^ ][^ ]* \([^ ][^ ]*\).*/ "\1",/
- ' binary_op
+ ' "$binary_op"
echo ' NULL
};
sed -e '/^[^#]/!d
s/[ ][ ]*/ /g
s/^[^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\).*/ \1,/
- ' unary_op binary_op
+ ' "$unary_op" "$binary_op"
echo '};
const char op_argflag[] = {'
s/[ ][ ]*/ /g
s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]*$/& 0/
s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\)/ \1,/
- ' unary_op binary_op
+ ' "$unary_op" "$binary_op"
echo '};'
--- /dev/null
+/*
+myregexp.h
+
+Created: July 1995 by Philip Homburg <philip@cs.vu.nl>
+*/
+
+char *re_compile(char *pattern);
+int re_match(char *pattern, char *string);
*/
#include "bltin.h"
+#include "myregexp.h"
+#include <stdlib.h>
#define RE_END 0 /* end of regular expression */
#define RE_LITERAL 1 /* normal character follows */
char *match_begin[10];
short match_length[10];
short number_parens;
-static int match();
+static int match(char *pattern, char *string);
char stack[10];
int paren_num;
int i;
- char *malloc();
p = pattern;
if (*p == '^')
+int
re_match(pattern, string)
char *pattern;
char *string;
p++;
}
p++;
- if (found == negate || c == 0)
+ if (found == negate)
goto bad;
break;
case RE_LP:
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
+++ /dev/null
-#!/bin/sh
-make clean
-make && make install
#!/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
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
setvarcmd setvar
shiftcmd shift
trapcmd trap
-truecmd : true false
+truecmd : true
umaskcmd umask
+unaliascmd unalias
unsetcmd unset
waitcmd wait
+#foocmd foo
+aliascmd alias
--- /dev/null
+#!/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 $
/*-
- * 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.
#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);
}
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);
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)
}
-
/*
* 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);
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 $
+ */
--- /dev/null
+/*-
+ * 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 $
+ */
--- /dev/null
+/*
+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 $
+ */
--- /dev/null
+/*
+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 $
+ */
+++ /dev/null
-/*-
- * 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 */
--- /dev/null
+/*-
+ * 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;
+}
--- /dev/null
+/*-
+ * 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
/*-
- * 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.
#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>
/*
*/
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
*/
void
-exraise(e) {
+exraise(int e)
+{
if (handler == NULL)
abort();
exception = 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)
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
/*-
- * 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 */
/*
* 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);
/*
*/
#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 $
+ */
/*-
- * 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.
#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 */
int oexitstatus; /* saved exit status */
-#ifdef __STDC__
STATIC void evalloop(union node *);
STATIC void evalfor(union node *);
STATIC void evalcase(union node *, int);
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
-
/*
/*
- * The eval commmand.
+ * The eval command.
*/
-evalcmd(argc, argv)
- char **argv;
+int
+evalcmd(int argc, char **argv)
{
char *p;
char *concat;
*/
void
-evalstring(s)
- char *s;
- {
+evalstring(char *s)
+{
union node *n;
struct stackmark smark;
*/
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);
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:
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:
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;
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++;
STATIC void
-evalfor(n)
- union node *n;
- {
+evalfor(union node *n)
+{
struct arglist arglist;
union node *argp;
struct strlist *sp;
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;
}
STATIC void
-evalcase(n, flags)
- union node *n;
- {
+evalcase(union node *n, int flags)
+{
union node *cp;
union node *patp;
struct arglist arglist;
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)) {
*/
STATIC void
-evalsubshell(n, flags)
- union node *n;
- {
+evalsubshell(union node *n, int flags)
+{
struct job *jp;
int backgnd = (n->type == NBACKGND);
}
if (! backgnd) {
INTOFF;
- exitstatus = waitforjob(jp);
+ exitstatus = waitforjob(jp, (int *)NULL);
INTON;
}
}
*/
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;
}
}
}
*/
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++;
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]);
}
}
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;
}
*/
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 */
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);
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));
}
*/
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;
char **envp;
int varflag;
struct strlist *sp;
- register char *p;
int mode;
int pip[2];
struct cmdentry cmdentry;
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;
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)
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);
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 */
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)
/* 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 */
FORCEINTON;
close(pip[0]);
if (pip[1] != 1) {
- close(1);
- copyfd(pip[1], 1);
+ dup2(pip[1], 1);
close(pip[1]);
}
}
/* 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;
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;
exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
flushall();
cmddone:
+ cmdenviron = NULL;
out1 = &output;
out2 = &errout;
freestdout();
}
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;
}
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;
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]);
out:
if (lastarg)
setvar("_", lastarg, 0);
+ if (do_clearcmdentry)
+ clearcmdentry(0);
popstackmark(&smark);
}
*/
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());
}
* 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;
}
* 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) {
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 $
+ */
/*-
- * 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.
*
- * @(#)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 */
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 $
+ */
/*-
- * 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.
#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 */
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 *);
*/
void
-shellexec(argv, envp, path, index)
- char **argv, **envp;
- char *path;
- {
+shellexec(char **argv, char **envp, char *path, int index)
+{
char *cmdname;
int e;
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*/
#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
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;
growstackblock();
q = stackblock();
if (p != start) {
- bcopy(start, q, p - start);
+ memcpy(q, start, p - start);
q += p - start;
*q++ = '/';
}
/*** Command hashing code ***/
-hashcmd(argc, argv) char **argv; {
+int
+hashcmd(int argc __unused, char **argv __unused)
+{
struct tblentry **pp;
struct tblentry *cmdp;
int c;
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') {
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();
}
STATIC void
-printentry(cmdp)
- struct tblentry *cmdp;
- {
+printentry(struct tblentry *cmdp, int verbose)
+{
int index;
char *path;
char *name;
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);
*/
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;
prev = cmdp->param.index;
}
- path = pathval();
e = ENOENT;
index = -1;
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);
stunalloc(fullname);
goto success;
}
+#ifdef notdef
if (statb.st_uid == geteuid()) {
if ((statb.st_mode & 0100) == 0)
goto 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);
/* 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;
*/
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))
*/
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;
}
}
*/
void
-changepath(newval)
- char *newval;
- {
- char *old, *new;
+changepath(const char *newval)
+{
+ const char *old, *new;
int index;
int firstchange;
int bltin;
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 */
}
* PATH which has changed.
*/
-STATIC void
-clearcmdentry(firstchange) {
+void
+clearcmdentry(int firstchange)
+{
struct tblentry **tblp;
struct tblentry **pp;
struct tblentry *cmdp;
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 {
*/
#ifdef mkinit
-MKINIT void deletefuncs();
-
+INCLUDE "exec.h"
SHELLPROC {
deletefuncs();
}
#endif
void
-deletefuncs() {
+deletefuncs(void)
+{
struct tblentry **tblp;
struct tblentry **pp;
struct tblentry *cmdp;
* entry.
*/
-struct tblentry **lastcmdentry;
+STATIC struct tblentry **lastcmdentry;
STATIC struct tblentry *
-cmdlookup(name, add)
- char *name;
- {
+cmdlookup(char *name, int add)
+{
int hashval;
- register char *p;
+ char *p;
struct tblentry *cmdp;
struct tblentry **pp;
return cmdp;
}
-
/*
* Delete the command entry returned on the last lookup.
*/
STATIC void
-delete_cmd_entry() {
+delete_cmd_entry(void)
+{
struct tblentry *cmdp;
INTOFF;
-#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;
*/
void
-defun(name, func)
- char *name;
- union node *func;
- {
+defun(char *name, union node *func)
+{
struct cmdentry entry;
INTOFF;
* 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 $
+ */
/*-
- * 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.
*
- * @(#)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 */
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 $
+ */
/*-
- * 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
#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
};
-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());
/*
* 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;
/*
- * 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);
}
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];
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);
p = in.buf;
lastc = '\0';
+ nnl = 0;
+ /* Don't copy trailing newlines */
for (;;) {
if (--in.nleft < 0) {
if (in.fd < 0)
}
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",
+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))
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++;
*/
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;
}
*/
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;
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;
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;
}
*/
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;
* 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;
* 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;
}
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);
}
-#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;
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')
metaflag = 1;
} else if (*p == '\0')
break;
+ else if (*p == CTLQUOTEMARK)
+ continue;
else if (*p == CTLESC)
p++;
if (*p == '/') {
if (enddir != expdir)
metaflag++;
for (p = name ; ; p++) {
+ if (*p == CTLQUOTEMARK)
+ continue;
if (*p == CTLESC)
p++;
*enddir++ = *p;
if (start != name) {
p = name;
while (p < start) {
+ while (*p == CTLQUOTEMARK)
+ p++;
if (*p == CTLESC)
p++;
*enddir++ = *p++;
*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);
}
*/
STATIC void
-addfname(name)
- char *name;
- {
+addfname(char *name)
+{
char *p;
struct strlist *sp;
*/
STATIC struct strlist *
-expsort(str)
- struct strlist *str;
- {
+expsort(struct strlist *str)
+{
int len;
struct strlist *sp;
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;
*/
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;
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 '[': {
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)
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 {
return 0;
break;
}
-dft: default:
+dft: default:
+ if (squoted && *q == CTLESC)
+ q++;
if (*q++ != c)
return 0;
break;
*/
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++;
*/
int
-casematch(pattern, val)
- union node *pattern;
- char *val;
- {
+casematch(union node *pattern, char *val)
+{
struct stackmark smark;
int result;
char *p;
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 $
+ */
/*-
- * 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.
*
- * @(#)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 {
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 $
+ */
-# 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.
#
-# @(#)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.
fi
/bin/mv "$1" "$2"
}
+
+#
+# $PchId: cmv,v 1.2 2006/03/29 10:43:18 philip Exp $
-# 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.
#
-# @(#)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
echo "`pwd` $DSTACK"
return 0
}
+
+#
+# $PchId: dirs,v 1.2 2006/03/29 10:43:18 philip Exp $
-# 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.
#
-# @(#)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.
done
/bin/kill $args
}
+
+#
+# $PchId: kill,v 1.2 2006/03/29 10:43:18 philip Exp $
-# 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 $
-# 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 $
-# 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.
#
-# @(#)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
echo "`pwd` $DSTACK"
return 0
}
+
+#
+# $PchId: popd,v 1.2 2006/03/29 10:43:18 philip Exp $
-# 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.
#
-# @(#)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
echo "`pwd` $DSTACK"
return 0
}
+
+#
+# $PchId: pushd,v 1.2 2006/03/29 10:43:18 philip Exp $
-# 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 $
--- /dev/null
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 $
+ */
/*-
- * 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 $
+ */
/*-
- * 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
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"
RESET {
if (exception != EXSHELLPROC)
- parsenleft = 0; /* clear input buffer */
+ parselleft = parsenleft = 0; /* clear input buffer */
popallfiles();
}
*/
char *
-pfgets(line, len)
- char *line;
- {
- register char *p = line;
+pfgets(char *line, int len)
+{
+ char *p = line;
int nleft = len;
int c;
*/
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
}
}
}
-#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
*/
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");
*/
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);
parsefile->fd = fd;
if (parsefile->buf == NULL)
parsefile->buf = ckmalloc(BUFSIZ);
- parsenleft = 0;
+ parselleft = parsenleft = 0;
plinno = 1;
}
*/
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;
*/
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;
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;
*/
void
-popallfiles() {
+popallfiles(void)
+{
while (parsefile != &basepf)
popfile();
}
*/
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 $
+ */
/*-
- * 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.
*
- * @(#)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
/*-
- * 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;
}
#ifdef mkinit
+INCLUDE <sys/types.h>
+INCLUDE <stdlib.h>
SHELLPROC {
backgndpid = -1;
#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;
}
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
*/
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);
}
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);
*/
STATIC void
-freejob(jp)
- struct job *jp;
- {
+freejob(struct job *jp)
+{
struct procstat *ps;
int i;
ckfree(jp->ps);
jp->used = 0;
#if JOBS
- if (curjob == jp - jobtab + 1)
- curjob = 0;
+ deljob(jp);
#endif
INTON;
}
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) {
} 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;
*/
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
#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)) {
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)
}
}
error("No such job: %s", name);
+ /*NOTREACHED*/
+ return NULL;
}
*/
struct job *
-makejob(node, nprocs)
- union node *node;
- {
+makejob(union node *node __unused, int nprocs)
+{
int i;
struct job *jp;
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;
}
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));
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
* 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);
}
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)
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;
}
* 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
*/
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;
}
* 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;
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 */
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
}
}
}
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;
}
* 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
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;
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);
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:
}
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 {
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)
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;
}
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 $
+ */
/*-
- * 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.
*
- * @(#)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. */
#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
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 */
};
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 $
+ */
/*-
- * 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.
*
- * @(#)machdep.h 5.1 (Berkeley) 3/7/91
+ * @(#)machdep.h 8.2 (Berkeley) 5/4/95
*/
/*
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 $
+ */
/*-
- * 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?)
#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
*/
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;
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 $
+ */
/*-
- * 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 $
+ */
/*-
- * 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"
#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
* 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)) {
/*
* 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);
}
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;
}
*/
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);
}
*/
STATIC void
-read_profile(name)
- char *name;
- {
+read_profile(char *name)
+{
int fd;
INTOFF;
*/
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();
}
}
-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
/*-
- * 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 $
+ */
/*-
- * 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");
*/
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;
*/
char *
-savestr(s)
- char *s;
- {
- register char *p;
+savestr(char *s)
+{
+ char *p;
p = ckmalloc(strlen(s) + 1);
scopy(s, p);
* 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;
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;
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;
*/
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;
char *
-growstackstr() {
- int len = stackblocksize();
+growstackstr(void)
+{
+ int len;
+
+ len = stackblocksize();
if (herefd >= 0 && len >= 1024) {
xwrite(herefd, stackblock(), len);
sstrnleft = len - 1;
*/
char *
-makestrspace() {
- int len = stackblocksize() - sstrnleft;
+makestrspace(void)
+{
+ int len;
+
+ len = stackblocksize() - sstrnleft;
growstackblock();
sstrnleft = stackblocksize() - len;
return stackblock() + len;
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 $
+ */
/*-
- * 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;
};
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);
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
#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)
#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 $
+ */
/*-
- * 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"
#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);
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;
}
STPUTC(c, p);
continue;
}
- if (eflag && c == '\\') {
+ if (!rflag && c == '\\') {
backslash++;
continue;
}
}
startword = 0;
if (backslash && c == '\\') {
- if (read(0, &c, 1) != 1) {
+ if (read(STDIN_FILENO, &c, 1) != 1) {
status = 1;
break;
}
-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 $
+ */
#!/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 $
/*-
- * 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"
/*
int nleft;
struct block *start;
struct block *last;
-};
+};
struct block {
struct block *next;
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 */
};
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);
}
* Parse an input file.
*/
-void
-readfile(fname)
- char *fname;
- {
+static void
+readfile(char *fname)
+{
FILE *fp;
char line[1024];
struct event *ep;
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) {
}
-int
-gooddefine(line)
- char *line;
- {
- register char *p;
+static int
+gooddefine(char *line)
+{
+ char *p;
if (! match("#define", line))
return 0; /* not a define */
}
-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;
}
-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')
}
-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);
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')
* Write the output to the file OUTTEMP.
*/
-void
-output() {
+static void
+output(void)
+{
FILE *fp;
char **pp;
struct event *ep;
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");
}
}
-/*
- * 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);
}
-void
-addchar(c, text)
- register struct text *text;
- {
+static void
+addchar(int c, struct text *text)
+{
struct block *bp;
if (--text->nleft < 0) {
/*
* 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) {
}
}
-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 $
+ */
/*-
- * 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
*/
#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 */
};
-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();
parsenode();
}
output(argv[2]);
- return 0;
+ exit(0);
}
-parsenode() {
+static void
+parsenode(void)
+{
char name[BUFLEN];
char tag[BUFLEN];
struct str *sp;
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) {
}
-parsefield() {
+static void
+parsefield(void)
+{
char name[BUFLEN];
char type[BUFLEN];
char decl[2 * BUFLEN];
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);
*/\n\
\n";
-output(file)
- char *file;
- {
+static void
+output(char *file)
+{
FILE *hfile;
FILE *cfile;
FILE *patfile;
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);
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);
-outsizes(cfile)
- FILE *cfile;
- {
+static void
+outsizes(FILE *cfile)
+{
int i;
fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes);
}
-outfunc(cfile, calcsize)
- FILE *cfile;
- {
+static void
+outfunc(FILE *cfile, int calcsize)
+{
struct str *sp;
struct field *fp;
int i;
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++) {
}
-indent(amount, fp)
- FILE *fp;
- {
+static void
+indent(int amount, FILE *fp)
+{
while (amount >= 8) {
putc('\t', fp);
amount -= 8;
}
-int
-nextfield(buf)
- char *buf;
- {
- register char *p, *q;
+static int
+nextfield(char *buf)
+{
+ char *p, *q;
p = linep;
while (*p == ' ' || *p == '\t')
}
-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;
-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 $
+ */
/*-
- * 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 */
fprintf(cfile, "};\n");
exit(0);
}
+
+/*
+ * $PchId: mksignames.c,v 1.2 2001/05/14 19:22:26 philip Exp $
+ */
/*-
- * 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;
/* 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 }
};
* 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;
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);
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);
}
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);
}
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);
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");
* Clear the syntax table.
*/
-filltable(dftval)
- char *dftval;
- {
+static void
+filltable(char *dftval)
+{
int i;
for (i = 0 ; i < size ; i++)
* Initialize the syntax table with default values.
*/
-init() {
+static void
+init(void)
+{
filltable("CWORD");
syntax[0] = "CEOF";
syntax[base + CTLESC] = "CCTL";
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";
}
* 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;
}
* Output the syntax table.
*/
-print(name)
- char *name;
- {
+static void
+print(char *name)
+{
int i;
int col;
* 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)
* Output digit conversion table (if digits are not contiguous).
*/
-digit_convert() {
+static void
+digit_convert(void)
+{
int maxdigit;
static char digit[] = "0123456789";
char *p;
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 $
+ */
#!/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.
#
-# @(#)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)
# 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 ";"
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[] = {'
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
then
echo "#define KWDOFFSET $i"
echo
- echo "char *const parsekwd[] = {"
+ echo "const char *const parsekwd[] = {"
go=true
fi
if [ "$go" ]
echo ' 0
};'
-rm /tmp/ka$$
+rm $temp
+
+#
+# $PchId: mktokens,v 1.5 2006/05/22 12:43:35 philip Exp $
--- /dev/null
+/*-
+ * 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 $
+ */
+
/*-
- * 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.
* 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"
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
*/
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')
}
-/*
- * 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;
*/
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);
}
*/
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 $
+ */
/*-
- * 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 $
+ */
/*-
- * 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
*/
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;
}
*/
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 $
+ */
-#!/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.
#
-# @(#)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
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
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<<!
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 $
/*-
- * 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
#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 **);
/*
*/
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
*/
STATIC void
-options(cmdline) {
- register char *p;
+options(int cmdline)
+{
+ char *p;
int val;
int c;
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 */
}
#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);
}
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
*/
void
-setparam(argv)
- char **argv;
- {
+setparam(char **argv)
+{
char **newparam;
char **ap;
int nparam;
*/
void
-freeparam(param)
- struct shparam *param;
- {
+freeparam(struct shparam *param)
+{
char **ap;
if (param->malloc) {
* The shift builtin command.
*/
-shiftcmd(argc, argv) char **argv; {
+int
+shiftcmd(int argc, char **argv)
+{
int n;
char **ap1, **ap2;
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++) {
* 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);
}
}
+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
* 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
*/
int
-nextopt(optstring)
- char *optstring;
- {
- register char *p, *q;
+nextopt(char *optstring)
+{
+ char *p, *q;
char c;
if ((p = optptr) == NULL || *p == '\0') {
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 $
+ */
/*-
- * 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
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 $
+ */
/*-
- * 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[] = "@(#)output.c 5.1 (Berkeley) 3/7/91";
+static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 5/31/93";
#endif /* not lint */
/*
#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
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('\'');
}
#ifdef __STDC__
void
-outfmt(struct output *file, char *fmt, ...) {
+outfmt(struct output *file, const char *fmt, ...)
+{
va_list ap;
va_start(ap, fmt);
void
-out1fmt(char *fmt, ...) {
+out1fmt(const char *fmt, ...)
+{
va_list ap;
va_start(ap, 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;
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)
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;
}
}
-
/*
- * 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;
-}
/*-
- * 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;
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);
#define OUTPUT_INCL
#endif
+
+/*
+ * $PchId: output.h,v 1.5 2006/05/23 12:04:54 philip Exp $
+ */
/*-
- * 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"
#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"
-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
#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);
/*
*/
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;
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;
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)
STATIC union node *
-andor() {
+andor(void)
+{
union node *n1, *n2, *n3;
int t;
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));
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;
}
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);
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);
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);
}
*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 {
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++;
}
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:
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);
}
}
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));
#endif
n->type = NDEFUN;
n->narg.next = command();
- return n;
+ goto checkneg;
} else {
tokpushback++;
break;
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)
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();
}
}
*/
STATIC void
-parseheredoc() {
+parseheredoc(void)
+{
struct heredoc *here;
union node *n;
here = heredoclist;
heredoclist = here->next;
if (needprompt) {
- putprompt(ps2val());
+ setprompt(2);
needprompt = 0;
}
readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
}
STATIC int
-peektoken() {
+peektoken(void)
+{
int t;
t = readtoken();
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) {
} 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)
#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;
if (pgetc() == '\n') {
startlinno = ++plinno;
if (doprompt)
- putprompt(ps2val());
+ setprompt(2);
+ else
+ setprompt(0);
continue;
}
pungetc();
#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) "ef;
+ (void) &dblquote;
+ (void) &varnest;
+ (void) &arinest;
+ (void) &parenlevel;
+ (void) &oldstyle;
+ (void) &prevsyntax;
+ (void) &syntax;
+ (void) &synentry;
+#endif
startlinno = plinno;
dblquote = 0;
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:
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: /* '$' */
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;
}
}
endword:
+ if (syntax == ARISYNTAX)
+ synerror("Missing '))'");
if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
synerror("Unterminated quoted string");
if (varnest != 0) {
}
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++);
plinno++;
needprompt = doprompt;
} else {
- ppushback(line, strlen(line));
+ pushstring(line, strlen(line), NULL);
}
}
}
np->type = NAPPEND;
else if (c == '&')
np->type = NTOFD;
+ else if (c == '|')
+ np->type = NCLOBBER;
else {
np->type = NTO;
pungetc();
}
} else if (c == '&')
np->type = NFROMFD;
+ else if (c == '>')
+ np->type = NFROMTO;
else {
np->type = NFROM;
pungetc();
#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");
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)
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)) {
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);
}
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;
*/
int
-goodname(name)
- char *name;
- {
- register char *p;
+goodname(char *name)
+{
+ char *p;
p = name;
if (! is_name(*p))
*/
STATIC void
-synexpect(token) {
+synexpect(int token)
+{
char msg[64];
if (token >= 0) {
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 $
+ */
/*-
- * 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.
*
- * @(#)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 $
+ */
/*-
- * 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.
#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 */
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
-
/*
*/
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;
}
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;
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
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:
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:
*/
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) {
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);
*/
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);
}
}
}
INTON;
}
-
-
/*
* Undo all redirections. Called on error or interrupt.
*/
#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) {
}
}
-
-
/*
- * 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;
-}
/*-
- * 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 $
+ */
--- /dev/null
+/*
+ * 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 $
+ */
/*-
- * 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 $
+ */
/*-
- * 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:
-static
-shcmd(cmd, fp)
- union node *cmd;
- FILE *fp;
- {
+static void
+shcmd(union node *cmd, FILE *fp)
+{
union node *np;
int first;
char *s;
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);
}
-static
-sharg(arg, fp)
- union node *arg;
- FILE *fp;
- {
+static void
+sharg(union node *arg, FILE *fp)
+{
char *p;
struct nodelist *bqlist;
int subtype;
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);
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);
}
}
-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++) {
putc('\t', fp);
}
}
-#endif
-
/*
#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);
}
}
putc('"', tracefile);
-#endif
}
-trargs(ap)
- char **ap;
- {
-#if DEBUG
+void
+trargs(char **ap)
+{
if (tracefile == NULL)
return;
while (*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 $
+ */
--- /dev/null
+/*-
+ * 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 $
+ */
+++ /dev/null
-/* 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 */
+++ /dev/null
-
-/**********************************************************/
-/*
-/* 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 */
-
/*-
- * 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
#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);
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);
}
-
/*
* 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;
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
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;
}
#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;
#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 $
+ */
/*-
- * 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 $
+ */
/*-
- * 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"
#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
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
*/
void
-initvar() {
+initvar(void)
+{
+ char ppid[20];
const struct varinit *ip;
struct var *vp;
struct var **vpp;
*vpp = vp;
vp->text = ip->text;
vp->flags = ip->flags;
+ vp->func = ip->func;
}
}
/*
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;
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 == '=')
}
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;
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
*/
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;
}
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;
}
*/
void
-listsetvar(list)
- struct strlist *list;
- {
+listsetvar(struct strlist *list)
+{
struct strlist *lp;
INTOFF;
*/
char *
-lookupvar(name)
- char *name;
- {
+lookupvar(char *name)
+{
struct var *v;
for (v = *hashvar(name) ; v ; v = v->next) {
*/
char *
-bltinlookup(name, doall)
- char *name;
- {
+bltinlookup(char *name, int doall)
+{
struct strlist *sp;
struct var *v;
}
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;
}
*/
char **
-environment() {
+environment(void)
+{
int nenv;
struct var **vpp;
struct var *vp;
*/
#ifdef mkinit
-MKINIT void shprocvar();
-
SHELLPROC {
shprocvar();
}
#endif
void
-shprocvar() {
+shprocvar(void)
+{
struct var **vpp;
struct var *vp, **prev;
*/
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;
*/
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++;
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;
}
}
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');
}
}
* The "local" command.
*/
-localcmd(argc, argv) char **argv; {
+int
+localcmd(int argc __unused, char **argv __unused)
+{
char *name;
if (! in_function())
*/
void
-mklocal(name)
- char *name;
- {
+mklocal(char *name)
+{
struct localvar *lvp;
struct var **vpp;
struct var *vp;
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);
*/
void
-poplocalvars() {
+poplocalvars(void)
+{
struct localvar *lvp;
struct var *vp;
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);
}
-setvarcmd(argc, argv) char **argv; {
+int
+setvarcmd(int argc, char **argv)
+{
if (argc <= 2)
return unsetcmd(argc, argv);
else if (argc == 3)
* 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;
}
* 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)
ckfree(vp);
}
INTON;
- return;
+ return (0);
}
}
+
+ return (0);
}
*/
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];
}
*/
STATIC int
-varequal(p, q)
- register char *p, *q;
- {
+varequal(char *p, char *q)
+{
while (*p == *q++) {
if (*p++ == '=')
return 1;
return 1;
return 0;
}
+
+/*
+ * $PchId: var.c,v 1.5 2006/05/22 12:28:49 philip Exp $
+ */
/*-
- * 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.
*
- * @(#)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
/*
*/
#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 $
+ */