(*
 * BatFilename - Extended Filename module
 * Copyright (C) 1996 Xavier Leroy
 *               2008 David Teller
 *
 * 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
 *)

(** Operations on file names. *)

val current_dir_name : string
(** The conventional name for the current directory (e.g. [.] in Unix). *)

val parent_dir_name : string
(** The conventional name for the parent of the current directory
   (e.g. [..] in Unix). *)

val dir_sep : string
(** The directory separator (e.g. [/] in Unix).
   @since 2.11.0 and OCaml 3.11.2 *)

val concat : string -> string -> string
(** [concat dir file] returns a file name that designates file
   [file] in directory [dir]. *)

val is_relative : string -> bool
(** Return [true] if the file name is relative to the current
   directory, [false] if it is absolute (i.e. in Unix, starts
   with [/]). *)

val is_implicit : string -> bool
(** Return [true] if the file name is relative and does not start
   with an explicit reference to the current directory ([./] or
   [../] in Unix), [false] if it starts with an explicit reference
   to the root directory or the current directory. *)

val check_suffix : string -> string -> bool
(** [check_suffix name suff] returns [true] if the filename [name]
    ends with the suffix [suff].

    Under Windows ports (including Cygwin), comparison is
    case-insensitive, relying on [String.lowercase_ascii].  Note that
    this does not match exactly the interpretation of case-insensitive
    filename equivalence from Windows.  *)

val chop_suffix : string -> string -> string
(** [chop_suffix name suff] removes the suffix [suff] from
   the filename [name]. The behavior is undefined if [name] does not
   end with the suffix [suff]. [chop_suffix_opt] is thus recommended
   instead.
*)

##V>=4.8##val chop_suffix_opt: suffix:string -> string -> string option
##V>=4.8##(** [chop_suffix_opt ~suffix filename] removes the suffix from
##V>=4.8##    the [filename] if possible, or returns [None] if the
##V>=4.8##    filename does not end with the suffix.
##V>=4.8##
##V>=4.8##    Under Windows ports (including Cygwin), comparison is
##V>=4.8##    case-insensitive, relying on [String.lowercase_ascii].  Note that
##V>=4.8##    this does not match exactly the interpretation of case-insensitive
##V>=4.8##    filename equivalence from Windows.
##V>=4.8##
##V>=4.8##    @since 2.11.0 and OCaml 4.08
##V>=4.8##*)


##V>=4.4##val extension : string -> string
##V>=4.4##(** [extension name] is the shortest suffix [ext] of [name0] where:
##V>=4.4##
##V>=4.4##    - [name0] is the longest suffix of [name] that does not
##V>=4.4##      contain a directory separator;
##V>=4.4##    - [ext] starts with a period;
##V>=4.4##    - [ext] is preceded by at least one non-period character
##V>=4.4##      in [name0].
##V>=4.4##
##V>=4.4##    If such a suffix does not exist, [extension name] is the empty
##V>=4.4##    string.
##V>=4.4##
##V>=4.4##    @since 2.11.0 and OCaml 4.04
##V>=4.4##*)

##V>=4.4##val remove_extension : string -> string
##V>=4.4##(** Return the given file name without its extension, as defined
##V>=4.4##    in {!Filename.extension}. If the extension is empty, the function
##V>=4.4##    returns the given file name.
##V>=4.4##
##V>=4.4##    The following invariant holds for any file name [s]:
##V>=4.4##
##V>=4.4##    [remove_extension s ^ extension s = s]
##V>=4.4##
##V>=4.4##    @since 2.11.0 and OCaml 4.04
##V>=4.4##*)

val chop_extension : string -> string
(** Same as {!Filename.remove_extension}, but raise [Invalid_argument]
    if the given name has an empty extension. *)


val basename : string -> string
(** Split a file name into directory name / base file name.
   If [name] is a valid file name, then [concat (dirname name) (basename name)]
   returns a file name which is equivalent to [name]. Moreover,
   after setting the current directory to [dirname name] (with {!Sys.chdir}),
   references to [basename name] (which is a relative file name)
   designate the same file as [name] before the call to {!Sys.chdir}.

   This function conforms to the specification of POSIX.1-2008 for the
   [basename] utility. *)

val dirname : string -> string
(** See {!Filename.basename}.
   This function conforms to the specification of POSIX.1-2008 for the
   [dirname] utility. *)

##V>=4.10##val null : string
##V>=4.10##(** [null] is ["/dev/null"] on POSIX and ["NUL"] on Windows. It represents a
##V>=4.10##    file on the OS that discards all writes and returns end of file on reads.
##V>=4.10##
##V>=4.10##    @since 2.12.0 and OCaml 4.10
##V>=4.10##*)

val temp_file : ?temp_dir: string -> string -> string -> string
(** [temp_file prefix suffix] returns the name of a
   fresh temporary file in the temporary directory.
   The base name of the temporary file is formed by concatenating
   [prefix], then a suitably chosen integer number, then [suffix].
   The optional argument [temp_dir] indicates the temporary directory
   to use, defaulting to the current result of {!Filename.get_temp_dir_name}.
   The temporary file is created empty, with permissions [0o600]
   (readable and writable only by the file owner).  The file is
   guaranteed to be different from any other file that existed when
   [temp_file] was called.
   Raise [Sys_error] if the file could not be created.
   @before 3.11.2 no ?temp_dir optional argument
*)

