From 9661aaa830fd00df65d3bf64cfe25cfd56f35024 Mon Sep 17 00:00:00 2001 From: Shahms King Date: Wed, 22 May 2019 10:02:47 -0700 Subject: [PATCH] support Python multi-line values with empty first line --- ini_test.go | 5 +++++ parser.go | 59 ++++++++++++++++++++++++++++++----------------------- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/ini_test.go b/ini_test.go index 767b461..7193823 100644 --- a/ini_test.go +++ b/ini_test.go @@ -507,11 +507,16 @@ long_rsa_private_key = -----BEGIN RSA PRIVATE KEY----- foobar barfoo -----END RSA PRIVATE KEY----- +multiline_list = + first + second + third `)) So(err, ShouldBeNil) So(f, ShouldNotBeNil) So(f.Section("long").Key("long_rsa_private_key").String(), ShouldEqual, "-----BEGIN RSA PRIVATE KEY-----\nfoo\nbar\nfoobar\nbarfoo\n-----END RSA PRIVATE KEY-----") + So(f.Section("long").Key("multiline_list").String(), ShouldEqual, "\nfirst\nsecond\nthird") }) Convey("Can parse big python-compatible INI files", func() { diff --git a/parser.go b/parser.go index a869651..4a95b55 100644 --- a/parser.go +++ b/parser.go @@ -204,6 +204,9 @@ func (p *parser) readValue(in []byte, bufferSize int) (string, error) { line := strings.TrimLeftFunc(string(in), unicode.IsSpace) if len(line) == 0 { + if p.options.AllowPythonMultilineValues && len(in) > 0 && in[len(in)-1] == '\n' { + return p.readPythonMultilines(line, bufferSize) + } return "", nil } @@ -272,42 +275,46 @@ func (p *parser) readValue(in []byte, bufferSize int) (string, error) { line = strings.Replace(line, `\#`, "#", -1) } } else if p.options.AllowPythonMultilineValues && lastChar == '\n' { - parserBufferPeekResult, _ := p.buf.Peek(bufferSize) - peekBuffer := bytes.NewBuffer(parserBufferPeekResult) + return p.readPythonMultilines(line, bufferSize) + } - val := line + return line, nil +} - for { - peekData, peekErr := peekBuffer.ReadBytes('\n') - if peekErr != nil { - if peekErr == io.EOF { - return val, nil - } - return "", peekErr - } +func (p *parser) readPythonMultilines(line string, bufferSize int) (string, error) { + parserBufferPeekResult, _ := p.buf.Peek(bufferSize) + peekBuffer := bytes.NewBuffer(parserBufferPeekResult) - peekMatches := pythonMultiline.FindStringSubmatch(string(peekData)) - if len(peekMatches) != 3 { - return val, nil - } + val := line - // NOTE: Return if not a python-ini multi-line value. - currentIdentSize := len(peekMatches[1]) - if currentIdentSize <= 0 { + for { + peekData, peekErr := peekBuffer.ReadBytes('\n') + if peekErr != nil { + if peekErr == io.EOF { return val, nil } + return "", peekErr + } - // NOTE: Just advance the parser reader (buffer) in-sync with the peek buffer. - _, err := p.readUntil('\n') - if err != nil { - return "", err - } + peekMatches := pythonMultiline.FindStringSubmatch(string(peekData)) + if len(peekMatches) != 3 { + return val, nil + } - val += fmt.Sprintf("\n%s", peekMatches[2]) + // NOTE: Return if not a python-ini multi-line value. + currentIdentSize := len(peekMatches[1]) + if currentIdentSize <= 0 { + return val, nil } - } - return line, nil + // NOTE: Just advance the parser reader (buffer) in-sync with the peek buffer. + _, err := p.readUntil('\n') + if err != nil { + return "", err + } + + val += fmt.Sprintf("\n%s", peekMatches[2]) + } } // parse parses data through an io.Reader.