(*
 * BatSys - additional and modified functions for System
 * Copyright (C) 1996 Xavier Leroy
 * Copyright (C) 2009 David Teller, LIFO, Universite d'Orleans
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version,
 * with the special exception on linking described in file LICENSE.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *)

(** System interface.

    This module defines higher-level functions than the {!Unix} module
    and should, wherever possible, be used rather than the {!Unix} module
    to ensure portability.

    @author Xavier Leroy (Base module)
    @author David Teller
*)

##V>=4.09##external argv : string array = "%sys_argv"
##V<4.09##val argv : string array
(** The command line arguments given to the process.
    The first element is the command name used to invoke the program.
    The following elements are the command-line arguments
    given to the program. *)

val executable_name : string
(** The name of the file containing the executable currently running. *)

external file_exists : string -> bool = "caml_sys_file_exists"
(** Test if a file with the given name exists. *)

external is_directory : string -> bool = "caml_sys_is_directory"
(** Returns [true] if the given name refers to a directory,
    [false] if it refers to another kind of file.
    @raise Sys_error if no file exists with the given name.
    @since 3.10.0
*)

external remove : string -> unit = "caml_sys_remove"
(** Remove the given file name from the file system. *)

external rename : string -> string -> unit = "caml_sys_rename"
(** Rename a file. The first argument is the old name and the
    second is the new name. If there is already another file
    under the new name, [rename] may replace it, or raise an
    exception, depending on your operating system. *)

external getenv : string -> string = "caml_sys_getenv"
(** Return the value associated to a variable in the process
    environment. @raise Not_found if the variable is unbound. *)

val getenv_opt: string -> string option
(** Return the value associated to a variable in the process
    environment or [None] if the variable is unbound.
    @since 4.05
*)

external command : string -> int = "caml_sys_system_command"
(** Execute the given shell command and return its exit code. *)

##V<4.3##external time : unit -> float = "caml_sys_time"
##V>=4.3##external time : unit -> (float [@unboxed]) =
##V>=4.3##  "caml_sys_time" "caml_sys_time_unboxed" [@@noalloc]
(** Return the processor time, in seconds, used by the program
    since the beginning of execution. *)

external chdir : string -> unit = "caml_sys_chdir"
(** Change the current working directory of the process. *)

external getcwd : unit -> string = "caml_sys_getcwd"
(** Return the current working directory of the process. *)

external readdir : string -> string array = "caml_sys_read_directory"
(** Return the names of all files present in the given directory.
    Names denoting the current directory and the parent directory
    (["."] and [".."] in Unix) are not returned.  Each string in the
    result is a file name rather than a complete path.  There is no
    guarantee that the name strings in the resulting array will appear
    in any specific order; they are not, in particular, guaranteed to
    appear in alphabetical order. *)

val interactive : bool ref
(** This reference is initially set to [false] in standalone
    programs and to [true] if the code is being executed under
    the interactive toplevel system [ocaml]. *)

val os_type : string
(** Operating system currently executing the OCaml program. One of
    -  ["Unix"] (for all Unix versions, including Linux and Mac OS X),
    -  ["Win32"] (for MS-Windows, OCaml compiled with MSVC++ or Mingw),
    -  ["Cygwin"] (for MS-Windows, OCaml compiled with Cygwin). *)

##V>=4.4##type backend_type = Sys.backend_type =
##V>=4.4##  | Native
##V>=4.4##  | Bytecode
##V>=4.4##  | Other of string (**)
##V>=4.4##(** Currently, the official distribution only supports [Native] and
##V>=4.4##    [Bytecode], but it can be other backends with alternative
##V>=4.4##    compilers, for example, javascript.
##V>=4.4##
##V>=4.4##    @since 2.5.3 and 4.04 *)
##V>=4.4##
##V>=4.4##val backend_type : backend_type
##V>=4.4##(** Backend type currently executing the OCaml program.
##V>=4.4##    @ since 2.5.3 and 4.04
##V>=4.4## *)

