xref: /illumos-gate/usr/src/cmd/expr/expr.c (revision cc22b130832529204c03214239a57aaadd05101f)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*cc22b130SRich Burridge  * Common Development and Distribution License (the "License").
6*cc22b130SRich Burridge  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
227c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
26*cc22b130SRich Burridge  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <regexpr.h>
317c478bd9Sstevel@tonic-gate #include <locale.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <regex.h>
357c478bd9Sstevel@tonic-gate #include <limits.h>
367c478bd9Sstevel@tonic-gate #include <stdio.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate #include <errno.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #define	A_STRING 258
417c478bd9Sstevel@tonic-gate #define	NOARG 259
427c478bd9Sstevel@tonic-gate #define	OR 260
437c478bd9Sstevel@tonic-gate #define	AND 261
447c478bd9Sstevel@tonic-gate #define	EQ 262
457c478bd9Sstevel@tonic-gate #define	LT 263
467c478bd9Sstevel@tonic-gate #define	GT 264
477c478bd9Sstevel@tonic-gate #define	GEQ 265
487c478bd9Sstevel@tonic-gate #define	LEQ 266
497c478bd9Sstevel@tonic-gate #define	NEQ 267
507c478bd9Sstevel@tonic-gate #define	ADD 268
517c478bd9Sstevel@tonic-gate #define	SUBT 269
527c478bd9Sstevel@tonic-gate #define	MULT 270
537c478bd9Sstevel@tonic-gate #define	DIV 271
547c478bd9Sstevel@tonic-gate #define	REM 272
557c478bd9Sstevel@tonic-gate #define	MCH 273
567c478bd9Sstevel@tonic-gate #define	MATCH 274
57*cc22b130SRich Burridge #define	SUBSTR 275
58*cc22b130SRich Burridge #define	LENGTH 276
59*cc22b130SRich Burridge #define	INDEX  277
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /* size of subexpression array */
627c478bd9Sstevel@tonic-gate #define	MSIZE	LINE_MAX
637c478bd9Sstevel@tonic-gate #define	error(c)	errxx()
647c478bd9Sstevel@tonic-gate #define	EQL(x, y) (strcmp(x, y) == 0)
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #define	ERROR(c)	errxx()
677c478bd9Sstevel@tonic-gate #define	MAX_MATCH 20
687c478bd9Sstevel@tonic-gate static int ematch(char *, char *);
697c478bd9Sstevel@tonic-gate static void yyerror(char *);
707c478bd9Sstevel@tonic-gate static void errxx();
717c478bd9Sstevel@tonic-gate static void *exprmalloc(size_t size);
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate long atol();
747c478bd9Sstevel@tonic-gate char *strcpy(), *strncpy();
757c478bd9Sstevel@tonic-gate void exit();
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate static char *ltoa();
787c478bd9Sstevel@tonic-gate static char *lltoa();
797c478bd9Sstevel@tonic-gate static char	**Av;
807c478bd9Sstevel@tonic-gate static char *buf;
817c478bd9Sstevel@tonic-gate static int	Ac;
827c478bd9Sstevel@tonic-gate static int	Argi;
837c478bd9Sstevel@tonic-gate static int noarg;
847c478bd9Sstevel@tonic-gate static int paren;
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate  *	Array used to store subexpressions in regular expressions
877c478bd9Sstevel@tonic-gate  *	Only one subexpression allowed per regular expression currently
887c478bd9Sstevel@tonic-gate  */
897c478bd9Sstevel@tonic-gate static char Mstring[1][MSIZE];
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate static char *operator[] = {
937c478bd9Sstevel@tonic-gate 	"|", "&", "+", "-", "*", "/", "%", ":",
947c478bd9Sstevel@tonic-gate 	"=", "==", "<", "<=", ">", ">=", "!=",
957c478bd9Sstevel@tonic-gate 	"match",
967c478bd9Sstevel@tonic-gate 	"substr", "length", "index",
977c478bd9Sstevel@tonic-gate 	"\0" };
987c478bd9Sstevel@tonic-gate static	int op[] = {
997c478bd9Sstevel@tonic-gate 	OR, AND, ADD,  SUBT, MULT, DIV, REM, MCH,
1007c478bd9Sstevel@tonic-gate 	EQ, EQ, LT, LEQ, GT, GEQ, NEQ,
101*cc22b130SRich Burridge 	MATCH,
102*cc22b130SRich Burridge 	SUBSTR, LENGTH, INDEX
1037c478bd9Sstevel@tonic-gate 	};
1047c478bd9Sstevel@tonic-gate static	int pri[] = {
105*cc22b130SRich Burridge 	1, 2, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6, 7,
106*cc22b130SRich Burridge 	7, 7, 7
1077c478bd9Sstevel@tonic-gate 	};
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate  * clean_buf - XCU4 mod to remove leading zeros from negative signed
1127c478bd9Sstevel@tonic-gate  *		numeric output, e.g., -00001 becomes -1
1137c478bd9Sstevel@tonic-gate  */
1147c478bd9Sstevel@tonic-gate static void
1157c478bd9Sstevel@tonic-gate clean_buf(buf)
1167c478bd9Sstevel@tonic-gate 	char *buf;
1177c478bd9Sstevel@tonic-gate {
1187c478bd9Sstevel@tonic-gate 	int i = 0;
1197c478bd9Sstevel@tonic-gate 	int is_a_num = 1;
1207c478bd9Sstevel@tonic-gate 	int len;
1217c478bd9Sstevel@tonic-gate 	long long num;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	if (buf[0] == '\0')
1247c478bd9Sstevel@tonic-gate 		return;
1257c478bd9Sstevel@tonic-gate 	len = strlen(buf);
1267c478bd9Sstevel@tonic-gate 	if (len <= 0)
1277c478bd9Sstevel@tonic-gate 		return;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	if (buf[0] == '-') {
1307c478bd9Sstevel@tonic-gate 		i++;		/* Skip the leading '-' see while loop */
1317c478bd9Sstevel@tonic-gate 		if (len <= 1)	/* Is it a '-' all by itself? */
1327c478bd9Sstevel@tonic-gate 			return; /* Yes, so return */
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 		while (i < len) {
1357c478bd9Sstevel@tonic-gate 			if (! isdigit(buf[i])) {
1367c478bd9Sstevel@tonic-gate 				is_a_num = 0;
1377c478bd9Sstevel@tonic-gate 				break;
1387c478bd9Sstevel@tonic-gate 			}
1397c478bd9Sstevel@tonic-gate 			i++;
1407c478bd9Sstevel@tonic-gate 		}
1417c478bd9Sstevel@tonic-gate 		if (is_a_num) {
1427c478bd9Sstevel@tonic-gate 			(void) sscanf(buf, "%lld", &num);
1437c478bd9Sstevel@tonic-gate 			(void) sprintf(buf, "%lld", num);
1447c478bd9Sstevel@tonic-gate 		}
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * End XCU4 mods.
1507c478bd9Sstevel@tonic-gate  */
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate static int
1537c478bd9Sstevel@tonic-gate yylex()
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate 	char *p;
1567c478bd9Sstevel@tonic-gate 	int i;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	if (Argi >= Ac)
1597c478bd9Sstevel@tonic-gate 		return (NOARG);
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	p = Av[Argi];
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	if ((*p == '(' || *p == ')') && p[1] == '\0')
1647c478bd9Sstevel@tonic-gate 		return ((int)*p);
1657c478bd9Sstevel@tonic-gate 	for (i = 0; *operator[i]; ++i)
1667c478bd9Sstevel@tonic-gate 		if (EQL(operator[i], p))
1677c478bd9Sstevel@tonic-gate 			return (op[i]);
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	return (A_STRING);
1717c478bd9Sstevel@tonic-gate }
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate static char
1747c478bd9Sstevel@tonic-gate *rel(oper, r1, r2) register char *r1, *r2;
1757c478bd9Sstevel@tonic-gate {
1769d14cf08Spd 	long long i, l1, l2;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	if (ematch(r1, "-\\{0,1\\}[0-9]*$") &&
1797c478bd9Sstevel@tonic-gate 	    ematch(r2, "-\\{0,1\\}[0-9]*$")) {
1807c478bd9Sstevel@tonic-gate 		errno = 0;
1819d14cf08Spd 		l1 = strtoll(r1, (char **)NULL, 10);
1829d14cf08Spd 		l2 = strtoll(r2, (char **)NULL, 10);
1837c478bd9Sstevel@tonic-gate 		if (errno) {
1847c478bd9Sstevel@tonic-gate #ifdef XPG6
1857c478bd9Sstevel@tonic-gate 		/* XPG6: stdout will always contain newline even on error */
1867c478bd9Sstevel@tonic-gate 			(void) write(1, "\n", 1);
1877c478bd9Sstevel@tonic-gate #endif
1887c478bd9Sstevel@tonic-gate 			if (errno == ERANGE) {
1897c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1907c478bd9Sstevel@tonic-gate 				    "expr: Integer argument too large\n"));
1917c478bd9Sstevel@tonic-gate 				exit(3);
1927c478bd9Sstevel@tonic-gate 			} else {
1937c478bd9Sstevel@tonic-gate 				perror("expr");
1947c478bd9Sstevel@tonic-gate 				exit(3);
1957c478bd9Sstevel@tonic-gate 			}
1967c478bd9Sstevel@tonic-gate 		}
1979d14cf08Spd 		switch (oper) {
1989d14cf08Spd 		case EQ:
1999d14cf08Spd 			i = (l1 == l2);
2009d14cf08Spd 			break;
2019d14cf08Spd 		case GT:
2029d14cf08Spd 			i = (l1 > l2);
2039d14cf08Spd 			break;
2049d14cf08Spd 		case GEQ:
2059d14cf08Spd 			i = (l1 >= l2);
2069d14cf08Spd 			break;
2079d14cf08Spd 		case LT:
2089d14cf08Spd 			i = (l1 < l2);
2099d14cf08Spd 			break;
2109d14cf08Spd 		case LEQ:
2119d14cf08Spd 			i = (l1 <= l2);
2129d14cf08Spd 			break;
2139d14cf08Spd 		case NEQ:
2149d14cf08Spd 			i = (l1 != l2);
2159d14cf08Spd 			break;
2169d14cf08Spd 		}
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 	else
2199d14cf08Spd 	{
2209d14cf08Spd 			i = strcoll(r1, r2);
2219d14cf08Spd 		switch (oper) {
2229d14cf08Spd 		case EQ:
2239d14cf08Spd 			i = i == 0;
2249d14cf08Spd 			break;
2259d14cf08Spd 		case GT:
2269d14cf08Spd 			i = i > 0;
2279d14cf08Spd 			break;
2289d14cf08Spd 		case GEQ:
2299d14cf08Spd 			i = i >= 0;
2309d14cf08Spd 			break;
2319d14cf08Spd 		case LT:
2329d14cf08Spd 			i = i < 0;
2339d14cf08Spd 			break;
2349d14cf08Spd 		case LEQ:
2359d14cf08Spd 			i = i <= 0;
2369d14cf08Spd 			break;
2379d14cf08Spd 		case NEQ:
2389d14cf08Spd 			i = i != 0;
2399d14cf08Spd 			break;
2409d14cf08Spd 		}
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 	return (i ? "1": "0");
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate static char
2467c478bd9Sstevel@tonic-gate *arith(oper, r1, r2) char *r1, *r2;
2477c478bd9Sstevel@tonic-gate {
2487c478bd9Sstevel@tonic-gate 	long long i1, i2;
2497c478bd9Sstevel@tonic-gate 	register char *rv;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	if (!(ematch(r1, "-\\{0,1\\}[0-9]*$") &&
2527c478bd9Sstevel@tonic-gate 	    ematch(r2, "-\\{0,1\\}[0-9]*$")))
2537c478bd9Sstevel@tonic-gate 		yyerror("non-numeric argument");
2547c478bd9Sstevel@tonic-gate 	errno = 0;
2557c478bd9Sstevel@tonic-gate 	i1 = strtoll(r1, (char **)NULL, 10);
2567c478bd9Sstevel@tonic-gate 	i2 = strtoll(r2, (char **)NULL, 10);
2577c478bd9Sstevel@tonic-gate 	if (errno) {
2587c478bd9Sstevel@tonic-gate #ifdef XPG6
2597c478bd9Sstevel@tonic-gate 	/* XPG6: stdout will always contain newline even on error */
2607c478bd9Sstevel@tonic-gate 		(void) write(1, "\n", 1);
2617c478bd9Sstevel@tonic-gate #endif
2627c478bd9Sstevel@tonic-gate 		if (errno == ERANGE) {
2637c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
2647c478bd9Sstevel@tonic-gate 			    "expr: Integer argument too large\n"));
2657c478bd9Sstevel@tonic-gate 			exit(3);
2667c478bd9Sstevel@tonic-gate 		} else {
2677c478bd9Sstevel@tonic-gate 			perror("expr");
2687c478bd9Sstevel@tonic-gate 			exit(3);
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	switch (oper) {
2737c478bd9Sstevel@tonic-gate 	case ADD:
2747c478bd9Sstevel@tonic-gate 		i1 = i1 + i2;
2757c478bd9Sstevel@tonic-gate 		break;
2767c478bd9Sstevel@tonic-gate 	case SUBT:
2777c478bd9Sstevel@tonic-gate 		i1 = i1 - i2;
2787c478bd9Sstevel@tonic-gate 		break;
2797c478bd9Sstevel@tonic-gate 	case MULT:
2807c478bd9Sstevel@tonic-gate 		i1 = i1 * i2;
2817c478bd9Sstevel@tonic-gate 		break;
2827c478bd9Sstevel@tonic-gate 	case DIV:
2837c478bd9Sstevel@tonic-gate 		if (i2 == 0)
2847c478bd9Sstevel@tonic-gate 			yyerror("division by zero");
2857c478bd9Sstevel@tonic-gate 		i1 = i1 / i2;
2867c478bd9Sstevel@tonic-gate 		break;
2877c478bd9Sstevel@tonic-gate 	case REM:
2887c478bd9Sstevel@tonic-gate 		if (i2 == 0)
2897c478bd9Sstevel@tonic-gate 			yyerror("division by zero");
2907c478bd9Sstevel@tonic-gate 		i1 = i1 % i2;
2917c478bd9Sstevel@tonic-gate 		break;
2927c478bd9Sstevel@tonic-gate 	}
2937c478bd9Sstevel@tonic-gate 	rv = exprmalloc(25);
2947c478bd9Sstevel@tonic-gate 	(void) strcpy(rv, lltoa(i1));
2957c478bd9Sstevel@tonic-gate 	return (rv);
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate static char
2997c478bd9Sstevel@tonic-gate *conj(oper, r1, r2)
3007c478bd9Sstevel@tonic-gate 	char *r1, *r2;
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate 	register char *rv;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	switch (oper) {
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	case OR:
3077c478bd9Sstevel@tonic-gate 		if (EQL(r1, "0") || EQL(r1, "")) {
3087c478bd9Sstevel@tonic-gate 			if (EQL(r2, "0") || EQL(r2, ""))
3097c478bd9Sstevel@tonic-gate 				rv = "0";
3107c478bd9Sstevel@tonic-gate 			else
3117c478bd9Sstevel@tonic-gate 				rv = r2;
3127c478bd9Sstevel@tonic-gate 		} else
3137c478bd9Sstevel@tonic-gate 			rv = r1;
3147c478bd9Sstevel@tonic-gate 		break;
3157c478bd9Sstevel@tonic-gate 	case AND:
3167c478bd9Sstevel@tonic-gate 		if (EQL(r1, "0") || EQL(r1, ""))
3177c478bd9Sstevel@tonic-gate 			rv = "0";
3187c478bd9Sstevel@tonic-gate 		else if (EQL(r2, "0") || EQL(r2, ""))
3197c478bd9Sstevel@tonic-gate 			rv = "0";
3207c478bd9Sstevel@tonic-gate 		else
3217c478bd9Sstevel@tonic-gate 			rv = r1;
3227c478bd9Sstevel@tonic-gate 		break;
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 	return (rv);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate char *
3287c478bd9Sstevel@tonic-gate substr(char *v, char *s, char *w)
3297c478bd9Sstevel@tonic-gate {
3307c478bd9Sstevel@tonic-gate 	int si, wi;
3317c478bd9Sstevel@tonic-gate 	char *res;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	si = atol(s);
3347c478bd9Sstevel@tonic-gate 	wi = atol(w);
3357c478bd9Sstevel@tonic-gate 	while (--si)
3367c478bd9Sstevel@tonic-gate 		if (*v) ++v;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	res = v;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	while (wi--)
3417c478bd9Sstevel@tonic-gate 		if (*v) ++v;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	*v = '\0';
3447c478bd9Sstevel@tonic-gate 	return (res);
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate char *
3487c478bd9Sstevel@tonic-gate index(char *s, char *t)
3497c478bd9Sstevel@tonic-gate {
3507c478bd9Sstevel@tonic-gate 	long i, j;
3517c478bd9Sstevel@tonic-gate 	char *rv;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	for (i = 0; s[i]; ++i)
3547c478bd9Sstevel@tonic-gate 		for (j = 0; t[j]; ++j)
3557c478bd9Sstevel@tonic-gate 			if (s[i] == t[j]) {
3567c478bd9Sstevel@tonic-gate 				(void) strcpy(rv = exprmalloc(8), ltoa(++i));
3577c478bd9Sstevel@tonic-gate 				return (rv);
3587c478bd9Sstevel@tonic-gate 			}
3597c478bd9Sstevel@tonic-gate 	return ("0");
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate char *
3637c478bd9Sstevel@tonic-gate length(char *s)
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate 	long i = 0;
3667c478bd9Sstevel@tonic-gate 	char *rv;
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	while (*s++) ++i;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	rv = exprmalloc(8);
3717c478bd9Sstevel@tonic-gate 	(void) strcpy(rv, ltoa(i));
3727c478bd9Sstevel@tonic-gate 	return (rv);
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate static char *
3767c478bd9Sstevel@tonic-gate match(char *s, char *p)
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate 	char *rv;
3797c478bd9Sstevel@tonic-gate 	long val;			/* XCU4 */
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	(void) strcpy(rv = exprmalloc(8), ltoa(val = (long)ematch(s, p)));
3827c478bd9Sstevel@tonic-gate 	if (nbra /* && val != 0 */) {
3837c478bd9Sstevel@tonic-gate 		rv = exprmalloc((unsigned)strlen(Mstring[0]) + 1);
3847c478bd9Sstevel@tonic-gate 		(void) strcpy(rv, Mstring[0]);
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 	return (rv);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate /*
3917c478bd9Sstevel@tonic-gate  * ematch 	- XCU4 mods involve calling compile/advance which simulate
3927c478bd9Sstevel@tonic-gate  *		  the obsolete compile/advance functions using regcomp/regexec
3937c478bd9Sstevel@tonic-gate  */
3947c478bd9Sstevel@tonic-gate static int
3957c478bd9Sstevel@tonic-gate ematch(char *s, char *p)
3967c478bd9Sstevel@tonic-gate {
3977c478bd9Sstevel@tonic-gate 	static char *expbuf;
3987c478bd9Sstevel@tonic-gate 	char *nexpbuf;
3997c478bd9Sstevel@tonic-gate 	int num;
4007c478bd9Sstevel@tonic-gate #ifdef XPG4
4017c478bd9Sstevel@tonic-gate 	int nmatch;		/* number of matched bytes */
4027c478bd9Sstevel@tonic-gate 	char tempbuf[256];
4037c478bd9Sstevel@tonic-gate 	char *tmptr1 = 0;	/* If tempbuf is not large enough */
4047c478bd9Sstevel@tonic-gate 	char *tmptr;
4057c478bd9Sstevel@tonic-gate 	int nmbchars;		/* number characters in multibyte string */
4067c478bd9Sstevel@tonic-gate #endif
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	nexpbuf = compile(p, (char *)0, (char *)0);	/* XCU4 regex mod */
4097c478bd9Sstevel@tonic-gate 	if (0 /* XXX nbra > 1*/)
4107c478bd9Sstevel@tonic-gate 		yyerror("Too many '\\('s");
4117c478bd9Sstevel@tonic-gate 	if (regerrno) {
4127c478bd9Sstevel@tonic-gate 		if (regerrno != 41 || expbuf == NULL)
4137c478bd9Sstevel@tonic-gate 			errxx();
4147c478bd9Sstevel@tonic-gate 	} else {
4157c478bd9Sstevel@tonic-gate 		if (expbuf)
4167c478bd9Sstevel@tonic-gate 			free(expbuf);
4177c478bd9Sstevel@tonic-gate 		expbuf = nexpbuf;
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate 	if (advance(s, expbuf)) {
4207c478bd9Sstevel@tonic-gate 		if (nbra > 0) {
4217c478bd9Sstevel@tonic-gate 			p = braslist[0];
4227c478bd9Sstevel@tonic-gate 			num = braelist[0] - p;
4237c478bd9Sstevel@tonic-gate 			if ((num > MSIZE - 1) || (num < 0))
4247c478bd9Sstevel@tonic-gate 				yyerror("string too long");
4257c478bd9Sstevel@tonic-gate 			(void) strncpy(Mstring[0], p, num);
4267c478bd9Sstevel@tonic-gate 			Mstring[0][num] = '\0';
4277c478bd9Sstevel@tonic-gate 		}
4287c478bd9Sstevel@tonic-gate #ifdef XPG4
4297c478bd9Sstevel@tonic-gate 		/*
4307c478bd9Sstevel@tonic-gate 		 *  Use mbstowcs to find the number of multibyte characters
4317c478bd9Sstevel@tonic-gate 		 *  in the multibyte string beginning at s, and
4327c478bd9Sstevel@tonic-gate 		 *  ending at loc2.  Create a separate string
4337c478bd9Sstevel@tonic-gate 		 *  of the substring, so it can be passed to mbstowcs.
4347c478bd9Sstevel@tonic-gate 		 */
4357c478bd9Sstevel@tonic-gate 		nmatch = loc2 - s;
4367c478bd9Sstevel@tonic-gate 		if (nmatch > ((sizeof (tempbuf) / sizeof (char)) - 1)) {
4377c478bd9Sstevel@tonic-gate 			tmptr1 = exprmalloc(nmatch + 1);
4387c478bd9Sstevel@tonic-gate 			tmptr = tmptr1;
4397c478bd9Sstevel@tonic-gate 		} else {
4407c478bd9Sstevel@tonic-gate 			tmptr = tempbuf;
4417c478bd9Sstevel@tonic-gate 		}
4427c478bd9Sstevel@tonic-gate 		memcpy(tmptr, s, nmatch);
4437c478bd9Sstevel@tonic-gate 		*(tmptr + nmatch) = '\0';
4447c478bd9Sstevel@tonic-gate 		if ((nmbchars = mbstowcs(NULL, tmptr, NULL)) == -1) {
4457c478bd9Sstevel@tonic-gate 			yyerror("invalid multibyte character encountered");
4467c478bd9Sstevel@tonic-gate 			if (tmptr1 != NULL)
4477c478bd9Sstevel@tonic-gate 				free(tmptr1);
4487c478bd9Sstevel@tonic-gate 			return (0);
4497c478bd9Sstevel@tonic-gate 		}
4507c478bd9Sstevel@tonic-gate 		if (tmptr1 != NULL)
4517c478bd9Sstevel@tonic-gate 			free(tmptr1);
4527c478bd9Sstevel@tonic-gate 		return (nmbchars);
4537c478bd9Sstevel@tonic-gate #else
4547c478bd9Sstevel@tonic-gate 		return (loc2-s);
4557c478bd9Sstevel@tonic-gate #endif
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 	return (0);
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate static void
4617c478bd9Sstevel@tonic-gate errxx()
4627c478bd9Sstevel@tonic-gate {
4637c478bd9Sstevel@tonic-gate 	yyerror("RE error");
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate static void
4677c478bd9Sstevel@tonic-gate yyerror(char *s)
4687c478bd9Sstevel@tonic-gate {
4697c478bd9Sstevel@tonic-gate #ifdef XPG6
4707c478bd9Sstevel@tonic-gate 	/* XPG6: stdout will always contain newline even on error */
4717c478bd9Sstevel@tonic-gate 	(void) write(1, "\n", 1);
4727c478bd9Sstevel@tonic-gate #endif
4737c478bd9Sstevel@tonic-gate 	(void) write(2, "expr: ", 6);
4747c478bd9Sstevel@tonic-gate 	(void) write(2, gettext(s), (unsigned)strlen(gettext(s)));
4757c478bd9Sstevel@tonic-gate 	(void) write(2, "\n", 1);
4767c478bd9Sstevel@tonic-gate 	exit(2);
4777c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate static char *
4817c478bd9Sstevel@tonic-gate ltoa(long l)
4827c478bd9Sstevel@tonic-gate {
4837c478bd9Sstevel@tonic-gate 	static char str[20];
4847c478bd9Sstevel@tonic-gate 	char *sp = &str[18];	/* u370 */
4857c478bd9Sstevel@tonic-gate 	int i;
4867c478bd9Sstevel@tonic-gate 	int neg = 0;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	if ((unsigned long)l == 0x80000000UL)
4897c478bd9Sstevel@tonic-gate 		return ("-2147483648");
4907c478bd9Sstevel@tonic-gate 	if (l < 0)
4917c478bd9Sstevel@tonic-gate 		++neg, l = -l;
4927c478bd9Sstevel@tonic-gate 	str[19] = '\0';
4937c478bd9Sstevel@tonic-gate 	do {
4947c478bd9Sstevel@tonic-gate 		i = l % 10;
4957c478bd9Sstevel@tonic-gate 		*sp-- = '0' + i;
4967c478bd9Sstevel@tonic-gate 		l /= 10;
4977c478bd9Sstevel@tonic-gate 	} while (l);
4987c478bd9Sstevel@tonic-gate 	if (neg)
4997c478bd9Sstevel@tonic-gate 		*sp-- = '-';
5007c478bd9Sstevel@tonic-gate 	return (++sp);
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate static char *
5047c478bd9Sstevel@tonic-gate lltoa(long long l)
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 	static char str[25];
5077c478bd9Sstevel@tonic-gate 	char *sp = &str[23];
5087c478bd9Sstevel@tonic-gate 	int i;
5097c478bd9Sstevel@tonic-gate 	int neg = 0;
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	if (l == 0x8000000000000000ULL)
5127c478bd9Sstevel@tonic-gate 		return ("-9223372036854775808");
5137c478bd9Sstevel@tonic-gate 	if (l < 0)
5147c478bd9Sstevel@tonic-gate 		++neg, l = -l;
5157c478bd9Sstevel@tonic-gate 	str[24] = '\0';
5167c478bd9Sstevel@tonic-gate 	do {
5177c478bd9Sstevel@tonic-gate 		i = l % 10;
5187c478bd9Sstevel@tonic-gate 		*sp-- = '0' + i;
5197c478bd9Sstevel@tonic-gate 		l /= 10;
5207c478bd9Sstevel@tonic-gate 	} while (l);
5217c478bd9Sstevel@tonic-gate 	if (neg)
5227c478bd9Sstevel@tonic-gate 		*sp-- = '-';
5237c478bd9Sstevel@tonic-gate 	return (++sp);
5247c478bd9Sstevel@tonic-gate }
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate static char *
5277c478bd9Sstevel@tonic-gate expres(int prior, int par)
5287c478bd9Sstevel@tonic-gate {
5297c478bd9Sstevel@tonic-gate 	int ylex, temp, op1;
5307c478bd9Sstevel@tonic-gate 	char *r1, *ra, *rb, *rc;
5317c478bd9Sstevel@tonic-gate 	ylex = yylex();
5327c478bd9Sstevel@tonic-gate 	if (ylex >= NOARG && ylex < MATCH) {
5337c478bd9Sstevel@tonic-gate 		yyerror("syntax error");
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 	if (ylex == A_STRING) {
5367c478bd9Sstevel@tonic-gate 		r1 = Av[Argi++];
5377c478bd9Sstevel@tonic-gate 		temp = Argi;
5387c478bd9Sstevel@tonic-gate 	} else {
5397c478bd9Sstevel@tonic-gate 		if (ylex == '(') {
5407c478bd9Sstevel@tonic-gate 			paren++;
5417c478bd9Sstevel@tonic-gate 			Argi++;
5427c478bd9Sstevel@tonic-gate 			r1 = expres(0, Argi);
5437c478bd9Sstevel@tonic-gate 			Argi--;
5447c478bd9Sstevel@tonic-gate 		}
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate lop:
5477c478bd9Sstevel@tonic-gate 	ylex = yylex();
5487c478bd9Sstevel@tonic-gate 	if (ylex > NOARG && ylex < MATCH) {
5497c478bd9Sstevel@tonic-gate 		op1 = ylex;
5507c478bd9Sstevel@tonic-gate 		Argi++;
5517c478bd9Sstevel@tonic-gate 		if (pri[op1-OR] <= prior)
5527c478bd9Sstevel@tonic-gate 			return (r1);
5537c478bd9Sstevel@tonic-gate 		else {
5547c478bd9Sstevel@tonic-gate 			switch (op1) {
5557c478bd9Sstevel@tonic-gate 			case OR:
5567c478bd9Sstevel@tonic-gate 			case AND:
5577c478bd9Sstevel@tonic-gate 				r1 = conj(op1, r1, expres(pri[op1-OR], 0));
5587c478bd9Sstevel@tonic-gate 				break;
5597c478bd9Sstevel@tonic-gate 			case EQ:
5607c478bd9Sstevel@tonic-gate 			case LT:
5617c478bd9Sstevel@tonic-gate 			case GT:
5627c478bd9Sstevel@tonic-gate 			case LEQ:
5637c478bd9Sstevel@tonic-gate 			case GEQ:
5647c478bd9Sstevel@tonic-gate 			case NEQ:
5657c478bd9Sstevel@tonic-gate 				r1 = rel(op1, r1, expres(pri[op1-OR], 0));
5667c478bd9Sstevel@tonic-gate 				break;
5677c478bd9Sstevel@tonic-gate 			case ADD:
5687c478bd9Sstevel@tonic-gate 			case SUBT:
5697c478bd9Sstevel@tonic-gate 			case MULT:
5707c478bd9Sstevel@tonic-gate 			case DIV:
5717c478bd9Sstevel@tonic-gate 			case REM:
5727c478bd9Sstevel@tonic-gate 				r1 = arith(op1, r1, expres(pri[op1-OR], 0));
5737c478bd9Sstevel@tonic-gate 				break;
5747c478bd9Sstevel@tonic-gate 			case MCH:
5757c478bd9Sstevel@tonic-gate 				r1 = match(r1, expres(pri[op1-OR], 0));
5767c478bd9Sstevel@tonic-gate 				break;
5777c478bd9Sstevel@tonic-gate 			}
5787c478bd9Sstevel@tonic-gate 			if (noarg == 1) {
5797c478bd9Sstevel@tonic-gate 				return (r1);
5807c478bd9Sstevel@tonic-gate 			}
5817c478bd9Sstevel@tonic-gate 			Argi--;
5827c478bd9Sstevel@tonic-gate 			goto lop;
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 	ylex = yylex();
5867c478bd9Sstevel@tonic-gate 	if (ylex == ')') {
5877c478bd9Sstevel@tonic-gate 		if (par == Argi) {
5887c478bd9Sstevel@tonic-gate 			yyerror("syntax error");
5897c478bd9Sstevel@tonic-gate 		}
5907c478bd9Sstevel@tonic-gate 		if (par != 0) {
5917c478bd9Sstevel@tonic-gate 			paren--;
5927c478bd9Sstevel@tonic-gate 			Argi++;
5937c478bd9Sstevel@tonic-gate 		}
5947c478bd9Sstevel@tonic-gate 		Argi++;
5957c478bd9Sstevel@tonic-gate 		return (r1);
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate 	ylex = yylex();
598*cc22b130SRich Burridge 	if (ylex > MCH && ylex <= INDEX) {
5997c478bd9Sstevel@tonic-gate 		if (Argi == temp) {
6007c478bd9Sstevel@tonic-gate 			return (r1);
6017c478bd9Sstevel@tonic-gate 		}
6027c478bd9Sstevel@tonic-gate 		op1 = ylex;
6037c478bd9Sstevel@tonic-gate 		Argi++;
6047c478bd9Sstevel@tonic-gate 		switch (op1) {
6057c478bd9Sstevel@tonic-gate 		case MATCH:
6067c478bd9Sstevel@tonic-gate 			rb = expres(pri[op1-OR], 0);
6077c478bd9Sstevel@tonic-gate 			ra = expres(pri[op1-OR], 0);
6087c478bd9Sstevel@tonic-gate 			break;
6097c478bd9Sstevel@tonic-gate 		case SUBSTR:
6107c478bd9Sstevel@tonic-gate 			rc = expres(pri[op1-OR], 0);
6117c478bd9Sstevel@tonic-gate 			rb = expres(pri[op1-OR], 0);
6127c478bd9Sstevel@tonic-gate 			ra = expres(pri[op1-OR], 0);
6137c478bd9Sstevel@tonic-gate 			break;
6147c478bd9Sstevel@tonic-gate 		case LENGTH:
6157c478bd9Sstevel@tonic-gate 			ra = expres(pri[op1-OR], 0);
6167c478bd9Sstevel@tonic-gate 			break;
6177c478bd9Sstevel@tonic-gate 		case INDEX:
6187c478bd9Sstevel@tonic-gate 			rb = expres(pri[op1-OR], 0);
6197c478bd9Sstevel@tonic-gate 			ra = expres(pri[op1-OR], 0);
6207c478bd9Sstevel@tonic-gate 			break;
6217c478bd9Sstevel@tonic-gate 		}
6227c478bd9Sstevel@tonic-gate 		switch (op1) {
6237c478bd9Sstevel@tonic-gate 		case MATCH:
6247c478bd9Sstevel@tonic-gate 			r1 = match(rb, ra);
6257c478bd9Sstevel@tonic-gate 			break;
6267c478bd9Sstevel@tonic-gate 		case SUBSTR:
6277c478bd9Sstevel@tonic-gate 			r1 = substr(rc, rb, ra);
6287c478bd9Sstevel@tonic-gate 			break;
6297c478bd9Sstevel@tonic-gate 		case LENGTH:
6307c478bd9Sstevel@tonic-gate 			r1 = length(ra);
6317c478bd9Sstevel@tonic-gate 			break;
6327c478bd9Sstevel@tonic-gate 		case INDEX:
6337c478bd9Sstevel@tonic-gate 			r1 = index(rb, ra);
6347c478bd9Sstevel@tonic-gate 			break;
6357c478bd9Sstevel@tonic-gate 		}
6367c478bd9Sstevel@tonic-gate 		if (noarg == 1) {
6377c478bd9Sstevel@tonic-gate 			return (r1);
6387c478bd9Sstevel@tonic-gate 		}
6397c478bd9Sstevel@tonic-gate 		Argi--;
6407c478bd9Sstevel@tonic-gate 		goto lop;
6417c478bd9Sstevel@tonic-gate 	}
6427c478bd9Sstevel@tonic-gate 	ylex = yylex();
6437c478bd9Sstevel@tonic-gate 	if (ylex == NOARG) {
6447c478bd9Sstevel@tonic-gate 		noarg = 1;
6457c478bd9Sstevel@tonic-gate 	}
6467c478bd9Sstevel@tonic-gate 	return (r1);
6477c478bd9Sstevel@tonic-gate }
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate void *
6507c478bd9Sstevel@tonic-gate exprmalloc(size_t size)
6517c478bd9Sstevel@tonic-gate {
6527c478bd9Sstevel@tonic-gate 	void *rv;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	if ((rv = malloc(size)) == NULL) {
6557c478bd9Sstevel@tonic-gate 		char *s = gettext("malloc error");
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 		(void) write(2, "expr: ", 6);
6587c478bd9Sstevel@tonic-gate 		(void) write(2, s, (unsigned)strlen(s));
6597c478bd9Sstevel@tonic-gate 		(void) write(2, "\n", 1);
6607c478bd9Sstevel@tonic-gate 		exit(3);
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 	return (rv);
6637c478bd9Sstevel@tonic-gate }
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate int
6667c478bd9Sstevel@tonic-gate main(int argc, char **argv)
6677c478bd9Sstevel@tonic-gate {
6687c478bd9Sstevel@tonic-gate 	/*
6697c478bd9Sstevel@tonic-gate 	 * XCU4 allow "--" as argument
6707c478bd9Sstevel@tonic-gate 	 */
6717c478bd9Sstevel@tonic-gate 	if (argc > 1 && strcmp(argv[1], "--") == 0)
6727c478bd9Sstevel@tonic-gate 		argv++, argc--;
6737c478bd9Sstevel@tonic-gate 	/*
6747c478bd9Sstevel@tonic-gate 	 * XCU4 - print usage message when invoked without args
6757c478bd9Sstevel@tonic-gate 	 */
6767c478bd9Sstevel@tonic-gate 	if (argc < 2) {
6777c478bd9Sstevel@tonic-gate #ifdef XPG6
6787c478bd9Sstevel@tonic-gate 	/* XPG6: stdout will always contain newline even on error */
6797c478bd9Sstevel@tonic-gate 		(void) write(1, "\n", 1);
6807c478bd9Sstevel@tonic-gate #endif
6817c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Usage: expr expression\n"));
6827c478bd9Sstevel@tonic-gate 		exit(3);
6837c478bd9Sstevel@tonic-gate 	}
6847c478bd9Sstevel@tonic-gate 	Ac = argc;
6857c478bd9Sstevel@tonic-gate 	Argi = 1;
6867c478bd9Sstevel@tonic-gate 	noarg = 0;
6877c478bd9Sstevel@tonic-gate 	paren = 0;
6887c478bd9Sstevel@tonic-gate 	Av = argv;
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
6917c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
6927c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
6937c478bd9Sstevel@tonic-gate #endif
6947c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
6957c478bd9Sstevel@tonic-gate 	buf = expres(0, 1);
6967c478bd9Sstevel@tonic-gate 	if (Ac != Argi || paren != 0) {
6977c478bd9Sstevel@tonic-gate 		yyerror("syntax error");
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 	/*
7007c478bd9Sstevel@tonic-gate 	 * XCU4 - strip leading zeros from numeric output
7017c478bd9Sstevel@tonic-gate 	 */
7027c478bd9Sstevel@tonic-gate 	clean_buf(buf);
7037c478bd9Sstevel@tonic-gate 	(void) write(1, buf, (unsigned)strlen(buf));
7047c478bd9Sstevel@tonic-gate 	(void) write(1, "\n", 1);
7057c478bd9Sstevel@tonic-gate 	return ((strcmp(buf, "0") == 0 || buf[0] == 0) ? 1 : 0);
7067c478bd9Sstevel@tonic-gate }
707