diff --git a/ini_test.go b/ini_test.go index 306a2a8..aaad1a0 100644 --- a/ini_test.go +++ b/ini_test.go @@ -567,6 +567,31 @@ key = test value more text assert.Equal(t, `test value more text`, f.Section("").Key("key").String()) }) + t.Run("unescape double quotes with backslash continuation", func(t *testing.T) { + f, err := LoadSources(LoadOptions{ + UnescapeValueDoubleQuotes: true, + }, []byte(`hello = "!f() { \ + echo "hello world"; \ +};f"`)) + require.NoError(t, err) + require.NotNil(t, f) + + expected := `!f() { \ + echo "hello world"; \ +};f` + assert.Equal(t, expected, f.Section("").Key("hello").String()) + + t.Run("inverse case", func(t *testing.T) { + _, err := LoadSources(LoadOptions{ + UnescapeValueDoubleQuotes: true, + IgnoreContinuation: true, + }, []byte(`hello = "!f() { \ + echo "hello world"; \ +};f"`)) + require.Error(t, err) + }) + }) + t.Run("can parse small python-compatible INI files", func(t *testing.T) { f, err := LoadSources(LoadOptions{ AllowPythonMultilineValues: true, diff --git a/parser.go b/parser.go index 44fc526..909d633 100644 --- a/parser.go +++ b/parser.go @@ -181,6 +181,13 @@ func (p *parser) readMultilines(line, val, valQuote string) (string, error) { pos := strings.LastIndex(next, valQuote) if pos > -1 { + // Check if the line ends with backslash continuation after the quote + restOfLine := strings.TrimRight(next[pos+len(valQuote):], "\r\n") + if !p.options.IgnoreContinuation && strings.HasSuffix(strings.TrimSpace(restOfLine), "\\") { + val += next + continue + } + val += next[:pos] comment, has := cleanComment([]byte(next[pos:]))