##V>=4.1##val unix : bool
##V>=4.1##(** True if [Sys.os_type = "Unix"].
##V>=4.1##    @since 4.01.0 *)
##V>=4.1##
##V>=4.1##val win32 : bool
##V>=4.1##(** True if [Sys.os_type = "Win32"].
##V>=4.1##    @since 4.01.0 *)
##V>=4.1##
##V>=4.1##val cygwin : bool
##V>=4.1##(** True if [Sys.os_type = "Cygwin"].
##V>=4.1##    @since 4.01.0 *)

val word_size : int
(** Size of one word on the machine currently executing the OCaml
    program, in bits: 32 or 64. *)

##V>=4.3##val int_size : int
##V>=4.3##(** Size of an int.  It is 31 bits (resp. 63 bits) when using the
##V>=4.3##    OCaml compiler on a 32 bits (resp. 64 bits) platform.  It may
##V>=4.3##    differ for other compilers, e.g. it is 32 bits when compiling to
##V>=4.3##    JavaScript.
##V>=4.3##    @since 2.5.0 and OCaml 4.03.0 *)

val big_endian : bool
(** Whether the machine currently executing the OCaml program is big-endian.
    @since 4.00.0 *)

val max_string_length : int
(** Maximum length of a string. *)

val max_array_length : int
(** Maximum length of a normal array.  The maximum length of a float
    array is [max_array_length/2] on 32-bit machines and
    [max_array_length] on 64-bit machines. *)

##V>=4.08##val max_floatarray_length : int
##V>=4.08##(** Maximum length of a floatarray. This is also the maximum length of
##V>=4.08##    a [float array] when OCaml is configured with
##V>=4.08##    [--enable-flat-float-array]. *)

##V>=4.3##external runtime_variant : unit -> string = "caml_runtime_variant"
##V>=4.3##(** Return the name of the runtime variant the program is running on.
##V>=4.3##    This is normally the argument given to [-runtime-variant] at compile
##V>=4.3##    time, but for byte-code it can be changed after compilation.
##V>=4.3##    @since 2.5.0 and OCaml 4.03.0 *)

##V>=4.3##external runtime_parameters : unit -> string = "caml_runtime_parameters"
##V>=4.3##(** Return the value of the runtime parameters, in the same format
##V>=4.3##    as the contents of the [OCAMLRUNPARAM] environment variable.
##V>=4.3##    @since 2.5.0 and OCaml 4.03.0 *)

##V>=5.1##external is_regular_file : string -> bool = "caml_sys_is_regular_file"

(** {6 Signal handling} *)


type signal_behavior = Sys.signal_behavior =
    Signal_default
  | Signal_ignore
  | Signal_handle of (int -> unit)
  (** What to do when receiving a signal:
      - [Signal_default]: take the default behavior
       (usually: abort the program)
      - [Signal_ignore]: ignore the signal
      - [Signal_handle f]: call function [f], giving it the signal
      number as argument. *)

external signal :
  int -> signal_behavior -> signal_behavior = "caml_install_signal_handler"
(** Set the behavior of the system on receipt of a given signal.  The
    first argument is the signal number.  Return the behavior
    previously associated with the signal.
    @raise Invalid_argument If the signal number is
    invalid (or not available on your system). *)

val set_signal : int -> signal_behavior -> unit
(** Same as {!Sys.signal} but return value is ignored. *)


(** {7 Signal numbers for the standard POSIX signals.} *)

val sigabrt : int
(** Abnormal termination *)

val sigalrm : int
(** Timeout *)

val sigfpe : int
(** Arithmetic exception *)

val sighup : int
(** Hangup on controlling terminal *)

val sigill : int
(** Invalid hardware instruction *)

val sigint : int
(** Interactive interrupt (ctrl-C) *)

val sigkill : int
(** Termination (cannot be ignored) *)

val sigpipe : int
(** Broken pipe *)

val sigquit : int
(** Interactive termination *)

val sigsegv : int
(** Invalid memory reference *)

val sigterm : int
(** Termination *)

val sigusr1 : int
(** Application-defined signal 1 *)

val sigusr2 : int
(** Application-defined signal 2 *)

val sigchld : int
(** Child process terminated *)

val sigcont : int
(** Continue *)

val sigstop : int
(** Stop *)

val sigtstp : int
(** Interactive stop *)

val sigttin : int
(** Terminal read from background process *)

val sigttou : int
(** Terminal write from background process *)

val sigvtalrm : int
(** Timeout in virtual time *)

