(* Copyright 2012 Tony Garnock-Jones . *) (* This file is part of Hop. *) (* Hop is free software: you can redistribute it and/or modify it *) (* under the terms of the GNU General Public License as published by the *) (* Free Software Foundation, either version 3 of the License, or (at your *) (* option) any later version. *) (* Hop is distributed in the hope that it will be useful, but *) (* WITHOUT ANY WARRANTY; without even the implied warranty of *) (* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *) (* General Public License for more details. *) (* You should have received a copy of the GNU General Public License *) (* along with Hop. If not, see . *) open Lwt open Sexp open Printf let message_not_understood context m = Log.warn "Message not understood" [str context; Message.sexp_of_message m] let create_thread name cleanup main initarg = let guarded_main initarg = try_lwt main initarg with e -> lwt () = Log.warn "Thread died with exception" [Str name; str (Printexc.to_string e)] in (match cleanup with | Some cleaner -> cleaner e | None -> return ()) in guarded_main initarg let daemon_thread_died name nested_cleaner e = lwt () = (match nested_cleaner with | Some c -> c e | None -> return ()) in Server_control.shutdown_now [litstr "Daemon thread exited"; Str name]; return () let create_daemon_thread name cleanup main initarg = create_thread name (Some (daemon_thread_died name cleanup)) main initarg let starts_with s1 s2 = try Str.first_chars s1 (String.length s2) = s2 with _ -> false let ends_with s1 s2 = try Str.last_chars s1 (String.length s2) = s2 with _ -> false let strip s = let len = String.length s in let ws i = Char.code (String.get s i) <= 32 in let rec left index = if index < len && ws index then left (index + 1) else index in let rec right index = if index >= 0 && ws index then right (index - 1) else index in let l = left 0 in let r = 1 + right (len - 1) in if r <= l then "" else String.sub s l (r - l) let strsub replacement_fn s = let len = String.length s in let finish_span low high acc = String.sub s low (high - low) :: acc in let finish acc = String.concat "" (List.rev acc) in let rec outer_loop acc low = let rec inner_loop high = if high = len then finish (finish_span low high acc) else match replacement_fn (String.get s high) with | Some handler -> let (replacement, new_low) = handler (s, high) in outer_loop (replacement :: finish_span low high acc) new_low | None -> inner_loop (high + 1) in inner_loop low in outer_loop [] 0 let unhex_char c = match c with | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' -> Char.code c - Char.code '0' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' -> Char.code c - Char.code 'a' + 10 | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' -> Char.code c - Char.code 'A' + 10 | _ -> -1 let unhex s = let len = String.length s in let rec loop index acc = if index = len then acc else loop (index + 1) (acc * 16 + unhex_char (String.get s index)) in loop 0 0 let stream_to_string s = lwt pieces = Lwt_stream.to_list s in return (String.concat "" pieces) let stream_generator f = let mbox = Lwt_mvar.create_empty () in let yield v = Lwt_mvar.put mbox (Some v) in ignore (lwt () = f yield in Lwt_mvar.put mbox None); Lwt_stream.from (fun () -> Lwt_mvar.take mbox) let file_contents filename = let ch = open_in filename in let len = in_channel_length ch in let buf = Bytes.make len ' ' in really_input ch buf 0 len; close_in ch; buf let rec split_at xs n = match n with | 0 -> ([], xs) | _ -> match xs with | [] -> raise (Failure "Util.split_at") | x :: xs' -> let (hs, ts) = split_at xs' (n - 1) in (x :: hs, ts) let rec list_make n v = match n with | 0 -> [] | _ -> v :: list_make (n - 1) v let rec split_at_fill v xs n = match n with | 0 -> ([], xs) | _ -> match xs with | [] -> (list_make n v, []) | x :: xs' -> let (hs, ts) = split_at_fill v xs' (n - 1) in (x :: hs, ts)