hush: use ash's read builtin
No binary (build failed)
—
(log yok)
| @@ -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 | |
| @@ -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, | |
| @@ -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: | |
| @@ -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, | |
| @@ -84,6 +84,9 @@ | |
| #if ENABLE_HUSH_CASE | |
| # include <fnmatch.h> | |
| #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; |
| - | //TODO: bash unbackslashes input, splits words and puts them in argv[i] |
| + | 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; |
| + | } |
| - | 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 | |
| @@ -0,0 +1,5 @@ | |
| + | test 1: | abc1 def | |
| + | test 2: | \abc2 d\ef | |
| + | test 3: |abc3 def| |
| + | test 4: |\abc4 d\ef| |
| + | Done |
| @@ -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 |
| @@ -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. |
| @@ -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." ) |
| @@ -0,0 +1,3 @@ | |
| + | test |
| + | tes |
| + | tes |
| @@ -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") |
| @@ -0,0 +1,2 @@ | |
| + | testbest |
| + | test\ |
| @@ -0,0 +1,2 @@ | |
| + | echo -e 'test\\\nbest' | (read reply; echo "$reply") |
| + | echo -e 'test\\\nbest' | (read -r reply; echo "$reply") |
| @@ -0,0 +1,4 @@ | |
| + | >< |
| + | >< |
| + | >test< |
| + | >test< |
| @@ -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<") |
| @@ -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); | |
| @@ -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 <[email protected]> | |
| 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 <[email protected]> | |
| * | |
| @@ -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--; | |
| @@ -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; | |