@@ -203,7 +203,7 @@ fn parse_dictionary_string_list(line: &str) -> Option<DictionaryStringList<'_>>
203203 return None ;
204204 }
205205 let value = & list[ value_quote. len_utf8 ( ) ..list. len ( ) - value_quote. len_utf8 ( ) ] ;
206- if value . contains ( value_quote) || value. contains ( '\n' ) {
206+ if contains_unescaped_delimiter ( value , value_quote) || value. contains ( '\n' ) {
207207 return None ;
208208 }
209209 Some ( DictionaryStringList {
@@ -260,7 +260,7 @@ fn parse_list_string_item(line: &str) -> Option<ListStringItem<'_>> {
260260 return None ;
261261 }
262262 let content = & rest[ quote. len_utf8 ( ) ..rest. len ( ) - quote. len_utf8 ( ) ] ;
263- if content . contains ( quote) || content. contains ( '\n' ) {
263+ if contains_unescaped_delimiter ( content , quote) || content. contains ( '\n' ) {
264264 return None ;
265265 }
266266 Some ( ListStringItem {
@@ -383,7 +383,7 @@ fn parse_string_assignment(line: &str) -> Option<StringAssignment<'_>> {
383383 return None ;
384384 }
385385 // If the quote appears unescaped inside content, bail (ambiguous)
386- if content . contains ( quote) {
386+ if contains_unescaped_delimiter ( content , quote) {
387387 return None ;
388388 }
389389 Some ( StringAssignment {
@@ -395,6 +395,21 @@ fn parse_string_assignment(line: &str) -> Option<StringAssignment<'_>> {
395395 } )
396396}
397397
398+ fn contains_unescaped_delimiter ( content : & str , delimiter : char ) -> bool {
399+ let mut backslashes = 0usize ;
400+ for character in content. chars ( ) {
401+ if character == delimiter && backslashes % 2 == 0 {
402+ return true ;
403+ }
404+ if character == '\\' {
405+ backslashes += 1 ;
406+ } else {
407+ backslashes = 0 ;
408+ }
409+ }
410+ false
411+ }
412+
398413fn format_string_assignment ( asg : & StringAssignment < ' _ > ) -> Vec < String > {
399414 // Use `=` then `+=` lines — EasyBuild-common and already handled by the
400415 // restricted parser (adjacent parenthesized string literals are not).
0 commit comments