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