@@ -1391,72 +1391,97 @@ impl<'a> Parser<'a> {
1391
1391
fn parse_str_until ( & mut self , endpoint : & [ Option < char > ] , check_inline_comment : bool ) -> Result < String , ParseError > {
1392
1392
let mut result: String = String :: new ( ) ;
1393
1393
1394
+ let mut in_line_continuation = false ;
1395
+
1394
1396
while !endpoint. contains ( & self . ch ) {
1395
1397
match self . char_or_eof ( endpoint) ? {
1396
1398
#[ cfg( feature = "inline-comment" ) ]
1397
- space if check_inline_comment && ( space == ' ' || space == '\t' ) => {
1399
+ ch if check_inline_comment && ( ch == ' ' || ch == '\t' ) => {
1398
1400
self . bump ( ) ;
1399
1401
1400
1402
match self . ch {
1401
1403
Some ( '#' ) | Some ( ';' ) => {
1402
1404
// [space]#, [space]; starts an inline comment
1403
- break ;
1405
+ self . parse_comment ( ) ;
1406
+ if in_line_continuation {
1407
+ result. push ( ch) ;
1408
+ continue ;
1409
+ } else {
1410
+ break ;
1411
+ }
1404
1412
}
1405
1413
Some ( _) => {
1406
- result. push ( space ) ;
1414
+ result. push ( ch ) ;
1407
1415
continue ;
1408
1416
}
1409
1417
None => {
1410
- result. push ( space ) ;
1418
+ result. push ( ch ) ;
1411
1419
}
1412
1420
}
1413
1421
}
1414
- '\\' if self . opt . enabled_escape => {
1422
+ #[ cfg( feature = "inline-comment" ) ]
1423
+ ch if check_inline_comment && in_line_continuation && ( ch == '#' || ch == ';' ) => {
1424
+ self . parse_comment ( ) ;
1425
+ continue ;
1426
+ }
1427
+ '\\' => {
1415
1428
self . bump ( ) ;
1416
- match self . char_or_eof ( endpoint) ? {
1417
- '0' => result. push ( '\0' ) ,
1418
- 'a' => result. push ( '\x07' ) ,
1419
- 'b' => result. push ( '\x08' ) ,
1420
- 't' => result. push ( '\t' ) ,
1421
- 'r' => result. push ( '\r' ) ,
1422
- 'n' => result. push ( '\n' ) ,
1423
- '\n' => ( ) ,
1424
- 'x' => {
1425
- // Unicode 4 character
1426
- let mut code: String = String :: with_capacity ( 4 ) ;
1427
- for _ in 0 ..4 {
1428
- self . bump ( ) ;
1429
- let ch = self . char_or_eof ( endpoint) ?;
1430
- if ch == '\\' {
1429
+ let Some ( ch) = self . ch else {
1430
+ result. push ( '\\' ) ;
1431
+ continue ;
1432
+ } ;
1433
+
1434
+ if matches ! ( ch, '\n' ) {
1435
+ in_line_continuation = true ;
1436
+ } else if self . opt . enabled_escape {
1437
+ match ch {
1438
+ '0' => result. push ( '\0' ) ,
1439
+ 'a' => result. push ( '\x07' ) ,
1440
+ 'b' => result. push ( '\x08' ) ,
1441
+ 't' => result. push ( '\t' ) ,
1442
+ 'r' => result. push ( '\r' ) ,
1443
+ 'n' => result. push ( '\n' ) ,
1444
+ '\n' => self . bump ( ) ,
1445
+ 'x' => {
1446
+ // Unicode 4 character
1447
+ let mut code: String = String :: with_capacity ( 4 ) ;
1448
+ for _ in 0 ..4 {
1431
1449
self . bump ( ) ;
1432
- if self . ch != Some ( '\n' ) {
1433
- return self . error ( format ! (
1434
- "expecting \" \\ \\ n\" but \
1450
+ let ch = self . char_or_eof ( endpoint) ?;
1451
+ if ch == '\\' {
1452
+ self . bump ( ) ;
1453
+ if self . ch != Some ( '\n' ) {
1454
+ return self . error ( format ! (
1455
+ "expecting \" \\ \\ n\" but \
1435
1456
found \" {:?}\" .",
1436
- self . ch
1437
- ) ) ;
1457
+ self . ch
1458
+ ) ) ;
1459
+ }
1438
1460
}
1439
- }
1440
1461
1441
- code. push ( ch) ;
1442
- }
1443
- let r = u32:: from_str_radix ( & code[ ..] , 16 ) ;
1444
- match r. ok ( ) . and_then ( char:: from_u32) {
1445
- Some ( ch) => result. push ( ch) ,
1446
- None => return self . error ( "unknown character in \\ xHH form" ) ,
1462
+ code. push ( ch) ;
1463
+ }
1464
+ let r = u32:: from_str_radix ( & code[ ..] , 16 ) ;
1465
+ match r. ok ( ) . and_then ( char:: from_u32) {
1466
+ Some ( ch) => result. push ( ch) ,
1467
+ None => return self . error ( "unknown character in \\ xHH form" ) ,
1468
+ }
1447
1469
}
1470
+ c => result. push ( c) ,
1448
1471
}
1449
- c => result. push ( c) ,
1472
+ } else {
1473
+ result. push ( '\\' ) ;
1474
+ result. push ( ch) ;
1450
1475
}
1451
1476
}
1452
- ch => {
1453
- result. push ( ch) ;
1454
- }
1477
+ ch => result. push ( ch) ,
1455
1478
}
1456
1479
self . bump ( ) ;
1457
1480
}
1458
1481
1459
1482
let _ = check_inline_comment;
1483
+ let _ = in_line_continuation;
1484
+
1460
1485
Ok ( result)
1461
1486
}
1462
1487
@@ -1540,11 +1565,6 @@ impl<'a> Parser<'a> {
1540
1565
fn parse_str_until_eol ( & mut self , check_inline_comment : bool ) -> Result < String , ParseError > {
1541
1566
let r = self . parse_str_until ( & [ Some ( '\n' ) , Some ( '\r' ) , None ] , check_inline_comment) ?;
1542
1567
1543
- #[ cfg( feature = "inline-comment" ) ]
1544
- if check_inline_comment && matches ! ( self . ch, Some ( '#' ) | Some ( ';' ) ) {
1545
- self . parse_comment ( ) ;
1546
- }
1547
-
1548
1568
Ok ( r)
1549
1569
}
1550
1570
}
@@ -1828,6 +1848,48 @@ Otherline\"
1828
1848
assert_eq ! ( ini. get_from( Some ( "section name" ) , "Key" ) . unwrap( ) , "Value\n Otherline" ) ;
1829
1849
}
1830
1850
1851
+ #[ test]
1852
+ fn string_multiline_escape ( ) {
1853
+ let input = r"
1854
+ [section name]
1855
+ # This is a comment
1856
+ Key = Value \
1857
+ Otherline
1858
+ " ;
1859
+ let ini = Ini :: load_from_str_opt (
1860
+ input,
1861
+ ParseOption {
1862
+ enabled_escape : false ,
1863
+ ..Default :: default ( )
1864
+ } ,
1865
+ )
1866
+ . unwrap ( ) ;
1867
+ assert_eq ! ( ini. get_from( Some ( "section name" ) , "Key" ) . unwrap( ) , "Value Otherline" ) ;
1868
+ }
1869
+
1870
+ #[ cfg( feature = "inline-comment" ) ]
1871
+ #[ test]
1872
+ fn string_multiline_inline_comment ( ) {
1873
+ let input = r"
1874
+ [section name]
1875
+ # This is a comment
1876
+ Key = Value \
1877
+ # This is also a comment
1878
+ ; This is also a comment
1879
+ # This is also a comment
1880
+ Otherline
1881
+ " ;
1882
+ let ini = Ini :: load_from_str_opt (
1883
+ input,
1884
+ ParseOption {
1885
+ enabled_escape : false ,
1886
+ ..Default :: default ( )
1887
+ } ,
1888
+ )
1889
+ . unwrap ( ) ;
1890
+ assert_eq ! ( ini. get_from( Some ( "section name" ) , "Key" ) . unwrap( ) , "Value Otherline" ) ;
1891
+ }
1892
+
1831
1893
#[ test]
1832
1894
fn string_comment ( ) {
1833
1895
let input = "
@@ -2035,10 +2097,7 @@ Key = 'Value # This is not a comment ; at all'
2035
2097
#[ test]
2036
2098
fn load_from_str_noescape ( ) {
2037
2099
let input = "path=C:\\ Windows\\ Some\\ Folder\\ " ;
2038
- let opt = Ini :: load_from_str_noescape ( input) ;
2039
- assert ! ( opt. is_ok( ) ) ;
2040
-
2041
- let output = opt. unwrap ( ) ;
2100
+ let output = Ini :: load_from_str_noescape ( input) . unwrap ( ) ;
2042
2101
assert_eq ! ( output. len( ) , 1 ) ;
2043
2102
let sec = output. section ( None :: < String > ) . unwrap ( ) ;
2044
2103
assert_eq ! ( sec. len( ) , 1 ) ;
0 commit comments