val sigprof : int
(** Profiling interrupt *)

val sigbus : int
(** Bus error
    @since 2.5.0 *)

val sigpoll : int
(** Pollable event
    @since 2.5.0 *)

val sigsys : int
(** Bad argument to routine
    @since 2.5.0 *)

val sigtrap : int
(** Trace/breakpoint trap
    @since 2.5.0 *)

val sigurg : int
(** Urgent condition on socket
    @since 2.5.0 *)

val sigxcpu : int
(** Timeout in cpu time
    @since 2.5.0 *)

val sigxfsz : int
(** File size limit exceeded
    @since 2.5.0 *)


exception Break
(** Exception raised on interactive interrupt if {!Sys.catch_break}
    is on. *)


val catch_break : bool -> unit
(** [catch_break] governs whether interactive interrupt (ctrl-C)
    terminates the program or raises [Break].
    Call [catch_break true] to enable raising [Break],
    and [catch_break false] to let the system
    terminate the program on user interrupt. *)


val ocaml_version : string
(** [ocaml_version] is the version of OCaml.
    It is a string of the form ["major.minor[.patchlevel][+additional-info]"],
    where [major], [minor], and [patchlevel] are integers, and
    [additional-info] is an arbitrary string. The [[.patchlevel]] and
    [[+additional-info]] parts may be absent. *)

##V>=4.14##val development_version : bool
##V>=4.14##(** [true] if this is a development version, [false] otherwise.
##V>=4.14##    @since 4.14.0
##V>=4.14##*)

##V>=4.14##type extra_prefix = Sys.extra_prefix = Plus | Tilde
##V>=4.14##type extra_info = Sys.extra_info
##V>=4.14##type ocaml_release_info = Sys.ocaml_release_info = {
##V>=4.14##    major : int;
##V>=4.14##    minor : int;
##V>=4.14##    patchlevel : int;
##V>=4.14##    extra : extra_info option
##V>=4.14##}

##V>=4.14##val ocaml_release : ocaml_release_info

val files_of: string -> string BatEnum.t
    (**As {!readdir} but the results are presented as an enumeration
       of names.*)

##V>=4.3##val enable_runtime_warnings: bool -> unit
##V>=4.3##(** Control whether the OCaml runtime system can emit warnings
##V>=4.3##    on stderr.  Currently, the only supported warning is triggered
##V>=4.3##    when a channel created by [open_*] functions is finalized without
##V>=4.3##    being closed.  Runtime warnings are enabled by default.
##V>=4.3##    @since 2.5.0 and OCaml 4.03 *)

##V>=4.3##val runtime_warnings_enabled: unit -> bool
##V>=4.3##(** Return whether runtime warnings are currently enabled.
##V>=4.3##    @since 2.5.0 and OCaml 4.03 *)

(** {6 Optimization} *)

##V>=4.3##external opaque_identity : 'a -> 'a = "%opaque"
##V=4.2##val opaque_identity : 'a -> 'a
(** For the purposes of optimization, [opaque_identity] behaves like an
    unknown (and thus possibly side-effecting) function.

    At runtime, [opaque_identity] disappears altogether.

    A typical use of this function is to prevent pure computations from being
    optimized away in benchmarking loops.  For example:
    {[
      for _round = 1 to 100_000 do
        ignore (Sys.opaque_identity (my_pure_computation ()))
      done
    ]}

    The compiler primitive was added to OCaml 4.03, but we emulate it
    under 4.02 using the -opaque compilation flag. There is no easy
    way for Batteries to emulate it correctly under older OCaml
    versions.

    @since 2.5.0 and OCaml 4.02
 *)

##V>=4.10##module Immediate64 = Sys.Immediate64

##V>=4.12##external mkdir : string -> int -> unit = "caml_sys_mkdir"
##V>=4.12##(** Create a directory with the given permissions.
##V>=4.12##
##V>=4.12##    @since 3.3.0 and 4.12.0
##V>=4.12##*)
##V>=4.12##
##V>=4.12##external rmdir : string -> unit = "caml_sys_rmdir"
##V>=4.12##(** Remove an empty directory.
##V>=4.12##
##V>=4.12##    @since 3.3.0 and 4.12.0
##V>=4.12##*)
