xref: /onnv-gate/usr/src/cmd/expr/expr.c (revision 12836:0d0733997434)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*12836Srich.burridge@oracle.com  * Common Development and Distribution License (the "License").
6*12836Srich.burridge@oracle.com  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
220Sstevel@tonic-gate /*	  All Rights Reserved  	*/
230Sstevel@tonic-gate 
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
26*12836Srich.burridge@oracle.com  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <stdlib.h>
300Sstevel@tonic-gate #include <regexpr.h>
310Sstevel@tonic-gate #include <locale.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include <unistd.h>
340Sstevel@tonic-gate #include <regex.h>
350Sstevel@tonic-gate #include <limits.h>
360Sstevel@tonic-gate #include <stdio.h>
370Sstevel@tonic-gate #include <ctype.h>
380Sstevel@tonic-gate #include <errno.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #define	A_STRING 258
410Sstevel@tonic-gate #define	NOARG 259
420Sstevel@tonic-gate #define	OR 260
430Sstevel@tonic-gate #define	AND 261
440Sstevel@tonic-gate #define	EQ 262
450Sstevel@tonic-gate #define	LT 263
460Sstevel@tonic-gate #define	GT 264
470Sstevel@tonic-gate #define	GEQ 265
480Sstevel@tonic-gate #define	LEQ 266
490Sstevel@tonic-gate #define	NEQ 267
500Sstevel@tonic-gate #define	ADD 268
510Sstevel@tonic-gate #define	SUBT 269
520Sstevel@tonic-gate #define	MULT 270
530Sstevel@tonic-gate #define	DIV 271
540Sstevel@tonic-gate #define	REM 272
550Sstevel@tonic-gate #define	MCH 273
560Sstevel@tonic-gate #define	MATCH 274
57*12836Srich.burridge@oracle.com #define	SUBSTR 275
58*12836Srich.burridge@oracle.com #define	LENGTH 276
59*12836Srich.burridge@oracle.com #define	INDEX  277
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /* size of subexpression array */
620Sstevel@tonic-gate #define	MSIZE	LINE_MAX
630Sstevel@tonic-gate #define	error(c)	errxx()
640Sstevel@tonic-gate #define	EQL(x, y) (strcmp(x, y) == 0)
650Sstevel@tonic-gate 
660Sstevel@tonic-gate #define	ERROR(c)	errxx()
670Sstevel@tonic-gate #define	MAX_MATCH 20
680Sstevel@tonic-gate static int ematch(char *, char *);
690Sstevel@tonic-gate static void yyerror(char *);
700Sstevel@tonic-gate static void errxx();
710Sstevel@tonic-gate static void *exprmalloc(size_t size);
720Sstevel@tonic-gate 
730Sstevel@tonic-gate long atol();
740Sstevel@tonic-gate char *strcpy(), *strncpy();
750Sstevel@tonic-gate void exit();
760Sstevel@tonic-gate 
770Sstevel@tonic-gate static char *ltoa();
780Sstevel@tonic-gate static char *lltoa();
790Sstevel@tonic-gate static char	**Av;
800Sstevel@tonic-gate static char *buf;
810Sstevel@tonic-gate static int	Ac;
820Sstevel@tonic-gate static int	Argi;
830Sstevel@tonic-gate static int noarg;
840Sstevel@tonic-gate static int paren;
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate  *	Array used to store subexpressions in regular expressions
870Sstevel@tonic-gate  *	Only one subexpression allowed per regular expression currently
880Sstevel@tonic-gate  */
890Sstevel@tonic-gate static char Mstring[1][MSIZE];
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 
920Sstevel@tonic-gate static char *operator[] = {
930Sstevel@tonic-gate 	"|", "&", "+", "-", "*", "/", "%", ":",
940Sstevel@tonic-gate 	"=", "==", "<", "<=", ">", ">=", "!=",
950Sstevel@tonic-gate 	"match",
960Sstevel@tonic-gate 	"substr", "length", "index",
970Sstevel@tonic-gate 	"\0" };
980Sstevel@tonic-gate static	int op[] = {
990Sstevel@tonic-gate 	OR, AND, ADD,  SUBT, MULT, DIV, REM, MCH,
1000Sstevel@tonic-gate 	EQ, EQ, LT, LEQ, GT, GEQ, NEQ,
101*12836Srich.burridge@oracle.com 	MATCH,
102*12836Srich.burridge@oracle.com 	SUBSTR, LENGTH, INDEX
1030Sstevel@tonic-gate 	};
1040Sstevel@tonic-gate static	int pri[] = {
105*12836Srich.burridge@oracle.com 	1, 2, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6, 7,
106*12836Srich.burridge@oracle.com 	7, 7, 7
1070Sstevel@tonic-gate 	};
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate /*
1110Sstevel@tonic-gate  * clean_buf - XCU4 mod to remove leading zeros from negative signed
1120Sstevel@tonic-gate  *		numeric output, e.g., -00001 becomes -1
1130Sstevel@tonic-gate  */
1140Sstevel@tonic-gate static void
clean_buf(buf)1150Sstevel@tonic-gate clean_buf(buf)
1160Sstevel@tonic-gate 	char *buf;
1170Sstevel@tonic-gate {
1180Sstevel@tonic-gate 	int i = 0;
1190Sstevel@tonic-gate 	int is_a_num = 1;
1200Sstevel@tonic-gate 	int len;
1210Sstevel@tonic-gate 	long long num;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	if (buf[0] == '\0')
1240Sstevel@tonic-gate 		return;
1250Sstevel@tonic-gate 	len = strlen(buf);
1260Sstevel@tonic-gate 	if (len <= 0)
1270Sstevel@tonic-gate 		return;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	if (buf[0] == '-') {
1300Sstevel@tonic-gate 		i++;		/* Skip the leading '-' see while loop */
1310Sstevel@tonic-gate 		if (len <= 1)	/* Is it a '-' all by itself? */
1320Sstevel@tonic-gate 			return; /* Yes, so return */
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 		while (i < len) {
1350Sstevel@tonic-gate 			if (! isdigit(buf[i])) {
1360Sstevel@tonic-gate 				is_a_num = 0;
1370Sstevel@tonic-gate 				break;
1380Sstevel@tonic-gate 			}
1390Sstevel@tonic-gate 			i++;
1400Sstevel@tonic-gate 		}
1410Sstevel@tonic-gate 		if (is_a_num) {
1420Sstevel@tonic-gate 			(void) sscanf(buf, "%lld", &num);
1430Sstevel@tonic-gate 			(void) sprintf(buf, "%lld", num);
1440Sstevel@tonic-gate 		}
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate /*
1490Sstevel@tonic-gate  * End XCU4 mods.
1500Sstevel@tonic-gate  */
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate static int
yylex()1530Sstevel@tonic-gate yylex()
1540Sstevel@tonic-gate {
1550Sstevel@tonic-gate 	char *p;
1560Sstevel@tonic-gate 	int i;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	if (Argi >= Ac)
1590Sstevel@tonic-gate 		return (NOARG);
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	p = Av[Argi];
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	if ((*p == '(' || *p == ')') && p[1] == '\0')
1640Sstevel@tonic-gate 		return ((int)*p);
1650Sstevel@tonic-gate 	for (i = 0; *operator[i]; ++i)
1660Sstevel@tonic-gate 		if (EQL(operator[i], p))
1670Sstevel@tonic-gate 			return (op[i]);
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	return (A_STRING);
1710Sstevel@tonic-gate }
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate static char
rel(oper,r1,r2)1740Sstevel@tonic-gate *rel(oper, r1, r2) register char *r1, *r2;
1750Sstevel@tonic-gate {
1761355Spd155743 	long long i, l1, l2;
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	if (ematch(r1, "-\\{0,1\\}[0-9]*$") &&
1790Sstevel@tonic-gate 	    ematch(r2, "-\\{0,1\\}[0-9]*$")) {
1800Sstevel@tonic-gate 		errno = 0;
1811355Spd155743 		l1 = strtoll(r1, (char **)NULL, 10);
1821355Spd155743 		l2 = strtoll(r2, (char **)NULL, 10);
1830Sstevel@tonic-gate 		if (errno) {
1840Sstevel@tonic-gate #ifdef XPG6
1850Sstevel@tonic-gate 		/* XPG6: stdout will always contain newline even on error */
1860Sstevel@tonic-gate 			(void) write(1, "\n", 1);
1870Sstevel@tonic-gate #endif
1880Sstevel@tonic-gate 			if (errno == ERANGE) {
1890Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1900Sstevel@tonic-gate 				    "expr: Integer argument too large\n"));
1910Sstevel@tonic-gate 				exit(3);
1920Sstevel@tonic-gate 			} else {
1930Sstevel@tonic-gate 				perror("expr");
1940Sstevel@tonic-gate 				exit(3);
1950Sstevel@tonic-gate 			}
1960Sstevel@tonic-gate 		}
1971355Spd155743 		switch (oper) {
1981355Spd155743 		case EQ:
1991355Spd155743 			i = (l1 == l2);
2001355Spd155743 			break;
2011355Spd155743 		case GT:
2021355Spd155743 			i = (l1 > l2);
2031355Spd155743 			break;
2041355Spd155743 		case GEQ:
2051355Spd155743 			i = (l1 >= l2);
2061355Spd155743 			break;
2071355Spd155743 		case LT:
2081355Spd155743 			i = (l1 < l2);
2091355Spd155743 			break;
2101355Spd155743 		case LEQ:
2111355Spd155743 			i = (l1 <= l2);
2121355Spd155743 			break;
2131355Spd155743 		case NEQ:
2141355Spd155743 			i = (l1 != l2);
2151355Spd155743 			break;
2161355Spd155743 		}
2170Sstevel@tonic-gate 	}
2180Sstevel@tonic-gate 	else
2191355Spd155743 	{
2201355Spd155743 			i = strcoll(r1, r2);
2211355Spd155743 		switch (oper) {
2221355Spd155743 		case EQ:
2231355Spd155743 			i = i == 0;
2241355Spd155743 			break;
2251355Spd155743 		case GT:
2261355Spd155743 			i = i > 0;
2271355Spd155743 			break;
2281355Spd155743 		case GEQ:
2291355Spd155743 			i = i >= 0;
2301355Spd155743 			break;
2311355Spd155743 		case LT:
2321355Spd155743 			i = i < 0;
2331355Spd155743 			break;
2341355Spd155743 		case LEQ:
2351355Spd155743 			i = i <= 0;
2361355Spd155743 			break;
2371355Spd155743 		case NEQ:
2381355Spd155743 			i = i != 0;
2391355Spd155743 			break;
2401355Spd155743 		}
2410Sstevel@tonic-gate 	}
2420Sstevel@tonic-gate 	return (i ? "1": "0");
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate static char
arith(oper,r1,r2)2460Sstevel@tonic-gate *arith(oper, r1, r2) char *r1, *r2;
2470Sstevel@tonic-gate {
2480Sstevel@tonic-gate 	long long i1, i2;
2490Sstevel@tonic-gate 	register char *rv;
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	if (!(ematch(r1, "-\\{0,1\\}[0-9]*$") &&
2520Sstevel@tonic-gate 	    ematch(r2, "-\\{0,1\\}[0-9]*$")))
2530Sstevel@tonic-gate 		yyerror("non-numeric argument");
2540Sstevel@tonic-gate 	errno = 0;
2550Sstevel@tonic-gate 	i1 = strtoll(r1, (char **)NULL, 10);
2560Sstevel@tonic-gate 	i2 = strtoll(r2, (char **)NULL, 10);
2570Sstevel@tonic-gate 	if (errno) {
2580Sstevel@tonic-gate #ifdef XPG6
2590Sstevel@tonic-gate 	/* XPG6: stdout will always contain newline even on error */
2600Sstevel@tonic-gate 		(void) write(1, "\n", 1);
2610Sstevel@tonic-gate #endif
2620Sstevel@tonic-gate 		if (errno == ERANGE) {
2630Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
2640Sstevel@tonic-gate 			    "expr: Integer argument too large\n"));
2650Sstevel@tonic-gate 			exit(3);
2660Sstevel@tonic-gate 		} else {
2670Sstevel@tonic-gate 			perror("expr");
2680Sstevel@tonic-gate 			exit(3);
2690Sstevel@tonic-gate 		}
2700Sstevel@tonic-gate 	}
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	switch (oper) {
2730Sstevel@tonic-gate 	case ADD:
2740Sstevel@tonic-gate 		i1 = i1 + i2;
2750Sstevel@tonic-gate 		break;
2760Sstevel@tonic-gate 	case SUBT:
2770Sstevel@tonic-gate 		i1 = i1 - i2;
2780Sstevel@tonic-gate 		break;
2790Sstevel@tonic-gate 	case MULT:
2800Sstevel@tonic-gate 		i1 = i1 * i2;
2810Sstevel@tonic-gate 		break;
2820Sstevel@tonic-gate 	case DIV:
2830Sstevel@tonic-gate 		if (i2 == 0)
2840Sstevel@tonic-gate 			yyerror("division by zero");
2850Sstevel@tonic-gate 		i1 = i1 / i2;
2860Sstevel@tonic-gate 		break;
2870Sstevel@tonic-gate 	case REM:
2880Sstevel@tonic-gate 		if (i2 == 0)
2890Sstevel@tonic-gate 			yyerror("division by zero");
2900Sstevel@tonic-gate 		i1 = i1 % i2;
2910Sstevel@tonic-gate 		break;
2920Sstevel@tonic-gate 	}
2930Sstevel@tonic-gate 	rv = exprmalloc(25);
2940Sstevel@tonic-gate 	(void) strcpy(rv, lltoa(i1));
2950Sstevel@tonic-gate 	return (rv);
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate static char
conj(oper,r1,r2)2990Sstevel@tonic-gate *conj(oper, r1, r2)
3000Sstevel@tonic-gate 	char *r1, *r2;
3010Sstevel@tonic-gate {
3020Sstevel@tonic-gate 	register char *rv;
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	switch (oper) {
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	case OR:
3070Sstevel@tonic-gate 		if (EQL(r1, "0") || EQL(r1, "")) {
3080Sstevel@tonic-gate 			if (EQL(r2, "0") || EQL(r2, ""))
3090Sstevel@tonic-gate 				rv = "0";
3100Sstevel@tonic-gate 			else
3110Sstevel@tonic-gate 				rv = r2;
3120Sstevel@tonic-gate 		} else
3130Sstevel@tonic-gate 			rv = r1;
3140Sstevel@tonic-gate 		break;
3150Sstevel@tonic-gate 	case AND:
3160Sstevel@tonic-gate 		if (EQL(r1, "0") || EQL(r1, ""))
3170Sstevel@tonic-gate 			rv = "0";
3180Sstevel@tonic-gate 		else if (EQL(r2, "0") || EQL(r2, ""))
3190Sstevel@tonic-gate 			rv = "0";
3200Sstevel@tonic-gate 		else
3210Sstevel@tonic-gate 			rv = r1;
3220Sstevel@tonic-gate 		break;
3230Sstevel@tonic-gate 	}
3240Sstevel@tonic-gate 	return (rv);
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate char *
substr(char * v,char * s,char * w)3280Sstevel@tonic-gate substr(char *v, char *s, char *w)
3290Sstevel@tonic-gate {
3300Sstevel@tonic-gate 	int si, wi;
3310Sstevel@tonic-gate 	char *res;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	si = atol(s);
3340Sstevel@tonic-gate 	wi = atol(w);
3350Sstevel@tonic-gate 	while (--si)
3360Sstevel@tonic-gate 		if (*v) ++v;
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	res = v;
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	while (wi--)
3410Sstevel@tonic-gate 		if (*v) ++v;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	*v = '\0';
3440Sstevel@tonic-gate 	return (res);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate char *
index(char * s,char * t)3480Sstevel@tonic-gate index(char *s, char *t)
3490Sstevel@tonic-gate {
3500Sstevel@tonic-gate 	long i, j;
3510Sstevel@tonic-gate 	char *rv;
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	for (i = 0; s[i]; ++i)
3540Sstevel@tonic-gate 		for (j = 0; t[j]; ++j)
3550Sstevel@tonic-gate 			if (s[i] == t[j]) {
3560Sstevel@tonic-gate 				(void) strcpy(rv = exprmalloc(8), ltoa(++i));
3570Sstevel@tonic-gate 				return (rv);
3580Sstevel@tonic-gate 			}
3590Sstevel@tonic-gate 	return ("0");
3600Sstevel@tonic-gate }
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate char *
length(char * s)3630Sstevel@tonic-gate length(char *s)
3640Sstevel@tonic-gate {
3650Sstevel@tonic-gate 	long i = 0;
3660Sstevel@tonic-gate 	char *rv;
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	while (*s++) ++i;
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	rv = exprmalloc(8);
3710Sstevel@tonic-gate 	(void) strcpy(rv, ltoa(i));
3720Sstevel@tonic-gate 	return (rv);
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate static char *
match(char * s,char * p)3760Sstevel@tonic-gate match(char *s, char *p)
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate 	char *rv;
3790Sstevel@tonic-gate 	long val;			/* XCU4 */
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	(void) strcpy(rv = exprmalloc(8), ltoa(val = (long)ematch(s, p)));
3820Sstevel@tonic-gate 	if (nbra /* && val != 0 */) {
3830Sstevel@tonic-gate 		rv = exprmalloc((unsigned)strlen(Mstring[0]) + 1);
3840Sstevel@tonic-gate 		(void) strcpy(rv, Mstring[0]);
3850Sstevel@tonic-gate 	}
3860Sstevel@tonic-gate 	return (rv);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate /*
3910Sstevel@tonic-gate  * ematch 	- XCU4 mods involve calling compile/advance which simulate
3920Sstevel@tonic-gate  *		  the obsolete compile/advance functions using regcomp/regexec
3930Sstevel@tonic-gate  */
3940Sstevel@tonic-gate static int
ematch(char * s,char * p)3950Sstevel@tonic-gate ematch(char *s, char *p)
3960Sstevel@tonic-gate {
3970Sstevel@tonic-gate 	static char *expbuf;
3980Sstevel@tonic-gate 	char *nexpbuf;
3990Sstevel@tonic-gate 	int num;
4000Sstevel@tonic-gate #ifdef XPG4
4010Sstevel@tonic-gate 	int nmatch;		/* number of matched bytes */
4020Sstevel@tonic-gate 	char tempbuf[256];
4030Sstevel@tonic-gate 	char *tmptr1 = 0;	/* If tempbuf is not large enough */
4040Sstevel@tonic-gate 	char *tmptr;
4050Sstevel@tonic-gate 	int nmbchars;		/* number characters in multibyte string */
4060Sstevel@tonic-gate #endif
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	nexpbuf = compile(p, (char *)0, (char *)0);	/* XCU4 regex mod */
4090Sstevel@tonic-gate 	if (0 /* XXX nbra > 1*/)
4100Sstevel@tonic-gate 		yyerror("Too many '\\('s");
4110Sstevel@tonic-gate 	if (regerrno) {
4120Sstevel@tonic-gate 		if (regerrno != 41 || expbuf == NULL)
4130Sstevel@tonic-gate 			errxx();
4140Sstevel@tonic-gate 	} else {
4150Sstevel@tonic-gate 		if (expbuf)
4160Sstevel@tonic-gate 			free(expbuf);
4170Sstevel@tonic-gate 		expbuf = nexpbuf;
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 	if (advance(s, expbuf)) {
4200Sstevel@tonic-gate 		if (nbra > 0) {
4210Sstevel@tonic-gate 			p = braslist[0];
4220Sstevel@tonic-gate 			num = braelist[0] - p;
4230Sstevel@tonic-gate 			if ((num > MSIZE - 1) || (num < 0))
4240Sstevel@tonic-gate 				yyerror("string too long");
4250Sstevel@tonic-gate 			(void) strncpy(Mstring[0], p, num);
4260Sstevel@tonic-gate 			Mstring[0][num] = '\0';
4270Sstevel@tonic-gate 		}
4280Sstevel@tonic-gate #ifdef XPG4
4290Sstevel@tonic-gate 		/*
4300Sstevel@tonic-gate 		 *  Use mbstowcs to find the number of multibyte characters
4310Sstevel@tonic-gate 		 *  in the multibyte string beginning at s, and
4320Sstevel@tonic-gate 		 *  ending at loc2.  Create a separate string
4330Sstevel@tonic-gate 		 *  of the substring, so it can be passed to mbstowcs.
4340Sstevel@tonic-gate 		 */
4350Sstevel@tonic-gate 		nmatch = loc2 - s;
4360Sstevel@tonic-gate 		if (nmatch > ((sizeof (tempbuf) / sizeof (char)) - 1)) {
4370Sstevel@tonic-gate 			tmptr1 = exprmalloc(nmatch + 1);
4380Sstevel@tonic-gate 			tmptr = tmptr1;
4390Sstevel@tonic-gate 		} else {
4400Sstevel@tonic-gate 			tmptr = tempbuf;
4410Sstevel@tonic-gate 		}
4420Sstevel@tonic-gate 		memcpy(tmptr, s, nmatch);
4430Sstevel@tonic-gate 		*(tmptr + nmatch) = '\0';
4440Sstevel@tonic-gate 		if ((nmbchars = mbstowcs(NULL, tmptr, NULL)) == -1) {
4450Sstevel@tonic-gate 			yyerror("invalid multibyte character encountered");
4460Sstevel@tonic-gate 			if (tmptr1 != NULL)
4470Sstevel@tonic-gate 				free(tmptr1);
4480Sstevel@tonic-gate 			return (0);
4490Sstevel@tonic-gate 		}
4500Sstevel@tonic-gate 		if (tmptr1 != NULL)
4510Sstevel@tonic-gate 			free(tmptr1);
4520Sstevel@tonic-gate 		return (nmbchars);
4530Sstevel@tonic-gate #else
4540Sstevel@tonic-gate 		return (loc2-s);
4550Sstevel@tonic-gate #endif
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate 	return (0);
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate static void
errxx()4610Sstevel@tonic-gate errxx()
4620Sstevel@tonic-gate {
4630Sstevel@tonic-gate 	yyerror("RE error");
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate static void
yyerror(char * s)4670Sstevel@tonic-gate yyerror(char *s)
4680Sstevel@tonic-gate {
4690Sstevel@tonic-gate #ifdef XPG6
4700Sstevel@tonic-gate 	/* XPG6: stdout will always contain newline even on error */
4710Sstevel@tonic-gate 	(void) write(1, "\n", 1);
4720Sstevel@tonic-gate #endif
4730Sstevel@tonic-gate 	(void) write(2, "expr: ", 6);
4740Sstevel@tonic-gate 	(void) write(2, gettext(s), (unsigned)strlen(gettext(s)));
4750Sstevel@tonic-gate 	(void) write(2, "\n", 1);
4760Sstevel@tonic-gate 	exit(2);
4770Sstevel@tonic-gate 	/* NOTREACHED */
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate static char *
ltoa(long l)4810Sstevel@tonic-gate ltoa(long l)
4820Sstevel@tonic-gate {
4830Sstevel@tonic-gate 	static char str[20];
4840Sstevel@tonic-gate 	char *sp = &str[18];	/* u370 */
4850Sstevel@tonic-gate 	int i;
4860Sstevel@tonic-gate 	int neg = 0;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	if ((unsigned long)l == 0x80000000UL)
4890Sstevel@tonic-gate 		return ("-2147483648");
4900Sstevel@tonic-gate 	if (l < 0)
4910Sstevel@tonic-gate 		++neg, l = -l;
4920Sstevel@tonic-gate 	str[19] = '\0';
4930Sstevel@tonic-gate 	do {
4940Sstevel@tonic-gate 		i = l % 10;
4950Sstevel@tonic-gate 		*sp-- = '0' + i;
4960Sstevel@tonic-gate 		l /= 10;
4970Sstevel@tonic-gate 	} while (l);
4980Sstevel@tonic-gate 	if (neg)
4990Sstevel@tonic-gate 		*sp-- = '-';
5000Sstevel@tonic-gate 	return (++sp);
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate static char *
lltoa(long long l)5040Sstevel@tonic-gate lltoa(long long l)
5050Sstevel@tonic-gate {
5060Sstevel@tonic-gate 	static char str[25];
5070Sstevel@tonic-gate 	char *sp = &str[23];
5080Sstevel@tonic-gate 	int i;
5090Sstevel@tonic-gate 	int neg = 0;
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	if (l == 0x8000000000000000ULL)
5120Sstevel@tonic-gate 		return ("-9223372036854775808");
5130Sstevel@tonic-gate 	if (l < 0)
5140Sstevel@tonic-gate 		++neg, l = -l;
5150Sstevel@tonic-gate 	str[24] = '\0';
5160Sstevel@tonic-gate 	do {
5170Sstevel@tonic-gate 		i = l % 10;
5180Sstevel@tonic-gate 		*sp-- = '0' + i;
5190Sstevel@tonic-gate 		l /= 10;
5200Sstevel@tonic-gate 	} while (l);
5210Sstevel@tonic-gate 	if (neg)
5220Sstevel@tonic-gate 		*sp-- = '-';
5230Sstevel@tonic-gate 	return (++sp);
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate static char *
expres(int prior,int par)5270Sstevel@tonic-gate expres(int prior, int par)
5280Sstevel@tonic-gate {
5290Sstevel@tonic-gate 	int ylex, temp, op1;
5300Sstevel@tonic-gate 	char *r1, *ra, *rb, *rc;
5310Sstevel@tonic-gate 	ylex = yylex();
5320Sstevel@tonic-gate 	if (ylex >= NOARG && ylex < MATCH) {
5330Sstevel@tonic-gate 		yyerror("syntax error");
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 	if (ylex == A_STRING) {
5360Sstevel@tonic-gate 		r1 = Av[Argi++];
5370Sstevel@tonic-gate 		temp = Argi;
5380Sstevel@tonic-gate 	} else {
5390Sstevel@tonic-gate 		if (ylex == '(') {
5400Sstevel@tonic-gate 			paren++;
5410Sstevel@tonic-gate 			Argi++;
5420Sstevel@tonic-gate 			r1 = expres(0, Argi);
5430Sstevel@tonic-gate 			Argi--;
5440Sstevel@tonic-gate 		}
5450Sstevel@tonic-gate 	}
5460Sstevel@tonic-gate lop:
5470Sstevel@tonic-gate 	ylex = yylex();
5480Sstevel@tonic-gate 	if (ylex > NOARG && ylex < MATCH) {
5490Sstevel@tonic-gate 		op1 = ylex;
5500Sstevel@tonic-gate 		Argi++;
5510Sstevel@tonic-gate 		if (pri[op1-OR] <= prior)
5520Sstevel@tonic-gate 			return (r1);
5530Sstevel@tonic-gate 		else {
5540Sstevel@tonic-gate 			switch (op1) {
5550Sstevel@tonic-gate 			case OR:
5560Sstevel@tonic-gate 			case AND:
5570Sstevel@tonic-gate 				r1 = conj(op1, r1, expres(pri[op1-OR], 0));
5580Sstevel@tonic-gate 				break;
5590Sstevel@tonic-gate 			case EQ:
5600Sstevel@tonic-gate 			case LT:
5610Sstevel@tonic-gate 			case GT:
5620Sstevel@tonic-gate 			case LEQ:
5630Sstevel@tonic-gate 			case GEQ:
5640Sstevel@tonic-gate 			case NEQ:
5650Sstevel@tonic-gate 				r1 = rel(op1, r1, expres(pri[op1-OR], 0));
5660Sstevel@tonic-gate 				break;
5670Sstevel@tonic-gate 			case ADD:
5680Sstevel@tonic-gate 			case SUBT:
5690Sstevel@tonic-gate 			case MULT:
5700Sstevel@tonic-gate 			case DIV:
5710Sstevel@tonic-gate 			case REM:
5720Sstevel@tonic-gate 				r1 = arith(op1, r1, expres(pri[op1-OR], 0));
5730Sstevel@tonic-gate 				break;
5740Sstevel@tonic-gate 			case MCH:
5750Sstevel@tonic-gate 				r1 = match(r1, expres(pri[op1-OR], 0));
5760Sstevel@tonic-gate 				break;
5770Sstevel@tonic-gate 			}
5780Sstevel@tonic-gate 			if (noarg == 1) {
5790Sstevel@tonic-gate 				return (r1);
5800Sstevel@tonic-gate 			}
5810Sstevel@tonic-gate 			Argi--;
5820Sstevel@tonic-gate 			goto lop;
5830Sstevel@tonic-gate 		}
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate 	ylex = yylex();
5860Sstevel@tonic-gate 	if (ylex == ')') {
5870Sstevel@tonic-gate 		if (par == Argi) {
5880Sstevel@tonic-gate 			yyerror("syntax error");
5890Sstevel@tonic-gate 		}
5900Sstevel@tonic-gate 		if (par != 0) {
5910Sstevel@tonic-gate 			paren--;
5920Sstevel@tonic-gate 			Argi++;
5930Sstevel@tonic-gate 		}
5940Sstevel@tonic-gate 		Argi++;
5950Sstevel@tonic-gate 		return (r1);
5960Sstevel@tonic-gate 	}
5970Sstevel@tonic-gate 	ylex = yylex();
598*12836Srich.burridge@oracle.com 	if (ylex > MCH && ylex <= INDEX) {
5990Sstevel@tonic-gate 		if (Argi == temp) {
6000Sstevel@tonic-gate 			return (r1);
6010Sstevel@tonic-gate 		}
6020Sstevel@tonic-gate 		op1 = ylex;
6030Sstevel@tonic-gate 		Argi++;
6040Sstevel@tonic-gate 		switch (op1) {
6050Sstevel@tonic-gate 		case MATCH:
6060Sstevel@tonic-gate 			rb = expres(pri[op1-OR], 0);
6070Sstevel@tonic-gate 			ra = expres(pri[op1-OR], 0);
6080Sstevel@tonic-gate 			break;
6090Sstevel@tonic-gate 		case SUBSTR:
6100Sstevel@tonic-gate 			rc = expres(pri[op1-OR], 0);
6110Sstevel@tonic-gate 			rb = expres(pri[op1-OR], 0);
6120Sstevel@tonic-gate 			ra = expres(pri[op1-OR], 0);
6130Sstevel@tonic-gate 			break;
6140Sstevel@tonic-gate 		case LENGTH:
6150Sstevel@tonic-gate 			ra = expres(pri[op1-OR], 0);
6160Sstevel@tonic-gate 			break;
6170Sstevel@tonic-gate 		case INDEX:
6180Sstevel@tonic-gate 			rb = expres(pri[op1-OR], 0);
6190Sstevel@tonic-gate 			ra = expres(pri[op1-OR], 0);
6200Sstevel@tonic-gate 			break;
6210Sstevel@tonic-gate 		}
6220Sstevel@tonic-gate 		switch (op1) {
6230Sstevel@tonic-gate 		case MATCH:
6240Sstevel@tonic-gate 			r1 = match(rb, ra);
6250Sstevel@tonic-gate 			break;
6260Sstevel@tonic-gate 		case SUBSTR:
6270Sstevel@tonic-gate 			r1 = substr(rc, rb, ra);
6280Sstevel@tonic-gate 			break;
6290Sstevel@tonic-gate 		case LENGTH:
6300Sstevel@tonic-gate 			r1 = length(ra);
6310Sstevel@tonic-gate 			break;
6320Sstevel@tonic-gate 		case INDEX:
6330Sstevel@tonic-gate 			r1 = index(rb, ra);
6340Sstevel@tonic-gate 			break;
6350Sstevel@tonic-gate 		}
6360Sstevel@tonic-gate 		if (noarg == 1) {
6370Sstevel@tonic-gate 			return (r1);
6380Sstevel@tonic-gate 		}
6390Sstevel@tonic-gate 		Argi--;
6400Sstevel@tonic-gate 		goto lop;
6410Sstevel@tonic-gate 	}
6420Sstevel@tonic-gate 	ylex = yylex();
6430Sstevel@tonic-gate 	if (ylex == NOARG) {
6440Sstevel@tonic-gate 		noarg = 1;
6450Sstevel@tonic-gate 	}
6460Sstevel@tonic-gate 	return (r1);
6470Sstevel@tonic-gate }
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate void *
exprmalloc(size_t size)6500Sstevel@tonic-gate exprmalloc(size_t size)
6510Sstevel@tonic-gate {
6520Sstevel@tonic-gate 	void *rv;
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	if ((rv = malloc(size)) == NULL) {
6550Sstevel@tonic-gate 		char *s = gettext("malloc error");
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 		(void) write(2, "expr: ", 6);
6580Sstevel@tonic-gate 		(void) write(2, s, (unsigned)strlen(s));
6590Sstevel@tonic-gate 		(void) write(2, "\n", 1);
6600Sstevel@tonic-gate 		exit(3);
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate 	return (rv);
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate int
main(int argc,char ** argv)6660Sstevel@tonic-gate main(int argc, char **argv)
6670Sstevel@tonic-gate {
6680Sstevel@tonic-gate 	/*
6690Sstevel@tonic-gate 	 * XCU4 allow "--" as argument
6700Sstevel@tonic-gate 	 */
6710Sstevel@tonic-gate 	if (argc > 1 && strcmp(argv[1], "--") == 0)
6720Sstevel@tonic-gate 		argv++, argc--;
6730Sstevel@tonic-gate 	/*
6740Sstevel@tonic-gate 	 * XCU4 - print usage message when invoked without args
6750Sstevel@tonic-gate 	 */
6760Sstevel@tonic-gate 	if (argc < 2) {
6770Sstevel@tonic-gate #ifdef XPG6
6780Sstevel@tonic-gate 	/* XPG6: stdout will always contain newline even on error */
6790Sstevel@tonic-gate 		(void) write(1, "\n", 1);
6800Sstevel@tonic-gate #endif
6810Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Usage: expr expression\n"));
6820Sstevel@tonic-gate 		exit(3);
6830Sstevel@tonic-gate 	}
6840Sstevel@tonic-gate 	Ac = argc;
6850Sstevel@tonic-gate 	Argi = 1;
6860Sstevel@tonic-gate 	noarg = 0;
6870Sstevel@tonic-gate 	paren = 0;
6880Sstevel@tonic-gate 	Av = argv;
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
6910Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
6920Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
6930Sstevel@tonic-gate #endif
6940Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
6950Sstevel@tonic-gate 	buf = expres(0, 1);
6960Sstevel@tonic-gate 	if (Ac != Argi || paren != 0) {
6970Sstevel@tonic-gate 		yyerror("syntax error");
6980Sstevel@tonic-gate 	}
6990Sstevel@tonic-gate 	/*
7000Sstevel@tonic-gate 	 * XCU4 - strip leading zeros from numeric output
7010Sstevel@tonic-gate 	 */
7020Sstevel@tonic-gate 	clean_buf(buf);
7030Sstevel@tonic-gate 	(void) write(1, buf, (unsigned)strlen(buf));
7040Sstevel@tonic-gate 	(void) write(1, "\n", 1);
7050Sstevel@tonic-gate 	return ((strcmp(buf, "0") == 0 || buf[0] == 0) ? 1 : 0);
7060Sstevel@tonic-gate }
707