1 /* expr -- evaluate expressions.
2 Copyright (C) 1986-2016 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* Author: Mike Parker.
18 Modified for arbitrary-precision calculation by James Youngman.
20 This program evaluates expressions. Each token (operator, operand,
21 parenthesis) of the expression must be a separate argument. The
22 parser used is a reasonably general one, though any incarnation of
23 it is language-specific. It is especially nice for expressions.
25 No parse tree is needed; a new node is evaluated immediately.
26 One function can handle multiple operators all of equal precedence,
27 provided they all associate ((x op x) op x).
29 Define EVAL_TRACE to print an evaluation trace. */
33 #include <sys/types.h>
38 #include "long-options.h"
39 #include "strnumcmp.h"
42 /* Various parts of this code assume size_t fits into unsigned long
43 int, the widest unsigned type that GMP supports. */
44 verify (SIZE_MAX
<= ULONG_MAX
);
53 static void integer_overflow (char) ATTRIBUTE_NORETURN
;
54 /* Approximate gmp.h well enough for expr.c's purposes. */
55 typedef intmax_t mpz_t
[1];
56 static void mpz_clear (mpz_t z
) { (void) z
; }
57 static void mpz_init_set_ui (mpz_t z
, unsigned long int i
) { z
[0] = i
; }
59 mpz_init_set_str (mpz_t z
, char *s
, int base
)
61 return xstrtoimax (s
, NULL
, base
, z
, NULL
) == LONGINT_OK
? 0 : -1;
64 mpz_add (mpz_t r
, mpz_t a0
, mpz_t b0
)
69 if ((val
< a
) != (b
< 0))
70 integer_overflow ('+');
74 mpz_sub (mpz_t r
, mpz_t a0
, mpz_t b0
)
79 if ((a
< val
) != (b
< 0))
80 integer_overflow ('-');
84 mpz_mul (mpz_t r
, mpz_t a0
, mpz_t b0
)
89 if (! (a
== 0 || b
== 0
90 || ((val
< 0) == ((a
< 0) ^ (b
< 0)) && val
/ a
== b
)))
91 integer_overflow ('*');
95 mpz_tdiv_q (mpz_t r
, mpz_t a0
, mpz_t b0
)
100 /* Some x86-style hosts raise an exception for INT_MIN / -1. */
101 if (a
< - INTMAX_MAX
&& b
== -1)
102 integer_overflow ('/');
106 mpz_tdiv_r (mpz_t r
, mpz_t a0
, mpz_t b0
)
111 /* Some x86-style hosts raise an exception for INT_MIN % -1. */
112 r
[0] = a
< - INTMAX_MAX
&& b
== -1 ? 0 : a
% b
;
115 mpz_get_str (char const *str
, int base
, mpz_t z
)
117 (void) str
; (void) base
;
118 char buf
[INT_BUFSIZE_BOUND (intmax_t)];
119 return xstrdup (imaxtostr (z
[0], buf
));
124 return z
[0] < 0 ? -1 : 0 < z
[0];
127 mpz_fits_ulong_p (mpz_t z
)
129 return 0 <= z
[0] && z
[0] <= ULONG_MAX
;
131 static unsigned long int
137 mpz_out_str (FILE *stream
, int base
, mpz_t z
)
140 char buf
[INT_BUFSIZE_BOUND (intmax_t)];
141 return fputs (imaxtostr (z
[0], buf
), stream
) != EOF
;
145 /* The official name of this program (e.g., no 'g' prefix). */
146 #define PROGRAM_NAME "expr"
149 proper_name ("Mike Parker"), \
150 proper_name ("James Youngman"), \
151 proper_name ("Paul Eggert")
156 /* Invalid expression: e.g., its form does not conform to the
157 grammar for expressions. Our grammar is an extension of the
161 /* An internal error occurred, e.g., arithmetic overflow, storage
166 /* The kinds of value we can have. */
172 typedef enum valtype TYPE
;
177 TYPE type
; /* Which kind. */
179 { /* The value itself. */
184 typedef struct valinfo VALUE
;
186 /* The arguments given to the program, minus the program name. */
189 static VALUE
*eval (bool);
190 static bool nomoreargs (void);
191 static bool null (VALUE
*v
);
192 static void printv (VALUE
*v
);
197 if (status
!= EXIT_SUCCESS
)
202 Usage: %s EXPRESSION\n\
205 program_name
, program_name
);
207 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
208 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
211 Print the value of EXPRESSION to standard output. A blank line below\n\
212 separates increasing precedence groups. EXPRESSION may be:\n\
214 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
216 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
220 ARG1 < ARG2 ARG1 is less than ARG2\n\
221 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
222 ARG1 = ARG2 ARG1 is equal to ARG2\n\
223 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
224 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
225 ARG1 > ARG2 ARG1 is greater than ARG2\n\
229 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
230 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
232 /* Tell xgettext that the "% A" below is not a printf-style
233 format string: xgettext:no-c-format */
236 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
237 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
238 ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
242 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
244 match STRING REGEXP same as STRING : REGEXP\n\
245 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
246 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
247 length STRING length of STRING\n\
250 + TOKEN interpret TOKEN as a string, even if it is a\n\
251 keyword like 'match' or an operator like '/'\n\
253 ( EXPRESSION ) value of EXPRESSION\n\
257 Beware that many operators need to be escaped or quoted for shells.\n\
258 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
259 Pattern matches return the string matched between \\( and \\) or null; if\n\
260 \\( and \\) are not used, they return the number of characters matched or 0.\n\
264 Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null\n\
265 or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.\n\
267 emit_ancillary_info (PROGRAM_NAME
);
272 /* Report a syntax error and exit. */
276 error (EXPR_INVALID
, 0, _("syntax error"));
280 /* Report an integer overflow for operation OP and exit. */
282 integer_overflow (char op
)
284 error (EXPR_FAILURE
, ERANGE
, "%c", op
);
285 abort (); /* notreached */
290 main (int argc
, char **argv
)
294 initialize_main (&argc
, &argv
);
295 set_program_name (argv
[0]);
296 setlocale (LC_ALL
, "");
297 bindtextdomain (PACKAGE
, LOCALEDIR
);
298 textdomain (PACKAGE
);
300 initialize_exit_failure (EXPR_FAILURE
);
301 atexit (close_stdout
);
303 parse_long_options (argc
, argv
, PROGRAM_NAME
, PACKAGE_NAME
, VERSION
,
304 usage
, AUTHORS
, (char const *) NULL
);
306 /* The above handles --help and --version.
307 Since there is no other invocation of getopt, handle '--' here. */
308 unsigned int u_argc
= argc
;
309 if (1 < u_argc
&& STREQ (argv
[1], "--"))
317 error (0, 0, _("missing operand"));
318 usage (EXPR_INVALID
);
331 /* Return a VALUE for I. */
334 int_value (unsigned long int i
)
336 VALUE
*v
= xmalloc (sizeof *v
);
338 mpz_init_set_ui (v
->u
.i
, i
);
342 /* Return a VALUE for S. */
345 str_value (char const *s
)
347 VALUE
*v
= xmalloc (sizeof *v
);
349 v
->u
.s
= xstrdup (s
);
353 /* Free VALUE V, including structure components. */
358 if (v
->type
== string
)
373 mpz_out_str (stdout
, 10, v
->u
.i
);
384 /* Return true if V is a null-string or zero-number. */
386 static bool _GL_ATTRIBUTE_PURE
392 return mpz_sgn (v
->u
.i
) == 0;
395 char const *cp
= v
->u
.s
;
415 /* Return true if CP takes the form of an integer. */
417 static bool _GL_ATTRIBUTE_PURE
418 looks_like_integer (char const *cp
)
430 /* Coerce V to a string value (can't fail). */
439 char *s
= mpz_get_str (NULL
, 10, v
->u
.i
);
452 /* Coerce V to an integer value. Return true on success, false on failure. */
465 if (! looks_like_integer (s
))
467 if (mpz_init_set_str (v
->u
.i
, s
, 10) != 0 && !HAVE_GMP
)
468 error (EXPR_FAILURE
, ERANGE
, "%s", (s
));
478 /* Extract a size_t value from an integer value I.
479 If the value is negative, return SIZE_MAX.
480 If the value is too large, return SIZE_MAX - 1. */
486 if (mpz_fits_ulong_p (i
))
488 unsigned long int ul
= mpz_get_ui (i
);
495 /* Return true and advance if the next token matches STR exactly.
496 STR must not be NULL. */
499 nextarg (char const *str
)
505 bool r
= STREQ (*args
, str
);
511 /* Return true if there no more tokens. */
520 /* Print evaluation trace and args remaining. */
529 for (a
= args
; *a
; a
++)
535 /* Do the : operator.
536 SV is the VALUE for the lhs (the string),
537 PV is the VALUE for the rhs (the pattern). */
540 docolon (VALUE
*sv
, VALUE
*pv
)
542 VALUE
*v
IF_LINT ( = NULL
);
544 struct re_pattern_buffer re_buffer
;
545 char fastmap
[UCHAR_MAX
+ 1];
546 struct re_registers re_regs
;
552 re_regs
.num_regs
= 0;
553 re_regs
.start
= NULL
;
556 re_buffer
.buffer
= NULL
;
557 re_buffer
.allocated
= 0;
558 re_buffer
.fastmap
= fastmap
;
559 re_buffer
.translate
= NULL
;
561 RE_SYNTAX_POSIX_BASIC
& ~RE_CONTEXT_INVALID_DUP
& ~RE_NO_EMPTY_RANGES
;
562 errmsg
= re_compile_pattern (pv
->u
.s
, strlen (pv
->u
.s
), &re_buffer
);
564 error (EXPR_INVALID
, 0, "%s", (errmsg
));
565 re_buffer
.newline_anchor
= 0;
567 matchlen
= re_match (&re_buffer
, sv
->u
.s
, strlen (sv
->u
.s
), 0, &re_regs
);
570 /* Were \(...\) used? */
571 if (re_buffer
.re_nsub
> 0)
573 sv
->u
.s
[re_regs
.end
[1]] = '\0';
574 v
= str_value (sv
->u
.s
+ re_regs
.start
[1]);
577 v
= int_value (matchlen
);
579 else if (matchlen
== -1)
581 /* Match failed -- return the right kind of null. */
582 if (re_buffer
.re_nsub
> 0)
589 (matchlen
== -2 ? errno
: EOVERFLOW
),
590 _("error in regular expression matcher"));
592 if (0 < re_regs
.num_regs
)
594 free (re_regs
.start
);
597 re_buffer
.fastmap
= NULL
;
598 regfree (&re_buffer
);
602 /* Handle bare operands and ( expr ) syntax. */
605 eval7 (bool evaluate
)
626 return str_value (*args
++);
629 /* Handle match, substr, index, and length keywords, and quoting "+". */
632 eval6 (bool evaluate
)
647 return str_value (*args
++);
649 else if (nextarg ("length"))
651 r
= eval6 (evaluate
);
653 v
= int_value (strlen (r
->u
.s
));
657 else if (nextarg ("match"))
659 l
= eval6 (evaluate
);
660 r
= eval6 (evaluate
);
671 else if (nextarg ("index"))
675 l
= eval6 (evaluate
);
676 r
= eval6 (evaluate
);
679 pos
= strcspn (l
->u
.s
, r
->u
.s
);
680 v
= int_value (l
->u
.s
[pos
] ? pos
+ 1 : 0);
685 else if (nextarg ("substr"))
688 l
= eval6 (evaluate
);
689 i1
= eval6 (evaluate
);
690 i2
= eval6 (evaluate
);
692 llen
= strlen (l
->u
.s
);
694 if (!toarith (i1
) || !toarith (i2
))
698 size_t pos
= getsize (i1
->u
.i
);
699 size_t len
= getsize (i2
->u
.i
);
701 if (llen
< pos
|| pos
== 0 || len
== 0 || len
== SIZE_MAX
)
705 size_t vlen
= MIN (len
, llen
- pos
+ 1);
707 v
= xmalloc (sizeof *v
);
709 v
->u
.s
= xmalloc (vlen
+ 1);
710 vlim
= mempcpy (v
->u
.s
, l
->u
.s
+ pos
- 1, vlen
);
720 return eval7 (evaluate
);
723 /* Handle : operator (pattern matching).
724 Calls docolon to do the real work. */
727 eval5 (bool evaluate
)
736 l
= eval6 (evaluate
);
741 r
= eval6 (evaluate
);
755 /* Handle *, /, % operators. */
758 eval4 (bool evaluate
)
762 enum { multiply
, divide
, mod
} fxn
;
767 l
= eval5 (evaluate
);
772 else if (nextarg ("/"))
774 else if (nextarg ("%"))
778 r
= eval5 (evaluate
);
781 if (!toarith (l
) || !toarith (r
))
782 error (EXPR_INVALID
, 0, _("non-integer argument"));
783 if (fxn
!= multiply
&& mpz_sgn (r
->u
.i
) == 0)
784 error (EXPR_INVALID
, 0, _("division by zero"));
785 ((fxn
== multiply
? mpz_mul
786 : fxn
== divide
? mpz_tdiv_q
788 (l
->u
.i
, l
->u
.i
, r
->u
.i
));
794 /* Handle +, - operators. */
797 eval3 (bool evaluate
)
801 enum { plus
, minus
} fxn
;
806 l
= eval4 (evaluate
);
811 else if (nextarg ("-"))
815 r
= eval4 (evaluate
);
818 if (!toarith (l
) || !toarith (r
))
819 error (EXPR_INVALID
, 0, _("non-integer argument"));
820 (fxn
== plus
? mpz_add
: mpz_sub
) (l
->u
.i
, l
->u
.i
, r
->u
.i
);
826 /* Handle comparisons. */
829 eval2 (bool evaluate
)
836 l
= eval3 (evaluate
);
842 less_than
, less_equal
, equal
, not_equal
, greater_equal
, greater_than
848 else if (nextarg ("<="))
850 else if (nextarg ("=") || nextarg ("=="))
852 else if (nextarg ("!="))
854 else if (nextarg (">="))
856 else if (nextarg (">"))
860 r
= eval3 (evaluate
);
868 if (looks_like_integer (l
->u
.s
) && looks_like_integer (r
->u
.s
))
869 cmp
= strintcmp (l
->u
.s
, r
->u
.s
);
873 cmp
= strcoll (l
->u
.s
, r
->u
.s
);
877 error (0, errno
, _("string comparison failed"));
878 error (0, 0, _("set LC_ALL='C' to work around the problem"));
879 error (EXPR_INVALID
, 0,
880 _("the strings compared were %s and %s"),
881 quotearg_n_style (0, locale_quoting_style
, l
->u
.s
),
882 quotearg_n_style (1, locale_quoting_style
, r
->u
.s
));
888 case less_than
: val
= (cmp
< 0); break;
889 case less_equal
: val
= (cmp
<= 0); break;
890 case equal
: val
= (cmp
== 0); break;
891 case not_equal
: val
= (cmp
!= 0); break;
892 case greater_equal
: val
= (cmp
>= 0); break;
893 case greater_than
: val
= (cmp
> 0); break;
907 eval1 (bool evaluate
)
915 l
= eval2 (evaluate
);
920 r
= eval2 (evaluate
&& !null (l
));
921 if (null (l
) || null (r
))
946 l
= eval1 (evaluate
);
951 r
= eval1 (evaluate
&& null (l
));