From 30b84410a3dc1666b13dfc19a4012868bf5497f1 Mon Sep 17 00:00:00 2001 From: Parker Duckworth Date: Tue, 17 Aug 2021 14:25:08 -0500 Subject: [PATCH 1/4] add read -p flag and test cases --- interp/builtin.go | 11 +++++++++++ interp/interp_test.go | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/interp/builtin.go b/interp/builtin.go index dcbe26bac..46813a47f 100644 --- a/interp/builtin.go +++ b/interp/builtin.go @@ -519,11 +519,14 @@ func (r *Runner) builtinCode(ctx context.Context, pos syntax.Pos, name string, a r.setErr(returnStatus(code)) case "read": raw := false + prompt := struct{provided bool; message string}{} fp := flagParser{remaining: args} for fp.more() { switch flag := fp.flag(); flag { case "-r": raw = true + case "-p": + prompt.provided, prompt.message = true, fp.value() default: r.errf("read: invalid option %q\n", flag) return 2 @@ -538,6 +541,14 @@ func (r *Runner) builtinCode(ctx context.Context, pos syntax.Pos, name string, a } } + if prompt.provided { + if prompt.message == "" { + r.errf("read: -p: option requires an argument\n") + return 2 + } + r.out(prompt.message) + } + line, err := r.readLine(raw) if err != nil { return 1 diff --git a/interp/interp_test.go b/interp/interp_test.go index 3a7b6565f..210a65b7a 100644 --- a/interp/interp_test.go +++ b/interp/interp_test.go @@ -2587,6 +2587,18 @@ set +o pipefail "IFS=: read a b c <<< '1\\:2:3'; echo \"$a\"; echo $b; echo $c", "1:2\n3\n\n", }, + { + "read -p", + "read: -p: option requires an argument\nexit status 2", + }, + { + "read -p 'Display me as a prompt. Continue? (y/n) ' choice <<< 'y'; echo $choice", + "Display me as a prompt. Continue? (y/n) y\n", + }, + { + "read -r -p 'Prompt and raw flag together: ' a <<< '\\a\\b\\c'; echo $a", + "Prompt and raw flag together: \\a\\b\\c\n", + }, // getopts { From de98352fc9be8cbddd1f455b72cde1cbe5547012 Mon Sep 17 00:00:00 2001 From: Parker Duckworth Date: Tue, 17 Aug 2021 14:35:00 -0500 Subject: [PATCH 2/4] more test cases --- interp/interp_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interp/interp_test.go b/interp/interp_test.go index 210a65b7a..88c26cd0e 100644 --- a/interp/interp_test.go +++ b/interp/interp_test.go @@ -2589,7 +2589,11 @@ set +o pipefail }, { "read -p", - "read: -p: option requires an argument\nexit status 2", + "read: -p: option requires an argument\nexit status 2 #JUSTERR", + }, + { + "read -X -p", + "read: invalid option \"-X\"\nexit status 2 #JUSTERR", }, { "read -p 'Display me as a prompt. Continue? (y/n) ' choice <<< 'y'; echo $choice", From 125cf47250413f5810d84d19f761df96d536127f Mon Sep 17 00:00:00 2001 From: Parker Duckworth Date: Tue, 17 Aug 2021 14:56:35 -0500 Subject: [PATCH 3/4] gofmt --- interp/builtin.go | 5 ++++- interp/interp_test.go | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/interp/builtin.go b/interp/builtin.go index 46813a47f..db0ad4be6 100644 --- a/interp/builtin.go +++ b/interp/builtin.go @@ -519,7 +519,10 @@ func (r *Runner) builtinCode(ctx context.Context, pos syntax.Pos, name string, a r.setErr(returnStatus(code)) case "read": raw := false - prompt := struct{provided bool; message string}{} + prompt := struct { + provided bool + message string + }{} fp := flagParser{remaining: args} for fp.more() { switch flag := fp.flag(); flag { diff --git a/interp/interp_test.go b/interp/interp_test.go index 88c26cd0e..92d2441a7 100644 --- a/interp/interp_test.go +++ b/interp/interp_test.go @@ -2588,8 +2588,8 @@ set +o pipefail "1:2\n3\n\n", }, { - "read -p", - "read: -p: option requires an argument\nexit status 2 #JUSTERR", + "read -p", + "read: -p: option requires an argument\nexit status 2 #JUSTERR", }, { "read -X -p", From 04e3638ce69b7f7fc0d5fec5bc7d35c968bb4f08 Mon Sep 17 00:00:00 2001 From: Parker Duckworth Date: Mon, 23 Aug 2021 14:29:25 -0500 Subject: [PATCH 4/4] refactor prompt handling --- interp/builtin.go | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/interp/builtin.go b/interp/builtin.go index db0ad4be6..8fd464177 100644 --- a/interp/builtin.go +++ b/interp/builtin.go @@ -518,18 +518,19 @@ func (r *Runner) builtinCode(ctx context.Context, pos syntax.Pos, name string, a } r.setErr(returnStatus(code)) case "read": + var prompt string raw := false - prompt := struct { - provided bool - message string - }{} fp := flagParser{remaining: args} for fp.more() { switch flag := fp.flag(); flag { case "-r": raw = true case "-p": - prompt.provided, prompt.message = true, fp.value() + prompt = fp.value() + if prompt == "" { + r.errf("read: -p: option requires an argument\n") + return 2 + } default: r.errf("read: invalid option %q\n", flag) return 2 @@ -544,12 +545,8 @@ func (r *Runner) builtinCode(ctx context.Context, pos syntax.Pos, name string, a } } - if prompt.provided { - if prompt.message == "" { - r.errf("read: -p: option requires an argument\n") - return 2 - } - r.out(prompt.message) + if prompt != "" { + r.out(prompt) } line, err := r.readLine(raw)