Merge pull request #625 from triska/os

ADDED: library(os), reasoning about environment variables.
This commit is contained in:
Mark Thom
2020-07-11 23:50:01 -03:00
committed by GitHub
6 changed files with 100 additions and 7 deletions

View File

@@ -442,6 +442,8 @@ The modules that ship with Scryer Prolog are also called
Predicates for opening and accepting TCP connections as streams. Predicates for opening and accepting TCP connections as streams.
TLS negotiation is performed via the option `tls(true)` in TLS negotiation is performed via the option `tls(true)` in
`socket_client_open/3`, yielding secure encrypted connections. `socket_client_open/3`, yielding secure encrypted connections.
* [`os`](src/lib/os.pl)
Predicates for reasoning about environment variables.
* [`crypto`](src/lib/crypto.pl) * [`crypto`](src/lib/crypto.pl)
Cryptographically secure random numbers and hashes, HMAC-based Cryptographically secure random numbers and hashes, HMAC-based
key derivation (HKDF), password-based key derivation (PBKDF2), key derivation (HKDF), password-based key derivation (PBKDF2),

View File

@@ -306,6 +306,9 @@ pub enum SystemClauseType {
Ed25519KeyPairPublicKey, Ed25519KeyPairPublicKey,
LoadHTML, LoadHTML,
LoadXML, LoadXML,
GetEnv,
SetEnv,
UnsetEnv,
} }
impl SystemClauseType { impl SystemClauseType {
@@ -510,6 +513,9 @@ impl SystemClauseType {
&SystemClauseType::Ed25519KeyPairPublicKey => clause_name!("$ed25519_keypair_public_key"), &SystemClauseType::Ed25519KeyPairPublicKey => clause_name!("$ed25519_keypair_public_key"),
&SystemClauseType::LoadHTML => clause_name!("$load_html"), &SystemClauseType::LoadHTML => clause_name!("$load_html"),
&SystemClauseType::LoadXML => clause_name!("$load_xml"), &SystemClauseType::LoadXML => clause_name!("$load_xml"),
&SystemClauseType::GetEnv => clause_name!("$getenv"),
&SystemClauseType::SetEnv => clause_name!("$setenv"),
&SystemClauseType::UnsetEnv => clause_name!("$unsetenv"),
} }
} }
@@ -694,6 +700,9 @@ impl SystemClauseType {
("$ed25519_keypair_public_key", 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey), ("$ed25519_keypair_public_key", 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey),
("$load_html", 3) => Some(SystemClauseType::LoadHTML), ("$load_html", 3) => Some(SystemClauseType::LoadHTML),
("$load_xml", 3) => Some(SystemClauseType::LoadXML), ("$load_xml", 3) => Some(SystemClauseType::LoadXML),
("$getenv", 2) => Some(SystemClauseType::GetEnv),
("$setenv", 2) => Some(SystemClauseType::SetEnv),
("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv),
_ => None, _ => None,
} }
} }

View File

@@ -44,6 +44,7 @@ must_be_(var, Term) :-
). ).
must_be_(integer, Term) :- check_(integer, integer, Term). must_be_(integer, Term) :- check_(integer, integer, Term).
must_be_(atom, Term) :- check_(atom, atom, Term). must_be_(atom, Term) :- check_(atom, atom, Term).
must_be_(character, T) :- check_(character, character, T).
must_be_(list, Term) :- check_(ilist, list, Term). must_be_(list, Term) :- check_(ilist, list, Term).
must_be_(type, Term) :- check_(type, type, Term). must_be_(type, Term) :- check_(type, type, Term).
must_be_(boolean, Term) :- check_(boolean, boolean, Term). must_be_(boolean, Term) :- check_(boolean, boolean, Term).
@@ -56,6 +57,10 @@ check_(Pred, Type, Term) :-
boolean(B) :- ( B == true ; B == false ). boolean(B) :- ( B == true ; B == false ).
character(C) :-
atom(C),
atom_length(C, 1).
ilist(V) :- var(V), instantiation_error(must_be/2). ilist(V) :- var(V), instantiation_error(must_be/2).
ilist([]). ilist([]).
ilist([_|Ls]) :- ilist(Ls). ilist([_|Ls]) :- ilist(Ls).
@@ -63,6 +68,7 @@ ilist([_|Ls]) :- ilist(Ls).
type(type). type(type).
type(integer). type(integer).
type(atom). type(atom).
type(character).
type(list). type(list).
type(var). type(var).
type(boolean). type(boolean).
@@ -90,6 +96,7 @@ can_be(Type, Term) :-
can_(integer, Term) :- integer(Term). can_(integer, Term) :- integer(Term).
can_(atom, Term) :- atom(Term). can_(atom, Term) :- atom(Term).
can_(character, T) :- character(T).
can_(list, Term) :- list_or_partial_list(Term). can_(list, Term) :- list_or_partial_list(Term).
can_(boolean, Term) :- boolean(Term). can_(boolean, Term) :- boolean(Term).

