From cad6074cdcffa789fa34b96fa38c416b23c4779f Mon Sep 17 00:00:00 2001 From: Javier Sagredo Date: Mon, 15 Jun 2026 23:43:40 +0200 Subject: [PATCH] Better visuals for documentation in library(tls), library(process) 1. Trailing whitespaces makes Doclog not render lists as lists. 2. TLS module documentation was only visible in Prolog source code. --- src/lib/process.pl | 44 ++++++------- src/lib/tls.pl | 152 +++++++++++++++++++++++---------------------- 2 files changed, 100 insertions(+), 96 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index 371006d8..f764180b 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -1,9 +1,9 @@ :- module(process, [ - process_create/3, + process_create/3, process_id/2, - process_release/1, - process_wait/2, - process_wait/3, + process_release/1, + process_wait/2, + process_wait/3, process_kill/1 ]). @@ -18,7 +18,7 @@ % Create a new process by executing the executable Exe and passing it the Arguments Args. % % Note: On windows please take note of [windows argument splitting](https://doc.rust-lang.org/std/process/index.html#windows-argument-splitting). -% +% % Options is a list consisting of the following options: % % * `cwd(+Path)` Set the processes working directory to `Path` @@ -31,11 +31,11 @@ % `env/1` and `environment/1` may not be both specified. % % The following stdio `Spec` are available: -% +% % * `std` inherit the current processes original stdio streams (does currently not account for stdio being changed by `set_input` or `set_output`) -% * `file(+Path)` attach the strea to the file at `Path` +% * `file(+Path)` attach the stream to the file at `Path` % * `null` discards writes and behaves as eof for read. Equivalent to using `file(/dev/null)` -% * `pipe(-Steam)` create a new pipe and assigne one end to the created process and the other end to `Stream` +% * `pipe(-Steam)` create a new pipe and assign one end to the created process and the other end to `Stream` % % Specifying an option multiple times is an error, when an option is not specified the following defaults apply: % @@ -104,7 +104,7 @@ process_wait(Process, Status) :- call_with_error_context(process_wait(Process, S % process_wait(Process, Status, Options) :- call_with_error_context(process_wait_(Process, Status, Options), predicate-process_wait/3). -process_wait_(Process, Status, Options) :- +process_wait_(Process, Status, Options) :- valid_process(Process), check_options( [ @@ -138,10 +138,10 @@ valid_bool(false). % On Unix this sends SIGKILL. % % Only works for processes spawned with `process_create/3` that have not yet been release with `process_release/1` -% +% process_kill(Process) :- call_with_error_context(process_kill_(Process), predicate-process_kill/1). -process_kill_(Process) :- +process_kill_(Process) :- valid_process(Process), '$process_kill'(Process). @@ -166,7 +166,7 @@ must_be_known_options_(Valid, Found, [X|XS], Domain) :- ; domain_error(Domain, X, []) ) , ( member(Option, Found) -> domain_error(non_duplicate_options, Option , []) - ; member(Option, Valid) -> true + ; member(Option, Valid) -> true ; domain_error(Domain, Option, []) ), must_be_known_options_(Valid, [Option | Found], XS, Domain). @@ -184,17 +184,17 @@ option_names(option(Names,_,_,_), Names). extract_options(KnownOptions, Options) :- call_with_error_context(extract_options_(KnownOptions, Options), predicate-extract_options/2). extract_options_([], _). -extract_options_([X | XS], Options) :- +extract_options_([X | XS], Options) :- option(Kinds, Pred, Default, Choice) = X, tfilter(find_option(Kinds), Options, Solutions), ( Solutions = [] -> Choice = Default - ; Solutions = [Provided] -> functor(Pred, Name, Arity), ArityP1 is Arity+1, call_with_error_context(call(Pred, Provided),predicate-Name/ArityP1), Choice = Provided + ; Solutions = [Provided] -> functor(Pred, Name, Arity), ArityP1 is Arity+1, call_with_error_context(call(Pred, Provided),predicate-Name/ArityP1), Choice = Provided ; domain_error(non_conflicting_options, Solutions, []) ), extract_options_(XS, Options). -find_option(Names, Found, T) :- - functor(Found, Name, 1), +find_option(Names, Found, T) :- + functor(Found, Name, 1), memberd_t(Name, Names, T). valid_stdio(IO) :- arg(1, IO, Arg), @@ -208,20 +208,20 @@ valid_stdio_(null). valid_stdio_(pipe(Stream)) :- must_be(var, Stream). valid_stdio_(file(Path)) :- must_be(chars, Path). -valid_env(env(E)) :- +valid_env(env(E)) :- must_be(list, E), - ( valid_env_(E) -> true + ( valid_env_(E) -> true ; domain_error(process_create_option, env(E), []) ). -valid_env(environment(E)) :- +valid_env(environment(E)) :- must_be(list, E), - ( valid_env_(E) -> true + ( valid_env_(E) -> true ; domain_error(process_create_option, environment(E), []) ). valid_env_([]). -valid_env_([N=V|ES]) :- - must_be(chars, N), +valid_env_([N=V|ES]) :- + must_be(chars, N), must_be(chars, V), valid_env_(ES). diff --git a/src/lib/tls.pl b/src/lib/tls.pl index 3fae7aeb..c317857c 100644 --- a/src/lib/tls.pl +++ b/src/lib/tls.pl @@ -1,5 +1,4 @@ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Negotiation of TLS connections. Written Dec. 2021 by Markus Triska (triska@metalevel.at) Part of Scryer Prolog. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -13,29 +12,17 @@ :- use_module(library(lists)). :- use_module(library(error)). -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TLS Clients - =========== - - Use tls_client_context/2 to create a TLS context, for example with: - - tls_client_context(Context, [hostname("metalevel.at")]) - - Using the context and an existing stream S0 (for example, the - result of socket_client_open/3), a TLS stream S can be negotiated - with: - - tls_client_negotiate(Context, S0, S) - - S will be an encrypted and authenticated stream with the server. - - The advantage of separating the creation of the client context from - negotiating a connection is that the context can be created only once, - and quickly reused if needed. This is currently not implemented: In - the present implementation, a new internal "Connector" is created for - every connection, using the specified hostname. -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - +/** Negotiation of TLS connections. +*/ + +%% tls_client_context(-Context, +Options) +% +% Use `tls_client_context/2` to create a TLS context, for example with: +% +% ``` +% tls_client_context(Context, [hostname("metalevel.at")]) +% ``` +% tls_client_context(tls_context(Host), Options) :- must_be(list, Options), ( member(hostname(Host), Options) -> @@ -43,58 +30,59 @@ tls_client_context(tls_context(Host), Options) :- ; Host = "" ). +%% tls_client_negotiate(+Context, +Stream0, -Stream) +% +% Using the context and an existing stream `S0` (for example, the result of +% `socket_client_open/3`), a TLS stream `S` can be negotiated with: +% +% ``` +% tls_client_negotiate(Context, S0, S) +% ``` +% +% `S` will be an encrypted and authenticated stream with the server. +% +% The advantage of separating the creation of the client context from +% negotiating a connection is that the context can be created only once, and +% quickly reused if needed. This is currently not implemented: In the present +% implementation, a new internal "Connector" is created for every connection, +% using the specified hostname. tls_client_negotiate(tls_context(Host), S0, S) :- '$tls_client_connect'(Host, S0, S). -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TLS Servers - =========== - - Use tls_server_context/2 to create a TLS context, for example with: - - tls_server_context(Context, [pkcs12(Chars)]) - - where Chars is a list of characters with the contents of a - DER-formatted PKCS #12 archive. The option password(Ps) can be used - to specify the password Ps (also a string) for decrypting the key. - On some versions of OSX, and potentially also on other platforms, - empty passwords are not supported. - - The archive should contain a leaf certificate and its private key, - as well any intermediate certificates that should be sent to - clients to allow them to build a chain to a trusted root. The chain - certificates should be in order from the leaf certificate towards - the root. - - PKCS #12 archives typically have the file extension .p12 or .pfx, - and can be created with the OpenSSL pkcs12 tool: - - $ openssl pkcs12 -export -out identity.pfx \ - -inkey key.pem -in cert.pem -certfile chain_certs.pem - - - You can use phrase_from_file/3 from library(pio) and seq//1 from - library(dcgs) to read the contents of "identity.pfx" into a string: - - phrase_from_file(seq(Chars), "identity.pfx", [type(binary)]) - - The obtained context should be treated as an opaque Prolog term. - - Using the context and an existing stream S0 (for example, the - result of socket_server_accept/4), a TLS stream S can be negotiated - by a Prolog-based server with: - - tls_server_negotiate(Context, S0, S) - - S will be an encrypted and authenticated stream with the client. - - The advantage of separating the creation of the server context from - negotiating a connection is that the context can be created only - once, and quickly cloned for every incoming connection. This is - currently not implemented: In the present implementation, a new context - is created for every connection, using the specified parameters. -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - +%% tls_server_context(-Context, +Options) +% +% Use `tls_server_context/2` to create a TLS context, for example with: +% +% ``` +% tls_server_context(Context, [pkcs12(Chars)]) +% ``` +% +% where Chars is a list of characters with the contents of a DER-formatted PKCS +% #12 archive. The option `password(Ps)` can be used to specify the password +% `Ps` (also a string) for decrypting the key. On some versions of OSX, and +% potentially also on other platforms, empty passwords are not supported. +% +% The archive should contain a leaf certificate and its private key, as well any +% intermediate certificates that should be sent to clients to allow them to +% build a chain to a trusted root. The chain certificates should be in order +% from the leaf certificate towards the root. +% +% PKCS #12 archives typically have the file extension `.p12` or `.pfx`, and can +% be created with the OpenSSL `pkcs12` tool: +% +% ``` +% $ openssl pkcs12 -export -out identity.pfx \ +% -inkey key.pem -in cert.pem -certfile chain_certs.pem +% ``` +% +% You can use `phrase_from_file/3` from `library(pio)` and `seq//1` from +% `library(dcgs)` to read the contents of `identity.pfx` into a string: +% +% ``` +% phrase_from_file(seq(Chars), "identity.pfx", [type(binary)]) +% ``` +% +% The obtained context should be treated as an opaque Prolog term. tls_server_context(tls_context(Cert,Password), Options) :- ( member(pcks12(Cert), Options) -> must_be(chars, Cert) @@ -105,6 +93,22 @@ tls_server_context(tls_context(Cert,Password), Options) :- ; Password = "" ). +%% tls_server_negotiate(+Context, +Stream0, -Stream) +% +% Using the context and an existing stream `S0` (for example, the result of +% `socket_server_accept/4`), a TLS stream `S` can be negotiated by a +% Prolog-based server with: +% +% ``` +% tls_server_negotiate(Context, S0, S) +% ``` +% +% `S` will be an encrypted and authenticated stream with the client. +% +% The advantage of separating the creation of the server context from +% negotiating a connection is that the context can be created only once, and +% quickly cloned for every incoming connection. This is currently not +% implemented: In the present implementation, a new context is created for every +% connection, using the specified parameters. tls_server_negotiate(tls_context(Cert,Password), S0, S) :- '$tls_accept_client'(Cert, Password, S0, S). - -- 2.54.0