diff --git a/shell/Kbuild b/shell/Kbuild index 155ac6f0f..d8306dc96 100644 --- a/shell/Kbuild +++ b/shell/Kbuild @@ -6,7 +6,7 @@ lib-y:= lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o builtin_read.o -lib-$(CONFIG_HUSH) += hush.o match.o +lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o builtin_read.o lib-$(CONFIG_CTTYHACK) += cttyhack.o lib-$(CONFIG_SH_MATH_SUPPORT) += math.o diff --git a/shell/ash.c b/shell/ash.c index c7deffd08..31dc59253 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -1884,7 +1884,7 @@ getoptsreset(const char *value) * Return of a legal variable name (a letter or underscore followed by zero or * more letters, underscores, and digits). */ -static char * +static char* FAST_FUNC endofname(const char *name) { char *p; @@ -1991,7 +1991,7 @@ findvar(struct var **vpp, const char *name) /* * Find the value of a variable. Returns NULL if not set. */ -static const char * +static const char* FAST_FUNC lookupvar(const char *name) { struct var *v; @@ -2114,6 +2114,12 @@ setvar(const char *name, const char *val, int flags) INT_ON; } +static void FAST_FUNC +setvar2(const char *name, const char *val) +{ + setvar(name, val, 0); +} + #if ENABLE_ASH_GETOPTS /* * Safe version of setvar, returns 1 on success 0 on failure. @@ -5304,7 +5310,7 @@ ash_arith(const char *s) int errcode = 0; math_hooks.lookupvar = lookupvar; - math_hooks.setvar = setvar; + math_hooks.setvar = setvar2; math_hooks.endofname = endofname; INT_OFF; @@ -12526,7 +12532,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) } } - r = builtin_read(setvar, + r = shell_builtin_read(setvar2, argptr, bltinlookup("IFS"), /* can be NULL */ read_flags, diff --git a/shell/builtin_read.c b/shell/builtin_read.c index 24cfe08fb..412bcf869 100644 --- a/shell/builtin_read.c +++ b/shell/builtin_read.c @@ -21,7 +21,7 @@ #include "builtin_read.h" const char* FAST_FUNC -builtin_read(void (*setvar)(const char *name, const char *val, int flags), +shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), char **argv, const char *ifs, int read_flags, @@ -178,7 +178,7 @@ builtin_read(void (*setvar)(const char *name, const char *val, int flags), if (argv[1] != NULL && is_ifs) { buffer[bufpos] = '\0'; bufpos = 0; - setvar(*argv, buffer, 0); + setvar(*argv, buffer); argv++; /* can we skip one non-space ifs char? (2: yes) */ startword = isspace(c) ? 2 : 1; @@ -195,14 +195,14 @@ builtin_read(void (*setvar)(const char *name, const char *val, int flags), continue; buffer[bufpos + 1] = '\0'; /* Use the remainder as a value for the next variable */ - setvar(*argv, buffer, 0); + setvar(*argv, buffer); /* Set the rest to "" */ while (*++argv) - setvar(*argv, "", 0); + setvar(*argv, ""); } else { /* Note: no $IFS removal */ buffer[bufpos] = '\0'; - setvar("REPLY", buffer, 0); + setvar("REPLY", buffer); } ret: diff --git a/shell/builtin_read.h b/shell/builtin_read.h index 930d01428..bc23dc5ae 100644 --- a/shell/builtin_read.h +++ b/shell/builtin_read.h @@ -27,7 +27,7 @@ enum { }; const char* FAST_FUNC -builtin_read(void (*setvar)(const char *name, const char *val, int flags), +shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), char **argv, const char *ifs, int read_flags, diff --git a/shell/hush.c b/shell/hush.c index 88a7b988a..bb0ab8408 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -84,6 +84,9 @@ #if ENABLE_HUSH_CASE # include #endif + +#include "shell_common.h" +#include "builtin_read.h" #include "math.h" #include "match.h" #if ENABLE_HUSH_RANDOM_SUPPORT @@ -1307,7 +1310,7 @@ static struct variable *get_local_var(const char *name) return NULL; } -static const char *get_local_var_value(const char *name) +static const char* FAST_FUNC get_local_var_value(const char *name) { struct variable **pp = get_ptr_to_local_var(name); if (pp) @@ -1510,7 +1513,7 @@ static void unset_vars(char **strings) #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) +static char* FAST_FUNC endofname(const char *name) { char *p; @@ -1524,11 +1527,10 @@ static char *endofname(const char *name) return p; } -static void arith_set_local_var(const char *name, const char *val, int flags) +static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) { - /* arith code doesnt malloc space, so do it for it */ char *var = xasprintf("%s=%s", name, val); - set_local_var(var, flags, /*lvl:*/ 0, /*ro:*/ 0); + set_local_var(var, /*flags:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); } #endif @@ -2538,7 +2540,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char exp_str = expand_pseudo_dquoted(arg); hooks.lookupvar = get_local_var_value; - hooks.setvar = arith_set_local_var; + hooks.setvar = set_local_var_from_halves; hooks.endofname = endofname; res = arith(exp_str ? exp_str : arg, &errcode, &hooks); free(exp_str); @@ -6157,7 +6159,7 @@ static struct pipe *parse_stream(char **pstring, G.ifs = get_local_var_value("IFS"); if (G.ifs == NULL) - G.ifs = " \t\n"; + G.ifs = defifs; reset: #if ENABLE_HUSH_INTERACTIVE @@ -7727,24 +7729,37 @@ static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM) static int FAST_FUNC builtin_read(char **argv) { - char *string; - const char *name = "REPLY"; + const char *r; + char *opt_n = NULL; + char *opt_p = NULL; + char *opt_t = NULL; + char *opt_u = NULL; + int read_flags; - if (argv[1]) { - name = argv[1]; - /* bash (3.2.33(1)) bug: "read 0abcd" will execute, - * and _after_ that_ it will complain */ - if (!is_well_formed_var_name(name, '\0')) { - /* Mimic bash message */ - bb_error_msg("read: '%s': not a valid identifier", name); - return 1; - } + /* "!": do not abort on errors. + * Option string must start with "sr" to match BUILTIN_READ_xxx + */ + read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u); + if (read_flags == (uint32_t)-1) + return EXIT_FAILURE; + argv += optind; + + r = shell_builtin_read(set_local_var_from_halves, + argv, + get_local_var_value("IFS"), /* can be NULL */ + read_flags, + opt_n, + opt_p, + opt_t, + opt_u + ); + + if ((uintptr_t)r > 1) { + bb_error_msg("%s", r); + r = (char*)(uintptr_t)1; } -//TODO: bash unbackslashes input, splits words and puts them in argv[i] - - string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name), NULL); - return set_local_var(string, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); + return (uintptr_t)r; } /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set diff --git a/shell/hush_test/hush-read/read_REPLY.right b/shell/hush_test/hush-read/read_REPLY.right new file mode 100644 index 000000000..59f5d5487 --- /dev/null +++ b/shell/hush_test/hush-read/read_REPLY.right @@ -0,0 +1,5 @@ +test 1: | abc1 def | +test 2: | \abc2 d\ef | +test 3: |abc3 def| +test 4: |\abc4 d\ef| +Done diff --git a/shell/hush_test/hush-read/read_REPLY.tests b/shell/hush_test/hush-read/read_REPLY.tests new file mode 100755 index 000000000..ba20cae8d --- /dev/null +++ b/shell/hush_test/hush-read/read_REPLY.tests @@ -0,0 +1,5 @@ +echo ' \abc1 d\ef ' | ( read ; echo "test 1: |$REPLY|" ) +echo ' \abc2 d\ef ' | ( read -r ; echo "test 2: |$REPLY|" ) +echo ' \abc3 d\ef ' | ( read REPLY; echo "test 3: |$REPLY|" ) +echo ' \abc4 d\ef ' | ( read -r REPLY; echo "test 4: |$REPLY|" ) +echo Done diff --git a/shell/hush_test/hush-read/read_ifs.right b/shell/hush_test/hush-read/read_ifs.right new file mode 100644 index 000000000..b52334456 --- /dev/null +++ b/shell/hush_test/hush-read/read_ifs.right @@ -0,0 +1,10 @@ +test 1: .a. .b. .c. +test 2: .a. .b. .c. +test 3: .a. .. .b,c. +test 4: .a. .. .b,c. +test 5: .a. .. .c. +test 6: .a. .. .c. .d. +test 7: .a. .. .b,c,d , ,. +test 8: .. .a. .b. .c. +test 9: .a. .b. .c. .. +test A: .. .a. .. .b. .c. diff --git a/shell/hush_test/hush-read/read_ifs.tests b/shell/hush_test/hush-read/read_ifs.tests new file mode 100755 index 000000000..6e8311247 --- /dev/null +++ b/shell/hush_test/hush-read/read_ifs.tests @@ -0,0 +1,10 @@ +printf 'a\t\tb\tc\n' | ( IFS=$(printf "\t") read a b c; echo "test 1: .$a. .$b. .$c." ) +printf 'a\t\tb\tc\n' | ( IFS=$(printf " \t") read a b c; echo "test 2: .$a. .$b. .$c." ) +printf 'a,,b,c\n' | ( IFS="," read a b c; echo "test 3: .$a. .$b. .$c." ) +printf 'a,,b,c\n' | ( IFS=" ," read a b c; echo "test 4: .$a. .$b. .$c." ) +printf 'a ,, c\n' | ( IFS=" ," read a b c; echo "test 5: .$a. .$b. .$c." ) +printf 'a ,, c d\n' | ( IFS=" ," read a b c d; echo "test 6: .$a. .$b. .$c. .$d." ) +printf ' a,,b,c,d , ,\n' | ( IFS=" ," read a b c; echo "test 7: .$a. .$b. .$c." ) +printf '\t,\ta\t,\tb\tc' | ( IFS=$(printf " \t,") read a b c d; echo "test 8: .$a. .$b. .$c. .$d." ) +printf '\t\ta\t,\tb\tc' | ( IFS=$(printf " \t,") read a b c d; echo "test 9: .$a. .$b. .$c. .$d." ) +printf '\t,\ta\t,,\tb\tc' | ( IFS=$(printf " \t,") read a b c d e; echo "test A: .$a. .$b. .$c. .$d. .$e." ) diff --git a/shell/hush_test/hush-read/read_n.right b/shell/hush_test/hush-read/read_n.right new file mode 100644 index 000000000..1f81af0bc --- /dev/null +++ b/shell/hush_test/hush-read/read_n.right @@ -0,0 +1,3 @@ +test +tes +tes diff --git a/shell/hush_test/hush-read/read_n.tests b/shell/hush_test/hush-read/read_n.tests new file mode 100755 index 000000000..12423ba6e --- /dev/null +++ b/shell/hush_test/hush-read/read_n.tests @@ -0,0 +1,3 @@ +echo 'test' | (read reply; echo "$reply") +echo 'test' | (read -n 3 reply; echo "$reply") +echo 'test' | (read -n3 reply; echo "$reply") diff --git a/shell/hush_test/hush-read/read_r.right b/shell/hush_test/hush-read/read_r.right new file mode 100644 index 000000000..3536bf757 --- /dev/null +++ b/shell/hush_test/hush-read/read_r.right @@ -0,0 +1,2 @@ +testbest +test\ diff --git a/shell/hush_test/hush-read/read_r.tests b/shell/hush_test/hush-read/read_r.tests new file mode 100755 index 000000000..2c4cc6106 --- /dev/null +++ b/shell/hush_test/hush-read/read_r.tests @@ -0,0 +1,2 @@ +echo -e 'test\\\nbest' | (read reply; echo "$reply") +echo -e 'test\\\nbest' | (read -r reply; echo "$reply") diff --git a/shell/hush_test/hush-read/read_t.right b/shell/hush_test/hush-read/read_t.right new file mode 100644 index 000000000..04126cbe6 --- /dev/null +++ b/shell/hush_test/hush-read/read_t.right @@ -0,0 +1,4 @@ +>< +>< +>test< +>test< diff --git a/shell/hush_test/hush-read/read_t.tests b/shell/hush_test/hush-read/read_t.tests new file mode 100755 index 000000000..d65f1aeaa --- /dev/null +++ b/shell/hush_test/hush-read/read_t.tests @@ -0,0 +1,10 @@ +# bash 3.2 outputs: + +# >< +{ echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply<") +# >< +{ sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply<") +# >test< +{ echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply<") +# >test< +{ sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply<") diff --git a/shell/match.h b/shell/match.h index 98ff8745a..c022ceb25 100644 --- a/shell/match.h +++ b/shell/match.h @@ -5,6 +5,8 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN +//TODO! Why ash.c still uses internal version?! + typedef char *(*scan_t)(char *string, char *match, bool match_at_left); char *scanleft(char *string, char *match, bool match_at_left); diff --git a/shell/math.c b/shell/math.c index 76159b299..91fb28f05 100644 --- a/shell/math.c +++ b/shell/math.c @@ -25,14 +25,6 @@ * * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ -#include "libbb.h" -#include "math.h" - -#define a_e_h_t arith_eval_hooks_t -#define lookupvar (math_hooks->lookupvar) -#define setvar (math_hooks->setvar) -#define endofname (math_hooks->endofname) - /* Copyright (c) 2001 Aaron Lehmann Permission is hereby granted, free of charge, to any person obtaining @@ -99,7 +91,6 @@ * whitespace chars should be considered. Look below the "#include"s for a * precompiler test. */ - /* * Aug 26, 2001 Manuel Novoa III * @@ -109,7 +100,6 @@ * modified slightly to take account of my changes to the code. * */ - /* * (C) 2003 Vladimir Oleynik * @@ -126,6 +116,13 @@ * - protect $((num num)) as true zero expr (Manuel`s error) * - always use special isspace(), see comment from bash ;-) */ +#include "libbb.h" +#include "math.h" + +#define a_e_h_t arith_eval_hooks_t +#define lookupvar (math_hooks->lookupvar) +#define setvar (math_hooks->setvar ) +#define endofname (math_hooks->endofname) #define arith_isspace(arithval) \ (arithval == ' ' || arithval == '\n' || arithval == '\t') @@ -420,7 +417,7 @@ arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hoo } /* save to shell variable */ sprintf(buf, arith_t_fmt, rez); - setvar(numptr_m1->var, buf, 0); + setvar(numptr_m1->var, buf); /* after saving, make previous value for v++ or v-- */ if (op == TOK_POST_INC) rez--; diff --git a/shell/math.h b/shell/math.h index 7b7898ea0..2b0b2b89d 100644 --- a/shell/math.h +++ b/shell/math.h @@ -87,12 +87,13 @@ typedef long arith_t; #define strto_arith_t strtoul #endif -typedef const char *(*arith_var_lookup_t)(const char *name); -typedef void (*arith_var_set_t)(const char *name, const char *val, int flags); -typedef char *(*arith_var_endofname_t)(const char *name); +typedef const char* FAST_FUNC (*arith_var_lookup_t)(const char *name); +typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val); +typedef char* FAST_FUNC (*arith_var_endofname_t)(const char *name); + typedef struct arith_eval_hooks { - arith_var_lookup_t lookupvar; - arith_var_set_t setvar; + arith_var_lookup_t lookupvar; + arith_var_set_t setvar; arith_var_endofname_t endofname; } arith_eval_hooks_t;