]> Zhao Yanbai Git Server - minix.git/commitdiff
Importing NetBSD expr 77/277/2
authorLionel Sambuc <lionel@minix3.org>
Wed, 30 Jan 2013 17:52:21 +0000 (18:52 +0100)
committerLionel Sambuc <lionel@minix3.org>
Fri, 1 Feb 2013 10:41:47 +0000 (11:41 +0100)
Change-Id: Ifdb1160cbfeb1324f6fcd612e66112fa0940227c

bin/Makefile
bin/expr/Makefile [new file with mode: 0644]
bin/expr/expr.1 [new file with mode: 0644]
bin/expr/expr.y [new file with mode: 0644]
man/man1/Makefile
man/man1/expr.1 [deleted file]
releasetools/nbsd_ports

index 218137b64cbe48f9d9204628bb5164bd00990c9c..471e2039c1da010758efb7f05a27a7db08b16d74 100644 (file)
@@ -1,7 +1,7 @@
 #      $NetBSD: Makefile,v 1.22 2007/12/31 15:31:24 ad Exp $
 #      @(#)Makefile    8.1 (Berkeley) 5/31/93
 
-SUBDIR=        cat date echo ed \
+SUBDIR=        cat date echo ed expr \
        mkdir pax rm rmdir test
 
 .include <bsd.subdir.mk>
