(********************************************************************)
(*                                                                  *)
(*  environment.s7i  Support for program arguments and environment. *)
(*  Copyright (C) 1989 - 2014, 2020, 2021  Thomas Mertes            *)
(*                                                                  *)
(*  This file is part of the Seed7 Runtime Library.                 *)
(*                                                                  *)
(*  The Seed7 Runtime 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.                                      *)
(*                                                                  *)
(*  The Seed7 Runtime 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 program; if not, write to the    *)
(*  Free Software Foundation, Inc., 51 Franklin Street,             *)
(*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
(*                                                                  *)
(********************************************************************)


(**
 *  Return the argument vector of the program as [[array]] of [[string]]s.
 *  The name of the program is not part of the argument vector.
 *  @return an array of strings containing the argument vector.
 *)
const func array string: argv (PROGRAM)                is action "PRC_ARGS";


(**
 *  Returns the name of the program without path and extension.
 *  The name returned by ''name(PROGRAM)'' is the same for interpreted
 *  and compiled programs. The function ''name(PROGRAM)'' does not follow
 *  symbolic links. It determines, with which name a program was called.
 *  If several symbolic links refer to one program ''name(PROGRAM)''
 *  returns the name of the symbolic link.
 *  @return the name of the program.
 *)
const func string: name (PROGRAM)                      is action "PRG_OWN_NAME";


(**
 *  Return the absolute path of the program.
 *  For an interpreted program this is the absolute path of the source file.
 *  For a compiled program this is the absolute path of the executable.
 *  The function path(PROGRAM) does follow symbolic links.
 *  @return the absolute path of the program.
 *)
const func string: path (PROGRAM)                      is action "PRG_OWN_PATH";


(**
 *  Returns the absolute path of the directory containing the program.
 *  The function dir(PROGRAM) allows placing configuration data in the
 *  directory of the program. The function is based on path(PROGRAM).
 *  @return The absolute path of the directory containing the program.
 *)
const func string: dir (PROGRAM) is func
  result
    var string: absolutePath is "";
  local
    var integer: slashPos is 0;
  begin
    absolutePath := path(PROGRAM);
    slashPos := rpos(absolutePath, '/');
    if slashPos = 1 then
      absolutePath := "/";
    elsif slashPos > 1 then
      absolutePath := absolutePath[.. pred(slashPos)];
    end if;
  end func;


(**
 *  Returns the filename of the program without path.
 *  The function is based on path(PROGRAM).
 *  @return The filename of the program.
 *)
const func string: file (PROGRAM) is func
  result
    var string: filename is "";
  local
    var integer: slashPos is 0;
  begin
    filename := path(PROGRAM);
    slashPos := rpos(filename, '/');
    if slashPos <> 0 then
      filename := filename[succ(slashPos) ..];
    end if;
  end func;


const func integer: sourceLine (PROGRAM)               is action "PRC_LINE";


(**
 *  Terminate the program with the given exit ''status''.
 *  By convention, the exit status 0 indicates normal termination.
 *  This function does not return. Placing exit(0); at the end of the
 *  ''main'' function is unnecessary since leaving ''main'' terminates
 *  the program with an exit status of 0.
 *)
const proc: exit (in integer: status)                  is action "PRC_EXIT";


(**
 *  Terminate the program with the exit status 0.
 *  By convention, the exit status 0 indicates normal termination.
 *  This function does not return. Placing exit(PROGRAM); at the end of the
 *  ''main'' function is unnecessary since leaving ''main'' terminates
 *  the program with an exit status of 0.
 *)
const proc: exit (PROGRAM) is func
  begin
    exit(0);
  end func;


(**
 *  Determine the value of an environment variable.
 *  The function getenv searches the environment for an environment variable
 *  with the given ''name''. If such an environment variable exists the
 *  corresponding [[string]] value is returned.
 *  @return the value of an environment variable or "",
 *          if the requested environment variable does not exist.
 *  @exception MEMORY_ERROR Not enough memory to convert ''name'' to the
 *             system string type or not enough memory to represent the
 *             result string.
 *  @exception RANGE_ERROR ''name'' cannot be converted to the system string
 *             type or a system function returns an error.
 *)
const func string: getenv (in string: name)            is action "CMD_GETENV";


(**
 *  Add or change an environment variable.
 *  The function setenv searches the environment for an environment variable
 *  with the given ''name''. If such an environment variable exists the
 *  corresponding value is changed to ''value''. If no environment variable
 *  with the given ''name'' exists a new environment variable ''name'' with
 *  the value ''value'' is created.
 *  @exception MEMORY_ERROR Not enough memory to convert ''name'' or ''value''
 *             to the system string type.
 *  @exception RANGE_ERROR ''name'' or ''value'' cannot be converted to the
 *             system string type or a system function returns an error.
 *)
const proc: setenv (in string: name, in string: value) is action "CMD_SETENV";


(**
 *  Deletes the variable ''name'' from the environment.
 *  If ''name'' does not exist in the environment,
 *  then the function succeeds, and the environment is unchanged.
 *  @exception MEMORY_ERROR Not enough memory to convert ''name'' to the
 *             system string type.
 *  @exception RANGE_ERROR ''name'' cannot be converted to the system string
 *             type or a system function returns an error.
 *)
const proc: unsetenv (in string: name)                 is action "CMD_UNSETENV";


(**
 *  Returns the list of environment variable names as [[array]] of [[string]]s.
 *  @return the list of environment variable names.
 *  @exception MEMORY_ERROR Not enough memory to create the result.
 *)
const func array string: environment                   is action "CMD_ENVIRONMENT";