Line data Source code
1 : /* expr -- evaluate expressions.
2 : Copyright (C) 86, 1991-1997, 1999-2007 Free Software Foundation, Inc.
3 :
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.
8 :
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.
13 :
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/>. */
16 :
17 : /* Author: Mike Parker.
18 :
19 : This program evaluates expressions. Each token (operator, operand,
20 : parenthesis) of the expression must be a seperate argument. The
21 : parser used is a reasonably general one, though any incarnation of
22 : it is language-specific. It is especially nice for expressions.
23 :
24 : No parse tree is needed; a new node is evaluated immediately.
25 : One function can handle multiple operators all of equal precedence,
26 : provided they all associate ((x op x) op x).
27 :
28 : Define EVAL_TRACE to print an evaluation trace. */
29 :
30 : #include <config.h>
31 : #include <stdio.h>
32 : #include <sys/types.h>
33 : #include "system.h"
34 :
35 : #include <regex.h>
36 : #include "long-options.h"
37 : #include "error.h"
38 : #include "inttostr.h"
39 : #include "quotearg.h"
40 : #include "strnumcmp.h"
41 : #include "xstrtol.h"
42 :
43 : /* The official name of this program (e.g., no `g' prefix). */
44 : #define PROGRAM_NAME "expr"
45 :
46 : #define AUTHORS "Mike Parker"
47 :
48 : /* Exit statuses. */
49 : enum
50 : {
51 : /* Invalid expression: e.g., its form does not conform to the
52 : grammar for expressions. Our grammar is an extension of the
53 : POSIX grammar. */
54 : EXPR_INVALID = 2,
55 :
56 : /* An internal error occurred, e.g., arithmetic overflow, storage
57 : exhaustion. */
58 : EXPR_FAILURE
59 : };
60 :
61 : /* The kinds of value we can have. */
62 : enum valtype
63 : {
64 : integer,
65 : string
66 : };
67 : typedef enum valtype TYPE;
68 :
69 : /* A value is.... */
70 : struct valinfo
71 : {
72 : TYPE type; /* Which kind. */
73 : union
74 : { /* The value itself. */
75 : intmax_t i;
76 : char *s;
77 : } u;
78 : };
79 : typedef struct valinfo VALUE;
80 :
81 : /* The arguments given to the program, minus the program name. */
82 : static char **args;
83 :
84 : /* The name this program was run with. */
85 : char *program_name;
86 :
87 : static VALUE *eval (bool);
88 : static bool nomoreargs (void);
89 : static bool null (VALUE *v);
90 : static void printv (VALUE *v);
91 :
92 : void
93 4 : usage (int status)
94 : {
95 4 : if (status != EXIT_SUCCESS)
96 2 : fprintf (stderr, _("Try `%s --help' for more information.\n"),
97 : program_name);
98 : else
99 : {
100 2 : printf (_("\
101 : Usage: %s EXPRESSION\n\
102 : or: %s OPTION\n\
103 : "),
104 : program_name, program_name);
105 2 : putchar ('\n');
106 2 : fputs (HELP_OPTION_DESCRIPTION, stdout);
107 2 : fputs (VERSION_OPTION_DESCRIPTION, stdout);
108 2 : fputs (_("\
109 : \n\
110 : Print the value of EXPRESSION to standard output. A blank line below\n\
111 : separates increasing precedence groups. EXPRESSION may be:\n\
112 : \n\
113 : ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
114 : \n\
115 : ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
116 : "), stdout);
117 2 : fputs (_("\
118 : \n\
119 : ARG1 < ARG2 ARG1 is less than ARG2\n\
120 : ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
121 : ARG1 = ARG2 ARG1 is equal to ARG2\n\
122 : ARG1 != ARG2 ARG1 is unequal to ARG2\n\
123 : ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
124 : ARG1 > ARG2 ARG1 is greater than ARG2\n\
125 : "), stdout);
126 2 : fputs (_("\
127 : \n\
128 : ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
129 : ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
130 : "), stdout);
131 : /* Tell xgettext that the "% A" below is not a printf-style
132 : format string: xgettext:no-c-format */
133 2 : fputs (_("\
134 : \n\
135 : ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
136 : ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
137 : ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
138 : "), stdout);
139 2 : fputs (_("\
140 : \n\
141 : STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
142 : \n\
143 : match STRING REGEXP same as STRING : REGEXP\n\
144 : substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
145 : index STRING CHARS index in STRING where any CHARS is found, or 0\n\
146 : length STRING length of STRING\n\
147 : "), stdout);
148 2 : fputs (_("\
149 : + TOKEN interpret TOKEN as a string, even if it is a\n\
150 : keyword like `match' or an operator like `/'\n\
151 : \n\
152 : ( EXPRESSION ) value of EXPRESSION\n\
153 : "), stdout);
154 2 : fputs (_("\
155 : \n\
156 : Beware that many operators need to be escaped or quoted for shells.\n\
157 : Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
158 : Pattern matches return the string matched between \\( and \\) or null; if\n\
159 : \\( and \\) are not used, they return the number of characters matched or 0.\n\
160 : "), stdout);
161 2 : fputs (_("\
162 : \n\
163 : Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null\n\
164 : or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.\n\
165 : "), stdout);
166 2 : emit_bug_reporting_address ();
167 : }
168 4 : exit (status);
169 : }
170 :
171 : /* Report a syntax error and exit. */
172 : static void
173 27 : syntax_error (void)
174 : {
175 27 : error (EXPR_INVALID, 0, _("syntax error"));
176 0 : }
177 :
178 : /* Report an integer overflow for operation OP and exit. */
179 : static void
180 0 : integer_overflow (char op)
181 : {
182 0 : error (EXPR_FAILURE, ERANGE, "%c", op);
183 0 : }
184 :
185 : int
186 121 : main (int argc, char **argv)
187 : {
188 : VALUE *v;
189 :
190 : initialize_main (&argc, &argv);
191 121 : program_name = argv[0];
192 121 : setlocale (LC_ALL, "");
193 : bindtextdomain (PACKAGE, LOCALEDIR);
194 : textdomain (PACKAGE);
195 :
196 121 : initialize_exit_failure (EXPR_FAILURE);
197 121 : atexit (close_stdout);
198 :
199 121 : parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, VERSION,
200 : usage, AUTHORS, (char const *) NULL);
201 : /* The above handles --help and --version.
202 : Since there is no other invocation of getopt, handle `--' here. */
203 118 : if (argc > 1 && STREQ (argv[1], "--"))
204 : {
205 6 : --argc;
206 6 : ++argv;
207 : }
208 :
209 118 : if (argc <= 1)
210 : {
211 2 : error (0, 0, _("missing operand"));
212 2 : usage (EXPR_INVALID);
213 : }
214 :
215 116 : args = argv + 1;
216 :
217 116 : v = eval (true);
218 73 : if (!nomoreargs ())
219 1 : syntax_error ();
220 72 : printv (v);
221 :
222 72 : exit (null (v));
223 : }
224 :
225 : /* Return a VALUE for I. */
226 :
227 : static VALUE *
228 59 : int_value (intmax_t i)
229 : {
230 59 : VALUE *v = xmalloc (sizeof *v);
231 59 : v->type = integer;
232 59 : v->u.i = i;
233 59 : return v;
234 : }
235 :
236 : /* Return a VALUE for S. */
237 :
238 : static VALUE *
239 189 : str_value (char const *s)
240 : {
241 189 : VALUE *v = xmalloc (sizeof *v);
242 189 : v->type = string;
243 189 : v->u.s = xstrdup (s);
244 189 : return v;
245 : }
246 :
247 : /* Free VALUE V, including structure components. */
248 :
249 : static void
250 119 : freev (VALUE *v)
251 : {
252 119 : if (v->type == string)
253 103 : free (v->u.s);
254 119 : free (v);
255 119 : }
256 :
257 : /* Print VALUE V. */
258 :
259 : static void
260 72 : printv (VALUE *v)
261 : {
262 : char *p;
263 : char buf[INT_BUFSIZE_BOUND (intmax_t)];
264 :
265 72 : switch (v->type)
266 : {
267 59 : case integer:
268 59 : p = imaxtostr (v->u.i, buf);
269 59 : break;
270 13 : case string:
271 13 : p = v->u.s;
272 13 : break;
273 0 : default:
274 0 : abort ();
275 : }
276 :
277 72 : puts (p);
278 72 : }
279 :
280 : /* Return true if V is a null-string or zero-number. */
281 :
282 : static bool
283 82 : null (VALUE *v)
284 : {
285 82 : switch (v->type)
286 : {
287 59 : case integer:
288 59 : return v->u.i == 0;
289 23 : case string:
290 : {
291 23 : char const *cp = v->u.s;
292 23 : if (*cp == '\0')
293 2 : return true;
294 :
295 21 : cp += (*cp == '-');
296 :
297 : do
298 : {
299 23 : if (*cp != '0')
300 16 : return false;
301 : }
302 7 : while (*++cp);
303 :
304 5 : return true;
305 : }
306 0 : default:
307 0 : abort ();
308 : }
309 : }
310 :
311 : /* Return true if CP takes the form of an integer. */
312 :
313 : static bool
314 32 : looks_like_integer (char const *cp)
315 : {
316 32 : cp += (*cp == '-');
317 :
318 : do
319 35 : if (! ISDIGIT (*cp))
320 11 : return false;
321 24 : while (*++cp);
322 :
323 21 : return true;
324 : }
325 :
326 : /* Coerce V to a string value (can't fail). */
327 :
328 : static void
329 123 : tostring (VALUE *v)
330 : {
331 : char buf[INT_BUFSIZE_BOUND (intmax_t)];
332 :
333 123 : switch (v->type)
334 : {
335 0 : case integer:
336 0 : v->u.s = xstrdup (imaxtostr (v->u.i, buf));
337 0 : v->type = string;
338 0 : break;
339 123 : case string:
340 123 : break;
341 0 : default:
342 0 : abort ();
343 : }
344 123 : }
345 :
346 : /* Coerce V to an integer value. Return true on success, false on failure. */
347 :
348 : static bool
349 24 : toarith (VALUE *v)
350 : {
351 24 : switch (v->type)
352 : {
353 0 : case integer:
354 0 : return true;
355 24 : case string:
356 : {
357 : intmax_t value;
358 :
359 24 : if (! looks_like_integer (v->u.s))
360 4 : return false;
361 20 : if (xstrtoimax (v->u.s, NULL, 10, &value, NULL) != LONGINT_OK)
362 0 : error (EXPR_FAILURE, ERANGE, "%s", v->u.s);
363 20 : free (v->u.s);
364 20 : v->u.i = value;
365 20 : v->type = integer;
366 20 : return true;
367 : }
368 0 : default:
369 0 : abort ();
370 : }
371 : }
372 :
373 : /* Return true and advance if the next token matches STR exactly.
374 : STR must not be NULL. */
375 :
376 : static bool
377 2842 : nextarg (char const *str)
378 : {
379 2842 : if (*args == NULL)
380 1192 : return false;
381 : else
382 : {
383 1650 : bool r = STREQ (*args, str);
384 1650 : args += r;
385 1650 : return r;
386 : }
387 : }
388 :
389 : /* Return true if there no more tokens. */
390 :
391 : static bool
392 289 : nomoreargs (void)
393 : {
394 289 : return *args == 0;
395 : }
396 :
397 : #ifdef EVAL_TRACE
398 : /* Print evaluation trace and args remaining. */
399 :
400 : static void
401 : trace (fxn)
402 : char *fxn;
403 : {
404 : char **a;
405 :
406 : printf ("%s:", fxn);
407 : for (a = args; *a; a++)
408 : printf (" %s", *a);
409 : putchar ('\n');
410 : }
411 : #endif
412 :
413 : /* Do the : operator.
414 : SV is the VALUE for the lhs (the string),
415 : PV is the VALUE for the rhs (the pattern). */
416 :
417 : static VALUE *
418 51 : docolon (VALUE *sv, VALUE *pv)
419 : {
420 : VALUE *v IF_LINT (= NULL);
421 : const char *errmsg;
422 : struct re_pattern_buffer re_buffer;
423 : char fastmap[UCHAR_MAX + 1];
424 : struct re_registers re_regs;
425 : regoff_t matchlen;
426 :
427 51 : tostring (sv);
428 51 : tostring (pv);
429 :
430 51 : re_regs.num_regs = 0;
431 51 : re_regs.start = NULL;
432 51 : re_regs.end = NULL;
433 :
434 51 : re_buffer.buffer = NULL;
435 51 : re_buffer.allocated = 0;
436 51 : re_buffer.fastmap = fastmap;
437 51 : re_buffer.translate = NULL;
438 51 : re_syntax_options =
439 : RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP & ~RE_NO_EMPTY_RANGES;
440 51 : errmsg = re_compile_pattern (pv->u.s, strlen (pv->u.s), &re_buffer);
441 51 : if (errmsg)
442 12 : error (EXPR_INVALID, 0, "%s", errmsg);
443 39 : re_buffer.newline_anchor = 0;
444 :
445 39 : matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
446 39 : if (0 <= matchlen)
447 : {
448 : /* Were \(...\) used? */
449 14 : if (re_buffer.re_nsub > 0)
450 : {
451 0 : sv->u.s[re_regs.end[1]] = '\0';
452 0 : v = str_value (sv->u.s + re_regs.start[1]);
453 : }
454 : else
455 14 : v = int_value (matchlen);
456 : }
457 25 : else if (matchlen == -1)
458 : {
459 : /* Match failed -- return the right kind of null. */
460 25 : if (re_buffer.re_nsub > 0)
461 0 : v = str_value ("");
462 : else
463 25 : v = int_value (0);
464 : }
465 : else
466 0 : error (EXPR_FAILURE,
467 0 : (matchlen == -2 ? errno : EOVERFLOW),
468 : _("error in regular expression matcher"));
469 :
470 39 : if (0 < re_regs.num_regs)
471 : {
472 14 : free (re_regs.start);
473 14 : free (re_regs.end);
474 : }
475 39 : re_buffer.fastmap = NULL;
476 39 : regfree (&re_buffer);
477 39 : return v;
478 : }
479 :
480 : /* Handle bare operands and ( expr ) syntax. */
481 :
482 : static VALUE *
483 198 : eval7 (bool evaluate)
484 : {
485 : VALUE *v;
486 :
487 : #ifdef EVAL_TRACE
488 : trace ("eval7");
489 : #endif
490 198 : if (nomoreargs ())
491 17 : syntax_error ();
492 :
493 181 : if (nextarg ("("))
494 : {
495 2 : v = eval (evaluate);
496 1 : if (!nextarg (")"))
497 1 : syntax_error ();
498 0 : return v;
499 : }
500 :
501 179 : if (nextarg (")"))
502 1 : syntax_error ();
503 :
504 178 : return str_value (*args++);
505 : }
506 :
507 : /* Handle match, substr, index, and length keywords, and quoting "+". */
508 :
509 : static VALUE *
510 225 : eval6 (bool evaluate)
511 : {
512 : VALUE *l;
513 : VALUE *r;
514 : VALUE *v;
515 : VALUE *i1;
516 : VALUE *i2;
517 :
518 : #ifdef EVAL_TRACE
519 : trace ("eval6");
520 : #endif
521 225 : if (nextarg ("+"))
522 : {
523 18 : if (nomoreargs ())
524 7 : syntax_error ();
525 11 : return str_value (*args++);
526 : }
527 207 : else if (nextarg ("length"))
528 : {
529 1 : r = eval6 (evaluate);
530 1 : tostring (r);
531 1 : v = int_value (strlen (r->u.s));
532 1 : freev (r);
533 1 : return v;
534 : }
535 206 : else if (nextarg ("match"))
536 : {
537 2 : l = eval6 (evaluate);
538 2 : r = eval6 (evaluate);
539 1 : if (evaluate)
540 : {
541 1 : v = docolon (l, r);
542 1 : freev (l);
543 : }
544 : else
545 0 : v = l;
546 1 : freev (r);
547 1 : return v;
548 : }
549 204 : else if (nextarg ("index"))
550 : {
551 4 : l = eval6 (evaluate);
552 4 : r = eval6 (evaluate);
553 3 : tostring (l);
554 3 : tostring (r);
555 3 : v = int_value (strcspn (l->u.s, r->u.s) + 1);
556 3 : if (v->u.i == strlen (l->u.s) + 1)
557 2 : v->u.i = 0;
558 3 : freev (l);
559 3 : freev (r);
560 3 : return v;
561 : }
562 200 : else if (nextarg ("substr"))
563 : {
564 : size_t llen;
565 2 : l = eval6 (evaluate);
566 2 : i1 = eval6 (evaluate);
567 1 : i2 = eval6 (evaluate);
568 0 : tostring (l);
569 0 : llen = strlen (l->u.s);
570 0 : if (!toarith (i1) || !toarith (i2)
571 0 : || llen < i1->u.i
572 0 : || i1->u.i <= 0 || i2->u.i <= 0)
573 0 : v = str_value ("");
574 : else
575 : {
576 0 : size_t vlen = MIN (i2->u.i, llen - i1->u.i + 1);
577 : char *vlim;
578 0 : v = xmalloc (sizeof *v);
579 0 : v->type = string;
580 0 : v->u.s = xmalloc (vlen + 1);
581 0 : vlim = mempcpy (v->u.s, l->u.s + i1->u.i - 1, vlen);
582 0 : *vlim = '\0';
583 : }
584 0 : freev (l);
585 0 : freev (i1);
586 0 : freev (i2);
587 0 : return v;
588 : }
589 : else
590 198 : return eval7 (evaluate);
591 : }
592 :
593 : /* Handle : operator (pattern matching).
594 : Calls docolon to do the real work. */
595 :
596 : static VALUE *
597 155 : eval5 (bool evaluate)
598 : {
599 : VALUE *l;
600 : VALUE *r;
601 : VALUE *v;
602 :
603 : #ifdef EVAL_TRACE
604 : trace ("eval5");
605 : #endif
606 155 : l = eval6 (evaluate);
607 : while (1)
608 : {
609 206 : if (nextarg (":"))
610 : {
611 52 : r = eval6 (evaluate);
612 50 : if (evaluate)
613 : {
614 50 : v = docolon (l, r);
615 38 : freev (l);
616 38 : l = v;
617 : }
618 38 : freev (r);
619 : }
620 : else
621 232 : return l;
622 : }
623 : }
624 :
625 : /* Handle *, /, % operators. */
626 :
627 : static VALUE *
628 141 : eval4 (bool evaluate)
629 : {
630 : VALUE *l;
631 : VALUE *r;
632 : enum { multiply, divide, mod } fxn;
633 141 : intmax_t val = 0;
634 :
635 : #ifdef EVAL_TRACE
636 : trace ("eval4");
637 : #endif
638 141 : l = eval5 (evaluate);
639 : while (1)
640 : {
641 121 : if (nextarg ("*"))
642 8 : fxn = multiply;
643 105 : else if (nextarg ("/"))
644 4 : fxn = divide;
645 101 : else if (nextarg ("%"))
646 2 : fxn = mod;
647 : else
648 198 : return l;
649 14 : r = eval5 (evaluate);
650 11 : if (evaluate)
651 : {
652 11 : if (!toarith (l) || !toarith (r))
653 2 : error (EXPR_INVALID, 0, _("non-numeric argument"));
654 9 : if (fxn == multiply)
655 : {
656 5 : val = l->u.i * r->u.i;
657 8 : if (! (l->u.i == 0 || r->u.i == 0
658 3 : || ((val < 0) == ((l->u.i < 0) ^ (r->u.i < 0))
659 3 : && val / l->u.i == r->u.i)))
660 0 : integer_overflow ('*');
661 : }
662 : else
663 : {
664 4 : if (r->u.i == 0)
665 1 : error (EXPR_INVALID, 0, _("division by zero"));
666 3 : if (l->u.i < - INTMAX_MAX && r->u.i == -1)
667 : {
668 : /* Some x86-style hosts raise an exception for
669 : INT_MIN / -1 and INT_MIN % -1, so handle these
670 : problematic cases specially. */
671 0 : if (fxn == divide)
672 0 : integer_overflow ('/');
673 0 : val = 0;
674 : }
675 : else
676 3 : val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
677 : }
678 : }
679 8 : freev (l);
680 8 : freev (r);
681 8 : l = int_value (val);
682 : }
683 : }
684 :
685 : /* Handle +, - operators. */
686 :
687 : static VALUE *
688 137 : eval3 (bool evaluate)
689 : {
690 : VALUE *l;
691 : VALUE *r;
692 : enum { plus, minus } fxn;
693 137 : intmax_t val = 0;
694 :
695 : #ifdef EVAL_TRACE
696 : trace ("eval3");
697 : #endif
698 137 : l = eval4 (evaluate);
699 : while (1)
700 : {
701 97 : if (nextarg ("+"))
702 3 : fxn = plus;
703 94 : else if (nextarg ("-"))
704 1 : fxn = minus;
705 : else
706 186 : return l;
707 4 : r = eval4 (evaluate);
708 2 : if (evaluate)
709 : {
710 2 : if (!toarith (l) || !toarith (r))
711 2 : error (EXPR_INVALID, 0, _("non-numeric argument"));
712 0 : if (fxn == plus)
713 : {
714 0 : val = l->u.i + r->u.i;
715 0 : if ((val < l->u.i) != (r->u.i < 0))
716 0 : integer_overflow ('+');
717 : }
718 : else
719 : {
720 0 : val = l->u.i - r->u.i;
721 0 : if ((l->u.i < val) != (r->u.i < 0))
722 0 : integer_overflow ('-');
723 : }
724 : }
725 0 : freev (l);
726 0 : freev (r);
727 0 : l = int_value (val);
728 : }
729 : }
730 :
731 : /* Handle comparisons. */
732 :
733 : static VALUE *
734 123 : eval2 (bool evaluate)
735 : {
736 : VALUE *l;
737 :
738 : #ifdef EVAL_TRACE
739 : trace ("eval2");
740 : #endif
741 123 : l = eval3 (evaluate);
742 : while (1)
743 7 : {
744 : VALUE *r;
745 : enum
746 : {
747 : less_than, less_equal, equal, not_equal, greater_equal, greater_than
748 : } fxn;
749 93 : bool val = false;
750 :
751 93 : if (nextarg ("<"))
752 3 : fxn = less_than;
753 90 : else if (nextarg ("<="))
754 2 : fxn = less_equal;
755 88 : else if (nextarg ("=") || nextarg ("=="))
756 3 : fxn = equal;
757 85 : else if (nextarg ("!="))
758 2 : fxn = not_equal;
759 83 : else if (nextarg (">="))
760 2 : fxn = greater_equal;
761 81 : else if (nextarg (">"))
762 2 : fxn = greater_than;
763 : else
764 158 : return l;
765 14 : r = eval3 (evaluate);
766 :
767 7 : if (evaluate)
768 : {
769 : int cmp;
770 7 : tostring (l);
771 7 : tostring (r);
772 :
773 7 : if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))
774 0 : cmp = strintcmp (l->u.s, r->u.s);
775 : else
776 : {
777 7 : errno = 0;
778 7 : cmp = strcoll (l->u.s, r->u.s);
779 :
780 7 : if (errno)
781 : {
782 0 : error (0, errno, _("string comparison failed"));
783 0 : error (0, 0, _("Set LC_ALL='C' to work around the problem."));
784 0 : error (EXPR_INVALID, 0,
785 : _("The strings compared were %s and %s."),
786 0 : quotearg_n_style (0, locale_quoting_style, l->u.s),
787 0 : quotearg_n_style (1, locale_quoting_style, r->u.s));
788 : }
789 : }
790 :
791 7 : switch (fxn)
792 : {
793 2 : case less_than: val = (cmp < 0); break;
794 1 : case less_equal: val = (cmp <= 0); break;
795 1 : case equal: val = (cmp == 0); break;
796 1 : case not_equal: val = (cmp != 0); break;
797 1 : case greater_equal: val = (cmp >= 0); break;
798 1 : case greater_than: val = (cmp > 0); break;
799 0 : default: abort ();
800 : }
801 0 : }
802 :
803 7 : freev (l);
804 7 : freev (r);
805 7 : l = int_value (val);
806 : }
807 : }
808 :
809 : /* Handle &. */
810 :
811 : static VALUE *
812 120 : eval1 (bool evaluate)
813 : {
814 : VALUE *l;
815 : VALUE *r;
816 :
817 : #ifdef EVAL_TRACE
818 : trace ("eval1");
819 : #endif
820 120 : l = eval2 (evaluate);
821 : while (1)
822 : {
823 81 : if (nextarg ("&"))
824 : {
825 3 : r = eval2 (evaluate & ~ null (l));
826 2 : if (null (l) || null (r))
827 : {
828 1 : freev (l);
829 1 : freev (r);
830 1 : l = int_value (0);
831 : }
832 : else
833 1 : freev (r);
834 : }
835 : else
836 152 : return l;
837 : }
838 : }
839 :
840 : /* Handle |. */
841 :
842 : static VALUE *
843 118 : eval (bool evaluate)
844 : {
845 : VALUE *l;
846 : VALUE *r;
847 :
848 : #ifdef EVAL_TRACE
849 : trace ("eval");
850 : #endif
851 118 : l = eval1 (evaluate);
852 : while (1)
853 : {
854 77 : if (nextarg ("|"))
855 : {
856 2 : r = eval1 (evaluate & null (l));
857 1 : if (null (l))
858 : {
859 0 : freev (l);
860 0 : l = r;
861 0 : if (null (l))
862 : {
863 0 : freev (l);
864 0 : l = int_value (0);
865 : }
866 : }
867 : else
868 1 : freev (r);
869 : }
870 : else
871 148 : return l;
872 : }
873 : }
|