home *** CD-ROM | disk | FTP | other *** search
- Subject: v19i008: A reimplementation of the System V shell, Part08/08
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: ka@june.cs.washington.edu (Kenneth Almquist)
- Posting-number: Volume 19, Issue 8
- Archive-name: ash/part08
-
- # This is part 8 of ash. To unpack, feed it into the shell (not csh).
- # The ash distribution consists of eight pieces. Be sure you get them all.
- # After you unpack everything, read the file README.
-
- if test ! -d bltin
- then mkdir bltin
- fi
- echo extracting bltin/binary_op
- cat > bltin/binary_op <<\EOF
- # List of binary operators used by test/expr.
- #
- # Copyright 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.
-
- OR1 -o 1
- OR2 | 1
- AND1 -a 2
- AND2 & 2
- STREQ = 4 OP_STRING
- STRNE != 4 OP_STRING
- EQ -eq 4 OP_INT
- NE -ne 4 OP_INT
- GT -gt 4 OP_INT
- LT -lt 4 OP_INT
- LE -le 4 OP_INT
- GE -ge 4 OP_INT
- PLUS + 5 OP_INT
- MINUS - 5 OP_INT
- TIMES * 6 OP_INT
- DIVIDE / 6 OP_INT
- REM % 6 OP_INT
- MATCHPAT : 7 OP_STRING
- EOF
- if test `wc -c < bltin/binary_op` -ne 588
- then echo 'bltin/binary_op is the wrong size'
- fi
- echo extracting bltin/bltin.h
- cat > bltin/bltin.h <<\EOF
- /*
- * 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 "../output.h"
- #define stdout out1
- #define stderr out2
- #define printf out1fmt
- #define putc(c, file) outc(c, file)
- #define putchar(c) out1c(c)
- #define fprintf outfmt
- #define fputs outstr
- #define fflush flushout
- #define INITARGS(argv)
- #else
- #undef NULL
- #include <stdio.h>
- #undef main
- #define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
- #endif
-
- #ifdef __STDC__
- pointer stalloc(int);
- void error(char *, ...);
- #else
- pointer stalloc();
- void error();
- #endif
-
-
- extern char *commandname;
- EOF
- if test `wc -c < bltin/bltin.h` -ne 1011
- then echo 'bltin/bltin.h is the wrong size'
- fi
- echo extracting bltin/catf.1
- cat > bltin/catf.1 <<\EOF
- .TH CATF 1
- .SH NAME \" Copyright (C) 1989 by Kenneth Almquist.
- catf \- concatenate files
- .SH SYNOPSIS
- .B catf
- .I file...
- .SH COPYRIGHT
- .if n Copyright (C) 1989 by Kenneth Almquist.
- .if t Copyright \(co 1989 by Kenneth Almquist.
- .SH DESCRIPTION
- Catf copies the files specified as arguments to the standard output.
- As a special case, the file name ``-'' causes
- .I catf
- to read from the standard input.
- .SH "HISTORICAL NOTE"
- Early versions of UNIX had a program which was very similar to
- .IR catf .
- It was named
- .IR cat .
- EOF
- if test `wc -c < bltin/catf.1` -ne 521
- then echo 'bltin/catf.1 is the wrong size'
- fi
- echo extracting bltin/catf.c
- cat > bltin/catf.c <<\EOF
- /*
- * Copy the files given as arguments to the standard output. The file
- * name "-" refers to the standard input.
- *
- * 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 catfcmd
-
- #include "bltin.h"
- #include "../error.h"
- #include <sys/param.h>
- #include <fcntl.h>
-
-
- #ifdef SBUFSIZE
- #define BUFSIZE() SBUFSIZE
- #else
- #ifdef MAXBSIZE
- #define BUFSIZE() MAXBSIZE
- #else
- #define BUFSIZE() BSIZE
- #endif
- #endif
-
-
- main(argc, argv) char **argv; {
- char *filename;
- char *buf = stalloc(BUFSIZE());
- int fd;
- int i;
- #ifdef SHELL
- volatile int input;
- struct jmploc jmploc;
- struct jmploc *volatile savehandler;
- #endif
-
- INITARGS(argv);
- #ifdef SHELL
- input = -1;
- if (setjmp(jmploc.loc)) {
- close(input);
- handler = savehandler;
- longjmp(handler, 1);
- }
- savehandler = handler;
- handler = &jmploc;
- #endif
- while ((filename = *++argv) != NULL) {
- if (filename[0] == '-' && filename[1] == '\0') {
- fd = 0;
- } else {
- #ifdef SHELL
- INTOFF;
- if ((fd = open(filename, O_RDONLY)) < 0)
- error("Can't open %s", filename);
- input = fd;
- INTON;
- #else
- if ((fd = open(filename, O_RDONLY)) < 0) {
- fprintf(stderr, "catf: Can't open %s\n", filename);
- exit(2);
- }
- #endif
- }
- while ((i = read(fd, buf, BUFSIZE())) > 0) {
- #ifdef SHELL
- if (out1 == &memout) {
- register char *p;
- for (p = buf ; --i >= 0 ; p++) {
- outc(*p, &memout);
- }
- } else {
- write(1, buf, i);
- }
- #else
- write(1, buf, i);
- #endif
- }
- if (fd != 0)
- close(fd);
- }
- #ifdef SHELL
- handler = savehandler;
- #endif
- }
- EOF
- if test `wc -c < bltin/catf.c` -ne 1795
- then echo 'bltin/catf.c is the wrong size'
- fi
- echo extracting bltin/echo.1
- cat > bltin/echo.1 <<\EOF
- .TH ECHO 1
- .SH NAME \" Copyright (C) 1989 by Kenneth Almquist.
- echo \- produce message in a shell script
- .SH SYNOPSIS
- .B echo
- [
- .B -n
- |
- .B -e
- ]
- .I args...
- .SH COPYRIGHT
- .if n Copyright (C) 1989 by Kenneth Almquist.
- .if t Copyright \(co 1989 by Kenneth Almquist.
- .SH DESCRIPTION
- .I Echo
- prints its arguments on the standard output, separated by spaces.
- Unless the
- .B -n
- option is present, a newline is output following the arguments.
- The
- .B -e
- option causes
- .I echo
- to treat the escape sequences specially, as described in the following
- paragraph. The
- .B -e
- option is the default, and is provided solely for compatibility with
- other systems.
- Only one of the options
- .B -n
- and
- .B -e
- may be given.
- .PP
- If any of the following sequences of characters is encountered during
- output, the sequence is not output. Instead, the specified action is
- performed:
- .nr i 0.6i
- .de i
- .sp
- .ti -\\niu
- \\$1 \c
- .if \w'\\$1'-\\ni .br
- ..
- .in 1.1i
- .ta 0.6i
- .i \eb
- A backspace character is output.
- .i \ec
- Subsequent output is suppressed. This is normally used at the end of the
- last argument to suppress the trailing newline that
- .I echo
- would otherwise output.
- .i \ef
- Output a form feed.
- .i \en
- Output a newline character.
- .i \er
- Output a carriage return.
- .i \et
- Output a (horizontal) tab character.
- .i \ev
- Output a vertical tab.
- .i \e0\fIdigits\fR
- Output the character whose value is given by zero to three digits.
- If there are zero digits, a nul character is output.
- .i \e\e
- Output a backslash.
- .in -1.1i
- .SH HINTS
- Remember that backslash is special to the shell and needs to be escaped.
- To output a message to standard error, say
- .sp
- .ti +1i
- echo message >&2
- .SH BUGS
- The octal character escape mechanism (\e0\fIdigits\fR) differs from the
- C language mechanism.
- .PP
- There is no way to force
- .I echo
- to treat its arguments literally, rather than interpreting them as
- options and escape sequences.
- EOF
- if test `wc -c < bltin/echo.1` -ne 1879
- then echo 'bltin/echo.1 is the wrong size'
- fi
- echo extracting bltin/echo.c
- cat > bltin/echo.c <<\EOF
- /*
- * 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
-
- #include "bltin.h"
-
- #define eflag 1
-
-
- main(argc, argv) char **argv; {
- register char **ap;
- register char *p;
- register char c;
- int count;
- int nflag = 0;
- #ifndef eflag
- int eflag = 0;
- #endif
-
- ap = argv;
- if (argc)
- ap++;
- if ((p = *ap) != NULL) {
- if (equal(p, "-n")) {
- nflag++;
- ap++;
- } else if (equal(p, "-e")) {
- #ifndef 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;
- }
- }
- putchar(c);
- }
- if (*ap)
- putchar(' ');
- }
- if (! nflag)
- putchar('\n');
- return 0;
- }
- EOF
- if test `wc -c < bltin/echo.c` -ne 1419
- then echo 'bltin/echo.c is the wrong size'
- fi
- echo extracting bltin/error.c
- cat > bltin/error.c <<\EOF
- /*
- * 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 <stdio.h>
-
- char *commandname;
-
-
- void
- #ifdef __STDC__
- error(char *msg, ...) {
- #else
- error(msg)
- char *msg;
- {
- #endif
-
- fprintf(stderr, "%s: %s\n", commandname, msg);
- exit(2);
- }
- EOF
- if test `wc -c < bltin/error.c` -ne 422
- then echo 'bltin/error.c is the wrong size'
- fi
- echo extracting bltin/expr.1
- cat > bltin/expr.1 <<\EOF
- .TH EXPR 1
- .SH NAME \" Copyright (C) 1989 by Kenneth Almquist.
- expr, text \- evaluate expressions
- .SH SYNOPSIS
- .B expr
- .I expression
- .br
- .B test
- .I expression
- .br
- .B [
- .I expression
- .B ]
- .SH COPYRIGHT
- .if n Copyright (C) 1989 by Kenneth Almquist.
- .if t Copyright \(co 1989 by Kenneth Almquist.
- .SH DESCRIPTION
- .I Expr
- evaluates the expression and prints the result.
- .I Test
- evaluates the expression without printing the result.
- The ``[''
- command is a synonym for
- .IR test ;
- when invoked under this name
- the last argument to
- .I expr
- must be a ``]'', which is deleted and not considered part of the expression.
- .PP
- Three data types may occur in the
- .IR expression :
- string, integer, and boolean.
- The rules for conversion are as follows:
- .sp
- .nr i 2
- .ta \nii
- .in +\nii
- .ti -\nii
- \fIstring\fR->\fIinteger\fR Done via
- .IR atoi (3).
- .ti -\nii
- \fIinteger\fR->\fIstring\fR Convert to decimal reprentation.
- .ti -\nii
- \fIstring\fR->\fIboolean\fR "" -> false, everything else to true.
- .ti -\nii
- \fIboolean\fR->\fIstring\fR false -> "", true -> "true".
- .ti -\nii
- \fIinteger\fR->\fIboolean\fR 0 -> false, everything else to true.
- .ti -\nii
- \fIboolean\fR->\fIinteger\fR false -> 0, true -> 1.
- .in -\nii
- .PP
- Any argument to
- .I expr
- which is not a legal operator is treated as a string operand of type
- .IR string .
- If the operand is enclosed in single quotes, these are deleted.
- (Note that single quotes are stripped by the shell, so the single quotes
- must be quoted, typically by enclosing them in double quotes.)
- .PP
- As a special case, if
- .I expression
- is omitted, the result is false.
- .PP
- We now list the operators. The syntax
- .sp
- .ti +8
- \fIinteger\fB op \fIinteger\fR -> \fIboolean\fB (3)\fR
- .sp
- means that \fBop\fR is a binary operator which takes operands of type
- \fIinteger\fR and produces a result of type \fIboolean\fR.
- The ``(3)'' means that the priority of \fBop\fR is 3.
- Operands are automaticly converted to the appropriate type. The type
- \fIany\fR is used for operator that take operands of any type.
- .nr p 1
- .de b
- .HP 0.5i
- \fI\\$1\fB \\$2 \fI\\$3\fR -> \\fI\\$4\\fR (\\np)
- .br
- ..
- .de u
- .HP 0.5i
- \\$1 \fI\\$2\fR -> \\fI\\$3\\fR (\\np)
- .br
- ..
- .b any -o any any
- Returns the value of the left hand operand if the left hand operand
- would yield
- .I true
- if converted to type
- .IR boolean ,
- and the value of the right hand operand otherwise.
- The right hand operand is evaluated only if necessary.
- ``|'' is a synonym for ``-o''.
- .nr p \np+1
- .b any -a any any
- Returns the value of the left hand operand if the left hand operand
- would yield
- .I false
- if converted to type
- .IR boolean ,
- and the value of the right hand operand otherwise.
- The right hand operand is evaluated only if necessary.
- ``&'' is a synonym for ``-a''.
- .nr p \np+1
- .u ! boolean boolean
- Returns true if the operand is false, and false if the operand is true.
- .nr p \np+1
- .b string = string boolean
- True if the two strings are equal.
- .b string != string boolean
- True if the two strings are not equal.
- .b integer -eq integer boolean
- True if the two operands are equal.
- .b integer -ne integer boolean
- True if the two operands are not equal.
- .b integer -gt integer boolean
- True if the first operand is greater than the second one.
- .b integer -lt integer boolean
- True if the first operand is less than the second one.
- .b integer -ge integer boolean
- True if the first operand is greater than or equal to the second one.
- .b integer -le integer boolean
- True if the first operand is less than or equal to the second one.
- .nr p \np+1
- .b integer + integer integer
- Add two integers.
- .b integer - integer integer
- Subtract two integers.
- .nr p \np+1
- .b integer * integer integer
- Multiply two integers. ``*'' is special to the shell, so you generally
- have to write this operator as ``\e*''.
- .b integer / integer integer
- Divide two integers.
- .b integer % integer integer
- Returns the remainder when the first operand is divided by the second one.
- .nr p \np+1
- .b string : string "integer or string"
- The second operand is interpreted as a regular expression (as in the
- System V
- .I ed
- program).
- This operator attempts to match part (or all) of the first operand
- with the regular expression. The match must start at the beginning of
- the first operand.
- If the regular expression contains and \e( \e) pairs, then the result
- of this operator is the string which is matched by the regular expression
- between these pairs, or the null string if no match occurred. Otherwise,
- the result is the number of characters matched by the regular expression,
- or zero if no no match occurred.
- .nr p \np+1
- .u -n string integer
- Returns the number of characters in the string.
- .u -z string boolean
- Returns true if the string contains zero characters.
- .u -t integer boolean
- Returns true if the specified file descriptor is associated with a tty.
- .PP
- The remaining operators all deal with files. Except as noted, they return
- false if the
- specified file does not exist. The ones dealing with permission use
- the effective user and group ids of the shell.
- .u -r string boolean
- True if you have read permission on the file.
- .u -w string boolean
- True if you have write permission on the file.
- .u -x string boolean
- True if you have execute permission on the file.
- .u -f string boolean
- True if the file is a regular file.
- .u -d string boolean
- True if the file is a directory.
- .u -c string boolean
- True if the file is a character special file.
- .u -b string boolean
- True if the file is a block special file.
- .u -p string boolean
- True if the file is a named pipe (i.e. a fifo).
- .u -u string boolean
- True if the file is setuid.
- .u -g string boolean
- True if the file is setgid.
- .u -k string boolean
- True if the file has the sticky bit set.
- .u -s string "integer or boolean"
- Returns the size of the file, or 0 if the file does not exist.
- .SH "EXIT CODE"
- 0 if the result of
- .I expression
- would be
- .I true
- if the result were converted to
- .IR boolean .
- .br
- 1 if the result of
- .I expression
- would be
- .I false
- if the result were converted to
- .IR boolean .
- .br
- 2 if
- .I expression
- is syntactically incorrect.
- .SH EXAMPLES
- .HP 0.5i
- filesize=`expr -s file`
- .br
- Sets the shell variable
- .I filesize
- to the size of
- .IR file .
- .HP 0.5i
- if [ -s file ]; then command; fi
- .br
- Execute
- .I command
- if
- .I file
- exists and is not empty.
- .HP 0.5i
- x=`expr "'$x'" : '.\{4\}\(.\{0,3\}\)'`
- .br
- Sets
- .I x
- to the substring of
- .I x
- beginning after the fourth character of
- .I x
- and continuing for three characters or until the end of the string,
- whichever comes first.
- .HP 0.5i
- x=`expr X"$x" : X'.\{4\}\(.\{0,3\}\)'`
- .br
- This example is the same as the previous one, but it uses a leading
- ``X'' rather than single quotes to make things work when the value of
- .I x
- looks like an operator. An alternative would be to write
- .HP 0.5i
- x=`expr "'$x'" : '.\{4\}\(.\{0,3\}\)'`
- .br
- This encloses the value of
- .I x
- in single quotes to keep it from being confused with an operator,
- which is simpler than the preceding example, but also less portable.
- .SH BUGS
- The relational operators of the System V
- .I expr
- command are not implemented.
- .PP
- Certain features of this version of
- .I expr
- are not present in System V, so care should be used when writing
- portable code.
- EOF
- if test `wc -c < bltin/expr.1` -ne 7136
- then echo 'bltin/expr.1 is the wrong size'
- fi
- echo extracting bltin/expr.c
- cat > bltin/expr.c <<\EOF
- /*
- * The expr and test commands.
- *
- * 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 exprcmd
-
- #include "bltin.h"
- #include "operators.h"
- #include <sys/types.h>
- #include <sys/stat.h>
-
-
- #define STACKSIZE 12
- #define NESTINCR 16
-
- /* data types */
- #define STRING 0
- #define INTEGER 1
- #define BOOLEAN 2
-
-
- /*
- * This structure hold a value. The type keyword specifies the type of
- * the value, and the union u holds the value. The value of a boolean
- * is stored in u.num (1 = TRUE, 0 = FALSE).
- */
-
- struct value {
- int type;
- union {
- char *string;
- long num;
- } u;
- };
-
-
- struct operator {
- short op; /* which operator */
- short pri; /* priority of operator */
- };
-
-
- struct filestat {
- char *name; /* name of file */
- int rcode; /* return code from stat */
- struct stat stat; /* status info on file */
- };
-
-
- extern char *match_begin[10]; /* matched string */
- extern short match_length[10]; /* defined in regexp.c */
- extern short number_parens; /* number of \( \) pairs */
-
-
- #ifdef __STDC__
- int expr_is_false(struct value *);
- void expr_operator(int, struct value *, struct filestat *);
- int lookup_op(char *, char *const*);
- char *re_compile(char *); /* defined in regexp.c */
- int re_match(char *, char *); /* defined in regexp.c */
- long atol(const char *);
- #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();
- #endif
-
-
-
- main(argc, argv) char **argv; {
- char **ap;
- char *opname;
- char c;
- char *p;
- int print;
- int nest; /* parenthises nesting */
- int op;
- int pri;
- int skipping;
- int binary;
- struct operator opstack[STACKSIZE];
- struct operator *opsp;
- struct value valstack[STACKSIZE + 1];
- struct value *valsp;
- struct filestat fs;
-
- INITARGS(argv);
- c = **argv;
- print = 1;
- if (c == 't')
- print = 0;
- else if (c == '[') {
- if (! equal(argv[argc - 1], "]"))
- error("missing ]");
- argv[argc - 1] = NULL;
- print = 0;
- }
- ap = argv + 1;
- fs.name = NULL;
-
- /*
- * We use operator precedence parsing, evaluating the expression
- * as we parse it. Parentheses are handled by bumping up the
- * priority of operators using the variable "nest." We use the
- * variable "skipping" to turn off evaluation temporarily for the
- * short circuit boolean operators. (It is important do the short
- * circuit evaluation because under NFS a stat operation can take
- * infinitely long.)
- */
-
- nest = 0;
- skipping = 0;
- opsp = opstack + STACKSIZE;
- valsp = valstack;
- if (*ap == NULL) {
- valstack[0].type = BOOLEAN;
- valstack[0].u.num = 0;
- goto done;
- }
- for (;;) {
- opname = *ap++;
- if (opname == NULL)
- syntax: error("syntax error");
- if (opname[0] == '(' && opname[1] == '\0') {
- nest += NESTINCR;
- continue;
- } else if (*ap && (op = lookup_op(opname, unary_op)) >= 0) {
- if (opsp == &opstack[0])
- overflow: error("Expression too complex");
- --opsp;
- opsp->op = op;
- opsp->pri = op_priority[op] + nest;
- 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++;
- }
- for (;;) {
- opname = *ap++;
- if (opname == NULL) {
- if (nest != 0)
- goto syntax;
- pri = 0;
- break;
- }
- if (opname[0] != ')' || opname[1] != '\0') {
- if ((op = lookup_op(opname, binary_op)) < 0)
- goto syntax;
- op += FIRST_BINARY_OP;
- pri = op_priority[op] + nest;
- break;
- }
- if ((nest -= NESTINCR) < 0)
- goto syntax;
- }
- while (opsp < &opstack[STACKSIZE] && opsp->pri >= pri) {
- binary = opsp->op;
- for (;;) {
- valsp--;
- c = op_argflag[opsp->op];
- if (c == OP_INT) {
- if (valsp->type == STRING)
- valsp->u.num = atol(valsp->u.string);
- valsp->type = INTEGER;
- } else if (c >= OP_STRING) { /* OP_STRING or OP_FILE */
- if (valsp->type == INTEGER) {
- p = stalloc(32);
- #ifdef SHELL
- fmtstr(p, 32, "%d", valsp->u.num);
- #else
- sprintf(p, "%d", valsp->u.num);
- #endif
- valsp->u.string = p;
- } else if (valsp->type == BOOLEAN) {
- if (valsp->u.num)
- valsp->u.string = "true";
- else
- valsp->u.string = "";
- }
- valsp->type = STRING;
- if (c == OP_FILE
- && (fs.name == NULL
- || ! equal(fs.name, valsp->u.string))) {
- fs.name = valsp->u.string;
- fs.rcode = stat(valsp->u.string, &fs.stat);
- }
- }
- if (binary < FIRST_BINARY_OP)
- break;
- binary = 0;
- }
- if (! skipping)
- expr_operator(opsp->op, valsp, &fs);
- else if (opsp->op == AND1 || opsp->op == OR1)
- skipping--;
- valsp++; /* push value */
- opsp++; /* pop operator */
- }
- if (opname == NULL)
- break;
- if (opsp == &opstack[0])
- goto overflow;
- if (op == AND1 || op == AND2) {
- op = AND1;
- if (skipping || expr_is_false(valsp - 1))
- skipping++;
- }
- if (op == OR1 || op == OR2) {
- op = OR1;
- if (skipping || ! expr_is_false(valsp - 1))
- skipping++;
- }
- opsp--;
- opsp->op = op;
- opsp->pri = pri;
- }
- done:
- if (print) {
- if (valstack[0].type == STRING)
- printf("%s\n", valstack[0].u.string);
- else if (valstack[0].type == INTEGER)
- printf("%ld\n", valstack[0].u.num);
- else if (valstack[0].u.num != 0)
- printf("true\n");
- }
- return expr_is_false(&valstack[0]);
- }
-
-
- int
- expr_is_false(val)
- struct value *val;
- {
- if (val->type == STRING) {
- if (val->u.string[0] == '\0')
- return 1;
- } else { /* INTEGER or BOOLEAN */
- if (val->u.num == 0)
- return 1;
- }
- return 0;
- }
-
-
- /*
- * Execute an operator. Op is the operator. Sp is the stack pointer;
- * sp[0] refers to the first operand, sp[1] refers to the second operand
- * (if any), and the result is placed in sp[0]. The operands are converted
- * to the type expected by the operator before expr_operator is called.
- * Fs is a pointer to a structure which holds the value of the last call
- * to stat, to avoid repeated stat calls on the same file.
- */
-
- void
- expr_operator(op, sp, fs)
- int op;
- struct value *sp;
- struct filestat *fs;
- {
- int i;
-
- switch (op) {
- case NOT:
- sp->u.num = expr_is_false(sp);
- sp->type = BOOLEAN;
- break;
- case ISREAD:
- i = 04;
- goto permission;
- case ISWRITE:
- i = 02;
- goto permission;
- case ISEXEC:
- i = 01;
- permission:
- if (fs->stat.st_uid == geteuid())
- i <<= 6;
- else if (fs->stat.st_gid == getegid())
- i <<= 3;
- goto filebit; /* true if (stat.st_mode & i) != 0 */
- case ISFILE:
- i = S_IFREG;
- goto filetype;
- case ISDIR:
- i = S_IFDIR;
- goto filetype;
- case ISCHAR:
- i = S_IFCHR;
- goto filetype;
- case ISBLOCK:
- i = S_IFBLK;
- goto filetype;
- case ISFIFO:
- #ifdef S_IFIFO
- i = S_IFIFO;
- goto filetype;
- #else
- goto false;
- #endif
- filetype:
- if ((fs->stat.st_mode & S_IFMT) == i && fs->rcode >= 0) {
- true:
- sp->u.num = 1;
- } else {
- false:
- sp->u.num = 0;
- }
- sp->type = BOOLEAN;
- break;
- case ISSETUID:
- i = S_ISUID;
- goto filebit;
- case ISSETGID:
- i = S_ISGID;
- goto filebit;
- case ISSTICKY:
- i = S_ISVTX;
- filebit:
- if (fs->stat.st_mode & i && fs->rcode >= 0)
- goto true;
- goto false;
- case ISSIZE:
- sp->u.num = fs->rcode >= 0? fs->stat.st_size : 0L;
- sp->type = INTEGER;
- break;
- case ISTTY:
- sp->u.num = isatty(sp->u.num);
- sp->type = BOOLEAN;
- break;
- case NULSTR:
- if (sp->u.string[0] == '\0')
- goto true;
- goto false;
- case STRLEN:
- sp->u.num = strlen(sp->u.string);
- sp->type = INTEGER;
- break;
- case OR1:
- case AND1:
- /*
- * These operators are mostly handled by the parser. If we
- * get here it means that both operands were evaluated, so
- * the value is the value of the second operand.
- */
- *sp = *(sp + 1);
- break;
- case STREQ:
- case STRNE:
- i = 0;
- if (equal(sp->u.string, (sp + 1)->u.string))
- i++;
- if (op == STRNE)
- i = 1 - i;
- sp->u.num = i;
- sp->type = BOOLEAN;
- break;
- case EQ:
- if (sp->u.num == (sp + 1)->u.num)
- goto true;
- goto false;
- case NE:
- if (sp->u.num != (sp + 1)->u.num)
- goto true;
- goto false;
- case GT:
- if (sp->u.num > (sp + 1)->u.num)
- goto true;
- goto false;
- case LT:
- if (sp->u.num < (sp + 1)->u.num)
- goto true;
- goto false;
- case LE:
- if (sp->u.num <= (sp + 1)->u.num)
- goto true;
- goto false;
- case GE:
- if (sp->u.num >= (sp + 1)->u.num)
- goto true;
- goto false;
- case PLUS:
- sp->u.num += (sp + 1)->u.num;
- break;
- case MINUS:
- sp->u.num -= (sp + 1)->u.num;
- break;
- case TIMES:
- sp->u.num *= (sp + 1)->u.num;
- break;
- case DIVIDE:
- if ((sp + 1)->u.num == 0)
- error("Division by zero");
- sp->u.num /= (sp + 1)->u.num;
- break;
- case REM:
- if ((sp + 1)->u.num == 0)
- error("Division by zero");
- sp->u.num %= (sp + 1)->u.num;
- 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';
- } else {
- sp->u.num = match_length[0];
- sp->type = INTEGER;
- }
- } else {
- if (number_parens > 0) {
- sp->u.string[0] = '\0';
- } else {
- sp->u.num = 0;
- sp->type = INTEGER;
- }
- }
- }
- break;
- }
- }
-
-
- int
- lookup_op(name, table)
- char *name;
- char *const*table;
- {
- register char *const*tp;
- register char const *p;
- char c = name[1];
-
- for (tp = table ; (p = *tp) != NULL ; tp++) {
- if (p[1] == c && equal(p, name))
- return tp - table;
- }
- return -1;
- }
- EOF
- if test `wc -c < bltin/expr.c` -ne 10535
- then echo 'bltin/expr.c is the wrong size'
- fi
- echo extracting bltin/line.1
- cat > bltin/line.1 <<\EOF
- .TH LINE 1
- .SH NAME \" Copyright (C) 1989 by Kenneth Almquist.
- line \- read a line
- .SH SYNOPSIS
- .B line
- .SH COPYRIGHT
- .if n Copyright (C) 1989 by Kenneth Almquist.
- .if t Copyright \(co 1989 by Kenneth Almquist.
- .SH DESCRIPTION
- .I Line
- copies one line from its standard input to its standard output.
- If it encounters an end of file before reading a newline, it
- outputs a newline character and returns an exit status of 1.
- EOF
- if test `wc -c < bltin/line.1` -ne 423
- then echo 'bltin/line.1 is the wrong size'
- fi
- echo extracting bltin/line.c
- cat > bltin/line.c <<\EOF
- /*
- * The line command. Reads one line from the standard input and writes it
- * to the standard output.
- *
- * 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 linecmd
-
- #include "bltin.h"
-
-
- main(argc, argv) char **argv; {
- char c;
-
- for (;;) {
- if (read(0, &c, 1) != 1) {
- putchar('\n');
- return 1;
- }
- putchar(c);
- if (c == '\n')
- return 0;
- }
- }
- EOF
- if test `wc -c < bltin/line.c` -ne 562
- then echo 'bltin/line.c is the wrong size'
- fi
- echo extracting bltin/makefile
- cat > bltin/makefile <<\EOF
- # 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.
-
- LIBFILES=catfcmd.o echocmd.o exprcmd.o linecmd.o nlechocmd.o\
- operators.o regexp.o
- DEBUG=-g
- CFLAGS=$(DEBUG)
- #CC=gcc
-
- all:$P bltinlib.a catf echo expr line nlecho true umask
-
- bltinlib.a:$P $(LIBFILES)
- ar rc $@ $(LIBFILES)
-
- catf: catf.c bltin.h ../shell.h ../error.h error.o stalloc.o
- $(CC) $(CFLAGS) -o $@ catf.c error.o stalloc.o
-
- catfcmd.o: catf.c bltin.h ../shell.h ../error.h
- $(CC) -DSHELL $(CFLAGS) -c catf.c
- mv catf.o $@
-
- expr: expr.c bltin.h ../shell.h operators.h operators.o regexp.o error.o stalloc.o
- $(CC) $(CFLAGS) -o $@ expr.c operators.o regexp.o error.o stalloc.o
- -rm -f test '['
- ln expr test
- ln expr '['
-
- exprcmd.o: expr.c bltin.h ../shell.h operators.h
- $(CC) -DSHELL $(CFLAGS) -c expr.c
- mv expr.o $@
-
- operators.c operators.h: unary_op binary_op mkexpr
- ./mkexpr
-
- operators.o: ../shell.h operators.h
-
- regexp.o: bltin.h ../shell.h
-
- echo: echo.c bltin.h ../shell.h
- $(CC) $(CFLAGS) -o $@ echo.c
-
- echocmd.o: echo.c bltin.h ../shell.h
- $(CC) -DSHELL $(CFLAGS) -c echo.c
- mv echo.o $@
-
- line: line.c bltin.h ../shell.h
- $(CC) $(CFLAGS) -o $@ line.c
-
- linecmd.o: line.c bltin.h ../shell.h
- $(CC) -DSHELL $(CFLAGS) -c line.c
- mv line.o $@
-
- nlecho: nlecho.c bltin.h ../shell.h
- $(CC) $(CFLAGS) -o $@ nlecho.c
-
- nlechocmd.o: nlecho.c bltin.h ../shell.h
- $(CC) -DSHELL $(CFLAGS) -c nlecho.c
- mv nlecho.o $@
-
- umask: umask.c bltin.h
- $(CC) $(CFLAGS) -o $@ umask.c
-
- true:
- > :
- chmod 755 :
- rm -f true
- ln : true
-
- stalloc.o: ../shell.h
-
- EOF
- if test `wc -c < bltin/makefile` -ne 1653
- then echo 'bltin/makefile is the wrong size'
- fi
- echo extracting bltin/mkexpr
- cat > bltin/mkexpr <<\EOF
- # Copyright 1989 by Kenneth Almquist. All rights reserved.
- #
- # This file is part of ash. Ash is distributed under the terms specified
- # by the Ash General Public License. See the file named LICENSE.
-
- exec > operators.h
- awk '/^[^#]/ {printf "#define %s %d\n", $1, n++}' unary_op binary_op
- awk '/^[^#]/ {n++}
- END {printf "\n#define FIRST_BINARY_OP %d\n", n}
- ' unary_op
- 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 */
-
- extern char *const unary_op[];
- extern char *const binary_op[];
- extern const char op_priority[];
- extern const char op_argflag[];'
-
- exec > operators.c
- echo '/*
- * Operators used in the expr/test command.
- */
-
- #include "../shell.h"
- #include "operators.h"
-
- char *const unary_op[] = {'
- awk '/^[^#]/ {printf " \"%s\",\n", $2}' unary_op
- echo ' NULL
- };
-
- char *const binary_op[] = {'
- awk '/^[^#]/ {printf " \"%s\",\n", $2}' binary_op
- echo ' NULL
- };
-
- const char op_priority[] = {'
- awk '/^[^#]/ {printf " %s,\n", $3}' unary_op binary_op
- echo '};
-
- const char op_argflag[] = {'
- awk '/^[^#]/ {if (length($4) > 0) printf " %s,\n", $4
- else printf " 0,\n"}
- ' unary_op binary_op
- echo '};'
- EOF
- if test `wc -c < bltin/mkexpr` -ne 1256
- then echo 'bltin/mkexpr is the wrong size'
- fi
- chmod 755 bltin/mkexpr
- echo extracting bltin/nlecho.1
- cat > bltin/nlecho.1 <<\EOF
- .TH NLECHO 1
- .SH NAME \" Copyright (C) 1989 by Kenneth Almquist.
- nlecho \- echo arguments, one per line
- .SH SYNOPSIS
- .B nlecho
- [
- .I arg
- ] ...
- .SH COPYRIGHT
- .if n Copyright (C) 1989 by Kenneth Almquist.
- .if t Copyright \(co 1989 by Kenneth Almquist.
- .SH DESCRIPTION
- .I Nlecho
- prints its arguments on the standard output, one argument per line.
- EOF
- if test `wc -c < bltin/nlecho.1` -ne 345
- then echo 'bltin/nlecho.1 is the wrong size'
- fi
- echo extracting bltin/nlecho.c
- cat > bltin/nlecho.c <<\EOF
- /*
- * Echo the command argument to the standard output, one line at a time.
- * This command is useful for debugging th shell and whenever you what
- * to output strings literally.
- *
- * 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 nlechocmd
-
- #include "bltin.h"
-
-
- main(argc, argv) char **argv; {
- register char **ap;
-
- for (ap = argv + 1 ; *ap ; ap++) {
- fputs(*ap, stdout);
- putchar('\n');
- }
- return 0;
- }
- EOF
- if test `wc -c < bltin/nlecho.c` -ne 613
- then echo 'bltin/nlecho.c is the wrong size'
- fi
- echo extracting bltin/regexp.c
- cat > bltin/regexp.c <<\EOF
- /*
- * Regular expression matching for expr(1). Bugs: The upper bound of
- * a range specified by the \{ feature cannot be zero.
- *
- * 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 "bltin.h"
-
-
- #define RE_END 0 /* end of regular expression */
- #define RE_LITERAL 1 /* normal character follows */
- #define RE_DOT 2 /* "." */
- #define RE_CCL 3 /* "[...]" */
- #define RE_NCCL 4 /* "[^...]" */
- #define RE_LP 5 /* "\(" */
- #define RE_RP 6 /* "\)" */
- #define RE_MATCHED 7 /* "\digit" */
- #define RE_EOS 8 /* "$" matches end of string */
- #define RE_STAR 9 /* "*" */
- #define RE_RANGE 10 /* "\{num,num\}" */
-
-
-
- char *match_begin[10];
- short match_length[10];
- short number_parens;
-
-
-
- char *
- re_compile(pattern)
- char *pattern;
- {
- register char *p;
- register char c;
- char *comp;
- register char *q;
- char *begin;
- char *endp;
- register int len;
- int first;
- int type;
- char *stackp;
- char stack[10];
- int paren_num;
- int i;
- char *malloc();
-
- p = pattern;
- if (*p == '^')
- p++;
- comp = q = malloc(2 * strlen(p) + 1);
- begin = q;
- stackp = stack;
- paren_num = 0;
- for (;;) {
- switch (c = *p++) {
- case '\0':
- *q = '\0';
- goto out;
- case '.':
- *q++ = RE_DOT;
- len = 1;
- break;
- case '[':
- begin = q;
- *q = RE_CCL;
- if (*p == '^') {
- *q = RE_NCCL;
- p++;
- }
- q++;
- first = 1;
- while (*p != ']' || first == 1) {
- if (p[1] == '-' && p[2] != ']') {
- *q++ = '-';
- *q++ = p[0];
- *q++ = p[2];
- p += 3;
- } else if (*p == '-') {
- *q++ = '-';
- *q++ = '-';
- *q++ = '-';
- p++;
- } else {
- *q++ = *p++;
- }
- first = 0;
- }
- p++;
- *q++ = '\0';
- len = q - begin;
- break;
- case '$':
- if (*p != '\0')
- goto dft;
- *q++ = RE_EOS;
- break;
- case '*':
- if (len == 0)
- goto dft;
- type = RE_STAR;
- range:
- i = (type == RE_RANGE)? 3 : 1;
- endp = q + i;
- begin = q - len;
- do {
- --q;
- *(q + i) = *q;
- } while (--len > 0);
- q = begin;
- *q++ = type;
- if (type == RE_RANGE) {
- i = 0;
- while ((unsigned)(*p - '0') <= 9)
- i = 10 * i + (*p++ - '0');
- *q++ = i;
- if (*p != ',') {
- *q++ = i;
- } else {
- p++;
- i = 0;
- while ((unsigned)(*p - '0') <= 9)
- i = 10 * i + (*p++ - '0');
- *q++ = i;
- }
- if (*p != '\\' || *++p != '}')
- error("RE error");
- p++;
- }
- q = endp;
- break;
- case '\\':
- if ((c = *p++) == '(') {
- if (++paren_num > 9)
- error("RE error");
- *q++ = RE_LP;
- *q++ = paren_num;
- *stackp++ = paren_num;
- len = 0;
- } else if (c == ')') {
- if (stackp == stack)
- error("RE error");
- *q++ = RE_RP;
- *q++ = *--stackp;
- len = 0;
- } else if (c == '{') {
- type = RE_RANGE;
- goto range;
- } else if ((unsigned)(c - '1') < 9) {
- /* should check validity here */
- *q++ = RE_MATCHED;
- *q++ = c - '0';
- len = 2;
- } else {
- goto dft;
- }
- break;
- default:
- dft: *q++ = RE_LITERAL;
- *q++ = c;
- len = 2;
- break;
- }
- }
- out:
- if (stackp != stack)
- error("RE error");
- number_parens = paren_num;
- return comp;
- }
-
-
-
- re_match(pattern, string)
- char *pattern;
- char *string;
- {
- char **pp;
- static int match();
-
- match_begin[0] = string;
- for (pp = &match_begin[1] ; pp <= &match_begin[9] ; pp++)
- *pp = 0;
- return match(pattern, string);
- }
-
-
-
- static
- match(pattern, string)
- char *pattern;
- char *string;
- {
- register char *p, *q;
- int counting;
- int low, high, count;
- char *curpat;
- char *start_count;
- int negate;
- int found;
- char *r;
- int len;
- char c;
-
- p = pattern;
- q = string;
- counting = 0;
- for (;;) {
- if (counting) {
- if (++count > high)
- goto bad;
- p = curpat;
- }
- switch (*p++) {
- case RE_END:
- match_length[0] = q - match_begin[0];
- return 1;
- case RE_LITERAL:
- if (*q++ != *p++)
- goto bad;
- break;
- case RE_DOT:
- if (*q++ == '\0')
- goto bad;
- break;
- case RE_CCL:
- negate = 0;
- goto ccl;
- case RE_NCCL:
- negate = 1;
- ccl:
- found = 0;
- c = *q++;
- while (*p) {
- if (*p == '-') {
- if (c >= *++p && c <= *++p)
- found = 1;
- } else {
- if (c == *p)
- found = 1;
- }
- p++;
- }
- p++;
- if (found == negate)
- goto bad;
- break;
- case RE_LP:
- match_begin[*p++] = q;
- break;
- case RE_RP:
- match_length[*p] = q - match_begin[*p];
- p++;
- break;
- case RE_MATCHED:
- r = match_begin[*p];
- len = match_length[*p++];
- while (--len >= 0) {
- if (*q++ != *r++)
- goto bad;
- }
- break;
- case RE_EOS:
- if (*q != '\0')
- goto bad;
- break;
- case RE_STAR:
- low = 0;
- high = 32767;
- goto range;
- case RE_RANGE:
- low = *p++;
- high = *p++;
- if (high == 0)
- high = 32767;
- range:
- curpat = p;
- start_count = q;
- count = 0;
- counting++;
- break;
- }
- }
- bad:
- if (! counting)
- return 0;
- len = 1;
- if (*curpat == RE_MATCHED)
- len = match_length[curpat[1]];
- while (--count >= low) {
- if (match(p, start_count + count * len))
- return 1;
- }
- return 0;
- }
- EOF
- if test `wc -c < bltin/regexp.c` -ne 5073
- then echo 'bltin/regexp.c is the wrong size'
- fi
- echo extracting bltin/stalloc.c
- cat > bltin/stalloc.c <<\EOF
- /*
- * 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"
-
-
- void error();
- pointer malloc();
-
-
- pointer
- stalloc(nbytes) {
- register pointer p;
-
- if ((p = malloc(nbytes)) == NULL)
- error("Out of space");
- return p;
- }
- EOF
- if test `wc -c < bltin/stalloc.c` -ne 413
- then echo 'bltin/stalloc.c is the wrong size'
- fi
- echo extracting bltin/umask.c
- cat > bltin/umask.c <<\EOF
- /*
- * 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 <stdio.h>
-
-
- main(argc, argv) char **argv; {
- int mask;
-
- if (argc > 1) {
- fprintf(stderr, "umask: only builtin version of umask can set value\n");
- exit(2);
- }
- printf("%.4o\n", umask(0));
- return 0;
- }
- EOF
- if test `wc -c < bltin/umask.c` -ne 461
- then echo 'bltin/umask.c is the wrong size'
- fi
- echo extracting bltin/unary_op
- cat > bltin/unary_op <<\EOF
- # List of unary operators used by test/expr.
- #
- # 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.
-
- NOT ! 3
- ISREAD -r 12 OP_FILE
- ISWRITE -w 12 OP_FILE
- ISEXEC -x 12 OP_FILE
- ISFILE -f 12 OP_FILE
- ISDIR -d 12 OP_FILE
- ISCHAR -c 12 OP_FILE
- ISBLOCK -b 12 OP_FILE
- ISFIFO -p 12 OP_FILE
- ISSETUID -u 12 OP_FILE
- ISSETGID -g 12 OP_FILE
- ISSTICKY -k 12 OP_FILE
- ISSIZE -s 12 OP_FILE
- ISTTY -t 12 OP_INT
- NULSTR -z 12 OP_STRING
- STRLEN -n 12 OP_STRING
- EOF
- if test `wc -c < bltin/unary_op` -ne 628
- then echo 'bltin/unary_op is the wrong size'
- fi
- if test ! -d funcs
- then mkdir funcs
- fi
- echo extracting funcs/cmv
- cat > funcs/cmv <<\EOF
- # Conditional move--don't replace an existing file.
- # 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.
-
- cmv() {
- if test $# != 2
- then echo "cmv: arg count"
- return 2
- fi
- if test -f "$2" -o -w "$2"
- then echo "$2 exists"
- return 2
- fi
- /bin/mv "$1" "$2"
- }
- EOF
- if test `wc -c < funcs/cmv` -ne 384
- then echo 'funcs/cmv is the wrong size'
- fi
- echo extracting funcs/dirs
- cat > funcs/dirs <<\EOF
- # pushd, popd, and dirs --- written by Chris Bertin
- # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
- # as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
-
- pushd () {
- SAVE=`pwd`
- if [ "$1" = "" ]
- then if [ "$DSTACK" = "" ]
- then echo "pushd: directory stack empty."
- return 1
- fi
- set $DSTACK
- cd $1 || return
- shift 1
- DSTACK="$*"
- else cd $1 > /dev/null || return
- fi
- DSTACK="$SAVE $DSTACK"
- dirs
- }
-
- popd () {
- if [ "$DSTACK" = "" ]
- then echo "popd: directory stack empty."
- return 1
- fi
- set $DSTACK
- cd $1
- shift
- DSTACK=$*
- dirs
- }
-
- dirs () {
- echo "`pwd` $DSTACK"
- return 0
- }
- EOF
- if test `wc -c < funcs/dirs` -ne 609
- then echo 'funcs/dirs is the wrong size'
- fi
- echo extracting funcs/kill
- cat > funcs/kill <<\EOF
- # 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.
- #
- # Convert job names to process ids and then run /bin/kill.
-
- kill() {
- local args x
- args=
- for x in "$@"
- do case $x in
- %*) x=`jobid "$x"` ;;
- esac
- args="$args $x"
- done
- /bin/kill $args
- }
- EOF
- if test `wc -c < funcs/kill` -ne 372
- then echo 'funcs/kill is the wrong size'
- fi
- echo extracting funcs/login
- cat > funcs/login <<\EOF
- # 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.
- #
- # replaces the login builtin in the BSD shell
-
- login () exec login "$@"
- EOF
- if test `wc -c < funcs/login` -ne 250
- then echo 'funcs/login is the wrong size'
- fi
- echo extracting funcs/newgrp
- cat > funcs/newgrp <<\EOF
- # 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.
-
- newgrp() exec newgrp "$@"
- EOF
- if test `wc -c < funcs/newgrp` -ne 203
- then echo 'funcs/newgrp is the wrong size'
- fi
- rm -f funcs/popd
- ln funcs/dirs funcs/popd
- rm -f funcs/pushd
- ln funcs/dirs funcs/pushd
- echo extracting funcs/read
- cat > funcs/read <<\EOF
- # 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.
-
- read () {
- if test "$#" = 0
- then echo "Usage: read variable..."
- return 2
- fi
- read_line="`line`" read_status=$?
- read_flag="$-"
- set -f
- for read_word in $read_line
- do set +f
- if test $# -eq 0
- then eval "$read_var=\"\$$read_var \"'$read_word'"
- else eval "$1='$read_word'"
- read_var="$1"
- shift
- fi
- done
- set +f
- set "-$read_flag"
- while test $# -gt 0
- do eval "$1="
- shift
- done
- return "$read_status"
- }
- EOF
- if test `wc -c < funcs/read` -ne 597
- then echo 'funcs/read is the wrong size'
- fi
- echo extracting funcs/suspend
- cat > funcs/suspend <<\EOF
- # 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.
-
- suspend() {
- local -
- set +j
- kill -TSTP 0
- }
- EOF
- if test `wc -c < funcs/suspend` -ne 222
- then echo 'funcs/suspend is the wrong size'
- fi
- echo extracting funcs/tset
- cat > funcs/tset <<\EOF
- # Run the tset command, setting the shell variables appropriately. With
- # the -s flag, set TERMCAP as well as TERM. The -s flag 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.
-
- tset() {
- case $1 in
- -s) eval "$(/usr/ucb/tset "$@")"
- *) TERM=$(/usr/ucb/tset - "$@")
- esac
- }
- EOF
- if test `wc -c < funcs/tset` -ne 422
- then echo 'funcs/tset is the wrong size'
- fi
- echo Archive 8 unpacked
- exit
-
-