diff options
author | Mike Frysinger <vapier@gentoo.org> | 2009-04-02 10:02:37 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2009-04-02 10:02:37 +0000 |
commit | 98c52645c02dacebccae7d68d6c2627f9318fcf7 (patch) | |
tree | e0c64b5b24206f95e72fd060336f74cb459f2109 /shell/hush.c | |
parent | 551ffdccea39a9223ad451954db40fd7a6e20e79 (diff) | |
download | busybox-w32-98c52645c02dacebccae7d68d6c2627f9318fcf7.tar.gz busybox-w32-98c52645c02dacebccae7d68d6c2627f9318fcf7.tar.bz2 busybox-w32-98c52645c02dacebccae7d68d6c2627f9318fcf7.zip |
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.c | 102 |
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 @@ | |||
76 | #include <fnmatch.h> | 76 | #include <fnmatch.h> |
77 | #endif | 77 | #endif |
78 | 78 | ||
79 | #include "math.h" | ||
80 | |||
79 | #define HUSH_VER_STR "0.92" | 81 | #define HUSH_VER_STR "0.92" |
80 | 82 | ||
81 | #if defined SINGLE_APPLET_MAIN | 83 | #if defined SINGLE_APPLET_MAIN |
@@ -452,6 +454,9 @@ struct globals { | |||
452 | #if ENABLE_FEATURE_EDITING | 454 | #if ENABLE_FEATURE_EDITING |
453 | line_input_t *line_input_state; | 455 | line_input_t *line_input_state; |
454 | #endif | 456 | #endif |
457 | #if ENABLE_SH_MATH_SUPPORT | ||
458 | arith_eval_hooks_t hooks; | ||
459 | #endif | ||
455 | pid_t root_pid; | 460 | pid_t root_pid; |
456 | pid_t last_bg_pid; | 461 | pid_t last_bg_pid; |
457 | #if ENABLE_HUSH_JOB | 462 | #if ENABLE_HUSH_JOB |
@@ -1164,6 +1169,31 @@ static int unset_local_var(const char *name) | |||
1164 | return EXIT_SUCCESS; | 1169 | return EXIT_SUCCESS; |
1165 | } | 1170 | } |
1166 | 1171 | ||
1172 | #if ENABLE_SH_MATH_SUPPORT | ||
1173 | #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) | ||
1174 | #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) | ||
1175 | static char *endofname(const char *name) | ||
1176 | { | ||
1177 | char *p; | ||
1178 | |||
1179 | p = (char *) name; | ||
1180 | if (!is_name(*p)) | ||
1181 | return p; | ||
1182 | while (*++p) { | ||
1183 | if (!is_in_name(*p)) | ||
1184 | break; | ||
1185 | } | ||
1186 | return p; | ||
1187 | } | ||
1188 | |||
1189 | static void arith_set_local_var(const char *name, const char *val, int flags) | ||
1190 | { | ||
1191 | /* arith code doesnt malloc space, so do it for it */ | ||
1192 | char *var = xmalloc(strlen(name) + 1 + strlen(val) + 1); | ||
1193 | sprintf(var, "%s=%s", name, val); | ||
1194 | set_local_var(var, flags); | ||
1195 | } | ||
1196 | #endif | ||
1167 | 1197 | ||
1168 | /* | 1198 | /* |
1169 | * in_str support | 1199 | * in_str support |
@@ -1374,6 +1404,11 @@ static void o_addstr(o_string *o, const char *str, int len) | |||
1374 | o->data[o->length] = '\0'; | 1404 | o->data[o->length] = '\0'; |
1375 | } | 1405 | } |
1376 | 1406 | ||
1407 | static void o_addstrauto(o_string *o, const char *str) | ||
1408 | { | ||
1409 | o_addstr(o, str, strlen(str) + 1); | ||
1410 | } | ||
1411 | |||
1377 | static void o_addstr_duplicate_backslash(o_string *o, const char *str, int len) | 1412 | static void o_addstr_duplicate_backslash(o_string *o, const char *str, int len) |
1378 | { | 1413 | { |
1379 | while (len) { | 1414 | while (len) { |
@@ -1564,7 +1599,7 @@ static int o_glob(o_string *o, int n) | |||
1564 | char **argv = globdata.gl_pathv; | 1599 | char **argv = globdata.gl_pathv; |
1565 | o->length = pattern - o->data; /* "forget" pattern */ | 1600 | o->length = pattern - o->data; /* "forget" pattern */ |
1566 | while (1) { | 1601 | while (1) { |
1567 | o_addstr(o, *argv, strlen(*argv) + 1); | 1602 | o_addstrauto(o, *argv); |
1568 | n = o_save_ptr_helper(o, n); | 1603 | n = o_save_ptr_helper(o, n); |
1569 | argv++; | 1604 | argv++; |
1570 | if (!*argv) | 1605 | if (!*argv) |
@@ -1770,6 +1805,28 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1770 | goto store_val; | 1805 | goto store_val; |
1771 | } | 1806 | } |
1772 | #endif | 1807 | #endif |
1808 | #if ENABLE_SH_MATH_SUPPORT | ||
1809 | case '+': { /* <SPECIAL_VAR_SYMBOL>(cmd<SPECIAL_VAR_SYMBOL> */ | ||
1810 | arith_t res; | ||
1811 | char buf[30]; | ||
1812 | int errcode; | ||
1813 | *p = '\0'; | ||
1814 | ++arg; | ||
1815 | debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch); | ||
1816 | res = arith(arg, &errcode, &G.hooks); | ||
1817 | if (errcode < 0) | ||
1818 | switch (errcode) { | ||
1819 | case -3: maybe_die("arith", "exponent less than 0"); break; | ||
1820 | case -2: maybe_die("arith", "divide by zero"); break; | ||
1821 | case -5: maybe_die("arith", "expression recursion loop detected"); break; | ||
1822 | default: maybe_die("arith", "syntax error"); | ||
1823 | } | ||
1824 | sprintf(buf, arith_t_fmt, res); | ||
1825 | o_addstrauto(output, buf); | ||
1826 | debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res); | ||
1827 | break; | ||
1828 | } | ||
1829 | #endif | ||
1773 | default: /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */ | 1830 | default: /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */ |
1774 | case_default: { | 1831 | case_default: { |
1775 | bool exp_len = false, exp_null = false; | 1832 | 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) | |||
1877 | debug_print_list("expand_vars_to_list[a]", output, n); | 1934 | debug_print_list("expand_vars_to_list[a]", output, n); |
1878 | /* this part is literal, and it was already pre-quoted | 1935 | /* this part is literal, and it was already pre-quoted |
1879 | * if needed (much earlier), do not use o_addQstr here! */ | 1936 | * if needed (much earlier), do not use o_addQstr here! */ |
1880 | o_addstr(output, arg, strlen(arg) + 1); | 1937 | o_addstrauto(output, arg); |
1881 | debug_print_list("expand_vars_to_list[b]", output, n); | 1938 | debug_print_list("expand_vars_to_list[b]", output, n); |
1882 | } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */ | 1939 | } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */ |
1883 | && !(ored_ch & 0x80) /* and all vars were not quoted. */ | 1940 | && !(ored_ch & 0x80) /* and all vars were not quoted. */ |
@@ -3754,7 +3811,7 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
3754 | /* command remains "open", available for possible redirects */ | 3811 | /* command remains "open", available for possible redirects */ |
3755 | } | 3812 | } |
3756 | 3813 | ||
3757 | #if ENABLE_HUSH_TICK | 3814 | #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT |
3758 | /* Subroutines for copying $(...) and `...` things */ | 3815 | /* Subroutines for copying $(...) and `...` things */ |
3759 | static void add_till_backquote(o_string *dest, struct in_str *input); | 3816 | static void add_till_backquote(o_string *dest, struct in_str *input); |
3760 | /* '...' */ | 3817 | /* '...' */ |
@@ -3834,7 +3891,7 @@ static void add_till_backquote(o_string *dest, struct in_str *input) | |||
3834 | * echo $(echo 'TEST)' BEST) TEST) BEST | 3891 | * echo $(echo 'TEST)' BEST) TEST) BEST |
3835 | * echo $(echo \(\(TEST\) BEST) ((TEST) BEST | 3892 | * echo $(echo \(\(TEST\) BEST) ((TEST) BEST |
3836 | */ | 3893 | */ |
3837 | static void add_till_closing_curly_brace(o_string *dest, struct in_str *input) | 3894 | static void add_till_closing_paren(o_string *dest, struct in_str *input, bool dbl) |
3838 | { | 3895 | { |
3839 | int count = 0; | 3896 | int count = 0; |
3840 | while (1) { | 3897 | while (1) { |
@@ -3844,8 +3901,14 @@ static void add_till_closing_curly_brace(o_string *dest, struct in_str *input) | |||
3844 | if (ch == '(') | 3901 | if (ch == '(') |
3845 | count++; | 3902 | count++; |
3846 | if (ch == ')') | 3903 | if (ch == ')') |
3847 | if (--count < 0) | 3904 | if (--count < 0) { |
3848 | break; | 3905 | if (!dbl) |
3906 | break; | ||
3907 | if (i_peek(input) == ')') { | ||
3908 | i_getch(input); | ||
3909 | break; | ||
3910 | } | ||
3911 | } | ||
3849 | o_addchr(dest, ch); | 3912 | o_addchr(dest, ch); |
3850 | if (ch == '\'') { | 3913 | if (ch == '\'') { |
3851 | add_till_single_quote(dest, input); | 3914 | add_till_single_quote(dest, input); |
@@ -3866,7 +3929,7 @@ static void add_till_closing_curly_brace(o_string *dest, struct in_str *input) | |||
3866 | } | 3929 | } |
3867 | } | 3930 | } |
3868 | } | 3931 | } |
3869 | #endif /* ENABLE_HUSH_TICK */ | 3932 | #endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT */ |
3870 | 3933 | ||
3871 | /* Return code: 0 for OK, 1 for syntax error */ | 3934 | /* Return code: 0 for OK, 1 for syntax error */ |
3872 | static int handle_dollar(o_string *dest, struct in_str *input) | 3935 | 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) | |||
3983 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4046 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
3984 | break; | 4047 | break; |
3985 | } | 4048 | } |
3986 | #if ENABLE_HUSH_TICK | ||
3987 | case '(': { | 4049 | case '(': { |
3988 | //int pos = dest->length; | ||
3989 | i_getch(input); | 4050 | i_getch(input); |
4051 | |||
4052 | #if ENABLE_SH_MATH_SUPPORT | ||
4053 | if (i_peek(input) == '(') { | ||
4054 | i_getch(input); | ||
4055 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | ||
4056 | o_addchr(dest, quote_mask | '+'); | ||
4057 | add_till_closing_paren(dest, input, true); | ||
4058 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | ||
4059 | break; | ||
4060 | } | ||
4061 | #endif | ||
4062 | |||
4063 | #if ENABLE_HUSH_TICK | ||
4064 | //int pos = dest->length; | ||
3990 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4065 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
3991 | o_addchr(dest, quote_mask | '`'); | 4066 | o_addchr(dest, quote_mask | '`'); |
3992 | add_till_closing_curly_brace(dest, input); | 4067 | add_till_closing_paren(dest, input, false); |
3993 | //debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos); | 4068 | //debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos); |
3994 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4069 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4070 | #endif | ||
3995 | break; | 4071 | break; |
3996 | } | 4072 | } |
3997 | #endif | ||
3998 | case '_': | 4073 | case '_': |
3999 | i_getch(input); | 4074 | i_getch(input); |
4000 | ch = i_peek(input); | 4075 | ch = i_peek(input); |
@@ -4526,6 +4601,11 @@ int hush_main(int argc, char **argv) | |||
4526 | #if ENABLE_FEATURE_EDITING | 4601 | #if ENABLE_FEATURE_EDITING |
4527 | G.line_input_state = new_line_input_t(FOR_SHELL); | 4602 | G.line_input_state = new_line_input_t(FOR_SHELL); |
4528 | #endif | 4603 | #endif |
4604 | #if ENABLE_SH_MATH_SUPPORT | ||
4605 | G.hooks.lookupvar = lookup_param; | ||
4606 | G.hooks.setvar = arith_set_local_var; | ||
4607 | G.hooks.endofname = endofname; | ||
4608 | #endif | ||
4529 | /* XXX what should these be while sourcing /etc/profile? */ | 4609 | /* XXX what should these be while sourcing /etc/profile? */ |
4530 | G.global_argc = argc; | 4610 | G.global_argc = argc; |
4531 | G.global_argv = argv; | 4611 | G.global_argv = argv; |