My working unpac repository
at opam/upstream/seq 190 lines 5.8 kB view raw
1(**************************************************************************) 2(* *) 3(* OCaml *) 4(* *) 5(* Jerome Vouillon, projet Cristal, INRIA Rocquencourt *) 6(* OCaml port by John Malecki and Xavier Leroy *) 7(* *) 8(* Copyright 1996 Institut National de Recherche en Informatique et *) 9(* en Automatique. *) 10(* *) 11(* All rights reserved. This file is distributed under the terms of *) 12(* the GNU Lesser General Public License version 2.1, with the *) 13(* special exception on linking described in the file LICENSE. *) 14(* *) 15(**************************************************************************) 16 17(************************ Source management ****************************) 18 19open Misc 20open Primitives 21 22let source_extensions = [".ml"] 23 24(*** Conversion function. ***) 25 26let source_of_module pos mdle = 27 let pos_fname = pos.Lexing.pos_fname in 28 if Sys.file_exists pos_fname then pos_fname else 29 let is_submodule m m' = 30 let len' = String.length m' in 31 try 32 (String.sub m 0 len') = m' && (String.get m len') = '.' 33 with 34 Invalid_argument _ -> false in 35 let path = 36 Hashtbl.fold 37 (fun mdl dirs acc -> 38 if is_submodule mdle mdl then 39 dirs 40 else 41 acc) 42 Debugger_config.load_path_for 43 (Load_path.get_path_list ()) in 44 try 45 if pos_fname <> "" && Filename.is_relative pos_fname then 46 find_in_path_rel path pos_fname 47 else raise Not_found 48 with Not_found -> 49 let innermost_module = 50 try 51 let dot_index = String.rindex mdle '.' in 52 String.sub mdle (succ dot_index) (pred (String.length mdle - dot_index)) 53 with Not_found -> mdle in 54 let rec loop = 55 function 56 | [] -> raise Not_found 57 | ext :: exts -> 58 try find_in_path_normalized path (innermost_module ^ ext) 59 with Not_found -> loop exts 60 in loop source_extensions 61 62(*** Buffer cache ***) 63 64(* Buffer and cache (to associate lines and positions in the buffer). *) 65type buffer = string * (int * int) list ref 66 67let buffer_max_count = ref 10 68 69let buffer_list = 70 ref ([] : (string * buffer) list) 71 72let flush_buffer_list () = 73 buffer_list := [] 74 75let get_buffer pos mdle = 76 try List.assoc mdle !buffer_list with 77 Not_found -> 78 let inchan = open_in_bin (source_of_module pos mdle) in 79 let content = really_input_string inchan (in_channel_length inchan) in 80 let buffer = (content, ref []) in 81 buffer_list := 82 (list_truncate !buffer_max_count ((mdle, buffer)::!buffer_list)); 83 buffer 84 85let buffer_content = 86 (fst : buffer -> string) 87 88let buffer_length x = 89 String.length (buffer_content x) 90 91(*** Position conversions. ***) 92 93type position = int * int 94 95(* Insert a new pair (position, line) in the cache of the given buffer. *) 96let insert_pos buffer ((position, line) as pair) = 97 let rec new_list = 98 function 99 [] -> 100 [(position, line)] 101 | ((_pos, lin) as a::l) as l' -> 102 if lin < line then 103 pair::l' 104 else if lin = line then 105 l' 106 else 107 a::(new_list l) 108 in 109 let buffer_cache = snd buffer in 110 buffer_cache := new_list !buffer_cache 111 112(* Position of the next linefeed after `pos'. *) 113(* Position just after the buffer end if no linefeed found. *) 114(* Raise `Out_of_range' if already there. *) 115let next_linefeed (buffer, _) pos = 116 let len = String.length buffer in 117 if pos >= len then 118 raise Out_of_range 119 else 120 let rec search p = 121 if p = len || String.get buffer p = '\n' then 122 p 123 else 124 search (succ p) 125 in 126 search pos 127 128(* Go to next line. *) 129let next_line buffer (pos, line) = 130 (next_linefeed buffer pos + 1, line + 1) 131 132(* Convert a position in the buffer to a line number. *) 133let line_of_pos buffer position = 134 let rec find = 135 function 136 | [] -> 137 if position < 0 then 138 raise Out_of_range 139 else 140 (0, 1) 141 | ((pos, _line) as pair)::l -> 142 if pos > position then 143 find l 144 else 145 pair 146 and find_line previous = 147 let (pos, _line) as next = next_line buffer previous in 148 if pos <= position then 149 find_line next 150 else 151 previous 152 in 153 let result = find_line (find !(snd buffer)) in 154 insert_pos buffer result; 155 result 156 157(* Convert a line number to a position. *) 158let pos_of_line buffer line = 159 let rec find = 160 function 161 [] -> 162 if line <= 0 then 163 raise Out_of_range 164 else 165 (0, 1) 166 | ((_pos, lin) as pair)::l -> 167 if lin > line then 168 find l 169 else 170 pair 171 and find_pos previous = 172 let (_, lin) as next = next_line buffer previous in 173 if lin <= line then 174 find_pos next 175 else 176 previous 177 in 178 let result = find_pos (find !(snd buffer)) in 179 insert_pos buffer result; 180 result 181 182(* Convert a coordinate (line / column) into a position. *) 183(* --- The first line and column are line 1 and column 1. *) 184let point_of_coord buffer line column = 185 fst (pos_of_line buffer line) + (pred column) 186 187let start_and_cnum buffer pos = 188 let line_number = pos.Lexing.pos_lnum in 189 let start = point_of_coord buffer line_number 1 in 190 start, start + (pos.Lexing.pos_cnum - pos.Lexing.pos_bol)