aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2009-04-02 10:02:37 +0000
committerMike Frysinger <vapier@gentoo.org>2009-04-02 10:02:37 +0000
commit98c52645c02dacebccae7d68d6c2627f9318fcf7 (patch)
treee0c64b5b24206f95e72fd060336f74cb459f2109 /shell/hush.c
parent551ffdccea39a9223ad451954db40fd7a6e20e79 (diff)
downloadbusybox-98c52645c02dacebccae7d68d6c2627f9318fcf7.tar.gz
split math code out of ash and into a standalone library so we can use it in any shell (like hush!)
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c102
1 files changed, 91 insertions, 11 deletions
diff --git a/shell/hush.c b/shell/hush.c
index af6763517..e93e5a9a0 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -76,6 +76,8 @@
#include <fnmatch.h>
#endif
+#include "math.h"
+
#define HUSH_VER_STR "0.92"
#if defined SINGLE_APPLET_MAIN
@@ -452,6 +454,9 @@ struct globals {
#if ENABLE_FEATURE_EDITING
line_input_t *line_input_state;
#endif
+#if ENABLE_SH_MATH_SUPPORT
+ arith_eval_hooks_t hooks;
+#endif
pid_t root_pid;
pid_t last_bg_pid;
#if ENABLE_HUSH_JOB
@@ -1164,6 +1169,31 @@ static int unset_local_var(const char *name)
return EXIT_SUCCESS;
}
+#if ENABLE_SH_MATH_SUPPORT
+#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
+#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
+static char *endofname(const char *name)
+{
+ char *p;
+
+ p = (char *) name;
+ if (!is_name(*p))
+ return p;
+ while (*++p) {
+ if (!is_in_name(*p))
+ break;
+ }
+ return p;
+}
+
+static void arith_set_local_var(const char *name, const char *val, int flags)
+{
+ /* arith code doesnt malloc space, so do it for it */
+ char *var = xmalloc(strlen(name) + 1 + strlen(val) + 1);
+ sprintf(var, "%s=%s", name, val);
+ set_local_var(var, flags);
+}
+#endif
/*
* in_str support
@@ -1374,6 +1404,11 @@ static void o_addstr(o_string *o, const char *str, int len)
o->data[o->length] = '\0';
}
+static void o_addstrauto(o_string *o, const char *str)
+{
+ o_addstr(o, str, strlen(str) + 1);
+}
+
static void o_addstr_duplicate_backslash(o_string *o, const char *str, int len)
{
while (len) {
@@ -1564,7 +1599,7 @@ static int o_glob(o_string *o, int n)
char **argv = globdata.gl_pathv;
o->length = pattern - o->data; /* "forget" pattern */
while (1) {
- o_addstr(o, *argv, strlen(*argv) + 1);
+ o_addstrauto(o, *argv);
n = o_save_ptr_helper(o, n);
argv++;
if (!*argv)
@@ -1770,6 +1805,28 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
goto store_val;
}
#endif
+#if ENABLE_SH_MATH_SUPPORT
+ case '+': { /* <SPECIAL_VAR_SYMBOL>(cmd<SPECIAL_VAR_SYMBOL> */
+ arith_t res;
+ char buf[30];
+ int errcode;
+ *p = '\0';
+ ++arg;
+ debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch);
+ res = arith(arg, &errcode, &G.hooks);
+ if (errcode < 0)
+ switch (errcode) {
+ case -3: maybe_die("arith", "exponent less than 0"); break;
+ case -2: maybe_die("arith", "divide by zero"); break;
+ case -5: maybe_die("arith", "expression recursion loop detected"); break;
+ default: maybe_die("arith", "syntax error");
+ }
+ sprintf(buf, arith_t_fmt, res);
+ o_addstrauto(output, buf);
+ debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res);
+ break;
+ }
+#endif
default: /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */
case_default: {
bool exp_len = false, exp_null = false;
@@ -1877,7 +1934,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
debug_print_list("expand_vars_to_list[a]", output, n);
/* this part is literal, and it was already pre-quoted
* if needed (much earlier), do not use o_addQstr here! */
- o_addstr(output, arg, strlen(arg) + 1);
+ o_addstrauto(output, arg);
debug_print_list("expand_vars_to_list[b]", output, n);
} else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */
&& !(ored_ch & 0x80) /* and all vars were not quoted. */
@@ -3754,7 +3811,7 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
/* command remains "open", available for possible redirects */
}
-#if ENABLE_HUSH_TICK
+#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT
/* Subroutines for copying $(...) and `...` things */
static void add_till_backquote(o_string *dest, struct in_str *input);
/* '...' */
@@ -3834,7 +3891,7 @@ static void add_till_backquote(o_string *dest, struct in_str *input)
* echo $(echo 'TEST)' BEST) TEST) BEST
* echo $(echo \(\(TEST\) BEST) ((TEST) BEST
*/
-static void add_till_closing_curly_brace(o_string *dest, struct in_str *input)
+static void add_till_closing_paren(o_string *dest, struct in_str *input, bool dbl)
{
int count = 0;
while (1) {
@@ -3844,8 +3901,14 @@ static void add_till_closing_curly_brace(o_string *dest, struct in_str *input)
if (ch == '(')
count++;
if (ch == ')')
- if (--count < 0)
- break;
+ if (--count < 0) {
+ if (!dbl)
+ break;
+ if (i_peek(input) == ')') {
+ i_getch(input);
+ break;
+ }
+ }
o_addchr(dest, ch);
if (ch == '\'') {
add_till_single_quote(dest, input);
@@ -3866,7 +3929,7 @@ static void add_till_closing_curly_brace(o_string *dest, struct in_str *input)
}
}
}
-#endif /* ENABLE_HUSH_TICK */
+#endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT */
/* Return code: 0 for OK, 1 for syntax error */
static int handle_dollar(o_string *dest, struct in_str *input)
@@ -3983,18 +4046,30 @@ static int handle_dollar(o_string *dest, struct in_str *input)
o_addchr(dest, SPECIAL_VAR_SYMBOL);
break;
}
-#if ENABLE_HUSH_TICK
case '(': {
- //int pos = dest->length;
i_getch(input);
+
+#if ENABLE_SH_MATH_SUPPORT
+ if (i_peek(input) == '(') {
+ i_getch(input);
+ o_addchr(dest, SPECIAL_VAR_SYMBOL);
+ o_addchr(dest, quote_mask | '+');
+ add_till_closing_paren(dest, input, true);
+ o_addchr(dest, SPECIAL_VAR_SYMBOL);
+ break;
+ }
+#endif
+
+#if ENABLE_HUSH_TICK
+ //int pos = dest->length;
o_addchr(dest, SPECIAL_VAR_SYMBOL);
o_addchr(dest, quote_mask | '`');
- add_till_closing_curly_brace(dest, input);
+ add_till_closing_paren(dest, input, false);
//debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos);
o_addchr(dest, SPECIAL_VAR_SYMBOL);
+#endif
break;
}
-#endif
case '_':
i_getch(input);
ch = i_peek(input);
@@ -4526,6 +4601,11 @@ int hush_main(int argc, char **argv)
#if ENABLE_FEATURE_EDITING
G.line_input_state = new_line_input_t(FOR_SHELL);
#endif
+#if ENABLE_SH_MATH_SUPPORT
+ G.hooks.lookupvar = lookup_param;
+ G.hooks.setvar = arith_set_local_var;
+ G.hooks.endofname = endofname;
+#endif
/* XXX what should these be while sourcing /etc/profile? */
G.global_argc = argc;
G.global_argv = argv;