diff --git a/lib/fluent/config/basic_parser.rb b/lib/fluent/config/basic_parser.rb index 2a92f6b9b7..01b04e5228 100644 --- a/lib/fluent/config/basic_parser.rb +++ b/lib/fluent/config/basic_parser.rb @@ -28,6 +28,7 @@ def initialize(strscan) SPACING = /(?:[ \t\r\n]|\z|\#.*?(?:\z|[\r\n]))+/ ZERO_OR_MORE_SPACING = /(?:[ \t\r\n]|\z|\#.*?(?:\z|[\r\n]))*/ SPACING_WITHOUT_COMMENT = /(?:[ \t\r\n]|\z)+/ + LINE_END_WITHOUT_SPACING_AND_COMMENT = /(?:\z|[\r\n])/ module ClassMethods def symbol(string) @@ -71,6 +72,10 @@ def prev_match @ss[0] end + def check(pattern) + @ss.check(pattern) + end + def line_end skip(LINE_END) end diff --git a/lib/fluent/config/literal_parser.rb b/lib/fluent/config/literal_parser.rb index 403b7a12ee..67db779461 100644 --- a/lib/fluent/config/literal_parser.rb +++ b/lib/fluent/config/literal_parser.rb @@ -81,6 +81,11 @@ def scan_double_quoted_string while true if skip(/\"/) return string.join + elsif check(/[^"]#{LINE_END_WITHOUT_SPACING_AND_COMMENT}/) + if s = check(/[^\\]#{LINE_END_WITHOUT_SPACING_AND_COMMENT}/) + string << s + end + skip(/[^"]#{LINE_END_WITHOUT_SPACING_AND_COMMENT}/) elsif s = scan(/\\./) string << eval_escape_char(s[1,1]) elsif skip(/\#\{/) diff --git a/test/config/test_config_parser.rb b/test/config/test_config_parser.rb index 7012f16b08..11f48994cd 100644 --- a/test/config/test_config_parser.rb +++ b/test/config/test_config_parser.rb @@ -5,6 +5,7 @@ require "fluent/config/basic_parser" require "fluent/config/literal_parser" require "fluent/config/v1_parser" +require 'fluent/config/parser' module Fluent::Config module V1TestHelper @@ -129,6 +130,7 @@ def parse_text(text) test "requires escaping double quote" do assert_text_parsed_as(e('ROOT', '', {"k1" => '"'}), ' k1 "\\""') assert_parse_error(' k1 """') + assert_parse_error(' k1 ""\'') end test "removes backslash in front of a normal character" do @@ -138,6 +140,39 @@ def parse_text(text) test "accepts escape characters" do assert_text_parsed_as(e('ROOT', '', {"k1" => "\n"}), ' k1 "\\n"') end + + test "support multiline string" do + assert_text_parsed_as(e('ROOT', '', + {"k1" => %[line1 + line2] + }), + %[k1 "line1 + line2"] + ) + assert_text_parsed_as(e('ROOT', '', + {"k1" => %[line1 line2] + }), + %[k1 "line1\\ + line2"] + ) + assert_text_parsed_as(e('ROOT', '', + {"k1" => %[line1 + line2 + line3] + }), + %[k1 "line1 + line2 + line3"] + ) + assert_text_parsed_as(e('ROOT', '', + {"k1" => %[line1 + line2 line3] + }), + %[k1 "line1 + line2\\ + line3"] + ) + end end sub_test_case 'single quoted string' do diff --git a/test/config/test_literal_parser.rb b/test/config/test_literal_parser.rb index 75218b77aa..3e495fe332 100644 --- a/test/config/test_literal_parser.rb +++ b/test/config/test_literal_parser.rb @@ -109,6 +109,8 @@ def test_falseX test('"\\0"') { assert_parse_error('"\\0"') } # unknown escaped character test('"\\1"') { assert_parse_error('"\\1"') } # unknown escaped character test('"t') { assert_parse_error('"t') } # non-terminated quoted character + test("\"t\nt\"") { assert_text_parsed_as("t\nt", "\"t\nt\"" ) } # multiline string + test("\"t\\\nt\"") { assert_text_parsed_as("tt", "\"t\\\nt\"" ) } # multiline string test('t"') { assert_text_parsed_as('t"', 't"') } test('"."') { assert_text_parsed_as('.', '"."') } test('"*"') { assert_text_parsed_as('*', '"*"') }