xref: /illumos-gate/usr/src/cmd/expr/expr.c (revision da7fc762b82ced1a0ec19a51e04cdf823187ec77)
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
5cc22b130SRich Burridge  * Common Development and Distribution License (the "License").
6cc22b130SRich 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 /*
26cc22b130SRich 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
57cc22b130SRich Burridge #define	SUBSTR 275
58cc22b130SRich Burridge #define	LENGTH 276
59cc22b130SRich 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 static char *ltoa();
747c478bd9Sstevel@tonic-gate static char *lltoa();
757c478bd9Sstevel@tonic-gate static char	**Av;
767c478bd9Sstevel@tonic-gate static char *buf;
777c478bd9Sstevel@tonic-gate static int	Ac;
787c478bd9Sstevel@tonic-gate static int	Argi;
797c478bd9Sstevel@tonic-gate static int noarg;
807c478bd9Sstevel@tonic-gate static int paren;
817c478bd9Sstevel@tonic-gate /*
827c478bd9Sstevel@tonic-gate  *	Array used to store subexpressions in regular expressions
837c478bd9Sstevel@tonic-gate  *	Only one subexpression allowed per regular expression currently
847c478bd9Sstevel@tonic-gate  */
857c478bd9Sstevel@tonic-gate static char Mstring[1][MSIZE];
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static char *operator[] = {
897c478bd9Sstevel@tonic-gate 	"|", "&", "+", "-", "*", "/", "%", ":",
907c478bd9Sstevel@tonic-gate 	"=", "==", "<", "<=", ">", ">=", "!=",
917c478bd9Sstevel@tonic-gate 	"match",
927c478bd9Sstevel@tonic-gate 	"substr", "length", "index",
937c478bd9Sstevel@tonic-gate 	"\0" };
947c478bd9Sstevel@tonic-gate static	int op[] = {
957c478bd9Sstevel@tonic-gate 	OR, AND, ADD,  SUBT, MULT, DIV, REM, MCH,
967c478bd9Sstevel@tonic-gate 	EQ, EQ, LT, LEQ, GT, GEQ, NEQ,
97cc22b130SRich Burridge 	MATCH,
98cc22b130SRich Burridge 	SUBSTR, LENGTH, INDEX
997c478bd9Sstevel@tonic-gate 	};
1007c478bd9Sstevel@tonic-gate static	int pri[] = {
101cc22b130SRich Burridge 	1, 2, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6, 7,
102cc22b130SRich Burridge 	7, 7, 7
1037c478bd9Sstevel@tonic-gate 	};
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate /*
1077c478bd9Sstevel@tonic-gate  * clean_buf - XCU4 mod to remove leading zeros from negative signed
1087c478bd9Sstevel@tonic-gate  *		numeric output, e.g., -00001 becomes -1
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate static void
clean_buf(char * buf)111023a3eeeSToomas Soome clean_buf(char *buf)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate 	int i = 0;
1147c478bd9Sstevel@tonic-gate 	int is_a_num = 1;
1157c478bd9Sstevel@tonic-gate 	int len;
1167c478bd9Sstevel@tonic-gate 	long long num;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	if (buf[0] == '\0')
1197c478bd9Sstevel@tonic-gate 		return;
1207c478bd9Sstevel@tonic-gate 	len = strlen(buf);
1217c478bd9Sstevel@tonic-gate 	if (len <= 0)
1227c478bd9Sstevel@tonic-gate 		return;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	if (buf[0] == '-') {
1257c478bd9Sstevel@tonic-gate 		i++;		/* Skip the leading '-' see while loop */
1267c478bd9Sstevel@tonic-gate 		if (len <= 1)	/* Is it a '-' all by itself? */
1277c478bd9Sstevel@tonic-gate 			return; /* Yes, so return */
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 		while (i < len) {
1307c478bd9Sstevel@tonic-gate 			if (! isdigit(buf[i])) {
1317c478bd9Sstevel@tonic-gate 				is_a_num = 0;
1327c478bd9Sstevel@tonic-gate 				break;
1337c478bd9Sstevel@tonic-gate 			}
1347c478bd9Sstevel@tonic-gate 			i++;
1357c478bd9Sstevel@tonic-gate 		}
1367c478bd9Sstevel@tonic-gate 		if (is_a_num) {
1377c478bd9Sstevel@tonic-gate 			(void) sscanf(buf, "%lld", &num);
1387c478bd9Sstevel@tonic-gate 			(void) sprintf(buf, "%lld", num);
1397c478bd9Sstevel@tonic-gate 		}
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate /*
1447c478bd9Sstevel@tonic-gate  * End XCU4 mods.
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate static int
yylex(void)148*da7fc762SToomas Soome yylex(void)
1497c478bd9Sstevel@tonic-gate {
1507c478bd9Sstevel@tonic-gate 	char *p;
1517c478bd9Sstevel@tonic-gate 	int i;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	if (Argi >= Ac)
1547c478bd9Sstevel@tonic-gate 		return (NOARG);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	p = Av[Argi];
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	if ((*p == '(' || *p == ')') && p[1] == '\0')
1597c478bd9Sstevel@tonic-gate 		return ((int)*p);
1607c478bd9Sstevel@tonic-gate 	for (i = 0; *operator[i]; ++i)
1617c478bd9Sstevel@tonic-gate 		if (EQL(operator[i], p))
1627c478bd9Sstevel@tonic-gate 			return (op[i]);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	return (A_STRING);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
168*da7fc762SToomas Soome static char *
rel(int oper,char * r1,char * r2)169*da7fc762SToomas Soome rel(int oper, char *r1, char *r2)
1707c478bd9Sstevel@tonic-gate {
1719d14cf08Spd155743 	long long i, l1, l2;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	if (ematch(r1, "-\\{0,1\\}[0-9]*$") &&
1747c478bd9Sstevel@tonic-gate 	    ematch(r2, "-\\{0,1\\}[0-9]*$")) {
1757c478bd9Sstevel@tonic-gate 		errno = 0;
1769d14cf08Spd155743 		l1 = strtoll(r1, (char **)NULL, 10);
1779d14cf08Spd155743 		l2 = strtoll(r2, (char **)NULL, 10);
1787c478bd9Sstevel@tonic-gate 		if (errno) {
1797c478bd9Sstevel@tonic-gate #ifdef XPG6
1807c478bd9Sstevel@tonic-gate 		/* XPG6: stdout will always contain newline even on error */
1817c478bd9Sstevel@tonic-gate 			(void) write(1, "\n", 1);
1827c478bd9Sstevel@tonic-gate #endif
1837c478bd9Sstevel@tonic-gate 			if (errno == ERANGE) {
1847c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1857c478bd9Sstevel@tonic-gate 				    "expr: Integer argument too large\n"));
1867c478bd9Sstevel@tonic-gate 				exit(3);
1877c478bd9Sstevel@tonic-gate 			} else {
1887c478bd9Sstevel@tonic-gate 				perror("expr");
1897c478bd9Sstevel@tonic-gate 				exit(3);
1907c478bd9Sstevel@tonic-gate 			}
1917c478bd9Sstevel@tonic-gate 		}
1929d14cf08Spd155743 		switch (oper) {
1939d14cf08Spd155743 		case EQ:
1949d14cf08Spd155743 			i = (l1 == l2);
1959d14cf08Spd155743 			break;
1969d14cf08Spd155743 		case GT:
1979d14cf08Spd155743 			i = (l1 > l2);
1989d14cf08Spd155743 			break;
1999d14cf08Spd155743 		case GEQ:
2009d14cf08Spd155743 			i = (l1 >= l2);
2019d14cf08Spd155743 			break;
2029d14cf08Spd155743 		case LT:
2039d14cf08Spd155743 			i = (l1 < l2);
2049d14cf08Spd155743 			break;
2059d14cf08Spd155743 		case LEQ:
2069d14cf08Spd155743 			i = (l1 <= l2);
2079d14cf08Spd155743 			break;
2089d14cf08Spd155743 		case NEQ:
2099d14cf08Spd155743 			i = (l1 != l2);
2109d14cf08Spd155743 			break;
2119d14cf08Spd155743 		}
2127c478bd9Sstevel@tonic-gate 	}
2137c478bd9Sstevel@tonic-gate 	else
2149d14cf08Spd155743 	{
2157c478bd9Sstevel@tonic-gate 			i = strcoll(r1, r2);
2167c478bd9Sstevel@tonic-gate 		switch (oper) {
2177c478bd9Sstevel@tonic-gate 		case EQ:
2187c478bd9Sstevel@tonic-gate 			i = i == 0;
2197c478bd9Sstevel@tonic-gate 			break;
2207c478bd9Sstevel@tonic-gate 		case GT:
2217c478bd9Sstevel@tonic-gate 			i = i > 0;
2227c478bd9Sstevel@tonic-gate 			break;
2237c478bd9Sstevel@tonic-gate 		case GEQ:
2247c478bd9Sstevel@tonic-gate 			i = i >= 0;
2257c478bd9Sstevel@tonic-gate 			break;
2267c478bd9Sstevel@tonic-gate 		case LT:
2277c478bd9Sstevel@tonic-gate 			i = i < 0;
2287c478bd9Sstevel@tonic-gate 			break;
2297c478bd9Sstevel@tonic-gate 		case LEQ:
2307c478bd9Sstevel@tonic-gate 			i = i <= 0;
2317c478bd9Sstevel@tonic-gate 			break;
2327c478bd9Sstevel@tonic-gate 		case NEQ:
2337c478bd9Sstevel@tonic-gate 			i = i != 0;
2347c478bd9Sstevel@tonic-gate 			break;
2357c478bd9Sstevel@tonic-gate 		}
2369d14cf08Spd155743 	}
2377c478bd9Sstevel@tonic-gate 	return (i ? "1": "0");
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate 
240*da7fc762SToomas Soome static char *
arith(int oper,char * r1,char * r2)241*da7fc762SToomas Soome arith(int oper, char *r1, char *r2)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate 	long long i1, i2;
244*da7fc762SToomas Soome 	char *rv;
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	if (!(ematch(r1, "-\\{0,1\\}[0-9]*$") &&
2477c478bd9Sstevel@tonic-gate 	    ematch(r2, "-\\{0,1\\}[0-9]*$")))
2487c478bd9Sstevel@tonic-gate 		yyerror("non-numeric argument");
2497c478bd9Sstevel@tonic-gate 	errno = 0;
2507c478bd9Sstevel@tonic-gate 	i1 = strtoll(r1, (char **)NULL, 10);
2517c478bd9Sstevel@tonic-gate 	i2 = strtoll(r2, (char **)NULL, 10);
2527c478bd9Sstevel@tonic-gate 	if (errno) {
2537c478bd9Sstevel@tonic-gate #ifdef XPG6
2547c478bd9Sstevel@tonic-gate 	/* XPG6: stdout will always contain newline even on error */
2557c478bd9Sstevel@tonic-gate 		(void) write(1, "\n", 1);
2567c478bd9Sstevel@tonic-gate #endif
2577c478bd9Sstevel@tonic-gate 		if (errno == ERANGE) {
2587c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
2597c478bd9Sstevel@tonic-gate 			    "expr: Integer argument too large\n"));
2607c478bd9Sstevel@tonic-gate 			exit(3);
2617c478bd9Sstevel@tonic-gate 		} else {
2627c478bd9Sstevel@tonic-gate 			perror("expr");
2637c478bd9Sstevel@tonic-gate 			exit(3);
2647c478bd9Sstevel@tonic-gate 		}
2657c478bd9Sstevel@tonic-gate 	}
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	switch (oper) {
2687c478bd9Sstevel@tonic-gate 	case ADD:
2697c478bd9Sstevel@tonic-gate 		i1 = i1 + i2;
2707c478bd9Sstevel@tonic-gate 		break;
2717c478bd9Sstevel@tonic-gate 	case SUBT:
2727c478bd9Sstevel@tonic-gate 		i1 = i1 - i2;
2737c478bd9Sstevel@tonic-gate 		break;
2747c478bd9Sstevel@tonic-gate 	case MULT:
2757c478bd9Sstevel@tonic-gate 		i1 = i1 * i2;
2767c478bd9Sstevel@tonic-gate 		break;
2777c478bd9Sstevel@tonic-gate 	case DIV:
2787c478bd9Sstevel@tonic-gate 		if (i2 == 0)
2797c478bd9Sstevel@tonic-gate 			yyerror("division by zero");
2807c478bd9Sstevel@tonic-gate 		i1 = i1 / i2;
2817c478bd9Sstevel@tonic-gate 		break;
2827c478bd9Sstevel@tonic-gate 	case REM:
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 	}
2887c478bd9Sstevel@tonic-gate 	rv = exprmalloc(25);
2897c478bd9Sstevel@tonic-gate 	(void) strcpy(rv, lltoa(i1));
2907c478bd9Sstevel@tonic-gate 	return (rv);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate static char
conj(int oper,char * r1,char * r2)294*da7fc762SToomas Soome *conj(int oper, char *r1, char *r2)
2957c478bd9Sstevel@tonic-gate {
296*da7fc762SToomas Soome 	char *rv;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	switch (oper) {
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	case OR:
3017c478bd9Sstevel@tonic-gate 		if (EQL(r1, "0") || EQL(r1, "")) {
3027c478bd9Sstevel@tonic-gate 			if (EQL(r2, "0") || EQL(r2, ""))
3037c478bd9Sstevel@tonic-gate 				rv = "0";
3047c478bd9Sstevel@tonic-gate 			else
3057c478bd9Sstevel@tonic-gate 				rv = r2;
3067c478bd9Sstevel@tonic-gate 		} else
3077c478bd9Sstevel@tonic-gate 			rv = r1;
3087c478bd9Sstevel@tonic-gate 		break;
3097c478bd9Sstevel@tonic-gate 	case AND:
3107c478bd9Sstevel@tonic-gate 		if (EQL(r1, "0") || EQL(r1, ""))
3117c478bd9Sstevel@tonic-gate 			rv = "0";
3127c478bd9Sstevel@tonic-gate 		else if (EQL(r2, "0") || EQL(r2, ""))
3137c478bd9Sstevel@tonic-gate 			rv = "0";
3147c478bd9Sstevel@tonic-gate 		else
3157c478bd9Sstevel@tonic-gate 			rv = r1;
3167c478bd9Sstevel@tonic-gate 		break;
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 	return (rv);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate char *
substr(char * v,char * s,char * w)3227c478bd9Sstevel@tonic-gate substr(char *v, char *s, char *w)
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate 	int si, wi;
3257c478bd9Sstevel@tonic-gate 	char *res;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	si = atol(s);
3287c478bd9Sstevel@tonic-gate 	wi = atol(w);
3297c478bd9Sstevel@tonic-gate 	while (--si)
3307c478bd9Sstevel@tonic-gate 		if (*v) ++v;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	res = v;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	while (wi--)
3357c478bd9Sstevel@tonic-gate 		if (*v) ++v;
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	*v = '\0';
3387c478bd9Sstevel@tonic-gate 	return (res);
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate char *
index(char * s,char * t)3427c478bd9Sstevel@tonic-gate index(char *s, char *t)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate 	long i, j;
3457c478bd9Sstevel@tonic-gate 	char *rv;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	for (i = 0; s[i]; ++i)
3487c478bd9Sstevel@tonic-gate 		for (j = 0; t[j]; ++j)
3497c478bd9Sstevel@tonic-gate 			if (s[i] == t[j]) {
3507c478bd9Sstevel@tonic-gate 				(void) strcpy(rv = exprmalloc(8), ltoa(++i));
3517c478bd9Sstevel@tonic-gate 				return (rv);
3527c478bd9Sstevel@tonic-gate 			}
3537c478bd9Sstevel@tonic-gate 	return ("0");
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate char *
length(char * s)3577c478bd9Sstevel@tonic-gate length(char *s)
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate 	long i = 0;
3607c478bd9Sstevel@tonic-gate 	char *rv;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	while (*s++) ++i;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	rv = exprmalloc(8);
3657c478bd9Sstevel@tonic-gate 	(void) strcpy(rv, ltoa(i));
3667c478bd9Sstevel@tonic-gate 	return (rv);
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate static char *
match(char * s,char * p)3707c478bd9Sstevel@tonic-gate match(char *s, char *p)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 	char *rv;
3737c478bd9Sstevel@tonic-gate 	long val;			/* XCU4 */
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	(void) strcpy(rv = exprmalloc(8), ltoa(val = (long)ematch(s, p)));
3767c478bd9Sstevel@tonic-gate 	if (nbra /* && val != 0 */) {
3777c478bd9Sstevel@tonic-gate 		rv = exprmalloc((unsigned)strlen(Mstring[0]) + 1);
3787c478bd9Sstevel@tonic-gate 		(void) strcpy(rv, Mstring[0]);
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 	return (rv);
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate /*
3857c478bd9Sstevel@tonic-gate  * ematch	- XCU4 mods involve calling compile/advance which simulate
3867c478bd9Sstevel@tonic-gate  *		  the obsolete compile/advance functions using regcomp/regexec
3877c478bd9Sstevel@tonic-gate  */
3887c478bd9Sstevel@tonic-gate static int
ematch(char * s,char * p)3897c478bd9Sstevel@tonic-gate ematch(char *s, char *p)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	static char *expbuf;
3927c478bd9Sstevel@tonic-gate 	char *nexpbuf;
3937c478bd9Sstevel@tonic-gate 	int num;
3947c478bd9Sstevel@tonic-gate #ifdef XPG4
3957c478bd9Sstevel@tonic-gate 	int nmatch;		/* number of matched bytes */
3967c478bd9Sstevel@tonic-gate 	char tempbuf[256];
3977c478bd9Sstevel@tonic-gate 	char *tmptr1 = 0;	/* If tempbuf is not large enough */
3987c478bd9Sstevel@tonic-gate 	char *tmptr;
3997c478bd9Sstevel@tonic-gate 	int nmbchars;		/* number characters in multibyte string */
4007c478bd9Sstevel@tonic-gate #endif
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	nexpbuf = compile(p, (char *)0, (char *)0);	/* XCU4 regex mod */
4037c478bd9Sstevel@tonic-gate 	if (0 /* XXX nbra > 1*/)
4047c478bd9Sstevel@tonic-gate 		yyerror("Too many '\\('s");
4057c478bd9Sstevel@tonic-gate 	if (regerrno) {
4067c478bd9Sstevel@tonic-gate 		if (regerrno != 41 || expbuf == NULL)
4077c478bd9Sstevel@tonic-gate 			errxx();
4087c478bd9Sstevel@tonic-gate 	} else {
4097c478bd9Sstevel@tonic-gate 		if (expbuf)
4107c478bd9Sstevel@tonic-gate 			free(expbuf);
4117c478bd9Sstevel@tonic-gate 		expbuf = nexpbuf;
4127c478bd9Sstevel@tonic-gate 	}
4137c478bd9Sstevel@tonic-gate 	if (advance(s, expbuf)) {
4147c478bd9Sstevel@tonic-gate 		if (nbra > 0) {
4157c478bd9Sstevel@tonic-gate 			p = braslist[0];
4167c478bd9Sstevel@tonic-gate 			num = braelist[0] - p;
4177c478bd9Sstevel@tonic-gate 			if ((num > MSIZE - 1) || (num < 0))
4187c478bd9Sstevel@tonic-gate 				yyerror("string too long");
4197c478bd9Sstevel@tonic-gate 			(void) strncpy(Mstring[0], p, num);
4207c478bd9Sstevel@tonic-gate 			Mstring[0][num] = '\0';
4217c478bd9Sstevel@tonic-gate 		}
4227c478bd9Sstevel@tonic-gate #ifdef XPG4
4237c478bd9Sstevel@tonic-gate 		/*
4247c478bd9Sstevel@tonic-gate 		 *  Use mbstowcs to find the number of multibyte characters
4257c478bd9Sstevel@tonic-gate 		 *  in the multibyte string beginning at s, and
4267c478bd9Sstevel@tonic-gate 		 *  ending at loc2.  Create a separate string
4277c478bd9Sstevel@tonic-gate 		 *  of the substring, so it can be passed to mbstowcs.
4287c478bd9Sstevel@tonic-gate 		 */
4297c478bd9Sstevel@tonic-gate 		nmatch = loc2 - s;
4307c478bd9Sstevel@tonic-gate 		if (nmatch > ((sizeof (tempbuf) / sizeof (char)) - 1)) {
4317c478bd9Sstevel@tonic-gate 			tmptr1 = exprmalloc(nmatch + 1);
4327c478bd9Sstevel@tonic-gate 			tmptr = tmptr1;
4337c478bd9Sstevel@tonic-gate 		} else {
4347c478bd9Sstevel@tonic-gate 			tmptr = tempbuf;
4357c478bd9Sstevel@tonic-gate 		}
4367c478bd9Sstevel@tonic-gate 		memcpy(tmptr, s, nmatch);
4377c478bd9Sstevel@tonic-gate 		*(tmptr + nmatch) = '\0';
438023a3eeeSToomas Soome 		if ((nmbchars = mbstowcs(NULL, tmptr, 0)) == -1) {
4397c478bd9Sstevel@tonic-gate 			yyerror("invalid multibyte character encountered");
4407c478bd9Sstevel@tonic-gate 			if (tmptr1 != NULL)
4417c478bd9Sstevel@tonic-gate 				free(tmptr1);
4427c478bd9Sstevel@tonic-gate 			return (0);
4437c478bd9Sstevel@tonic-gate 		}
4447c478bd9Sstevel@tonic-gate 		if (tmptr1 != NULL)
4457c478bd9Sstevel@tonic-gate 			free(tmptr1);
4467c478bd9Sstevel@tonic-gate 		return (nmbchars);
4477c478bd9Sstevel@tonic-gate #else
4487c478bd9Sstevel@tonic-gate 		return (loc2-s);
4497c478bd9Sstevel@tonic-gate #endif
4507c478bd9Sstevel@tonic-gate 	}
4517c478bd9Sstevel@tonic-gate 	return (0);
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate static void
errxx()4557c478bd9Sstevel@tonic-gate errxx()
4567c478bd9Sstevel@tonic-gate {
4577c478bd9Sstevel@tonic-gate 	yyerror("RE error");
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate static void
yyerror(char * s)4617c478bd9Sstevel@tonic-gate yyerror(char *s)
4627c478bd9Sstevel@tonic-gate {
4637c478bd9Sstevel@tonic-gate #ifdef XPG6
4647c478bd9Sstevel@tonic-gate 	/* XPG6: stdout will always contain newline even on error */
4657c478bd9Sstevel@tonic-gate 	(void) write(1, "\n", 1);
4667c478bd9Sstevel@tonic-gate #endif
4677c478bd9Sstevel@tonic-gate 	(void) write(2, "expr: ", 6);
4687c478bd9Sstevel@tonic-gate 	(void) write(2, gettext(s), (unsigned)strlen(gettext(s)));
4697c478bd9Sstevel@tonic-gate 	(void) write(2, "\n", 1);
4707c478bd9Sstevel@tonic-gate 	exit(2);
4717c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate static char *
ltoa(long l)4757c478bd9Sstevel@tonic-gate ltoa(long l)
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate 	static char str[20];
4787c478bd9Sstevel@tonic-gate 	char *sp = &str[18];	/* u370 */
4797c478bd9Sstevel@tonic-gate 	int i;
4807c478bd9Sstevel@tonic-gate 	int neg = 0;
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	if ((unsigned long)l == 0x80000000UL)
4837c478bd9Sstevel@tonic-gate 		return ("-2147483648");
4847c478bd9Sstevel@tonic-gate 	if (l < 0)
4857c478bd9Sstevel@tonic-gate 		++neg, l = -l;
4867c478bd9Sstevel@tonic-gate 	str[19] = '\0';
4877c478bd9Sstevel@tonic-gate 	do {
4887c478bd9Sstevel@tonic-gate 		i = l % 10;
4897c478bd9Sstevel@tonic-gate 		*sp-- = '0' + i;
4907c478bd9Sstevel@tonic-gate 		l /= 10;
4917c478bd9Sstevel@tonic-gate 	} while (l);
4927c478bd9Sstevel@tonic-gate 	if (neg)
4937c478bd9Sstevel@tonic-gate 		*sp-- = '-';
4947c478bd9Sstevel@tonic-gate 	return (++sp);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate static char *
lltoa(long long l)4987c478bd9Sstevel@tonic-gate lltoa(long long l)
4997c478bd9Sstevel@tonic-gate {
5007c478bd9Sstevel@tonic-gate 	static char str[25];
5017c478bd9Sstevel@tonic-gate 	char *sp = &str[23];
5027c478bd9Sstevel@tonic-gate 	int i;
5037c478bd9Sstevel@tonic-gate 	int neg = 0;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	if (l == 0x8000000000000000ULL)
5067c478bd9Sstevel@tonic-gate 		return ("-9223372036854775808");
5077c478bd9Sstevel@tonic-gate 	if (l < 0)
5087c478bd9Sstevel@tonic-gate 		++neg, l = -l;
5097c478bd9Sstevel@tonic-gate 	str[24] = '\0';
5107c478bd9Sstevel@tonic-gate 	do {
5117c478bd9Sstevel@tonic-gate 		i = l % 10;
5127c478bd9Sstevel@tonic-gate 		*sp-- = '0' + i;
5137c478bd9Sstevel@tonic-gate 		l /= 10;
5147c478bd9Sstevel@tonic-gate 	} while (l);
5157c478bd9Sstevel@tonic-gate 	if (neg)
5167c478bd9Sstevel@tonic-gate 		*sp-- = '-';
5177c478bd9Sstevel@tonic-gate 	return (++sp);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate static char *
expres(int prior,int par)5217c478bd9Sstevel@tonic-gate expres(int prior, int par)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	int ylex, temp, op1;
5247c478bd9Sstevel@tonic-gate 	char *r1, *ra, *rb, *rc;
5257c478bd9Sstevel@tonic-gate 	ylex = yylex();
5267c478bd9Sstevel@tonic-gate 	if (ylex >= NOARG && ylex < MATCH) {
5277c478bd9Sstevel@tonic-gate 		yyerror("syntax error");
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 	if (ylex == A_STRING) {
5307c478bd9Sstevel@tonic-gate 		r1 = Av[Argi++];
5317c478bd9Sstevel@tonic-gate 		temp = Argi;
5327c478bd9Sstevel@tonic-gate 	} else {
5337c478bd9Sstevel@tonic-gate 		if (ylex == '(') {
5347c478bd9Sstevel@tonic-gate 			paren++;
5357c478bd9Sstevel@tonic-gate 			Argi++;
5367c478bd9Sstevel@tonic-gate 			r1 = expres(0, Argi);
5377c478bd9Sstevel@tonic-gate 			Argi--;
5387c478bd9Sstevel@tonic-gate 		}
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate lop:
5417c478bd9Sstevel@tonic-gate 	ylex = yylex();
5427c478bd9Sstevel@tonic-gate 	if (ylex > NOARG && ylex < MATCH) {
5437c478bd9Sstevel@tonic-gate 		op1 = ylex;
5447c478bd9Sstevel@tonic-gate 		Argi++;
5457c478bd9Sstevel@tonic-gate 		if (pri[op1-OR] <= prior)
5467c478bd9Sstevel@tonic-gate 			return (r1);
5477c478bd9Sstevel@tonic-gate 		else {
5487c478bd9Sstevel@tonic-gate 			switch (op1) {
5497c478bd9Sstevel@tonic-gate 			case OR:
5507c478bd9Sstevel@tonic-gate 			case AND:
5517c478bd9Sstevel@tonic-gate 				r1 = conj(op1, r1, expres(pri[op1-OR], 0));
5527c478bd9Sstevel@tonic-gate 				break;
5537c478bd9Sstevel@tonic-gate 			case EQ:
5547c478bd9Sstevel@tonic-gate 			case LT:
5557c478bd9Sstevel@tonic-gate 			case GT:
5567c478bd9Sstevel@tonic-gate 			case LEQ:
5577c478bd9Sstevel@tonic-gate 			case GEQ:
5587c478bd9Sstevel@tonic-gate 			case NEQ:
5597c478bd9Sstevel@tonic-gate 				r1 = rel(op1, r1, expres(pri[op1-OR], 0));
5607c478bd9Sstevel@tonic-gate 				break;
5617c478bd9Sstevel@tonic-gate 			case ADD:
5627c478bd9Sstevel@tonic-gate 			case SUBT:
5637c478bd9Sstevel@tonic-gate 			case MULT:
5647c478bd9Sstevel@tonic-gate 			case DIV:
5657c478bd9Sstevel@tonic-gate 			case REM:
5667c478bd9Sstevel@tonic-gate 				r1 = arith(op1, r1, expres(pri[op1-OR], 0));
5677c478bd9Sstevel@tonic-gate 				break;
5687c478bd9Sstevel@tonic-gate 			case MCH:
5697c478bd9Sstevel@tonic-gate 				r1 = match(r1, expres(pri[op1-OR], 0));
5707c478bd9Sstevel@tonic-gate 				break;
5717c478bd9Sstevel@tonic-gate 			}
5727c478bd9Sstevel@tonic-gate 			if (noarg == 1) {
5737c478bd9Sstevel@tonic-gate 				return (r1);
5747c478bd9Sstevel@tonic-gate 			}
5757c478bd9Sstevel@tonic-gate 			Argi--;
5767c478bd9Sstevel@tonic-gate 			goto lop;
5777c478bd9Sstevel@tonic-gate 		}
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 	ylex = yylex();
5807c478bd9Sstevel@tonic-gate 	if (ylex == ')') {
5817c478bd9Sstevel@tonic-gate 		if (par == Argi) {
5827c478bd9Sstevel@tonic-gate 			yyerror("syntax error");
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 		if (par != 0) {
5857c478bd9Sstevel@tonic-gate 			paren--;
5867c478bd9Sstevel@tonic-gate 			Argi++;
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 		Argi++;
5897c478bd9Sstevel@tonic-gate 		return (r1);
5907c478bd9Sstevel@tonic-gate 	}
5917c478bd9Sstevel@tonic-gate 	ylex = yylex();
592cc22b130SRich Burridge 	if (ylex > MCH && ylex <= INDEX) {
5937c478bd9Sstevel@tonic-gate 		if (Argi == temp) {
5947c478bd9Sstevel@tonic-gate 			return (r1);
5957c478bd9Sstevel@tonic-gate 		}
5967c478bd9Sstevel@tonic-gate 		op1 = ylex;
5977c478bd9Sstevel@tonic-gate 		Argi++;
5987c478bd9Sstevel@tonic-gate 		switch (op1) {
5997c478bd9Sstevel@tonic-gate 		case MATCH:
6007c478bd9Sstevel@tonic-gate 			rb = expres(pri[op1-OR], 0);
6017c478bd9Sstevel@tonic-gate 			ra = expres(pri[op1-OR], 0);
6027c478bd9Sstevel@tonic-gate 			break;
6037c478bd9Sstevel@tonic-gate 		case SUBSTR:
6047c478bd9Sstevel@tonic-gate 			rc = expres(pri[op1-OR], 0);
6057c478bd9Sstevel@tonic-gate 			rb = expres(pri[op1-OR], 0);
6067c478bd9Sstevel@tonic-gate 			ra = expres(pri[op1-OR], 0);
6077c478bd9Sstevel@tonic-gate 			break;
6087c478bd9Sstevel@tonic-gate 		case LENGTH:
6097c478bd9Sstevel@tonic-gate 			ra = expres(pri[op1-OR], 0);
6107c478bd9Sstevel@tonic-gate 			break;
6117c478bd9Sstevel@tonic-gate 		case INDEX:
6127c478bd9Sstevel@tonic-gate 			rb = expres(pri[op1-OR], 0);
6137c478bd9Sstevel@tonic-gate 			ra = expres(pri[op1-OR], 0);
6147c478bd9Sstevel@tonic-gate 			break;
6157c478bd9Sstevel@tonic-gate 		}
6167c478bd9Sstevel@tonic-gate 		switch (op1) {
6177c478bd9Sstevel@tonic-gate 		case MATCH:
6187c478bd9Sstevel@tonic-gate 			r1 = match(rb, ra);
6197c478bd9Sstevel@tonic-gate 			break;
6207c478bd9Sstevel@tonic-gate 		case SUBSTR:
6217c478bd9Sstevel@tonic-gate 			r1 = substr(rc, rb, ra);
6227c478bd9Sstevel@tonic-gate 			break;
6237c478bd9Sstevel@tonic-gate 		case LENGTH:
6247c478bd9Sstevel@tonic-gate 			r1 = length(ra);
6257c478bd9Sstevel@tonic-gate 			break;
6267c478bd9Sstevel@tonic-gate 		case INDEX:
6277c478bd9Sstevel@tonic-gate 			r1 = index(rb, ra);
6287c478bd9Sstevel@tonic-gate 			break;
6297c478bd9Sstevel@tonic-gate 		}
6307c478bd9Sstevel@tonic-gate 		if (noarg == 1) {
6317c478bd9Sstevel@tonic-gate 			return (r1);
6327c478bd9Sstevel@tonic-gate 		}
6337c478bd9Sstevel@tonic-gate 		Argi--;
6347c478bd9Sstevel@tonic-gate 		goto lop;
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 	ylex = yylex();
6377c478bd9Sstevel@tonic-gate 	if (ylex == NOARG) {
6387c478bd9Sstevel@tonic-gate 		noarg = 1;
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 	return (r1);
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate void *
exprmalloc(size_t size)6447c478bd9Sstevel@tonic-gate exprmalloc(size_t size)
6457c478bd9Sstevel@tonic-gate {
6467c478bd9Sstevel@tonic-gate 	void *rv;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	if ((rv = malloc(size)) == NULL) {
6497c478bd9Sstevel@tonic-gate 		char *s = gettext("malloc error");
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 		(void) write(2, "expr: ", 6);
6527c478bd9Sstevel@tonic-gate 		(void) write(2, s, (unsigned)strlen(s));
6537c478bd9Sstevel@tonic-gate 		(void) write(2, "\n", 1);
6547c478bd9Sstevel@tonic-gate 		exit(3);
6557c478bd9Sstevel@tonic-gate 	}
6567c478bd9Sstevel@tonic-gate 	return (rv);
6577c478bd9Sstevel@tonic-gate }
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)6607c478bd9Sstevel@tonic-gate main(int argc, char **argv)
6617c478bd9Sstevel@tonic-gate {
6627c478bd9Sstevel@tonic-gate 	/*
6637c478bd9Sstevel@tonic-gate 	 * XCU4 allow "--" as argument
6647c478bd9Sstevel@tonic-gate 	 */
6657c478bd9Sstevel@tonic-gate 	if (argc > 1 && strcmp(argv[1], "--") == 0)
6667c478bd9Sstevel@tonic-gate 		argv++, argc--;
6677c478bd9Sstevel@tonic-gate 	/*
6687c478bd9Sstevel@tonic-gate 	 * XCU4 - print usage message when invoked without args
6697c478bd9Sstevel@tonic-gate 	 */
6707c478bd9Sstevel@tonic-gate 	if (argc < 2) {
6717c478bd9Sstevel@tonic-gate #ifdef XPG6
6727c478bd9Sstevel@tonic-gate 	/* XPG6: stdout will always contain newline even on error */
6737c478bd9Sstevel@tonic-gate 		(void) write(1, "\n", 1);
6747c478bd9Sstevel@tonic-gate #endif
6757c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Usage: expr expression\n"));
6767c478bd9Sstevel@tonic-gate 		exit(3);
6777c478bd9Sstevel@tonic-gate 	}
6787c478bd9Sstevel@tonic-gate 	Ac = argc;
6797c478bd9Sstevel@tonic-gate 	Argi = 1;
6807c478bd9Sstevel@tonic-gate 	noarg = 0;
6817c478bd9Sstevel@tonic-gate 	paren = 0;
6827c478bd9Sstevel@tonic-gate 	Av = argv;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
6857c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
6867c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
6877c478bd9Sstevel@tonic-gate #endif
6887c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
6897c478bd9Sstevel@tonic-gate 	buf = expres(0, 1);
6907c478bd9Sstevel@tonic-gate 	if (Ac != Argi || paren != 0) {
6917c478bd9Sstevel@tonic-gate 		yyerror("syntax error");
6927c478bd9Sstevel@tonic-gate 	}
6937c478bd9Sstevel@tonic-gate 	/*
6947c478bd9Sstevel@tonic-gate 	 * XCU4 - strip leading zeros from numeric output
6957c478bd9Sstevel@tonic-gate 	 */
6967c478bd9Sstevel@tonic-gate 	clean_buf(buf);
6977c478bd9Sstevel@tonic-gate 	(void) write(1, buf, (unsigned)strlen(buf));
6987c478bd9Sstevel@tonic-gate 	(void) write(1, "\n", 1);
6997c478bd9Sstevel@tonic-gate 	return ((strcmp(buf, "0") == 0 || buf[0] == 0) ? 1 : 0);
7007c478bd9Sstevel@tonic-gate }
701