let to_stringstream strm = Stream2.map (fun line -> line ^ "\n") strm let to_file path strm = let chan = open_out_gen [Open_creat; Open_trunc; Open_wronly] 0o0644 path in Stream.iter (output_string chan) (to_stringstream strm); close_out chan (** Return a stream of the lines of a file *) let of_file path = let chan = open_in path in Stream.from (fun _ -> try Some (input_line chan) with End_of_file -> close_in chan; None | exn -> close_in chan; raise exn) (** Turn a stream of strings into a stream of lines. The buffer size is chosen to be the same as the number returned by Channel.line_buf but it doesn't need to be. *) let of_stringstream ?(bufsize=4096) strm = let buf = Charqueue.create bufsize (* Next line is constructed here *) and inb = Charqueue.make "" in (* Holds unused input *) Stream.from (fun n -> let rec loop () = try if Charqueue.empty inb then Charqueue.replace inb (Stream.next strm); let eol = Charqueue.index inb '\n' in Charqueue.add_string buf (Charqueue.head inb eol); Charqueue.discard inb (eol + 1); (* Discard newline *) let line = Charqueue.contents buf in Charqueue.clear buf; Some line with Not_found -> begin (* No newline in input buffer *) try (* No newlines in input buffer, append it to buffer *) Charqueue.add_string buf (Charqueue.contents inb); Charqueue.clear inb; loop () with Invalid_argument "Charqueue.extend" -> (* Too much text without finding eol *) prerr_endline "Line too long, splitting"; let line = Charqueue.contents buf in Charqueue.clear buf; Some line end | Invalid_argument "Charqueue.extend" -> (* Found eol, but resulting line was too long *) prerr_endline "Line too long, splitting"; let line = Charqueue.contents buf in Charqueue.clear buf; Some line | Stream.Failure -> (* End of input *) if Charqueue.empty buf then None else begin let line = Charqueue.contents buf in Charqueue.clear buf; Some line end in loop ())