diff --git a/bin/expr/Makefile b/bin/expr/Makefile
new file mode 100644 (file)
index 0000000..7c7612f
--- /dev/null
@@ -0,0 +1,6 @@
+#      $NetBSD: Makefile,v 1.14 2000/09/19 17:20:00 jdolecek Exp $
+
+PROG=          expr
+SRCS=          expr.y
+
+.include <bsd.prog.mk>
diff --git a/bin/expr/expr.1 b/bin/expr/expr.1
new file mode 100644 (file)
index 0000000..3fe39c4
--- /dev/null
@@ -0,0 +1,267 @@
+.\"    $NetBSD: expr.1,v 1.33 2012/08/12 17:27:04 wiz Exp $
+.\"
+.\" Copyright (c) 2000,2003 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by J.T. Conklin <jtc@NetBSD.org> and Jaromir Dolecek <jdolecek@NetBSD.org>.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+.\"
+.Dd April 20, 2004
+.Dt EXPR 1
+.Os
+.Sh NAME
+.Nm expr
+.Nd evaluate expression
+.Sh SYNOPSIS
+.Nm
+.Ar expression
+.Sh DESCRIPTION
+The
+.Nm
+utility evaluates
+.Ar expression
+and writes the result on standard output.
+.Pp
+All operators are separate arguments to the
+.Nm
+utility.
+Characters special to the command interpreter must be escaped.
+.Pp
+Operators are listed below in order of increasing precedence.
+Operators with equal precedence are grouped within { } symbols.
+.Bl -tag -width indent
+.It Ar expr1 Li \&| Ar expr2
+Returns the evaluation of
+.Ar expr1
+if it is neither an empty string nor zero;
+otherwise, returns the evaluation of
+.Ar expr2 .
+.It Ar expr1 Li \*[Am] Ar expr2
+Returns the evaluation of
+.Ar expr1
+if neither expression evaluates to an empty string or zero;
+otherwise, returns zero.
+.It Ar expr1 Li "{=, \*[Gt], \*[Ge], \*[Lt], \*[Le], !=}" Ar expr2
+Returns the results of integer comparison if both arguments are integers;
+otherwise, returns the results of string comparison using the locale-specific
+collation sequence.
+The result of each comparison is 1 if the specified relation is true,
+or 0 if the relation is false.
+.It Ar expr1 Li "{+, -}" Ar expr2
+Returns the results of addition or subtraction of integer-valued arguments.
+.It Ar expr1 Li "{*, /, %}" Ar expr2
+Returns the results of multiplication, integer division, or remainder of integer-valued arguments.
+.It Ar expr1 Li \&: Ar expr2
+The
+.Dq \&:
+operator matches
+.Ar expr1
+against
+.Ar expr2 ,
+which must be a regular expression.
+The regular expression is anchored
+to the beginning of the string with an implicit
+.Dq ^ .
+.Pp
+If the match succeeds and the pattern contains at least one regular
+expression subexpression
+.Dq "\e(...\e)" ,
+the string corresponding to
+.Dq "\e1"
+is returned;
+otherwise the matching operator returns the number of characters matched.
+If the match fails and the pattern contains a regular expression subexpression
+the null string is returned;
+otherwise 0.
+.It "( " Ar expr No " )"
+Parentheses are used for grouping in the usual manner.
+.El
+.Pp
+Additionally, the following keywords are recognized:
+.Bl -tag -width indent
+.It length Ar expr
+Returns the length of the specified string in bytes.
+.El
+.Pp
+Operator precedence (from highest to lowest):
+.Bl -enum -compact -offset indent
+.It
+parentheses
+.It
+length
+.It
+.Dq \&:
+.It
+.Dq "*" ,
+.Dq "/" ,
+and
+.Dq "%"
+.It
+.Dq "+"
+and
+.Dq "-"
+.It
+compare operators
+.It
+.Dq \*[Am]
+.It
+.Dq \&|
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width Ds -compact
+.It 0
+the expression is neither an empty string nor 0.
+.It 1
+the expression is an empty string or 0.
+.It 2
+the expression is invalid.
+.It \*[Gt]2
+an error occurred (such as memory allocation failure).
+.El
+.Sh EXAMPLES
+.Bl -enum
+.It
+The following example adds one to variable
+.Dq a :
+.Dl a=`expr $a + 1`
+.It
+The following example returns zero, due to subtraction having higher precedence
+than the
+.Dq \*[Am]
+operator:
+.Dl expr 1 '\*[Am]' 1 - 1
+.It
+The following example returns the filename portion of a pathname stored
+in variable
+.Dq a :
+.Dl expr "/$a" Li : '.*/\e(.*\e)'
+.It
+The following example returns the number of characters in variable
+.Dq a :
+.Dl expr $a Li : '.*'
+.El
+.Sh COMPATIBILITY
+This implementation of
+.Nm
+internally uses 64 bit representation of integers and checks for
+over- and underflows.
+It also treats
+.Dq /
+(the division mark) and option
+.Dq --
+correctly depending upon context.
+.Pp
+.Nm
+on other systems (including
+.Nx
+up to and including
+.Nx 1.5 )
+might not be so graceful.
+Arithmetic results might be arbitrarily
+limited on such systems, most commonly to 32 bit quantities.
+This means such
+.Nm
+can only process values between -2147483648 and +2147483647.
+.Pp
+On other systems,
+.Nm
+might also not work correctly for regular expressions where
+either side contains
+.Dq /
+(a single forward slash), like this:
+.Bd -literal -offset indent
+expr / : '.*/\e(.*\e)'
+.Ed
+.Pp
+If this is the case, you might use
+.Dq //
+(a double forward slash)
+to avoid confusion with the division operator:
+.Bd -literal -offset indent
+expr "//$a" : '.*/\e(.*\e)'
+.Ed
+.Pp
+According to
+.St -p1003.2 ,
+.Nm
+has to recognize special option
+.Dq -- ,
+treat it as a delimiter to mark the end of command
+line options, and ignore it.
+Some
+.Nm
+implementations don't recognize it at all; others
+might ignore it even in cases where doing so results in syntax
+error.
+There should be same result for both following examples,
+but it might not always be:
+.Bl -enum -compact -offset indent
+.It
+expr -- : .
+.It
+expr -- -- : .
+.El
+Although
+.Nx
+.Nm
+handles both cases correctly, you should not depend on this behavior
+for portability reasons and avoid passing a bare
+.Dq --
+as the first
+argument.
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2 .
+The
+.Ar length
+keyword is an extension for compatibility with GNU
+.Nm .
+.Sh AUTHORS
+Original implementation was written by
+.An J.T. Conklin
+.Aq jtc@NetBSD.org .
+It was rewritten for
+.Nx 1.6
+by
+.An Jaromir Dolecek
+.Aq jdolecek@NetBSD.org .
+.Sh NOTES
+The empty string
+.Do Dc
+cannot be matched with the intuitive:
+.Bd -literal -offset indent
+expr '' : '$'
+.Ed
+.Pp
+The reason is that the returned number of matched characters (zero)
+is indistinguishable from a failed match, so this returns failure.
+To match the empty string, use something like:
+.Bd -literal -offset indent
+expr x'' : 'x$'
+.Ed
diff --git a/bin/expr/expr.y b/bin/expr/expr.y
new file mode 100644 (file)
index 0000000..f368b6e
--- /dev/null
@@ -0,0 +1,459 @@
+/* $NetBSD: expr.y,v 1.38 2012/03/15 02:02:20 joerg Exp $ */
+
+/*_
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jaromir Dolecek <jdolecek@NetBSD.org> and J.T. Conklin <jtc@NetBSD.org>.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+%{
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: expr.y,v 1.38 2012/03/15 02:02:20 joerg Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <regex.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const char * const *av;
+
+static void yyerror(const char *, ...) __dead;
+static int yylex(void);
+static int is_zero_or_null(const char *);
+static int is_integer(const char *);
+static int64_t perform_arith_op(const char *, const char *, const char *);
+
+int main(int, const char * const *);
+
+#define YYSTYPE        const char *
+
+%}
+%token STRING
+%left SPEC_OR
+%left SPEC_AND
+%left COMPARE 
+%left ADD_SUB_OPERATOR
+%left MUL_DIV_MOD_OPERATOR
+%left SPEC_REG
+%left LENGTH
+%left LEFT_PARENT RIGHT_PARENT
+
+%%
+
+exp:   expr = {
+               (void) printf("%s\n", $1);
+               return (is_zero_or_null($1));
+               }
+       ;
+
+expr:  item { $$ = $1; }
+       | expr SPEC_OR expr = {
+               /*
+                * Return evaluation of first expression if it is neither
+                * an empty string nor zero; otherwise, returns the evaluation
+                * of second expression.
+                */
+               if (!is_zero_or_null($1))
+                       $$ = $1;
+               else
+                       $$ = $3;
+               }
+       | expr SPEC_AND expr = {
+               /*
+                * Returns the evaluation of first expr if neither expression
+                * evaluates to an empty string or zero; otherwise, returns
+                * zero.
+                */
+               if (!is_zero_or_null($1) && !is_zero_or_null($3))
+                       $$ = $1;
+               else
+                       $$ = "0";
+               }
+       | expr SPEC_REG expr = {
+               /*
+                * The ``:'' operator matches first expr against the second,
+                * which must be a regular expression.
+                */
+               regex_t rp;
+               regmatch_t rm[2];
+               int eval;
+
+               /* compile regular expression */
+               if ((eval = regcomp(&rp, $3, REG_BASIC)) != 0) {
+                       char errbuf[256];
+                       (void)regerror(eval, &rp, errbuf, sizeof(errbuf));
+                       yyerror("%s", errbuf);
+                       /* NOT REACHED */
+               }
+               
+               /* compare string against pattern --  remember that patterns 
+                  are anchored to the beginning of the line */
+               if (regexec(&rp, $1, 2, rm, 0) == 0 && rm[0].rm_so == 0) {
+                       char *val;
+                       if (rm[1].rm_so >= 0) {
+                               (void) asprintf(&val, "%.*s",
+                                       (int) (rm[1].rm_eo - rm[1].rm_so),
+                                       $1 + rm[1].rm_so);
+                       } else {
+                               (void) asprintf(&val, "%d",
+                                       (int)(rm[0].rm_eo - rm[0].rm_so));
+                       }
+                       if (val == NULL)
+                               err(1, NULL);
+                       $$ = val;
+               } else {
+                       if (rp.re_nsub == 0) {
+                               $$ = "0";
+                       } else {
+                               $$ = "";
+                       }
+               }
+
+               }
+       | expr ADD_SUB_OPERATOR expr = {
+               /* Returns the results of addition, subtraction */
+               char *val;
+               int64_t res;
+               
+               res = perform_arith_op($1, $2, $3);
+               (void) asprintf(&val, "%lld", (long long int) res);
+               if (val == NULL)
+                       err(1, NULL);
+               $$ = val;
+                }
+
+       | expr MUL_DIV_MOD_OPERATOR expr = {
+               /* 
+                * Returns the results of multiply, divide or remainder of 
+                * numeric-valued arguments.
+                */
+               char *val;
+               int64_t res;
+
+               res = perform_arith_op($1, $2, $3);
+               (void) asprintf(&val, "%lld", (long long int) res);
+               if (val == NULL)
+                       err(1, NULL);
+               $$ = val;
+
+               }
+       | expr COMPARE expr = {
+               /*
+                * Returns the results of integer comparison if both arguments
+                * are integers; otherwise, returns the results of string
+                * comparison using the locale-specific collation sequence.
+                * The result of each comparison is 1 if the specified relation
+                * is true, or 0 if the relation is false.
+                */
+
+               int64_t l, r;
+               int res;
+
+               res = 0;
+
+               /*
+                * Slight hack to avoid differences in the compare code
+                * between string and numeric compare.
+                */
+               if (is_integer($1) && is_integer($3)) {
+                       /* numeric comparison */
+                       l = strtoll($1, NULL, 10);
+                       r = strtoll($3, NULL, 10);
+               } else {
+                       /* string comparison */
+                       l = strcoll($1, $3);
+                       r = 0;
+               }
+
+               switch($2[0]) { 
+               case '=': /* equal */
+                       res = (l == r);
+                       break;
+               case '>': /* greater or greater-equal */
+                       if ($2[1] == '=')
+                               res = (l >= r);
+                       else
+                               res = (l > r);
+                       break;
+               case '<': /* lower or lower-equal */
+                       if ($2[1] == '=')
+                               res = (l <= r);
+                       else
+                               res = (l < r);
+                       break;
+               case '!': /* not equal */
+                       /* the check if this is != was done in yylex() */
+                       res = (l != r);
+               }
+
+               $$ = (res) ? "1" : "0";
+
+               }
+       | LEFT_PARENT expr RIGHT_PARENT { $$ = $2; }
+       | LENGTH expr {
+               /*
+                * Return length of 'expr' in bytes.
+                */
+               char *ln;
+
+               asprintf(&ln, "%ld", (long) strlen($2));
+               if (ln == NULL)
+                       err(1, NULL);
+               $$ = ln;
+               }
+       ;
+
+item:  STRING
+       | ADD_SUB_OPERATOR
+       | MUL_DIV_MOD_OPERATOR
+       | COMPARE
+       | SPEC_OR
+       | SPEC_AND
+       | SPEC_REG
+       | LENGTH
+       ;
+%%
+
+/*
+ * Returns 1 if the string is empty or contains only numeric zero.
+ */
+static int
+is_zero_or_null(const char *str)
+{
+       char *endptr;
+
+       return str[0] == '\0'
+               || ( strtoll(str, &endptr, 10) == 0LL
+                       && endptr[0] == '\0');
+}
+
+/*
+ * Returns 1 if the string is an integer.
+ */
+static int
+is_integer(const char *str)
+{
+       char *endptr;
+
+       (void) strtoll(str, &endptr, 10);
+       /* note we treat empty string as valid number */
+       return (endptr[0] == '\0');
+}
+
+static int64_t
+perform_arith_op(const char *left, const char *op, const char *right)
+{
+       int64_t res, sign, l, r;
+       u_int64_t temp;
+
+       res = 0;
+
+       if (!is_integer(left)) {
+               yyerror("non-integer argument '%s'", left);
+               /* NOTREACHED */
+       }
+       if (!is_integer(right)) {
+               yyerror("non-integer argument '%s'", right);
+               /* NOTREACHED */
+       }
+
+       errno = 0;
+       l = strtoll(left, NULL, 10);
+       if (errno == ERANGE) {
+               yyerror("value '%s' is %s is %lld", left,
+                   (l > 0) ? "too big, maximum" : "too small, minimum",
+                   (l > 0) ? LLONG_MAX : LLONG_MIN);
+               /* NOTREACHED */
+       }
+
+       errno = 0;
+       r = strtoll(right, NULL, 10);
+       if (errno == ERANGE) {
+               yyerror("value '%s' is %s is %lld", right,
+                   (l > 0) ? "too big, maximum" : "too small, minimum",
+                   (l > 0) ? LLONG_MAX : LLONG_MIN);
+               /* NOTREACHED */
+       }
+
+       switch(op[0]) {
+       case '+':
+               /* 
+                * Do the op into an unsigned to avoid overflow and then cast
+                * back to check the resulting signage. 
+                */
+               temp = l + r;
+               res = (int64_t) temp;
+               /* very simplistic check for over-& underflow */
+               if ((res < 0 && l > 0 && r > 0)
+                   || (res > 0 && l < 0 && r < 0)) 
+                       yyerror("integer overflow or underflow occurred for "
+                            "operation '%s %s %s'", left, op, right);
+               break;
+       case '-':
+               /* 
+                * Do the op into an unsigned to avoid overflow and then cast
+                * back to check the resulting signage. 
+                */
+               temp = l - r;
+               res = (int64_t) temp;
+               /* very simplistic check for over-& underflow */
+               if ((res < 0 && l > 0 && l > r)
+                   || (res > 0 && l < 0 && l < r) ) 
+                       yyerror("integer overflow or underflow occurred for "
+                           "operation '%s %s %s'", left, op, right);
+               break;
+       case '/':
+               if (r == 0) 
+                       yyerror("second argument to '%s' must not be zero", op);
+               res = l / r;
+                       
+               break;
+       case '%':
+               if (r == 0)
+                       yyerror("second argument to '%s' must not be zero", op);
+               res = l % r;
+               break;
+       case '*':
+               /* shortcut */
+               if ((l == 0) || (r == 0)) {
+                       res = 0;
+                       break;
+               }
+                               
+               sign = 1;
+               if (l < 0)
+                       sign *= -1;
+               if (r < 0)
+                       sign *= -1;
+
+               res = l * r;
+               /*
+                * XXX: not the most portable but works on anything with 2's
+                * complement arithmetic. If the signs don't match or the
+                * result was 0 on 2's complement this overflowed.
+                */
+               if ((res < 0 && sign > 0) || (res > 0 && sign < 0) || 
+                   (res == 0))
+                       yyerror("integer overflow or underflow occurred for "
+                           "operation '%s %s %s'", left, op, right);
+                       /* NOTREACHED */
+               break;
+       }
+       return res;
+}
+
+static const char *x = "|&=<>+-*/%:()";
+static const int x_token[] = {
+       SPEC_OR, SPEC_AND, COMPARE, COMPARE, COMPARE, ADD_SUB_OPERATOR,
+       ADD_SUB_OPERATOR, MUL_DIV_MOD_OPERATOR, MUL_DIV_MOD_OPERATOR, 
+       MUL_DIV_MOD_OPERATOR, SPEC_REG, LEFT_PARENT, RIGHT_PARENT
+};
+
+static int handle_ddash = 1;
+
+int
+yylex(void)
+{
+       const char *p = *av++;
+       int retval;
+
+       if (!p)
+               retval = 0;
+       else if (p[1] == '\0') {
+               const char *w = strchr(x, p[0]);
+               if (w) {
+                       retval = x_token[w-x];
+               } else {
+                       retval = STRING;
+               }
+       } else if (p[1] == '=' && p[2] == '\0'
+                       && (p[0] == '>' || p[0] == '<' || p[0] == '!'))
+               retval = COMPARE;
+       else if (handle_ddash && p[0] == '-' && p[1] == '-' && p[2] == '\0') {
+               /* ignore "--" if passed as first argument and isn't followed
+                * by another STRING */
+               retval = yylex();
+               if (retval != STRING && retval != LEFT_PARENT
+                   && retval != RIGHT_PARENT) {
+                       /* is not followed by string or parenthesis, use as
+                        * STRING */
+                       retval = STRING;
+                       av--;   /* was increased in call to yylex() above */
+                       p = "--";
+               } else {
+                       /* "--" is to be ignored */
+                       p = yylval;
+               }
+       } else if (strcmp(p, "length") == 0)
+               retval = LENGTH;
+       else
+               retval = STRING;
+
+       handle_ddash = 0;
+       yylval = p;
+
+       return retval;
+}
+
+/*
+ * Print error message and exit with error 2 (syntax error).
+ */
+static __printflike(1, 2) void
+yyerror(const char *fmt, ...)
+{
+       va_list arg;
+
+       va_start(arg, fmt);
+       verrx(2, fmt, arg);
+       va_end(arg);
+}
+
+int
+main(int argc, const char * const *argv)
+{
+       setprogname(argv[0]);
+       (void)setlocale(LC_ALL, "");
+
+       if (argc == 1) {
+               (void)fprintf(stderr, "usage: %s expression\n",
+                   getprogname());
+               exit(2);
+       }
+
+       av = argv + 1;
+
+       exit(yyparse());
+       /* NOTREACHED */
+}
index 6578906ee727cb2d2370522b360870ecdf7dc496..cbb2b675082cd69b3c84e95458cb377f9437c3f9 100644 (file)
@@ -4,7 +4,7 @@ MAN=    ash.1 at.1 banner.1 basename.1 \
        cp.1 crc.1 crontab.1 dd.1 \
        df.1 dhrystone.1 dosdir.1 dosread.1 doswrite.1 \
        dumpcore.1 eject.1 \