View File

@@ -57,13 +57,7 @@
list_of_chars(Cs) :- list_of_chars(Cs) :-
must_be(list, Cs), must_be(list, Cs),
( ground(Cs) -> maplist(must_be(character), Cs).
( member(C, Cs), \+ atom_length(C, 1) ->
type_error(char, C, files_and_directories)
; true
)
; instantiation_error(s)
).
directory_files(Directory, Files) :- directory_files(Directory, Files) :-
list_of_chars(Directory), list_of_chars(Directory),

58
src/lib/os.pl Normal file
View File

@@ -0,0 +1,58 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Predicates for reasoning about the operating system (OS) environment.
Written July 2020 by Markus Triska (triska@metalevel.at).
Lists of characters are used throughout to represent keys and values.
Example:
?- getenv("LANG", Ls).
Ls = "en_US.UTF-8"
; false.
Public domain code.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(os, [getenv/2,
setenv/2,
unsetenv/1]).
:- use_module(library(error)).
:- use_module(library(charsio)).
:- use_module(library(lists)).
getenv(Key, Value) :-
must_be_env_var(Key),
'$getenv'(Key, Value).
setenv(Key, Value) :-
must_be_env_var(Key),
must_be_chars(Value),
'$setenv'(Key, Value).
unsetenv(Key) :-
must_be_env_var(Key),
'$unsetenv'(Key).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
For now, we only support a restricted subset of variable names.
The reason is that Rust may panic if a key is empty, contains an
ASCII equals sign '=' or the NUL character '\0', or when the value
contains the NUL character.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
must_be_env_var(Cs) :-
must_be_chars(Cs),
Cs = [_|_],
( maplist(permitted, Cs) -> true
; domain_error(env_var, Cs, os)
).
permitted(C) :- char_type(C, alnum).
permitted(C) :- char_type(C, ascii_punctuation).
permitted('_').
must_be_chars(Cs) :-
must_be(list, Cs),
maplist(must_be(character), Cs).

View File

@@ -32,6 +32,7 @@ use std::net::{TcpListener, TcpStream};
use std::ops::Sub; use std::ops::Sub;
use std::rc::Rc; use std::rc::Rc;
use std::num::NonZeroU32; use std::num::NonZeroU32;
use std::env;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use crate::cpu_time::ProcessTime; use crate::cpu_time::ProcessTime;
@@ -5637,6 +5638,28 @@ impl MachineState {
} }
} }
} }
&SystemClauseType::GetEnv => {
let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
match env::var(key) {
Ok(value) => {
let cstr = self.heap.put_complete_string(&value);
self.unify(self[temp_v!(2)], cstr);
}
_ => {
self.fail = true;
return Ok(());
}
}
}
&SystemClauseType::SetEnv => {
let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
let value = self.heap_pstr_iter(self[temp_v!(2)]).to_string();
env::set_var(key, value);
}
&SystemClauseType::UnsetEnv => {
let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
env::remove_var(key);
}
}; };
return_from_clause!(self.last_call, self) return_from_clause!(self.last_call, self)