Codebase list ocaml-stdio / 2e1adb7
New upstream version 0.12.0 Stephane Glondu 4 years ago
18 changed file(s) with 642 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 _build
1 *.install
2 *.merlin
3
0 ## git version
1
2 - Added function `Out_channel.print_s`.
3
4 ## v0.10
5
6 - Enabled `-safe-string`.
7
8 - Added functions `Out_channel.output_bytes`, `Out_channel.output_substring`.
9
10 - Added functions `In_channel.equal` and `Out_channel.equal`, implemented as `phys_equal`.
11
12 ## v0.9
13
14 Initial release.
0 This repository contains open source software that is developed and
1 maintained by [Jane Street][js].
2
3 Contributions to this project are welcome and should be submitted via
4 GitHub pull requests.
5
6 Signing contributions
7 ---------------------
8
9 We require that you sign your contributions. Your signature certifies
10 that you wrote the patch or otherwise have the right to pass it on as
11 an open-source patch. The rules are pretty simple: if you can certify
12 the below (from [developercertificate.org][dco]):
13
14 ```
15 Developer Certificate of Origin
16 Version 1.1
17
18 Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
19 1 Letterman Drive
20 Suite D4700
21 San Francisco, CA, 94129
22
23 Everyone is permitted to copy and distribute verbatim copies of this
24 license document, but changing it is not allowed.
25
26
27 Developer's Certificate of Origin 1.1
28
29 By making a contribution to this project, I certify that:
30
31 (a) The contribution was created in whole or in part by me and I
32 have the right to submit it under the open source license
33 indicated in the file; or
34
35 (b) The contribution is based upon previous work that, to the best
36 of my knowledge, is covered under an appropriate open source
37 license and I have the right under that license to submit that
38 work with modifications, whether created in whole or in part
39 by me, under the same open source license (unless I am
40 permitted to submit under a different license), as indicated
41 in the file; or
42
43 (c) The contribution was provided directly to me by some other
44 person who certified (a), (b) or (c) and I have not modified
45 it.
46
47 (d) I understand and agree that this project and the contribution
48 are public and that a record of the contribution (including all
49 personal information I submit with it, including my sign-off) is
50 maintained indefinitely and may be redistributed consistent with
51 this project or the open source license(s) involved.
52 ```
53
54 Then you just add a line to every git commit message:
55
56 ```
57 Signed-off-by: Joe Smith <joe.smith@email.com>
58 ```
59
60 Use your real name (sorry, no pseudonyms or anonymous contributions.)
61
62 If you set your `user.name` and `user.email` git configs, you can sign
63 your commit automatically with git commit -s.
64
65 [dco]: http://developercertificate.org/
66 [js]: https://opensource.janestreet.com/
0 The MIT License
1
2 Copyright (c) 2016--2019 Jane Street Group, LLC <opensource@janestreet.com>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
0 INSTALL_ARGS := $(if $(PREFIX),--prefix $(PREFIX),)
1
2 default:
3 dune build
4
5 install:
6 dune install $(INSTALL_ARGS)
7
8 uninstall:
9 dune uninstall $(INSTALL_ARGS)
10
11 reinstall: uninstall install
12
13 clean:
14 dune clean
15
16 .PHONY: default install uninstall reinstall clean
0 * Standard IO Library for OCaml
1
2 Stdio provides input/output functions for OCaml. It re-exports the
3 buffered channels of the stdlib distributed with OCaml but with some
4 improvements.
0 (lang dune 1.5)
0 #!/bin/bash
1
2 exec ../base/gen-boot.sh stdio
0 (library (name stdio) (public_name stdio) (libraries base base.caml)
1 (preprocess no_preprocessing)
2 (lint
3 (pps ppx_base -check-doc-comments -type-conv-keep-w32=impl
4 -apply=js_style,type_conv)))
0 open! Base
1
2 module Sexplib = Base.Exported_for_specific_uses.Sexplib
3 module Ppx_sexp_conv_lib = Base.Exported_for_specific_uses.Ppx_sexp_conv_lib
0 open! Base
1 open! Import
2
3 type t = Caml.in_channel
4
5 let equal (t1 : t) t2 = phys_equal t1 t2
6
7 let seek = Caml.LargeFile.seek_in
8 let pos = Caml.LargeFile.pos_in
9 let length = Caml.LargeFile.in_channel_length
10
11 let stdin = Caml.stdin
12
13 let create ?(binary = true) file =
14 let flags = [Open_rdonly] in
15 let flags = if binary then Open_binary :: flags else flags in
16 Caml.open_in_gen flags 0o000 file
17 ;;
18
19 let close = Caml.close_in
20
21 let with_file ?binary file ~f = Exn.protectx (create ?binary file) ~f ~finally:close
22
23 let may_eof f = try Some (f ()) with End_of_file -> None
24
25 let input t ~buf ~pos ~len = Caml.input t buf pos len
26 let really_input t ~buf ~pos ~len =
27 may_eof (fun () -> Caml.really_input t buf pos len)
28 let really_input_exn t ~buf ~pos ~len =
29 Caml.really_input t buf pos len
30 let input_byte t = may_eof (fun () -> Caml.input_byte t)
31 let input_char t = may_eof (fun () -> Caml.input_char t)
32 let input_binary_int t = may_eof (fun () -> Caml.input_binary_int t)
33 let unsafe_input_value t = may_eof (fun () -> Caml.input_value t)
34 let input_buffer t buf ~len = may_eof (fun () -> Caml.Buffer.add_channel buf t len)
35
36 let set_binary_mode = Caml.set_binary_mode_in
37
38 let input_all t =
39 (* We use 65536 because that is the size of OCaml's IO buffers. *)
40 let buf_size = 65536 in
41 let buf = Bytes.create buf_size in
42 let buffer = Buffer.create buf_size in
43 let rec loop () =
44 let len = input t ~buf ~pos:0 ~len:(Bytes.length buf) in
45 if len > 0 then begin
46 Buffer.add_subbytes buffer buf ~pos:0 ~len;
47 loop ();
48 end
49 in
50 loop ();
51 Buffer.contents buffer;
52 ;;
53
54 let trim ~fix_win_eol line =
55 if fix_win_eol then begin
56 let len = String.length line in
57 if len > 0
58 && Char.equal (String.get line (len - 1)) '\r'
59 then String.sub line ~pos:0 ~len:(len - 1)
60 else line
61 end
62 else line
63
64 let input_line ?(fix_win_eol = true) t =
65 match may_eof (fun () -> Caml.input_line t) with
66 | None -> None
67 | Some line -> Some (trim ~fix_win_eol line)
68 ;;
69
70 let input_line_exn ?(fix_win_eol = true) t =
71 let line = Caml.input_line t in
72 trim ~fix_win_eol line
73
74 let fold_lines ?fix_win_eol t ~init ~f =
75 let rec loop ac =
76 match input_line ?fix_win_eol t with
77 | None -> ac
78 | Some line -> loop (f ac line)
79 in
80 loop init
81 ;;
82
83 let input_lines ?fix_win_eol t =
84 List.rev
85 (fold_lines ?fix_win_eol t ~init:[] ~f:(fun lines line -> line :: lines))
86 ;;
87
88 let iter_lines ?fix_win_eol t ~f =
89 fold_lines ?fix_win_eol t ~init:() ~f:(fun () line -> f line)
90 ;;
91
92 let read_lines fname = with_file fname ~f:input_lines
93
94 let read_all fname = with_file fname ~f:input_all
0 (** An input channel for doing blocking reads from input sources like files and sockets.
1
2 Note that an [In_channel.t] is a custom block with a finalizer, and so is allocated
3 directly to the major heap. Creating a lot of in_channels can result in many major
4 collections and poor performance.
5
6 Note that this is simply another interface on the [in_channel] type in the OCaml
7 standard library.
8 *)
9
10 open! Base
11 open! Import
12
13 type t = Caml.in_channel
14
15 include Equal.S with type t := t
16
17 val stdin : t
18
19 (** Channels are opened in binary mode iff [binary] is true. This only has an effect on
20 Windows.
21 *)
22
23 val create : ?binary:bool (** defaults to [true] *) -> string -> t
24
25 (** [with_file ~f fname] executes [~f] on the open channel from
26 [fname], and closes it afterwards. *)
27 val with_file : ?binary:bool (** defaults to [true] *) -> string -> f:(t -> 'a) -> 'a
28
29 (** [close t] closes [t], or does nothing if [t] is already closed, and may raise an
30 exception. *)
31 val close : t -> unit
32
33 val input : t -> buf:bytes -> pos:int -> len:int -> int
34 val really_input : t -> buf:bytes -> pos:int -> len:int -> unit option
35
36 (** Same as [Pervasives.really_input], for backwards compatibility *)
37 val really_input_exn : t -> buf:bytes -> pos:int -> len:int -> unit
38
39 (** Read one character from the given input channel. Return [None] if there are no more
40 characters to read. *)
41 val input_char : t -> char option
42
43 (** Same as [input_char], but return the 8-bit integer representing the character. Return
44 [None] if an end of file was reached. *)
45 val input_byte : t -> int option
46
47 (** Read an integer encoded in binary format (4 bytes, big-endian) from the given input
48 channel. See {!Pervasives.output_binary_int}. Return [None] if an end of file was
49 reached while reading the integer. *)
50 val input_binary_int : t -> int option
51
52 (** Ocaml's built-in marshal format *)
53 val unsafe_input_value : t -> _ option
54
55 (** [input_buffer t buf ~len] reads at most [len] characters from the input channel [t]
56 and stores them at the end of buffer [buf]. Return [None] if the channel contains
57 fewer than [len] characters. In this case, the characters are still added to the
58 buffer, so as to avoid loss of data. *)
59 val input_buffer : t -> Buffer.t -> len:int -> unit option
60
61 val input_all : t -> string
62
63 (** [input_line ?fix_win_eol t] reads a line from [t] and returns it, without
64 the newline ("\n") character at the end, and, if [fix_win_eol] the trailing
65 "\r\n" is dropped.
66 *)
67 val input_line : ?fix_win_eol:bool (** defaults to [true] *) -> t -> string option
68 val input_line_exn : ?fix_win_eol:bool (** defaults to [true] *) -> t -> string
69
70 (** [fold_lines ?fix_win_eol t ~init ~f] folds over the lines read from [t]
71 using [input_line]. Lines are provided to [f] in the order they are
72 found in the file. *)
73 val fold_lines
74 : ?fix_win_eol:bool (** defaults to [true] *)
75 -> t
76 -> init:'a
77 -> f:('a -> string -> 'a)
78 -> 'a
79
80 (** Completely reads an input channel and returns the results as a list of
81 strings. Each line in one string. *)
82 val input_lines : ?fix_win_eol:bool (** defaults to [true] *) -> t -> string list
83
84 (** [iter_lines ?fix_win_eol t ~f] applies [f] to each line read from [t] using
85 [input_line]. *)
86 val iter_lines
87 : ?fix_win_eol:bool (** defaults to [true] *)
88 -> t
89 -> f:(string -> unit)
90 -> unit
91
92 (** This works only for regular files. On files of other kinds, the behavior is
93 unspecified. *)
94 val seek : t -> int64 -> unit
95
96 val pos : t -> int64
97
98 (** Return the size (number of characters) of the regular file on which the given channel
99 is opened. If the channel is opened on a file that is not a regular file, the result
100 is meaningless. The returned size does not take into account the end-of-line
101 translations that can be performed when reading from a channel opened in text mode. *)
102 val length : t -> int64
103
104 (** same as [Pervasives.set_binary_mode_in], only applicable for Windows or Cygwin, no-op
105 otherwise *)
106 val set_binary_mode : t -> bool -> unit
107
108
109 (** [read_lines filename] reads the full contents of file and returns it as a list of
110 lines, closing the file when it's done. It's the equivalent of [with_file fname
111 ~f:input_lines] *)
112 val read_lines : string -> string list
113
114 (** [read_all filename] reads the full contents of file and returns it as a single
115 string, closing the file when it's done. It's the equivalent of [with_file fname
116 ~f:input_all] *)
117 val read_all : string -> string
0 open! Base
1 open! Import
2
3 type t = Caml.out_channel
4
5 let equal (t1 : t) t2 = phys_equal t1 t2
6
7 let seek = Caml.LargeFile.seek_out
8 let pos = Caml.LargeFile.pos_out
9 let length = Caml.LargeFile.out_channel_length
10
11 let stdout = Caml.stdout
12 let stderr = Caml.stderr
13
14 let sexp_of_t t =
15 if phys_equal t stderr
16 then Sexp.Atom "<stderr>"
17 else if phys_equal t stdout
18 then Sexp.Atom "<stdout>"
19 else Sexp.Atom "<Out_channel.t>"
20 ;;
21
22 type 'a with_create_args =
23 ?binary:bool
24 -> ?append:bool
25 -> ?fail_if_exists:bool
26 -> ?perm:int
27 -> 'a
28
29 let create ?(binary = true) ?(append = false) ?(fail_if_exists = false) ?(perm = 0o666) file =
30 let flags = [Open_wronly; Open_creat] in
31 let flags = (if binary then Open_binary else Open_text) :: flags in
32 let flags = (if append then Open_append else Open_trunc) :: flags in
33 let flags = (if fail_if_exists then Open_excl :: flags else flags) in
34 Caml.open_out_gen flags perm file
35 ;;
36
37 let set_binary_mode = Caml.set_binary_mode_out
38
39 let flush = Caml.flush
40
41 let close = Caml.close_out
42 let close_no_err = Caml.close_out_noerr
43
44 let output t ~buf ~pos ~len = Caml.output t buf pos len
45 let output_substring t ~buf ~pos ~len = Caml.output_substring t buf pos len
46 let output_string = Caml.output_string
47 let output_bytes = Caml.output_bytes
48 let output_char = Caml.output_char
49 let output_byte = Caml.output_byte
50 let output_binary_int = Caml.output_binary_int
51 let output_buffer = Caml.Buffer.output_buffer
52 let output_value = Caml.output_value
53
54 let newline t = output_string t "\n"
55
56 let output_lines t lines =
57 List.iter lines ~f:(fun line -> output_string t line; newline t)
58 ;;
59
60 let printf = Caml.Printf.printf
61 let eprintf = Caml.Printf.eprintf
62 let fprintf = Caml.Printf.fprintf
63 let kfprintf = Caml.Printf.kfprintf
64
65 let print_string = Caml.print_string
66 let print_endline = Caml.print_endline
67 let prerr_endline = Caml.prerr_endline
68
69 let print_s ?mach sexp =
70 print_endline
71 (match mach with
72 | Some () -> Sexp.to_string_mach sexp
73 | None -> Sexp.to_string_hum sexp)
74 ;;
75
76 let with_file ?binary ?append ?fail_if_exists ?perm file ~f =
77 Exn.protectx (create ?binary ?append ?fail_if_exists ?perm file) ~f ~finally:close
78 ;;
79
80 let write_lines file lines = with_file file ~f:(fun t -> output_lines t lines)
81
82 let write_all file ~data = with_file file ~f:(fun t -> output_string t data)
0 (** An output channel for doing blocking writes to destinations like files and sockets.
1
2 Note that an [Out_channel.t] is a custom block with a finalizer, and so is allocated
3 directly to the major heap. Creating a lot of out_channels can result in many major
4 collections and poor performance.
5
6 Note that this is simply another interface on the [out_channel] type in the OCaml
7 standard library.
8
9 As for the output functions in the standard library, all the functions in this module,
10 unless otherwise specified, can raise [Sys_error] when the system calls they invoke
11 fail.
12 *)
13
14 open! Base
15 open! Import
16
17 type t = Caml.out_channel [@@deriving_inline sexp_of]
18 include
19 sig [@@@ocaml.warning "-32"] val sexp_of_t : t -> Ppx_sexp_conv_lib.Sexp.t
20 end[@@ocaml.doc "@inline"]
21 [@@@end]
22
23 include Equal.S with type t := t
24
25 val stdout : t
26 val stderr : t
27
28 type 'a with_create_args =
29 ?binary:bool (** defaults to [true] *)
30 -> ?append:bool (** defaults to [false] *)
31 -> ?fail_if_exists:bool (** defaults to [false] *)
32 -> ?perm:int
33 -> 'a
34
35
36 val create : (string -> t) with_create_args
37 val with_file : (string -> f:(t -> 'a) -> 'a) with_create_args
38
39
40 (** [close t] flushes and closes [t], and may raise an exception. [close] returns () and
41 does not raise if [t] is already closed. [close] raises an exception if the close()
42 system call on the underlying file descriptor fails (i.e. returns -1), which would
43 happen in the following cases:
44
45 EBADF -- this would happen if someone else did close() system call on the underlying
46 fd, which I would think a rare event.
47
48 EINTR -- would happen if the system call was interrupted by a signal, which would be
49 rare. Also, I think we should probably just catch EINTR and re-attempt the close.
50 Unfortunately, we can't do that in OCaml because the OCaml library marks the
51 out_channel as closed even if the close syscall fails, so a subsequent call
52 [close_out_channel] will be a no-op. This should really be fixed in the OCaml library
53 C code, having it restart the close() syscall on EINTR. I put a couple CRs in
54 [fixed_close_channel], our rework of OCaml's [caml_ml_close_channel],
55
56 EIO -- I don't recall seeing this. I think it's rare.
57
58 See "man 2 close" for details.
59 *)
60 val close : t -> unit
61
62 (** [close_no_err] tries to flush and close [t]. It does not raise.*)
63 val close_no_err : t -> unit
64
65 val set_binary_mode : t -> bool -> unit
66
67 val flush : t -> unit
68
69 val output : t -> buf:bytes -> pos:int -> len:int -> unit
70 val output_string : t -> string -> unit
71 val output_substring : t -> buf:string -> pos:int -> len:int -> unit
72 val output_bytes : t -> Bytes.t -> unit
73 val output_char : t -> char -> unit
74 val output_byte : t -> int -> unit
75 val output_binary_int : t -> int -> unit
76 val output_buffer : t -> Buffer.t -> unit
77 val output_value : t -> _ -> unit (** OCaml's internal Marshal format *)
78
79 val newline : t -> unit
80
81 (** Outputs a list of lines, each terminated by a newline character *)
82 val output_lines : t -> string list -> unit
83
84 (** Formatted printing to an out channel. This is the same as [Printf.sprintf] except
85 that it outputs to [t] instead of returning a string. Similarly, the function
86 arguments corresponding to conversions specifications such as [%a] or [%t] takes [t]
87 as argument and must print to it instead of returning a string. *)
88 val fprintf : t -> ('a, t, unit) format -> 'a
89
90 (** [printf fmt] is the same as [fprintf stdout fmt] *)
91 val printf : ('a, t, unit) format -> 'a
92
93 (** [print_s sexp] outputs [sexp] on [stdout], by default using [Sexp.to_string_hum],
94 or, with [~mach:()], [Sexp.to_string_mach]. *)
95 val print_s : ?mach : unit -> Sexp.t -> unit
96
97 (** [printf fmt] is the same as [fprintf stderr fmt] *)
98 val eprintf : ('a, t, unit) format -> 'a
99
100 (** [kfprintf k t fmt] is the same as [fprintf t fmt], but instead of returning
101 immediately, passes the out channel to [k] at the end of printing. *)
102 val kfprintf : (t -> 'a) -> t -> ('b, t, unit, 'a) format4 -> 'b
103
104 (** [print_string s] = [output_string stdout s] *)
105 val print_string : string -> unit
106
107 (** [print_endline str] outputs [str] to [stdout] followed by a newline then flushes
108 [stdout] *)
109 val print_endline : string -> unit
110
111 (** [prerr_endline str] outputs [str] to [stderr] followed by a newline then flushes
112 [stderr] *)
113 val prerr_endline : string -> unit
114
115 val seek : t -> int64 -> unit
116 val pos : t -> int64
117 val length : t -> int64
118
119 (** The first argument of these is the file name to write to. *)
120 val write_lines : string -> string list -> unit
121 val write_all : string -> data:string -> unit
122
123
124
0 open! Base
1 open! Import
2
3 module In_channel = In_channel
4 module Out_channel = Out_channel
5
6 let stdin = In_channel.stdin
7 let stdout = Out_channel.stdout
8 let stderr = Out_channel.stderr
9
10 let eprintf = Out_channel.eprintf
11 let printf = Out_channel.printf
12 let print_s = Out_channel.print_s
13 let print_string = Out_channel.print_string
14 let print_endline = Out_channel.print_endline
15 let prerr_endline = Out_channel.prerr_endline
0 {1 Stdio: Standard IO Library for OCaml}
1
2 Stdio provides input/output functions for OCaml. It re-exports the
3 buffered channels of the stdlib distributed with OCaml but with some
4 improvements.
5
6 The full API is browsable {{!Stdio}{b here}}.
0 open! Base
1 open! Import
2
3 module In_channel = In_channel
4 module Out_channel = Out_channel
5
6 (** Same as {!In_channel.stdin} *)
7 val stdin : In_channel.t
8
9 (** Same as {!Out_channel.stdout} *)
10 val stdout : Out_channel.t
11
12 (** Same as {!Out_channel.stderr} *)
13 val stderr : Out_channel.t
14
15 (** Same as {!Out_channel.printf} *)
16 val printf : ('a, Out_channel.t, unit) format -> 'a
17
18 (** Same as {!Out_channel.print_s} *)
19 val print_s : ?mach : unit -> Sexp.t -> unit
20
21 (** Same as {!Out_channel.eprintf} *)
22 val eprintf : ('a, Out_channel.t, unit) format -> 'a
23
24 (** Same as {!Out_channel.print_string} *)
25 val print_string : string -> unit
26
27 (** Same as {!Out_channel.print_endline} *)
28 val print_endline : string -> unit
29
30 (** Same as {!Out_channel.prerr_endline} *)
31 val prerr_endline : string -> unit
0 opam-version: "2.0"
1 version: "v0.12.0"
2 maintainer: "opensource@janestreet.com"
3 authors: ["Jane Street Group, LLC <opensource@janestreet.com>"]
4 homepage: "https://github.com/janestreet/stdio"
5 bug-reports: "https://github.com/janestreet/stdio/issues"
6 dev-repo: "git+https://github.com/janestreet/stdio.git"
7 doc: "https://ocaml.janestreet.com/ocaml-core/latest/doc/stdio/index.html"
8 license: "MIT"
9 build: [
10 ["dune" "build" "-p" name "-j" jobs]
11 ]
12 depends: [
13 "ocaml" {>= "4.04.2"}
14 "base" {>= "v0.12" & < "v0.13"}
15 "dune" {build & >= "1.5.1"}
16 ]
17 synopsis: "Standard IO library for OCaml"
18 description: "
19 Stdio implements simple input/output functionalities for OCaml.
20
21 It re-exports the input/output functions of the OCaml standard
22 libraries using a more consistent API.
23 "