4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
22 /* All Rights Reserved */
26 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
61 /* size of subexpression array */
62 #define MSIZE LINE_MAX
63 #define error(c) errxx()
64 #define EQL(x, y) (strcmp(x, y) == 0)
66 #define ERROR(c) errxx()
68 static int ematch(char *, char *);
69 static void yyerror(char *);
71 static void *exprmalloc(size_t size
);
74 char *strcpy(), *strncpy();
86 * Array used to store subexpressions in regular expressions
87 * Only one subexpression allowed per regular expression currently
89 static char Mstring
[1][MSIZE
];
92 static char *operator[] = {
93 "|", "&", "+", "-", "*", "/", "%", ":",
94 "=", "==", "<", "<=", ">", ">=", "!=",
96 "substr", "length", "index",
99 OR
, AND
, ADD
, SUBT
, MULT
, DIV
, REM
, MCH
,
100 EQ
, EQ
, LT
, LEQ
, GT
, GEQ
, NEQ
,
102 SUBSTR
, LENGTH
, INDEX
105 1, 2, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6, 7,
111 * clean_buf - XCU4 mod to remove leading zeros from negative signed
112 * numeric output, e.g., -00001 becomes -1
130 i
++; /* Skip the leading '-' see while loop */
131 if (len
<= 1) /* Is it a '-' all by itself? */
132 return; /* Yes, so return */
135 if (! isdigit(buf
[i
])) {
142 (void) sscanf(buf
, "%lld", &num
);
143 (void) sprintf(buf
, "%lld", num
);
163 if ((*p
== '(' || *p
== ')') && p
[1] == '\0')
165 for (i
= 0; *operator[i
]; ++i
)
166 if (EQL(operator[i
], p
))
174 *rel(oper
, r1
, r2
) register char *r1
, *r2
;
178 if (ematch(r1
, "-\\{0,1\\}[0-9]*$") &&
179 ematch(r2
, "-\\{0,1\\}[0-9]*$")) {
181 l1
= strtoll(r1
, (char **)NULL
, 10);
182 l2
= strtoll(r2
, (char **)NULL
, 10);
185 /* XPG6: stdout will always contain newline even on error */
186 (void) write(1, "\n", 1);
188 if (errno
== ERANGE
) {
189 (void) fprintf(stderr
, gettext(
190 "expr: Integer argument too large\n"));
242 return (i
? "1": "0");
246 *arith(oper
, r1
, r2
) char *r1
, *r2
;
251 if (!(ematch(r1
, "-\\{0,1\\}[0-9]*$") &&
252 ematch(r2
, "-\\{0,1\\}[0-9]*$")))
253 yyerror("non-numeric argument");
255 i1
= strtoll(r1
, (char **)NULL
, 10);
256 i2
= strtoll(r2
, (char **)NULL
, 10);
259 /* XPG6: stdout will always contain newline even on error */
260 (void) write(1, "\n", 1);
262 if (errno
== ERANGE
) {
263 (void) fprintf(stderr
, gettext(
264 "expr: Integer argument too large\n"));
284 yyerror("division by zero");
289 yyerror("division by zero");
294 (void) strcpy(rv
, lltoa(i1
));
307 if (EQL(r1
, "0") || EQL(r1
, "")) {
308 if (EQL(r2
, "0") || EQL(r2
, ""))
316 if (EQL(r1
, "0") || EQL(r1
, ""))
318 else if (EQL(r2
, "0") || EQL(r2
, ""))
328 substr(char *v
, char *s
, char *w
)
348 index(char *s
, char *t
)
353 for (i
= 0; s
[i
]; ++i
)
354 for (j
= 0; t
[j
]; ++j
)
356 (void) strcpy(rv
= exprmalloc(8), ltoa(++i
));
371 (void) strcpy(rv
, ltoa(i
));
376 match(char *s
, char *p
)
381 (void) strcpy(rv
= exprmalloc(8), ltoa(val
= (long)ematch(s
, p
)));
382 if (nbra
/* && val != 0 */) {
383 rv
= exprmalloc((unsigned)strlen(Mstring
[0]) + 1);
384 (void) strcpy(rv
, Mstring
[0]);
391 * ematch - XCU4 mods involve calling compile/advance which simulate
392 * the obsolete compile/advance functions using regcomp/regexec
395 ematch(char *s
, char *p
)
401 int nmatch
; /* number of matched bytes */
403 char *tmptr1
= 0; /* If tempbuf is not large enough */
405 int nmbchars
; /* number characters in multibyte string */
408 nexpbuf
= compile(p
, (char *)0, (char *)0); /* XCU4 regex mod */
409 if (0 /* XXX nbra > 1*/)
410 yyerror("Too many '\\('s");
412 if (regerrno
!= 41 || expbuf
== NULL
)
419 if (advance(s
, expbuf
)) {
422 num
= braelist
[0] - p
;
423 if ((num
> MSIZE
- 1) || (num
< 0))
424 yyerror("string too long");
425 (void) strncpy(Mstring
[0], p
, num
);
426 Mstring
[0][num
] = '\0';
430 * Use mbstowcs to find the number of multibyte characters
431 * in the multibyte string beginning at s, and
432 * ending at loc2. Create a separate string
433 * of the substring, so it can be passed to mbstowcs.
436 if (nmatch
> ((sizeof (tempbuf
) / sizeof (char)) - 1)) {
437 tmptr1
= exprmalloc(nmatch
+ 1);
442 memcpy(tmptr
, s
, nmatch
);
443 *(tmptr
+ nmatch
) = '\0';
444 if ((nmbchars
= mbstowcs(NULL
, tmptr
, NULL
)) == -1) {
445 yyerror("invalid multibyte character encountered");
470 /* XPG6: stdout will always contain newline even on error */
471 (void) write(1, "\n", 1);
473 (void) write(2, "expr: ", 6);
474 (void) write(2, gettext(s
), (unsigned)strlen(gettext(s
)));
475 (void) write(2, "\n", 1);
484 char *sp
= &str
[18]; /* u370 */
488 if ((unsigned long)l
== 0x80000000UL
)
489 return ("-2147483648");
511 if (l
== 0x8000000000000000ULL
)
512 return ("-9223372036854775808");
527 expres(int prior
, int par
)
530 char *r1
, *ra
, *rb
, *rc
;
532 if (ylex
>= NOARG
&& ylex
< MATCH
) {
533 yyerror("syntax error");
535 if (ylex
== A_STRING
) {
542 r1
= expres(0, Argi
);
548 if (ylex
> NOARG
&& ylex
< MATCH
) {
551 if (pri
[op1
-OR
] <= prior
)
557 r1
= conj(op1
, r1
, expres(pri
[op1
-OR
], 0));
565 r1
= rel(op1
, r1
, expres(pri
[op1
-OR
], 0));
572 r1
= arith(op1
, r1
, expres(pri
[op1
-OR
], 0));
575 r1
= match(r1
, expres(pri
[op1
-OR
], 0));
588 yyerror("syntax error");
598 if (ylex
> MCH
&& ylex
<= INDEX
) {
606 rb
= expres(pri
[op1
-OR
], 0);
607 ra
= expres(pri
[op1
-OR
], 0);
610 rc
= expres(pri
[op1
-OR
], 0);
611 rb
= expres(pri
[op1
-OR
], 0);
612 ra
= expres(pri
[op1
-OR
], 0);
615 ra
= expres(pri
[op1
-OR
], 0);
618 rb
= expres(pri
[op1
-OR
], 0);
619 ra
= expres(pri
[op1
-OR
], 0);
627 r1
= substr(rc
, rb
, ra
);
650 exprmalloc(size_t size
)
654 if ((rv
= malloc(size
)) == NULL
) {
655 char *s
= gettext("malloc error");
657 (void) write(2, "expr: ", 6);
658 (void) write(2, s
, (unsigned)strlen(s
));
659 (void) write(2, "\n", 1);
666 main(int argc
, char **argv
)
669 * XCU4 allow "--" as argument
671 if (argc
> 1 && strcmp(argv
[1], "--") == 0)
674 * XCU4 - print usage message when invoked without args
678 /* XPG6: stdout will always contain newline even on error */
679 (void) write(1, "\n", 1);
681 (void) fprintf(stderr
, gettext("Usage: expr expression\n"));
690 (void) setlocale(LC_ALL
, "");
691 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
692 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
694 (void) textdomain(TEXT_DOMAIN
);
696 if (Ac
!= Argi
|| paren
!= 0) {
697 yyerror("syntax error");
700 * XCU4 - strip leading zeros from numeric output
703 (void) write(1, buf
, (unsigned)strlen(buf
));
704 (void) write(1, "\n", 1);
705 return ((strcmp(buf
, "0") == 0 || buf
[0] == 0) ? 1 : 0);