package patch
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file fname.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150type lexer_output = | Quoted of (string * string) | Unquoted | Error of string exception Cant_parse_octal let ascii_zero = 48 (* Char.code '0' *) let octal_to_char c1 c2 c3 = let char_to_digit c = Char.code c - ascii_zero in try Char.chr ( (char_to_digit c1 lsl 6) lor (char_to_digit c2 lsl 3) lor char_to_digit c3 ) with Invalid_argument _ -> raise Cant_parse_octal let lex_quoted_char s len i = match s.[i] with | 'a' -> Some ('\007', 2) | 'b' -> Some ('\b', 2) | 'f' -> Some ('\012', 2) | 'n' -> Some ('\n', 2) | 'r' -> Some ('\r', 2) | 't' -> Some ('\t', 2) | 'v' -> Some ('\011', 2) | '\\' -> Some ('\\', 2) | '"' -> Some ('"', 2) | '0'..'3' as c1 when len >= 3 -> begin match s.[i + 1], s.[i + 2] with | ('0'..'7' as c2), ('0'..'7' as c3) -> (try Some (octal_to_char c1 c2 c3, 4) with Cant_parse_octal -> None) | _, _ -> None end | _ -> None let rec lex_quoted_filename buf s len i = if len > 0 then match s.[i] with | '"' -> Quoted (Buffer.contents buf, Lib.String.slice ~start:(i + 1) s) | '\\' when len > 2 -> let char_size = match lex_quoted_char s (len - 1) (i + 1) with | Some (c, char_size) -> Buffer.add_char buf c; char_size | None -> Buffer.add_char buf s.[i]; 1 in lex_quoted_filename buf s (len - char_size) (i + char_size) | c -> Buffer.add_char buf c; lex_quoted_filename buf s (len - 1) (i + 1) else Unquoted let lex_filename buf s len = if len > 0 then match s.[0] with | '"' -> lex_quoted_filename buf s (len - 1) 1 | _ -> Unquoted else Error "empty filename" let parse_filename ~allow_space s = match lex_filename (Buffer.create 128) s (String.length s) with | Quoted x -> Ok x | Unquoted when not allow_space -> begin match Lib.String.cut ' ' s with | None -> Ok (s, "") | Some x -> Ok x end | Unquoted -> Ok (s, "") | Error msg -> Error msg let parse s = let filename_and_date = match Lib.String.cut '\t' s with | None -> parse_filename ~allow_space:false s | Some (filename, date) -> match parse_filename ~allow_space:true filename with | Ok (filename, "") -> Ok (filename, date) | Ok _ -> Error "Unexpected character after closing double-quote" | Error _ as err -> err in match filename_and_date with | Ok (filename, date) -> if filename = "/dev/null" || let date = String.trim date in Lib.String.is_prefix ~prefix:"1970-" date || Lib.String.is_prefix ~prefix:"1969-" date || Lib.String.is_suffix ~suffix:" 1970" date || Lib.String.is_suffix ~suffix:" 1969" date then (* See https://github.com/hannesm/patch/issues/8 *) Ok None else Ok (Some filename) | Error _ as err -> err let parse_git_filename s = match parse_filename ~allow_space:true s with | Ok (s, "") -> Ok s | Ok _ -> Error "Unexpected character after closing double-quote in header" | Error _ as err -> err let parse_git_header_rename ~from_ ~to_ s = let rec loop ~s ~len i = if i < (len : int) then match String.unsafe_get s i with | ' ' | '\t' -> let a = parse_git_filename (Lib.String.slice ~stop:i s) in let b = parse_git_filename (Lib.String.slice ~start:(i + 1) s) in begin match a, b with | Ok a, Ok b when Lib.String.is_suffix ~suffix:from_ a && Lib.String.is_suffix ~suffix:to_ b -> Some (a, b) | Ok _, Ok _ | Error _, _ | _, Error _ -> loop ~s ~len (i + 1) end | _ -> loop ~s ~len (i + 1) else None in loop ~s ~len:(String.length s) 0 let parse_git_header_same s = let rec loop ~best ~s ~len i = if i < (len : int) then match String.unsafe_get s i with | ' ' | '\t' -> let a = parse_git_filename (Lib.String.slice ~stop:i s) in let b = parse_git_filename (Lib.String.slice ~start:(i + 1) s) in begin match a, b with | Ok a, Ok b -> begin match best, Lib.String.count_common_suffix a b with | None, best -> loop ~best:(Some (best, a, b)) ~s ~len (i + 1) | Some (prev_best, _, _), best when best > (prev_best : int) -> loop ~best:(Some (best, a, b)) ~s ~len (i + 1) | Some _ as best, _ -> loop ~best ~s ~len (i + 1) end | Error _, _ | _, Error _ -> loop ~best ~s ~len (i + 1) end | _ -> loop ~best ~s ~len (i + 1) else match best with | None -> None | Some (_best, a, b) -> Some (a, b) in loop ~best:None ~s ~len:(String.length s) 0