Update Chris Demetriou's email address
[unix-history] / bin / expr / expr.y
index d267094..57ad502 100644 (file)
@@ -1,13 +1,18 @@
 %{
 /* Written by Pace Willisson (pace@blitz.com) 
 %{
 /* Written by Pace Willisson (pace@blitz.com) 
- * and placed in the public domain
+ * and placed in the public domain.
  *
  *
- * /b/source/CVS/src/bin/expr/expr.y,v 1.6 1993/06/14 19:59:07 jtc Exp
+ * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
+ *
+ * $Id : /b/source/CVS/src/bin/expr/expr.y,v 1.11 1993/08/17 16:01:23 jtc Exp $
  */
  */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <locale.h>
 #include <ctype.h>
 #include <ctype.h>
+#include <err.h>
   
 enum valtype {
        integer, string
   
 enum valtype {
        integer, string
@@ -76,7 +81,6 @@ expr: TOKEN
        | expr '/' expr { $$ = op_div ($1, $3); }
        | expr '%' expr { $$ = op_rem ($1, $3); }
        | expr ':' expr { $$ = op_colon ($1, $3); }
        | expr '/' expr { $$ = op_div ($1, $3); }
        | expr '%' expr { $$ = op_rem ($1, $3); }
        | expr ':' expr { $$ = op_colon ($1, $3); }
-       | '-' expr %prec UNARY { $$ = op_minus (NULL, $2); }
        ;
 
 
        ;
 
 
@@ -90,8 +94,7 @@ int i;
 
        vp = (struct val *) malloc (sizeof (*vp));
        if (vp == NULL) {
 
        vp = (struct val *) malloc (sizeof (*vp));
        if (vp == NULL) {
-               fprintf (stderr, "expr: out of memory\n");
-               exit (2);
+               err (2, NULL);
        }
 
        vp->type = integer;
        }
 
        vp->type = integer;
@@ -107,8 +110,7 @@ char *s;
 
        vp = (struct val *) malloc (sizeof (*vp));
        if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
 
        vp = (struct val *) malloc (sizeof (*vp));
        if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
-               fprintf (stderr, "expr: out of memory\n");
-               exit (2);
+               err (2, NULL);
        }
 
        vp->type = string;
        }
 
        vp->type = string;
@@ -171,8 +173,7 @@ struct val *vp;
 
        tmp = malloc (25);
        if (tmp == NULL) {
 
        tmp = malloc (25);
        if (tmp == NULL) {
-               fprintf (stderr, "expr: out of memory\n");
-               exit (2);
+               err (2, NULL);
        }
 
        sprintf (tmp, "%d", vp->u.i);
        }
 
        sprintf (tmp, "%d", vp->u.i);
@@ -219,13 +220,10 @@ int
 is_zero_or_null (vp)
 struct val *vp;
 {
 is_zero_or_null (vp)
 struct val *vp;
 {
-       /* Like most other versions of expr, this version will return
-          false for a string value of multiple zeros.*/
-
        if (vp->type == integer) {
                return (vp->u.i == 0);
        } else {
        if (vp->type == integer) {
                return (vp->u.i == 0);
        } else {
-               return (*vp->u.s == 0 || strcmp (vp->u.s, "0") == 0);
+               return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
        }
        /* NOTREACHED */
 }
        }
        /* NOTREACHED */
 }
@@ -235,6 +233,8 @@ main (argc, argv)
 int argc;
 char **argv;
 {
 int argc;
 char **argv;
 {
+       setlocale (LC_ALL, "");
+
        av = argv + 1;
 
        yyparse ();
        av = argv + 1;
 
        yyparse ();
@@ -244,18 +244,14 @@ char **argv;
        else
                printf ("%s\n", result->u.s);
 
        else
                printf ("%s\n", result->u.s);
 
-       if (is_zero_or_null (result))
-               exit (1);
-       else
-               exit (0);
+       exit (is_zero_or_null (result));
 }
 
 int
 yyerror (s)
 char *s;
 {
 }
 
 int
 yyerror (s)
 char *s;
 {
-       fprintf (stderr, "expr: syntax error\n");
-       exit (2);
+       errx (2, "syntax error");
 }
 
 
 }
 
 
@@ -292,16 +288,10 @@ struct val *a, *b;
 {
        struct val *r; 
 
 {
        struct val *r; 
 
-       /* attempt to coerce both arguments to integers */
-       (void) to_integer (a);
-       (void) to_integer (b);
-
-       /* But if either one of them really is a string, do 
-          a string comparison */
        if (isstring (a) || isstring (b)) {
                to_string (a);
                to_string (b);  
        if (isstring (a) || isstring (b)) {
                to_string (a);
                to_string (b);  
-               r = make_integer (strcmp (a->u.s, b->u.s) == 0);
+               r = make_integer (strcoll (a->u.s, b->u.s) == 0);
        } else {
                r = make_integer (a->u.i == b->u.i);
        }
        } else {
                r = make_integer (a->u.i == b->u.i);
        }
@@ -317,16 +307,10 @@ struct val *a, *b;
 {
        struct val *r;
 
 {
        struct val *r;
 
-       /* attempt to coerce both arguments to integers */
-       (void) to_integer (a);
-       (void) to_integer (b);
-
-       /* But if either one of them really is a string, do 
-          a string comparison */
        if (isstring (a) || isstring (b)) {
                to_string (a);
                to_string (b);
        if (isstring (a) || isstring (b)) {
                to_string (a);
                to_string (b);
-               r = make_integer (strcmp (a->u.s, b->u.s) > 0);
+               r = make_integer (strcoll (a->u.s, b->u.s) > 0);
        } else {
                r= make_integer (a->u.i > b->u.i);
        }
        } else {
                r= make_integer (a->u.i > b->u.i);
        }
@@ -342,16 +326,10 @@ struct val *a, *b;
 {
        struct val *r;
 
 {
        struct val *r;
 
-       /* attempt to coerce both arguments to integers */
-       (void) to_integer (a);
-       (void) to_integer (b);
-
-       /* But if either one of them really is a string, do 
-          a string comparison */
        if (isstring (a) || isstring (b)) {
                to_string (a);
                to_string (b);
        if (isstring (a) || isstring (b)) {
                to_string (a);
                to_string (b);
-               r = make_integer (strcmp (a->u.s, b->u.s) < 0);
+               r = make_integer (strcoll (a->u.s, b->u.s) < 0);
        } else {
                r = make_integer (a->u.i < b->u.i);
        }
        } else {
                r = make_integer (a->u.i < b->u.i);
        }
@@ -367,16 +345,10 @@ struct val *a, *b;
 {
        struct val *r;
 
 {
        struct val *r;
 
-       /* attempt to coerce both arguments to integers */
-       (void) to_integer (a);
-       (void) to_integer (b);
-
-       /* But if either one of them really is a string, do 
-          a string comparison */
        if (isstring (a) || isstring (b)) {
                to_string (a);
                to_string (b);
        if (isstring (a) || isstring (b)) {
                to_string (a);
                to_string (b);
-               r = make_integer (strcmp (a->u.s, b->u.s) >= 0);
+               r = make_integer (strcoll (a->u.s, b->u.s) >= 0);
        } else {
                r = make_integer (a->u.i >= b->u.i);
        }
        } else {
                r = make_integer (a->u.i >= b->u.i);
        }
@@ -392,16 +364,10 @@ struct val *a, *b;
 {
        struct val *r;
 
 {
        struct val *r;
 
-       /* attempt to coerce both arguments to integers */
-       (void) to_integer (a);
-       (void) to_integer (b);
-
-       /* But if either one of them really is a string, do 
-          a string comparison */
        if (isstring (a) || isstring (b)) {
                to_string (a);
                to_string (b);
        if (isstring (a) || isstring (b)) {
                to_string (a);
                to_string (b);
-               r = make_integer (strcmp (a->u.s, b->u.s) <= 0);
+               r = make_integer (strcoll (a->u.s, b->u.s) <= 0);
        } else {
                r = make_integer (a->u.i <= b->u.i);
        }
        } else {
                r = make_integer (a->u.i <= b->u.i);
        }
@@ -417,16 +383,10 @@ struct val *a, *b;
 {
        struct val *r;
 
 {
        struct val *r;
 
-       /* attempt to coerce both arguments to integers */
-       (void) to_integer (a);
-       (void) to_integer (b);
-
-       /* But if either one of them really is a string, do 
-          a string comparison */
        if (isstring (a) || isstring (b)) {
                to_string (a);
                to_string (b);
        if (isstring (a) || isstring (b)) {
                to_string (a);
                to_string (b);
-               r = make_integer (strcmp (a->u.s, b->u.s) != 0);
+               r = make_integer (strcoll (a->u.s, b->u.s) != 0);
        } else {
                r = make_integer (a->u.i != b->u.i);
        }
        } else {
                r = make_integer (a->u.i != b->u.i);
        }
@@ -443,8 +403,7 @@ struct val *a, *b;
        struct val *r;
 
        if (!to_integer (a) || !to_integer (b)) {
        struct val *r;
 
        if (!to_integer (a) || !to_integer (b)) {
-               fprintf (stderr, "expr: non-numeric argument\n");
-               exit (2);
+               errx (2, "non-numeric argument");
        }
 
        r = make_integer (a->u.i + b->u.i);
        }
 
        r = make_integer (a->u.i + b->u.i);
@@ -460,8 +419,7 @@ struct val *a, *b;
        struct val *r;
 
        if (!to_integer (a) || !to_integer (b)) {
        struct val *r;
 
        if (!to_integer (a) || !to_integer (b)) {
-               fprintf (stderr, "expr: non-numeric argument\n");
-               exit (2);
+               errx (2, "non-numeric argument");
        }
 
        r = make_integer (a->u.i - b->u.i);
        }
 
        r = make_integer (a->u.i - b->u.i);
@@ -477,8 +435,7 @@ struct val *a, *b;
        struct val *r;
 
        if (!to_integer (a) || !to_integer (b)) {
        struct val *r;
 
        if (!to_integer (a) || !to_integer (b)) {
-               fprintf (stderr, "expr: non-numeric argument\n");
-               exit (2);
+               errx (2, "non-numeric argument");
        }
 
        r = make_integer (a->u.i * b->u.i);
        }
 
        r = make_integer (a->u.i * b->u.i);
@@ -494,13 +451,11 @@ struct val *a, *b;
        struct val *r;
 
        if (!to_integer (a) || !to_integer (b)) {
        struct val *r;
 
        if (!to_integer (a) || !to_integer (b)) {
-               fprintf (stderr, "expr: non-numeric argument\n");
-               exit (2);
+               errx (2, "non-numeric argument");
        }
 
        if (b->u.i == 0) {
        }
 
        if (b->u.i == 0) {
-               fprintf (stderr, "expr: division by zero\n");
-               exit (2);
+               errx (2, "division by zero");
        }
 
        r = make_integer (a->u.i / b->u.i);
        }
 
        r = make_integer (a->u.i / b->u.i);
@@ -516,13 +471,11 @@ struct val *a, *b;
        struct val *r;
 
        if (!to_integer (a) || !to_integer (b)) {
        struct val *r;
 
        if (!to_integer (a) || !to_integer (b)) {
-               fprintf (stderr, "expr: non-numeric argument\n");
-               exit (2);
+               errx (2, "non-numeric argument");
        }
 
        if (b->u.i == 0) {
        }
 
        if (b->u.i == 0) {
-               fprintf (stderr, "expr: division by zero\n");
-               exit (2);
+               errx (2, "division by zero");
        }
 
        r = make_integer (a->u.i % b->u.i);
        }
 
        r = make_integer (a->u.i % b->u.i);
@@ -532,43 +485,43 @@ struct val *a, *b;
 }
        
 #include <regex.h>
 }
        
 #include <regex.h>
-#define SE_MAX 30
 
 struct val *
 op_colon (a, b)
 struct val *a, *b;
 {
        regex_t rp;
 
 struct val *
 op_colon (a, b)
 struct val *a, *b;
 {
        regex_t rp;
-       regmatch_t rm[SE_MAX];
+       regmatch_t rm[2];
        char errbuf[256];
        int eval;
        char errbuf[256];
        int eval;
-       char *newpat;
        struct val *v;
 
        struct val *v;
 
-       /* patterns are anchored to the beginning of the line */
-       newpat = malloc (strlen (b->u.s) + 2);
-       strcpy (newpat, "^");
-       strcat (newpat, b->u.s);
+       /* coerce to both arguments to strings */
+       to_string(a);
+       to_string(b);
 
        /* compile regular expression */
 
        /* compile regular expression */
-       if ((eval = regcomp (&rp, newpat, 0)) != 0) {
+       if ((eval = regcomp (&rp, b->u.s, 0)) != 0) {
                regerror (eval, &rp, errbuf, sizeof(errbuf));
                regerror (eval, &rp, errbuf, sizeof(errbuf));
-               fprintf (stderr, "expr: %s\n", errbuf);
-               exit (2);
+               errx (2, "%s", errbuf);
        }
        }
-       free (newpat);
 
        /* compare string against pattern */
 
        /* compare string against pattern */
-       if (regexec(&rp, a->u.s, SE_MAX, rm, 0) == 0) {
+       /* remember that patterns are anchored to the beginning of the line */
+       if (regexec(&rp, a->u.s, 2, rm, 0) == 0 && rm[0].rm_so == 0) {
                if (rm[1].rm_so >= 0) {
                if (rm[1].rm_so >= 0) {
-                       *(a->u.s + rm[1].rm_eo) = 0;
+                       *(a->u.s + rm[1].rm_eo) = '\0';
                        v = make_str (a->u.s + rm[1].rm_so);
 
                } else {
                        v = make_integer (rm[0].rm_eo - rm[0].rm_so);
                }
        } else {
                        v = make_str (a->u.s + rm[1].rm_so);
 
                } else {
                        v = make_integer (rm[0].rm_eo - rm[0].rm_so);
                }
        } else {
-               v = make_integer (0);
+               if (rp.re_nsub == 0) {
+                       v = make_integer (0);
+               } else {
+                       v = make_str ("");
+               }
        }
 
        /* free arguments and pattern buffer */
        }
 
        /* free arguments and pattern buffer */