diff --git a/read.go b/read.go index ea014f1..fff0448 100644 --- a/read.go +++ b/read.go @@ -12,7 +12,7 @@ import ( "gopkg.in/warnings.v0" ) -var unescape = map[rune]rune{'\\': '\\', '"': '"', 'n': '\n', 't': '\t'} +var unescape = map[rune]rune{'\\': '\\', '"': '"', 'n': '\n', 't': '\t', 'b': '\b'} // no error: invalid literals should be caught by scanner func unquote(s string) string { @@ -48,7 +48,7 @@ func unquote(s string) string { return string(u) } -func read(c *warnings.Collector, callback func(string,string,string,string,bool)error, +func read(c *warnings.Collector, callback func(string, string, string, string, bool) error, fset *token.FileSet, file *token.File, src []byte) error { // var s scanner.Scanner @@ -223,7 +223,7 @@ func readInto(config interface{}, fset *token.FileSet, file *token.File, // (as opposed to set to empty string). // // If callback returns an error, ReadWithCallback terminates with an error too. -func ReadWithCallback(reader io.Reader, callback func(string,string,string,string,bool)error) error { +func ReadWithCallback(reader io.Reader, callback func(string, string, string, string, bool) error) error { src, err := ioutil.ReadAll(reader) if err != nil { return err diff --git a/read_test.go b/read_test.go index d9ff5f8..e2727f1 100644 --- a/read_test.go +++ b/read_test.go @@ -1,13 +1,14 @@ package gcfg import ( + "bytes" "fmt" "math/big" "os" "reflect" - "testing" - "bytes" "strconv" + "testing" + "github.com/pkg/errors" ) @@ -127,6 +128,8 @@ var readtests = []struct { {"[section]\nname=\"va\\\"lue\"", &cBasic{Section: cBasicS1{Name: "va\"lue"}}, true}, {"[section]\nname=\"va\\nlue\"", &cBasic{Section: cBasicS1{Name: "va\nlue"}}, true}, {"[section]\nname=\"va\\tlue\"", &cBasic{Section: cBasicS1{Name: "va\tlue"}}, true}, + {"[section]\nname=x:\\\\path\\\\", &cBasic{Section: cBasicS1{Name: "x:\\path\\"}}, true}, + {"[section]\nname=\\b", &cBasic{Section: cBasicS1{Name: "\b"}}, true}, {"\n[section]\nname=\\", &cBasic{}, false}, {"\n[section]\nname=\\a", &cBasic{}, false}, {"\n[section]\nname=\"val\\a\"", &cBasic{}, false}, diff --git a/scanner/scanner.go b/scanner/scanner.go index f158676..b1eef06 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -170,7 +170,7 @@ func (s *Scanner) scanEscape(val bool) { switch ch { case '\\', '"': // ok - case 'n', 't': + case 'n', 't', 'b': if val { break // ok } @@ -232,10 +232,10 @@ loop: s.next() } if s.ch != '\n' { - s.error(offs, "unquoted '\\' must be followed by new line") - break loop + s.scanEscape(true) + } else { + s.next() } - s.next() case ch == '"': inQuote = !inQuote case ch == '\r': diff --git a/scanner/scanner_test.go b/scanner/scanner_test.go index 27db5e7..36f89e0 100644 --- a/scanner/scanner_test.go +++ b/scanner/scanner_test.go @@ -381,8 +381,8 @@ var errors = []struct { {"\"\n", token.STRING, 0, "string not terminated"}, {`="`, token.STRING, 1, "string not terminated"}, {"=\"\n", token.STRING, 1, "string not terminated"}, - {"=\\", token.STRING, 1, "unquoted '\\' must be followed by new line"}, - {"=\\\r", token.STRING, 1, "unquoted '\\' must be followed by new line"}, + {"=\\", token.STRING, 2, "unknown escape sequence"}, + {"=\\\r", token.STRING, 3, "unknown escape sequence"}, {`"\z"`, token.STRING, 2, "unknown escape sequence"}, {`"\a"`, token.STRING, 2, "unknown escape sequence"}, {`"\b"`, token.STRING, 2, "unknown escape sequence"},