[m-users.] How to get the environment

Volker Wysk post at volker-wysk.de
Mon Mar 25 04:06:51 AEDT 2019


Am Sonntag, 24. März 2019, 11:56:15 CET schrieb Volker Wysk:
> Am Sonntag, 24. März 2019, 02:34:36 CET schrieb Peter Wang:
> > On Fri, 22 Mar 2019 12:50:18 +0100, Volker Wysk <post at volker-wysk.de> 
wrote:
> > > Hi
> > > 
> > > There is io.get_environment_var/4, but this gets just one environment
> > > variable. For the posix.exec/5 predicate, the entire environment is
> > > needed, as a map(string,string). There are no foreign predicates for the
> > > other variants of exec (such as execv), which don't require the
> > > environment.
> > > 
> > > I've searched in the io and posix libraries, but couldn't find any way
> > > to
> > > query the entire environment. Could it be that there isn't any...?
> > 
> > Hi,
> > 
> > There isn't any yet, possibly because POSIX does not define any way to
> > do so. The foreign proc would need to read from the non-POSIX `environ'
> > global variable or _NSGetEnviron() on MacOS.
> 
> I could add support for the "exec" variants "execv" and "execvp", which use
> the existing environment, and don't take a new environment as an argument.
> This would be the first time I do something like this in Mercury, but it
> should not be difficult, since "execv" is already implemented.

I'v added "execv", "execvp" and "execvpe" to posix.exec. It works fine. See 
the attachment. It replaces the posix.exec.m file of the posix library.

Bye
Volker
-------------- next part --------------
:- module exec.
:- interface.

:- import_module list.
:- import_module map.
:- import_module string.
:- import_module io.

%-----------------------------------------------------------------------------%

:- type argv == list(string).

:- type env == map(string, string).

:- pred execve( string::in, argv::in, env::in, posix.result::out, io::di, io::uo) is det.
:- pred execvpe(string::in, argv::in, env::in, posix.result::out, io::di, io::uo) is det.
:- pred execvp( string::in, argv::in,          posix.result::out, io::di, io::uo) is det.
:- pred execv(  string::in, argv::in,          posix.result::out, io::di, io::uo) is det.
:- pred exec(   string::in, argv::in, env::in, posix.result::out, io::di, io::uo) is det.


%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%

:- implementation.

:- import_module array.
:- import_module pair.

% The execvpe function is declared in <unistd.h> only when __USE_GNU is defined.
% However, this does not work: 
%:- pragma foreign_decl("C", "#define __USE_GNU").
:- pragma foreign_decl("C", "#include <unistd.h>").

% Instead, the execvpe funtion is declared here:

:- pragma foreign_decl("C", "extern int execvpe(const char *__file, char *const __argv[], char *const __envp[]);").


%-----------------------------------------------------------------------------%
%
% Shared bits
% 


:- func variable(pair(string)) = string.

variable(Name - Value) = Name ++ "=" ++ Value.

:- func null = string.
:- pragma foreign_proc("C",
    null = (Null::out),
    [promise_pure, will_not_call_mercury, thread_safe],
"
    Null = NULL;
").



%-----------------------------------------------------------------------------%
%
% The execve command
%


% Synonym for execve, for backwards compatibility

exec(Command, Args, Env, Result, !IO) :-
    execve(Command, Args, Env, Result, !IO).


%
% int execve(const char *filename, char *const argv[], char *const envp[]);
%

execve(Command, Args, Env, Result, !IO) :-
    execve0(Command,
        array(Args ++ [null]),
        array(list.map(variable, map.to_assoc_list(Env)) ++ [null]),
        !IO
    ),
    errno(Err, !IO),
    Result = error(Err).



:- pred execve0(string::in,
    array(string)::array_ui, array(string)::array_ui,
    io::di, io::uo) is det.
:- pragma foreign_proc("C",
    execve0(Command::in, Args::array_ui, Env::array_ui, IO0::di, IO::uo),
    [promise_pure, will_not_call_mercury, tabled_for_io],
"
    int ret;

    do {
        ret = execve(Command,
            (char * const *) ((MR_ArrayType *)Args)->elements, 
            (char * const *) ((MR_ArrayType *)Env)->elements);
    } while (ret == -1 && MR_is_eintr(errno));
    IO = IO0;
").


%-----------------------------------------------------------------------------%
%
% The execvp command
%

%
% int execvp(const char *file, char *const argv[]);
%

execvp(Command, Args, Result, !IO) :-
    execvp0(Command,
            array(Args ++ [null]),
            !IO),
    errno(Err, !IO),
    Result = error(Err).



:- pred execvp0(string::in,
                array(string)::array_ui, 
                io::di, io::uo) is det.
:- pragma foreign_proc("C",
    execvp0(Command::in, Args::array_ui, IO0::di, IO::uo),
    [promise_pure, will_not_call_mercury, tabled_for_io],
"
    int ret;

    do {
        ret = execvp(Command,
            (char * const *) ((MR_ArrayType *)Args)->elements);
    } while (ret == -1 && MR_is_eintr(errno));
    IO = IO0;
").



%-----------------------------------------------------------------------------%
%
% The execv command
%

%
% int execv(const char *file, char *const argv[]);
%

execv(Command, Args, Result, !IO) :-
    execv0(Command,
            array(Args ++ [null]),
            !IO),
    errno(Err, !IO),
    Result = error(Err).



:- pred execv0(string::in,
                array(string)::array_ui, 
                io::di, io::uo) is det.
:- pragma foreign_proc("C",
    execv0(Command::in, Args::array_ui, IO0::di, IO::uo),
    [promise_pure, will_not_call_mercury, tabled_for_io],
"
    int ret;

    do {
        ret = execv(Command,
            (char * const *) ((MR_ArrayType *)Args)->elements);
    } while (ret == -1 && MR_is_eintr(errno));
    IO = IO0;
").



%-----------------------------------------------------------------------------%
%
% The execvpe command
%

%
% int execvpe(const char *file, char *const argv[], char *const envp[]);
%

execvpe(Command, Args, Env, Result, !IO) :-
    execvpe0(Command,
        array(Args ++ [null]),
        array(list.map(variable, map.to_assoc_list(Env)) ++ [null]),
        !IO
    ),
    errno(Err, !IO),
    Result = error(Err).



:- pred execvpe0(string::in,
    array(string)::array_ui, array(string)::array_ui,
    io::di, io::uo) is det.
:- pragma foreign_proc("C",
    execvpe0(Command::in, Args::array_ui, Env::array_ui, IO0::di, IO::uo),
    [promise_pure, will_not_call_mercury, tabled_for_io],
"
    int ret;

    do {
        ret = execvpe(Command,
            (char * const *) ((MR_ArrayType *)Args)->elements, 
            (char * const *) ((MR_ArrayType *)Env)->elements);
    } while (ret == -1 && MR_is_eintr(errno));
    IO = IO0;
").


More information about the users mailing list