(* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. *) open! IStd module F = Format (** apply a map function for escape sequences *) let escape_map map_fun s = let needs_escape = String.exists ~f:(fun c -> Option.is_some (map_fun c)) s in if needs_escape then ( let len = String.length s in let buf = Buffer.create len in for i = 0 to len - 1 do let c = String.unsafe_get s i in match map_fun c with None -> Buffer.add_char buf c | Some s' -> Buffer.add_string buf s' done ; Buffer.contents buf ) else (* not escaping anything, so don't waste memory on a copy of the string *) s let escape_xml s = let map = function | '"' -> Some """ | '>' -> Some ">" | '<' -> Some "<" | '&' -> Some "&" | '%' -> Some "%" | _ -> None in escape_map map s let escape_url s = let map = function | '!' -> Some "%21" | '"' -> Some "%22" | '#' -> Some "%23" | '$' -> Some "%24" | '&' -> Some "%26" | '\'' -> Some "%27" | '(' -> Some "%28" | ')' -> Some "%29" | '*' -> Some "%2A" | '+' -> Some "%2B" | ',' -> Some "%2C" | '/' -> Some "%2F" | ':' -> Some "%3A" | ';' -> Some "%3B" | '=' -> Some "%3D" | '?' -> Some "%3F" | '@' -> Some "%40" | '[' -> Some "%5B" | ']' -> Some "%5D" | _ -> None in escape_map map s let escape_dotty s = let map = function '"' -> Some "\\\"" | '\\' -> Some "\\\\" | _ -> None in escape_map map s let escape_path s = let map = function | c -> if String.equal (Char.escaped c) Filename.dir_sep then Some "_" else None in escape_map map s (* Python 2 sucks at utf8 so do not write unicode file names to disk as Python may need to see them *) let escape_filename s = let map = function | c when Char.to_int c > 127 -> Some "?" (* non-ascii character: escape *) | _ -> None in escape_map map s let escape_json s = escape_map (function '"' -> Some "\\\"" | '\\' -> Some "\\\\" | _ -> None) s let escape_double_quotes s = escape_map (function '"' -> Some "\\\"" | _ -> None) s let escape_in_single_quotes s = Printf.sprintf "'%s'" (escape_map (function '\'' -> Some "'\\''" | _ -> None) s) let escape_shell = let no_quote_needed = Str.regexp "^[A-Za-z0-9-_%/:,.]+$" in let easy_single_quotable = Str.regexp "^[^']+$" in let easy_double_quotable = Str.regexp "^[^$`\\!]+$" in function | "" -> "''" | arg -> if Str.string_match no_quote_needed arg 0 then arg else if Str.string_match easy_single_quotable arg 0 then F.sprintf "'%s'" arg else if Str.string_match easy_double_quotable arg 0 then escape_double_quotes arg |> F.sprintf "\"%s\"" else (* ends on-going single quote, output single quote inside double quotes, then open a new single quote *) escape_map (function '\'' -> Some "'\"'\"'" | _ -> None) arg |> F.sprintf "'%s'"