diff --git a/src/dune_rules/cram_exec.ml b/src/dune_rules/cram_exec.ml index 2adb9c76526..4c74f59b231 100644 --- a/src/dune_rules/cram_exec.ml +++ b/src/dune_rules/cram_exec.ml @@ -111,16 +111,39 @@ let translate_path_for_sh = On Windows, we still generate a [sh] script so we need to quote using Unix conventions. *) let quote_for_sh fn = - (* we lose some portability as [$'] isn't posix. I don't see a better way to - do this *) - let buf = Buffer.create (String.length fn + 2) in - Buffer.add_string buf "$'"; + (* we lose some portability as [$'] isn't posix. This is why we prefer single + quotes when possible *) + let has_single_quote = ref false in + (* minimum chars for [$'']*) + let posix_quote_len = ref 3 in String.iter fn ~f:(function - | '\'' -> Buffer.add_string buf "\'" - | '\\' -> Buffer.add_string buf "\\\\" - | c -> Buffer.add_char buf c); - Buffer.add_char buf '\''; - Buffer.contents buf + | '\'' -> + posix_quote_len := !posix_quote_len + 2; + has_single_quote := true + | '\\' -> posix_quote_len := !posix_quote_len + 2 + | _ -> incr posix_quote_len); + match !has_single_quote with + | false -> "'" ^ fn ^ "'" + | true -> + let len = !posix_quote_len in + let res = Bytes.create len in + Bytes.set res 0 '$'; + Bytes.set res 1 '\''; + Bytes.set res (len - 1) '\''; + let i = ref 2 in + String.iter fn ~f:(function + | '\'' -> + Bytes.set res !i '\\'; + Bytes.set res (!i + 1) '\''; + i := !i + 2 + | '\\' -> + Bytes.set res !i '\\'; + Bytes.set res (!i + 1) '\\'; + i := !i + 2 + | c -> + Bytes.set res !i c; + incr i); + Bytes.to_string res let cram_stanzas lexbuf = let rec loop acc =