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