Repository: benhoyt/goawk (go)

Issue:
-v must interpret escape sequences
Hi, @benhoyt.

`-v` must interpret escape sequences. I hate this spec of awk, but anyway, reality is what it is. ☹️

```console
$ goawk -v VAR='\t' 'BEGIN{printf VAR}' | hexdump -C
00000000  5c 74                                             |\t|

$ mawk -v VAR='\t' 'BEGIN{printf VAR}' | hexdump -C
00000000  09                                                |.|

$ gawk -v VAR='\t' 'BEGIN{printf VAR}' | hexdump -C
00000000  09                                                |.|
```


Pull request description:
Interpret escapes in -v and var=value arguments
This is odd, and doesn't seem to be explicitly stated in the POSIX spec, but it's how original-awk, mawk, and gawk all work. Portability trumps sanity. :-)

Fixes #129

Patch:
diff --git a/goawk.go b/goawk.go
index f3fca18..c2705ff 100644
--- a/goawk.go
+++ b/goawk.go
@@ -35,6 +35,7 @@ import (
 	"path/filepath"
 	"runtime"
 	"runtime/pprof"
+	"strconv"
 	"strings"
 	"unicode/utf8"
 
@@ -269,11 +270,17 @@ func main() {
 		Output: stdout,
 	}
 	for _, v := range vars {
-		parts := strings.SplitN(v, "=", 2)
-		if len(parts) != 2 {
+		equals := strings.IndexByte(v, '=')
+		if equals < 0 {
 			errorExitf("-v flag must be in format name=value")
 		}
-		config.Vars = append(config.Vars, parts[0], parts[1])
+		name, value := v[:equals], v[equals+1:]
+		// Oddly, -v must interpret escapes (issue #129)
+		unquoted, err := strconv.Unquote(`"` + value + `"`)
+		if err == nil {
+			value = unquoted
+		}
+		config.Vars = append(config.Vars, name, value)
 	}
 
 	if cpuprofile != "" {
diff --git a/interp/io.go b/interp/io.go
index dc9aa41..4924be6 100644
--- a/interp/io.go
+++ b/interp/io.go
@@ -741,7 +741,13 @@ func (p *interp) nextLine() (string, error) {
 				matches := varRegex.FindStringSubmatch(filename)
 				if len(matches) >= 3 {
 					// Yep, set variable to value and keep going
-					err := p.setVarByName(matches[1], matches[2])
+					name, val := matches[1], matches[2]
+					// Oddly, var=value args must interpret escapes (issue #129)
+					unquoted, err := strconv.Unquote(`"` + val + `"`)
+					if err == nil {
+						val = unquoted
+					}
+					err = p.setVarByName(name, val)
 					if err != nil {
 						return "", err
 					}


Test patch:
diff --git a/goawk_test.go b/goawk_test.go
index 9fb7637..f92d676 100644
--- a/goawk_test.go
+++ b/goawk_test.go
@@ -363,6 +363,7 @@ func TestCommandLine(t *testing.T) {
 		{[]string{"-v", "x=42", "-v", "y=foo", `BEGIN { print x, y }`}, "", "42 foo\n", ""},
 		{[]string{"-v", "RS=;", `$0`}, "a b;c\nd;e", "a b\nc\nd\ne\n", ""},
 		{[]string{"-vRS=;", `$0`}, "a b;c\nd;e", "a b\nc\nd\ne\n", ""},
+		{[]string{"-v", `X=x\ty`, `BEGIN { printf X }`}, "", "x\ty", ""},
 
 		// ARGV/ARGC handling
 		{[]string{`
@@ -392,6 +393,7 @@ func TestCommandLine(t *testing.T) {
 		{[]string{"-v", "A=1", "-f", "testdata/g.3", "B=2", "testdata/test.countries"}, "",
 			"A=1, B=0\n\tARGV[1] = B=2\n\tARGV[2] = testdata/test.countries\nA=1, B=2\n", ""},
 		{[]string{`END { print (x==42) }`, "x=42.0"}, "", "1\n", ""},
+		{[]string{`END { printf X }`, `X=a\tb`}, "", "a\tb", ""},
 		{[]string{"-v", "x=42.0", `BEGIN { print (x==42) }`}, "", "1\n", ""},
 		{[]string{`BEGIN { print(ARGV[1]<2, ARGV[2]<2); ARGV[1]="10"; ARGV[2]="10x"; print(ARGV[1]<2, ARGV[2]<2) }`,
 			"10", "10x"}, "", "0 1\n1 1\n", ""},