val with_temp_file : ?temp_dir: string -> string -> string -> (string -> 'a) -> 'a
(** [with_temp_file prfx sfx f] will execute [f tmp_fn] where
    [tmp_fn = temp_file prfx sfx];
    [tmp_fn] will be removed prior to returning the result of [f].
    I.e. run a function using a named temporary file, without forgetting
    to remove that file. *)

val open_temp_file :
          ?mode: open_flag list ->
##V>4.2## ?perms: int ->
          ?temp_dir: string -> string ->
          string -> string * out_channel
(** Same as {!Filename.temp_file}, but returns both the name of a fresh
   temporary file, and an output channel opened (atomically) on
   this file.  This function is more secure than [temp_file]: there
   is no risk that the temporary file will be modified (e.g. replaced
   by a symbolic link) before the program opens it.  The optional argument
   [mode] is a list of additional flags to control the opening of the file.
   It can contain one or several of [Open_append], [Open_binary],
   and [Open_text].  The default is [[Open_text]] (open in text mode).
##V>4.2## The file is created with permissions [perms] (defaults to readable and
##V>4.2## writable only by the file owner, [0o600]).

   @raise Sys_error if the file could not be opened.
*)

##V>=4.0##val get_temp_dir_name : unit -> string
##V>=4.0##(** The name of the temporary directory:
##V>=4.0##    Under Unix, the value of the [TMPDIR] environment variable, or "/tmp"
##V>=4.0##    if the variable is not set.
##V>=4.0##    Under Windows, the value of the [TEMP] environment variable, or "."
##V>=4.0##    if the variable is not set.
##V>=4.0##    The temporary directory can be changed with {!Filename.set_temp_dir_name}.
##V>=4.0##    @since 2.11.0 and OCaml 4.00.0
##V>=4.0##*)

##V>=4.0##val set_temp_dir_name : string -> unit
##V>=4.0##(** Change the temporary directory returned by {!Filename.get_temp_dir_name}
##V>=4.0##    and used by {!Filename.temp_file} and {!Filename.open_temp_file}.
##V>=4.0##    @since 2.11.0 and OCaml 4.00.0
##V>=4.0##*)

##V<5##val temp_dir_name : string
##V<5####V>=4.2##  [@@ocaml.deprecated "Use Filename.get_temp_dir_name instead"]
##V<5##(** The name of the initial temporary directory:
##V<5##    Under Unix, the value of the [TMPDIR] environment variable, or "/tmp"
##V<5##    if the variable is not set.
##V<5##    Under Windows, the value of the [TEMP] environment variable, or "."
##V<5##    if the variable is not set.
##V<5##    @deprecated You should use {!Filename.get_temp_dir_name} instead.
##V<5##    @since 2.11.0 and OCaml 3.09.1
##V<5##*)

val quote : string -> string
(** Return a quoted version of a file name, suitable for use as
    one argument in a command line, escaping all meta-characters.
    Warning: under Windows, the output is only suitable for use
    with programs that follow the standard Windows quoting
    conventions.
 *)

##V>=4.10##val quote_command :
##V>=4.10##       string -> ?stdin:string -> ?stdout:string -> ?stderr:string
##V>=4.10##              -> string list -> string
##V>=4.10##(** [quote_command cmd args] returns a quoted command line, suitable
##V>=4.10##    for use as an argument to {!Sys.command}, {!Unix.system}, and the
##V>=4.10##    {!Unix.open_process} functions.
##V>=4.10##
##V>=4.10##    The string [cmd] is the command to call.  The list [args] is
##V>=4.10##    the list of arguments to pass to this command.  It can be empty.
##V>=4.10##
##V>=4.10##    The optional arguments [?stdin] and [?stdout] and [?stderr] are
##V>=4.10##    file names used to redirect the standard input, the standard
##V>=4.10##    output, or the standard error of the command.
##V>=4.10##    If [~stdin:f] is given, a redirection [< f] is performed and the
##V>=4.10##    standard input of the command reads from file [f].
##V>=4.10##    If [~stdout:f] is given, a redirection [> f] is performed and the
##V>=4.10##    standard output of the command is written to file [f].
##V>=4.10##    If [~stderr:f] is given, a redirection [2> f] is performed and the
##V>=4.10##    standard error of the command is written to file [f].
##V>=4.10##    If both [~stdout:f] and [~stderr:f] are given, with the exact
##V>=4.10##    same file name [f], a [2>&1] redirection is performed so that the
##V>=4.10##    standard output and the standard error of the command are interleaved
##V>=4.10##    and redirected to the same file [f].
##V>=4.10##
##V>=4.10##    Under Unix and Cygwin, the command, the arguments, and the redirections
##V>=4.10##    if any are quoted using {!Filename.quote}, then concatenated.
##V>=4.10##    Under Win32, additional quoting is performed as required by the
##V>=4.10##    [cmd.exe] shell that is called by {!Sys.command}.
##V>=4.10##
##V>=4.10##    Raise [Failure] if the command cannot be escaped on the current platform.
##V>=4.10##
##V>=4.10##    @since 2.12.0 and OCaml 4.10
##V>=4.10##*)

##V<4.4## val extension : string -> string
##V<4.4##(* extension name is the shortest suffix ext of name0 where:
##V<4.4##
##V<4.4## - name0 is the longest suffix of name that does not contain a directory separator;
##V<4.4## - ext starts with a period;
##V<4.4## - ext is preceded by at least one non-period character in name0.
##V<4.4## If such a suffix does not exist, extension name is the empty string.
##V<4.4##
##V<4.4##   @since 2.11.0 *)

##V<4.4## val remove_extension : string -> string
##V<4.4##(* Return the given file name without its extension, as defined in
##V<4.4##   Filename.extension. If the extension is empty, the function returns
##V<4.4##   the given file name.
##V<4.4##
##V<4.4##   @since 2.11.0 *)

val split_extension : string -> string * string
(** [split_extension s] returns both the filename [s] without its extension
    and its extension in two distinct strings.
    For instance, [split_extension "foo.bar"] returns the pair ["foo",".bar"].

    @since 2.11.0 *)