-       env.1 expand.1 expr.1 factor.1 \
+       env.1 expand.1 factor.1 \
        finger.1 flexdoc.1 fold.1 format.1 fortune.1 \
        fsck.mfs.1 head.1 host.1 hostaddr.1 ifdef.1 \
        isodir.1 isoinfo.1 isoread.1 kill.1 \
@@ -54,8 +54,6 @@ MLINKS += compress.1 uncompress.1
 MLINKS += cp.1 mv.1
 MLINKS += cp.1 ln.1
 MLINKS += cp.1 cpdir.1
-MLINKS += expr.1 test.1
-MLINKS += expr.1 [.1
 MLINKS += svc.1 ci.1
 MLINKS += svc.1 co.1
 
diff --git a/man/man1/expr.1 b/man/man1/expr.1
deleted file mode 100644 (file)
index 9e04e73..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-.TH EXPR 1
-.SH NAME \"    Copyright (C) 1989 by Kenneth Almquist.
-expr, test, [ \- evaluate expressions
-.SH SYNOPSIS
-.B expr
-.I expression
-.br
-.B test
-.I expression
-.br
-.B [
-.I expression
-.B ]
-.SH DESCRIPTION
-.B Expr
-evaluates the expression and prints the result.
-.B Test
-evaluates the expression without printing the result.
-The ``[''
-command is a synonym for
-.BR test ;
-when invoked under this name
-the last argument to
-.B 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
-.BR atoi (3).
-.ti -\nii
-\fIinteger\fR\->\fIstring\fR   Convert to decimal representation.
-.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
-.B expr
-which is not a legal operator is treated as a string operand of type
-.BR string .
-.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 automatically converted to the appropriate type.  The type
-\fIany\fR is used for operator that take operands of any type.
-.nr p 1
-.de b
-.TP 0.5i
-\fI\\$1\fB \\$2 \fI\\$3\fR \-> \\fI\\$4\\fR  (\\np)
-..
-.de u
-.TP 0.5i
-\\$1 \fI\\$2\fR \-> \\fI\\$3\\fR  (\\np)
-..
-.b any \-o any any
-Returns the value of the left hand operand if the left hand operand
-would yield
-.B true
-if converted to type
-.BR 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
-.B false
-if converted to type
-.BR 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
-.B 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 \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 \-e string boolean
-True the file exists.
-.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.
-.u \-h string boolean
-True if the file is a symlink.  This is the only file test operator that
-does not follow symlinks, all others do.  So ``\-d'' and ``\-h''
-are both true on a symlink pointing to a directory.
-``\-L'' is a synonym for ``\-h''.
-.SH "EXIT CODE"
-0 if the result of 
-.I expression
-would be
-.B true
-if the result were converted to
-.BR boolean .
-.br
-1 if the result of 
-.I expression
-would be
-.B false
-if the result were converted to
-.BR boolean .
-.br
-2 if
-.I expression
-is syntactically incorrect.
-.SH EXAMPLES
-.TP 0.5i
-filesize=`expr \-s file`
-Sets the shell variable
-.I filesize
-to the size of
-.IR file .
-.TP 0.5i
-if [ \-s file ]; then command; fi
-Execute
-.I command
-if
-.I file
-exists and is not empty.
-.TP 0.5i
-x=`expr "$x" : '.\\{4\\}\\(.\\{0,3\\}\\)'`
-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.
-.TP 0.5i
-x=`expr X"$x" : X'.\\{4\\}\\(.\\{0,3\\}\\)'`
-This example is the same as the previous one, but it uses a leading
-``X'' to make things work when the value of
-.I x
-looks like an operator.
-.SH BUGS
-The relational operators of the System V
-.B expr
-command are not implemented.
-.PP
-Certain features of this version of
-.B expr
-are not present in System V, so care should be used when writing
-portable code.
-.SH COPYRIGHT
-Kenneth Almquist.
index e236e32f571e528c23fee1a0d1e557e0a1ac8f36..fd6a3c17d9f1db7959d366fce05f022fe06b35df 100644 (file)
@@ -10,6 +10,7 @@
 2011/08/27 12:55:09,bin/date
 2012/10/17 12:00:00,bin/echo
 2012/01/16 18:47:57,bin/ed
+2012/10/17 12:00:00,bin/expr
 2012/10/17 12:00:00,bin/Makefile
 2012/10/17 12:00:00,bin/Makefile.inc
 2008/07/20 00:52:40,bin/mkdir