* - reduced 464 bytes.
* - 64 math support
*
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
-
/* This program evaluates expressions. Each token (operator, operand,
* parenthesis) of the expression must be a separate argument. The
* parser used is a reasonably general one, though any incarnation of
*
* No parse tree is needed; a new node is evaluated immediately.
* One function can handle multiple operators all of equal precedence,
- * provided they all associate ((x op x) op x). */
-
-/* no getopt needed */
+ * provided they all associate ((x op x) op x).
+ */
+//config:config EXPR
+//config: bool "expr (6.6 kb)"
+//config: default y
+//config: help
+//config: expr is used to calculate numbers and print the result
+//config: to standard output.
+//config:
+//config:config EXPR_MATH_SUPPORT_64
+//config: bool "Extend Posix numbers support to 64 bit"
+//config: default y
+//config: depends on EXPR
+//config: help
+//config: Enable 64-bit math support in the expr applet. This will make
+//config: the applet slightly larger, but will allow computation with very
+//config: large numbers.
+
+//applet:IF_EXPR(APPLET_NOEXEC(expr, expr, BB_DIR_USR_BIN, BB_SUID_DROP, expr))
+
+//kbuild:lib-$(CONFIG_EXPR) += expr.o
+
+//usage:#define expr_trivial_usage
+//usage: "EXPRESSION"
+//usage:#define expr_full_usage "\n\n"
+//usage: "Print the value of EXPRESSION to stdout\n"
+//usage: "\n"
+//usage: "EXPRESSION may be:\n"
+//usage: " ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n"
+//usage: " ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n"
+//usage: " ARG1 < ARG2 1 if ARG1 is less than ARG2, else 0. Similarly:\n"
+//usage: " ARG1 <= ARG2\n"
+//usage: " ARG1 = ARG2\n"
+//usage: " ARG1 != ARG2\n"
+//usage: " ARG1 >= ARG2\n"
+//usage: " ARG1 > ARG2\n"
+//usage: " ARG1 + ARG2 Sum of ARG1 and ARG2. Similarly:\n"
+//usage: " ARG1 - ARG2\n"
+//usage: " ARG1 * ARG2\n"
+//usage: " ARG1 / ARG2\n"
+//usage: " ARG1 % ARG2\n"
+//usage: " STRING : REGEXP Anchored pattern match of REGEXP in STRING\n"
+//usage: " match STRING REGEXP Same as STRING : REGEXP\n"
+//usage: " substr STRING POS LENGTH Substring of STRING, POS counted from 1\n"
+//usage: " index STRING CHARS Index in STRING where any CHARS is found, or 0\n"
+//usage: " length STRING Length of STRING\n"
+//usage: " quote TOKEN Interpret TOKEN as a string, even if\n"
+//usage: " it is a keyword like 'match' or an\n"
+//usage: " operator like '/'\n"
+//usage: " (EXPRESSION) Value of EXPRESSION\n"
+//usage: "\n"
+//usage: "Beware that many operators need to be escaped or quoted for shells.\n"
+//usage: "Comparisons are arithmetic if both ARGs are numbers, else\n"
+//usage: "lexicographical. Pattern matches return the string matched between\n"
+//usage: "\\( and \\) or null; if \\( and \\) are not used, they return the number\n"
+//usage: "of characters matched or 0."
#include "libbb.h"
+#include "common_bufsiz.h"
#include "xregex.h"
#if ENABLE_EXPR_MATH_SUPPORT_64
/* The arguments given to the program, minus the program name. */
struct globals {
char **args;
-};
-#define G (*(struct globals*)&bb_common_bufsiz1)
+} FIX_ALIASING;
+#define G (*(struct globals*)bb_common_bufsiz1)
+#define INIT_G() do { \
+ setup_common_bufsiz(); \
+ /* NB: noexec applet - globals not zeroed */ \
+} while (0)
/* forward declarations */
static VALUE *eval(void);
VALUE *v;
v = xzalloc(sizeof(VALUE));
- if (INTEGER) /* otherwise xzaaloc did it already */
+ if (INTEGER) /* otherwise xzalloc did it already */
v->type = INTEGER;
v->u.i = i;
return v;
VALUE *v;
v = xzalloc(sizeof(VALUE));
- if (STRING) /* otherwise xzaaloc did it already */
+ if (STRING) /* otherwise xzalloc did it already */
v->type = STRING;
v->u.s = xstrdup(s);
return v;
arith_t li, ri;
if (!toarith(l) || !toarith(r))
- bb_error_msg_and_die("non-numeric argument");
+ bb_simple_error_msg_and_die("non-numeric argument");
li = l->u.i;
ri = r->u.i;
if (op == '+')
if (op == '*')
return li * ri;
if (ri == 0)
- bb_error_msg_and_die("division by zero");
+ bb_simple_error_msg_and_die("division by zero");
if (op == '/')
return li / ri;
return li % ri;
static VALUE *docolon(VALUE *sv, VALUE *pv)
{
+ enum { NMATCH = 2 };
VALUE *v;
regex_t re_buffer;
- const int NMATCH = 2;
regmatch_t re_regs[NMATCH];
tostring(sv);
VALUE *v;
if (!*G.args)
- bb_error_msg_and_die("syntax error");
+ bb_simple_error_msg_and_die("syntax error");
if (nextarg("(")) {
G.args++;
v = eval();
if (!nextarg(")"))
- bb_error_msg_and_die("syntax error");
+ bb_simple_error_msg_and_die("syntax error");
G.args++;
return v;
}
if (nextarg(")"))
- bb_error_msg_and_die("syntax error");
+ bb_simple_error_msg_and_die("syntax error");
return str_value(*G.args++);
}
G.args++; /* We have a valid token, so get the next argument. */
if (key == 1) { /* quote */
if (!*G.args)
- bb_error_msg_and_die("syntax error");
+ bb_simple_error_msg_and_die("syntax error");
return str_value(*G.args++);
}
if (key == 2) { /* length */
freev(i2);
}
return v;
-
}
/* Handle : operator (pattern matching).
{
VALUE *v;
+ INIT_G();
+
xfunc_error_retval = 2; /* coreutils compat */
G.args = argv + 1;
if (*G.args == NULL) {
- bb_error_msg_and_die("too few arguments");
+ bb_simple_error_msg_and_die("too few arguments");
}
v = eval();
if (*G.args)
- bb_error_msg_and_die("syntax error");
+ bb_simple_error_msg_and_die("syntax error");
if (v->type == INTEGER)
printf("%" PF_REZ "d\n", PF_REZ_TYPE v->u.i);
else