aboutsummaryrefslogtreecommitdiffstats
path: root/man3
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2024-07-19 01:29:42 +0200
committerMattias Andrée <maandree@kth.se>2024-07-19 01:29:42 +0200
commit4294ec0ed06ee34920c9edaeebaeb8b65c720791 (patch)
treee0cded59452597c04fb38f403745a384675cb5f9 /man3
downloadlibnormalform-4294ec0ed06ee34920c9edaeebaeb8b65c720791.tar.gz
libnormalform-4294ec0ed06ee34920c9edaeebaeb8b65c720791.tar.bz2
libnormalform-4294ec0ed06ee34920c9edaeebaeb8b65c720791.tar.xz
First commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
l---------man3/LIBNORMALFORM_AND.31
l---------man3/LIBNORMALFORM_IF.31
l---------man3/LIBNORMALFORM_IMPLY.31
l---------man3/LIBNORMALFORM_NAND.31
l---------man3/LIBNORMALFORM_NIF.31
l---------man3/LIBNORMALFORM_NIMPLY.31
l---------man3/LIBNORMALFORM_NOR.31
l---------man3/LIBNORMALFORM_OR.31
-rw-r--r--man3/LIBNORMALFORM_SENTENCE.361
l---------man3/LIBNORMALFORM_XNOR.31
l---------man3/LIBNORMALFORM_XOR.31
l---------man3/enum_libnormalform_builtin_transformer.31
l---------man3/enum_libnormalform_value.31
-rw-r--r--man3/libnormalform_all.3202
-rw-r--r--man3/libnormalform_and.3233
l---------man3/libnormalform_and2.31
l---------man3/libnormalform_and_checked.31
l---------man3/libnormalform_andl.31
l---------man3/libnormalform_andl_checked.31
-rw-r--r--man3/libnormalform_any.3294
l---------man3/libnormalform_builtin_transformer.31
-rw-r--r--man3/libnormalform_clone.3104
l---------man3/libnormalform_empty.31
-rw-r--r--man3/libnormalform_evaluate.378
l---------man3/libnormalform_existentially.31
l---------man3/libnormalform_exists.31
-rw-r--r--man3/libnormalform_false.370
-rw-r--r--man3/libnormalform_free.373
-rw-r--r--man3/libnormalform_from_string.3265
-rw-r--r--man3/libnormalform_function.3152
-rw-r--r--man3/libnormalform_if.3233
l---------man3/libnormalform_if2.31
l---------man3/libnormalform_if_checked.31
l---------man3/libnormalform_ifl.31
l---------man3/libnormalform_ifl_checked.31
-rw-r--r--man3/libnormalform_imply.3236
l---------man3/libnormalform_imply2.31
l---------man3/libnormalform_imply_checked.31
l---------man3/libnormalform_implyl.31
l---------man3/libnormalform_implyl_checked.31
l---------man3/libnormalform_map.31
l---------man3/libnormalform_mapping.31
-rw-r--r--man3/libnormalform_nand.3250
l---------man3/libnormalform_nand2.31
l---------man3/libnormalform_nand_checked.31
l---------man3/libnormalform_nandl.31
l---------man3/libnormalform_nandl_checked.31
l---------man3/libnormalform_nexists.31
-rw-r--r--man3/libnormalform_nif.3239
l---------man3/libnormalform_nif2.31
l---------man3/libnormalform_nif_checked.31
l---------man3/libnormalform_nifl.31
l---------man3/libnormalform_nifl_checked.31
-rw-r--r--man3/libnormalform_nimply.3241
l---------man3/libnormalform_nimply2.31
l---------man3/libnormalform_nimply_checked.31
l---------man3/libnormalform_nimplyl.31
l---------man3/libnormalform_nimplyl_checked.31
l---------man3/libnormalform_nonempty.31
-rw-r--r--man3/libnormalform_nor.3245
l---------man3/libnormalform_nor2.31
l---------man3/libnormalform_nor_checked.31
l---------man3/libnormalform_norl.31
l---------man3/libnormalform_norl_checked.31
-rw-r--r--man3/libnormalform_not.392
-rw-r--r--man3/libnormalform_one.3253
-rw-r--r--man3/libnormalform_or.3233
l---------man3/libnormalform_or2.31
l---------man3/libnormalform_or_checked.31
l---------man3/libnormalform_orl.31
l---------man3/libnormalform_orl_checked.31
-rw-r--r--man3/libnormalform_ref.3111
l---------man3/libnormalform_representation_spec.31
l---------man3/libnormalform_sentence.31
l---------man3/libnormalform_singleton.31
-rw-r--r--man3/libnormalform_to_string.3105
-rw-r--r--man3/libnormalform_transformation.3245
l---------man3/libnormalform_transformer.31
-rw-r--r--man3/libnormalform_true.370
l---------man3/libnormalform_unique.31
l---------man3/libnormalform_uniquely.31
l---------man3/libnormalform_universally.31
l---------man3/libnormalform_value.31
l---------man3/libnormalform_vand.31
l---------man3/libnormalform_vand_checked.31
-rw-r--r--man3/libnormalform_variable.3127
l---------man3/libnormalform_vif.31
l---------man3/libnormalform_vif_checked.31
l---------man3/libnormalform_vimply.31
l---------man3/libnormalform_vimply_checked.31
l---------man3/libnormalform_vnand.31
l---------man3/libnormalform_vnand_checked.31
l---------man3/libnormalform_vnif.31
l---------man3/libnormalform_vnif_checked.31
l---------man3/libnormalform_vnimply.31
l---------man3/libnormalform_vnimply_checked.31
l---------man3/libnormalform_vnor.31
l---------man3/libnormalform_vnor_checked.31
l---------man3/libnormalform_vor.31
l---------man3/libnormalform_vor_checked.31
l---------man3/libnormalform_vxnor.31
l---------man3/libnormalform_vxnor_checked.31
l---------man3/libnormalform_vxor.31
l---------man3/libnormalform_vxor_checked.31
-rw-r--r--man3/libnormalform_xnor.3245
l---------man3/libnormalform_xnor2.31
l---------man3/libnormalform_xnor_checked.31
l---------man3/libnormalform_xnorl.31
l---------man3/libnormalform_xnorl_checked.31
-rw-r--r--man3/libnormalform_xor.3242
l---------man3/libnormalform_xor2.31
l---------man3/libnormalform_xor_checked.31
l---------man3/libnormalform_xorl.31
l---------man3/libnormalform_xorl_checked.31
l---------man3/struct_libnormalform_function.31
l---------man3/struct_libnormalform_map.31
l---------man3/struct_libnormalform_mapping.31
l---------man3/struct_libnormalform_representation_spec.31
l---------man3/struct_libnormalform_sentence.31
l---------man3/struct_libnormalform_transformer.31
l---------man3/struct_libnormalform_variable.31
121 files changed, 4794 insertions, 0 deletions
diff --git a/man3/LIBNORMALFORM_AND.3 b/man3/LIBNORMALFORM_AND.3
new file mode 120000
index 0000000..1cc3b47
--- /dev/null
+++ b/man3/LIBNORMALFORM_AND.3
@@ -0,0 +1 @@
+libnormalform_and.3 \ No newline at end of file
diff --git a/man3/LIBNORMALFORM_IF.3 b/man3/LIBNORMALFORM_IF.3
new file mode 120000
index 0000000..f5174b0
--- /dev/null
+++ b/man3/LIBNORMALFORM_IF.3
@@ -0,0 +1 @@
+libnormalform_if.3 \ No newline at end of file
diff --git a/man3/LIBNORMALFORM_IMPLY.3 b/man3/LIBNORMALFORM_IMPLY.3
new file mode 120000
index 0000000..8956d98
--- /dev/null
+++ b/man3/LIBNORMALFORM_IMPLY.3
@@ -0,0 +1 @@
+libnormalform_imply.3 \ No newline at end of file
diff --git a/man3/LIBNORMALFORM_NAND.3 b/man3/LIBNORMALFORM_NAND.3
new file mode 120000
index 0000000..e25f19a
--- /dev/null
+++ b/man3/LIBNORMALFORM_NAND.3
@@ -0,0 +1 @@
+libnormalform_nand.3 \ No newline at end of file
diff --git a/man3/LIBNORMALFORM_NIF.3 b/man3/LIBNORMALFORM_NIF.3
new file mode 120000
index 0000000..d269483
--- /dev/null
+++ b/man3/LIBNORMALFORM_NIF.3
@@ -0,0 +1 @@
+libnormalform_nif.3 \ No newline at end of file
diff --git a/man3/LIBNORMALFORM_NIMPLY.3 b/man3/LIBNORMALFORM_NIMPLY.3
new file mode 120000
index 0000000..47711fc
--- /dev/null
+++ b/man3/LIBNORMALFORM_NIMPLY.3
@@ -0,0 +1 @@
+libnormalform_nimply.3 \ No newline at end of file
diff --git a/man3/LIBNORMALFORM_NOR.3 b/man3/LIBNORMALFORM_NOR.3
new file mode 120000
index 0000000..dd76dbe
--- /dev/null
+++ b/man3/LIBNORMALFORM_NOR.3
@@ -0,0 +1 @@
+libnormalform_nor.3 \ No newline at end of file
diff --git a/man3/LIBNORMALFORM_OR.3 b/man3/LIBNORMALFORM_OR.3
new file mode 120000
index 0000000..25bea64
--- /dev/null
+++ b/man3/LIBNORMALFORM_OR.3
@@ -0,0 +1 @@
+libnormalform_or.3 \ No newline at end of file
diff --git a/man3/LIBNORMALFORM_SENTENCE.3 b/man3/LIBNORMALFORM_SENTENCE.3
new file mode 100644
index 0000000..8af097e
--- /dev/null
+++ b/man3/LIBNORMALFORM_SENTENCE.3
@@ -0,0 +1,61 @@
+.TH LIBNORMALFORM_SENTENCE 3 LIBNORMALFORM
+.SH NAME
+LIBNORMALFORM_SENTENCE \- Logical sentence description object
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+typedef struct libnormalform_sentence LIBNORMALFORM_SENTENCE;
+.fi
+
+.SH DESCRIPTION
+The
+.B LIBNORMALFORM_SENTENCE
+type is a reference counted opaque data type used to
+describe logical sentences of the first order.
+.PP
+Instances of this type can have there references count
+increased using the
+.BR libnormalform_ref (3)
+function and decreased (and deallocated if 0 is reached)
+using the
+.BR libnormalform_free (3)
+function.
+.PP
+Because this type contains temporary memory and caches,
+and not mechanisms to avoid race conditions, instances
+of this type cannot be safely used by any function from
+two threads at the same time. However, the function
+.BR libnormalform_clone (3)
+can be used to create a brand new but identical instance
+which can safely be used in another thread.
+.PP
+Instances can be serialised, as human-readable strings,
+and deserialised using the
+.BR libnormalform_to_string (3)
+and
+.BR libnormalform_from_string (3)
+functions.
+.PP
+Apart from the
+.BR libnormalform_ref (3)
+and
+.BR libnormalform_clone (3)
+functions, every function that return objects of this
+type, will acquire the ownership of the any reference
+to instances of this type passed into the function,
+they will also fail without modifying
+.I errno
+if any of them are
+.IR NULL ,
+but they will still acquire the ownership of the
+references in this case or any other time they fail.
+
+.SH NOTES
+The name
+.B struct libnormalform_sentence
+is exposed only for type safety and should not be used.
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/LIBNORMALFORM_XNOR.3 b/man3/LIBNORMALFORM_XNOR.3
new file mode 120000
index 0000000..49b2b6c
--- /dev/null
+++ b/man3/LIBNORMALFORM_XNOR.3
@@ -0,0 +1 @@
+libnormalform_xnor.3 \ No newline at end of file
diff --git a/man3/LIBNORMALFORM_XOR.3 b/man3/LIBNORMALFORM_XOR.3
new file mode 120000
index 0000000..7da4f32
--- /dev/null
+++ b/man3/LIBNORMALFORM_XOR.3
@@ -0,0 +1 @@
+libnormalform_xor.3 \ No newline at end of file
diff --git a/man3/enum_libnormalform_builtin_transformer.3 b/man3/enum_libnormalform_builtin_transformer.3
new file mode 120000
index 0000000..9bb1a97
--- /dev/null
+++ b/man3/enum_libnormalform_builtin_transformer.3
@@ -0,0 +1 @@
+struct_libnormalform_transformer.3 \ No newline at end of file
diff --git a/man3/enum_libnormalform_value.3 b/man3/enum_libnormalform_value.3
new file mode 120000
index 0000000..8d964dc
--- /dev/null
+++ b/man3/enum_libnormalform_value.3
@@ -0,0 +1 @@
+struct_libnormalform_variable.3 \ No newline at end of file
diff --git a/man3/libnormalform_all.3 b/man3/libnormalform_all.3
new file mode 100644
index 0000000..901bba2
--- /dev/null
+++ b/man3/libnormalform_all.3
@@ -0,0 +1,202 @@
+.TH LIBNORMALFORM_ALL 3 LIBNORMALFORM
+.SH NAME
+libnormalform_all \- Universal qualifier
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+struct libnormalform_mapping {
+ void *\fIkey\fP;
+ void *\fIvalue\fP;
+};
+
+struct libnormalform_map {
+ struct libnormalform_mapping *\fImappings\fP;
+ size_t \fInmappings\fP;
+ void *\fIuser_data\fP;
+ const char *\fIidentifier\fP;
+ struct libnormalform_map *\fIcopy_for_clone\fP;
+};
+
+LIBNORMALFORM_SENTENCE *
+libnormalform_all(struct libnormalform_map *\fId\fP, LIBNORMALFORM_SENTENCE *\fIk\fP, LIBNORMALFORM_SENTENCE *\fIv\fP);
+
+LIBNORMALFORM_SENTENCE *
+libnormalform_universally(struct libnormalform_map *\fId\fP, LIBNORMALFORM_SENTENCE *\fIv\fP);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_all ()
+function creates a sentence that is true
+when and only when the sentence
+.I v
+is true for the
+.I .value
+for every element in
+.I d
+for which
+.I k
+is also true for the
+.I .key
+of the element.
+.PP
+The
+.BR libnormalform_universally ()
+function creates a sentence that is true
+when and only when the sentence
+.I v
+is true for the
+.I .value
+of every element in
+.IR d .
+.PP
+.I d->mappings
+and
+.I d->nmappings
+is used only be the
+.BR libnormalform_evaluate (3)
+function and must be set before
+.BR libnormalform_evaluate (3)
+is called, but need not be set
+earlier.
+.I d->nmappings
+shall be set to number of elements in
+the qualifers domain of interest, and
+.I d->mappings
+shall be set to the list of elements
+in the domain. Each element shall have its
+.I .key
+set to the value the antecedent formula
+.RI ( k )
+is tested on, and
+.I .value
+set to the value the predicate formula
+.RI ( v )
+is tested on; these fields may be
+.IR NULL ,
+and are ultimately evaluated via
+arguments passed to the
+.BR libnormalform_function (3)
+function but may undergo transformation
+via arguments passed to the
+.BR libnormalform_transformation (3)
+function on the way.
+.PP
+The values
+.I d->mappings
+and
+.I d->nmappings
+may be set differently every time the
+.BR libnormalform_evaluate (3)
+is called.
+.PP
+See
+.BR libnormalform_to_string (3)
+for the purpose of
+.IR d->identifier ,
+it need not be set before the
+.BR libnormalform_to_string (3)
+function is called.
+.PP
+See
+.BR libnormalform_clone (3)
+for the purpose of
+.IR d->copy_for_clone ,
+it need not be set before the
+.BR libnormalform_clone (3)
+function is called.
+.PP
+The application can set
+.I d->user_data
+set freely, and can opt to leave it
+unset. It is never used or reference
+by the library, but it could be used
+by the application to identify the
+domain.
+.PP
+.I d
+must not be
+.IR NULL .
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+These functions adopt the ownership of any
+.I LIBNORMALFORM_SENTENCE *
+passed into it. Therefore, the user shall
+not attempt to deallocate input sentences.
+This holds even on failure: if the function
+fails, input sentences are deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_all ()
+and
+.BR libnormalform_universally ()
+functions return an object representing
+the sentence; otherwise, the functions
+return
+.I NULL
+and set
+.I errno
+to indicate the error.
+
+.SH ERRORS
+The
+.BR libnormalform_all ()
+and
+.BR libnormalform_universally ()
+functions fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.PP
+These functions will also fail without setting
+.I errno
+if
+.I k
+or
+.I v
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_all (),
+.br
+.BR libnormalform_universally ()
+T} Thread safety MT-Safe race:\fIk\fP,\fIv\fP
+T{
+.BR libnormalform_all (),
+.br
+.BR libnormalform_universally ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_all (),
+.br
+.BR libnormalform_universally ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH SEE ALSO
+.BR libnormalform (7),
+.BR libnormalform_function (3)
diff --git a/man3/libnormalform_and.3 b/man3/libnormalform_and.3
new file mode 100644
index 0000000..bb65a74
--- /dev/null
+++ b/man3/libnormalform_and.3
@@ -0,0 +1,233 @@
+.TH LIBNORMALFORM_AND 3 LIBNORMALFORM
+.SH NAME
+libnormalform_and \- Conjunction
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_and(LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_andl(LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vand(LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_and_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_andl_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vand_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_and2(LIBNORMALFORM_SENTENCE *\fIp\fP, LIBNORMALFORM_SENTENCE *\fIq\fP);
+#define LIBNORMALFORM_AND(...) /* ... */
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_and ()
+function creates a sentence that is logically
+equivalent to the conjunction of the arguments,
+that is, a sentence that is true when and only
+when all subsentences are true.
+.PP
+The value of the
+.I xs
+parameter shall be a null-pointer terminated list
+of subsentences.
+.PP
+The
+.BR libnormalform_andl ()
+function is a variant of
+.BR libnormalform_and ()
+which uses variadic arguments instead of an array.
+.PP
+The
+.BR libnormalform_vand ()
+function is a variant of
+.BR libnormalform_andl ()
+which takes an
+.I va_list
+in place of variadic arguments.
+.PP
+The
+.BR libnormalform_and_checked (),
+.BR libnormalform_andl_checked (),
+and
+.BR libnormalform_vand_checked ()
+functions are variants of the
+.BR libnormalform_and (),
+.BR libnormalform_andl (),
+and
+.BR libnormalform_vand ()
+functions respectively which assumes
+that it is given
+.I n
+subsentances, and checks that all are
+.RI non- NULL .
+However, these functions still require
+the list of subsentences to be terminated
+using a null-pointer.
+.PP
+.I "libnormalform_and2(p, q)"
+is equivalent to
+.IR "libnormalform_andl_checked(2, p, q, NULL)" .
+.PP
+The
+.BR LIBNORMALFORM_AND
+macro is a wrapper for the
+.BR libnormalform_and_checked ()
+but is more similar to
+.BR libnormalform_andl ().
+Unlike
+.BR libnormalform_andl (),
+the argument list
+.I must not
+be terminated by a null-pointer, instead
+the macro automatically as the null-pointer.
+The macro will count the number of arguments
+it is given, therefore it will fail it the
+argument list is has an extra null-pointer.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+These functions adopt the ownership of any
+.I LIBNORMALFORM_SENTENCE *
+passed into it. Therefore, the user shall
+not attempt to deallocate input sentences.
+This holds even on failure: if the function
+fails, input sentences are deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_and ()
+function and its variants return an object
+representing the sentence; otherwise, the
+functions return
+.I NULL
+and set
+.I errno
+to indicate the error.
+
+.SH ERRORS
+These functions fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.PP
+The
+.BR libnormalform_and_checked (),
+.BR libnormalform_andl_checked (),
+and
+.BR libnormalform_vand_checked ()
+functions will also fail without setting
+.I errno
+if any of the first
+.I n
+.IR "LIBNORMALFORM_SENTENCE *" 's
+are
+.IR NULL .
+Likewise, the
+.BR libnormalform_and2 ()
+function will fail without setting
+.I errno
+if
+.I p
+or
+.I q
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_and (),
+.br
+.BR libnormalform_and_checked ()
+T} Thread safety MT-Safe race:\fIxs\fP and elements in \fIxs\fP
+T{
+.BR libnormalform_andl (),
+.br
+.BR libnormalform_andl_checked (),
+.br
+.BR libnormalform_and2 (),
+.br
+.BR LIBNORMALFORM_AND ()
+T} Thread safety MT-Safe race:parameters
+T{
+.BR libnormalform_vand (),
+.br
+.BR libnormalform_vand_checked ()
+T} Thread safety MT-Safe race:parameters and arguments in \fIargs\fP
+T{
+.BR libnormalform_and (),
+.br
+.BR libnormalform_andl (),
+.br
+.BR libnormalform_vand (),
+.br
+.BR libnormalform_and_checked (),
+.br
+.BR libnormalform_andl_checked (),
+.br
+.BR libnormalform_vand_checked (),
+.br
+.BR libnormalform_vand2 (),
+.br
+.BR LIBNORMALFORM_AND ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_and (),
+.br
+.BR libnormalform_andl (),
+.br
+.BR libnormalform_vand (),
+.br
+.BR libnormalform_and_checked (),
+.br
+.BR libnormalform_andl_checked (),
+.br
+.BR libnormalform_vand_checked (),
+.br
+.BR libnormalform_vand2 (),
+.br
+.BR LIBNORMALFORM_AND ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH NOTES
+If there are no subsentences, the resulting sentence is a tautology.
+.PP
+The connective is commutative and associative. It's truthtable is (0001).
+.PP
+The
+.BR LIBNORMALFORM_AND ()
+macro requires ISO C23 support.
+.PP
+Using
+.BR libnormalform_and2 (),
+has greatest performance, however
+.BR libnormalform_and ()
+is better at simplifying the sentence.
+The other functions are just wrappers for the
+.BR libnormalform_and ()
+function.
+.PP
+Side-effects in the arguments of the macro
+.BR LIBNORMALFORM_AND ()
+are guaranteed to be applied exactly once.
+The side-effects in each macro are applied
+in no particular order.
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_and2.3 b/man3/libnormalform_and2.3
new file mode 120000
index 0000000..85d5d8b
--- /dev/null
+++ b/man3/libnormalform_and2.3
@@ -0,0 +1 @@
+libnormalform_and_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_and_checked.3 b/man3/libnormalform_and_checked.3
new file mode 120000
index 0000000..1cc3b47
--- /dev/null
+++ b/man3/libnormalform_and_checked.3
@@ -0,0 +1 @@
+libnormalform_and.3 \ No newline at end of file
diff --git a/man3/libnormalform_andl.3 b/man3/libnormalform_andl.3
new file mode 120000
index 0000000..1cc3b47
--- /dev/null
+++ b/man3/libnormalform_andl.3
@@ -0,0 +1 @@
+libnormalform_and.3 \ No newline at end of file
diff --git a/man3/libnormalform_andl_checked.3 b/man3/libnormalform_andl_checked.3
new file mode 120000
index 0000000..85d5d8b
--- /dev/null
+++ b/man3/libnormalform_andl_checked.3
@@ -0,0 +1 @@
+libnormalform_and_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_any.3 b/man3/libnormalform_any.3
new file mode 100644
index 0000000..ac44b0b
--- /dev/null
+++ b/man3/libnormalform_any.3
@@ -0,0 +1,294 @@
+.TH LIBNORMALFORM_ANY 3 LIBNORMALFORM
+.SH NAME
+libnormalform_any \- Existential qualifier
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+struct libnormalform_mapping {
+ void *\fIkey\fP;
+ void *\fIvalue\fP;
+};
+
+struct libnormalform_map {
+ struct libnormalform_mapping *\fImappings\fP;
+ size_t \fInmappings\fP;
+ void *\fIuser_data\fP;
+ const char *\fIidentifier\fP;
+ struct libnormalform_map *\fIcopy_for_clone\fP;
+};
+
+LIBNORMALFORM_SENTENCE *
+libnormalform_any(struct libnormalform_map *\fId\fP, LIBNORMALFORM_SENTENCE *\fIk\fP, LIBNORMALFORM_SENTENCE *\fIv\fP);
+
+LIBNORMALFORM_SENTENCE *
+libnormalform_exists(struct libnormalform_map *\fId\fP, LIBNORMALFORM_SENTENCE *\fIk\fP);
+
+LIBNORMALFORM_SENTENCE *
+libnormalform_nexists(struct libnormalform_map *\fId\fP, LIBNORMALFORM_SENTENCE *\fIk\fP);
+
+LIBNORMALFORM_SENTENCE *
+libnormalform_existentially(struct libnormalform_map *\fId\fP, LIBNORMALFORM_SENTENCE *\fIv\fP);
+
+LIBNORMALFORM_SENTENCE *
+libnormalform_empty(struct libnormalform_map *\fId\fP);
+
+LIBNORMALFORM_SENTENCE *
+libnormalform_nonempty(struct libnormalform_map *\fId\fP);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_any ()
+function creates a sentence that is true
+when and only when the sentence
+.I v
+is true for the
+.I .value
+for at least one element in
+.I d
+for which
+.I k
+is also true for the
+.I .key
+of the element.
+.PP
+The
+.BR libnormalform_exists ()
+function creates a sentence that is true
+when and only when the sentence
+.I k
+is true for the
+.I .key
+of at least one element in
+.IR d .
+.PP
+The
+.BR libnormalform_nexists ()
+function creates a sentence that is true
+when and only when the sentence
+.I k
+is false for the
+.I .key
+of every element in
+.IR d .
+.PP
+The
+.BR libnormalform_existentially ()
+function creates a sentence that is true
+when and only when the sentence
+.I v
+is true for the
+.I .value
+of at least one element in
+.IR d .
+.PP
+The
+.BR libnormalform_empty ()
+function creates a sentence that is true
+when and only when
+.IR d
+contains no elements.
+.PP
+The
+.BR libnormalform_nonempty ()
+function creates a sentence that is true
+when and only when
+.IR d
+contains at least one element.
+.PP
+.I d->mappings
+and
+.I d->nmappings
+is used only be the
+.BR libnormalform_evaluate (3)
+function and must be set before
+.BR libnormalform_evaluate (3)
+is called, but need not be set
+earlier.
+.I d->nmappings
+shall be set to number of elements in
+the qualifers domain of interest, and
+.I d->mappings
+shall be set to the list of elements
+in the domain. Each element shall have its
+.I .key
+set to the value the antecedent formula
+.RI ( k )
+is tested on, and
+.I .value
+set to the value the predicate formula
+.RI ( v )
+is tested on; these fields may be
+.IR NULL ,
+and are ultimately evaluated via
+arguments passed to the
+.BR libnormalform_function (3)
+function but may undergo transformation
+via arguments passed to the
+.BR libnormalform_transformation (3)
+function on the way.
+.PP
+The values
+.I d->mappings
+and
+.I d->nmappings
+may be set differently every time the
+.BR libnormalform_evaluate (3)
+is called.
+.PP
+Although unused, the
+.BR libnormalform_empty ()
+and
+.BR libnormalform_nonempty ()
+functions require that
+.I d->mappings
+is properly set up (although the values
+in it can all be
+.IR NULL )
+before the
+.BR libnormalform_evaluate (3)
+function is called.
+.PP
+See
+.BR libnormalform_to_string (3)
+for the purpose of
+.IR d->identifier ,
+it need not be set before the
+.BR libnormalform_to_string (3)
+function is called.
+.PP
+See
+.BR libnormalform_clone (3)
+for the purpose of
+.IR d->copy_for_clone ,
+it need not be set before the
+.BR libnormalform_clone (3)
+function is called.
+.PP
+The application can set
+.I d->user_data
+set freely, and can opt to leave it
+unset. It is never used or reference
+by the library, but it could be used
+by the application to identify the
+domain.
+.PP
+.I d
+must not be
+.IR NULL .
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+These functions adopt the ownership of any
+.I LIBNORMALFORM_SENTENCE *
+passed into it. Therefore, the user shall
+not attempt to deallocate input sentences.
+This holds even on failure: if the function
+fails, input sentences are deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_any (),
+.BR libnormalform_exists (),
+.BR libnormalform_nexists (),
+.BR libnormalform_existentially (),
+.BR libnormalform_empty (),
+and
+.BR libnormalform_nonempty (),
+functions return an object representing
+the sentence; otherwise, the functions
+return
+.I NULL
+and set
+.I errno
+to indicate the error.
+
+.SH ERRORS
+The
+.BR libnormalform_any (),
+.BR libnormalform_exists (),
+.BR libnormalform_nexists (),
+.BR libnormalform_existentially (),
+.BR libnormalform_empty (),
+and
+.BR libnormalform_nonempty (),
+functions fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.PP
+These functions will also fail without setting
+.I errno
+if
+.I k
+or
+.I v
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_any (),
+.br
+.BR libnormalform_exists (),
+.br
+.BR libnormalform_nexists (),
+.br
+.BR libnormalform_existentially ()
+T} Thread safety MT-Safe race:\fIk\fP,\fIv\fP
+T{
+.BR libnormalform_empty (),
+.br
+.BR libnormalform_nonempty ()
+T} Thread safety MT-Safe
+T{
+.BR libnormalform_any (),
+.br
+.BR libnormalform_exists (),
+.br
+.BR libnormalform_nexists (),
+.br
+.BR libnormalform_existentially (),
+.br
+.BR libnormalform_empty (),
+.br
+.BR libnormalform_nonempty ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_any (),
+.br
+.BR libnormalform_exists (),
+.br
+.BR libnormalform_nexists (),
+.br
+.BR libnormalform_existentially (),
+.br
+.BR libnormalform_empty (),
+.br
+.BR libnormalform_nonempty ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH SEE ALSO
+.BR libnormalform (7),
+.BR libnormalform_function (3)
diff --git a/man3/libnormalform_builtin_transformer.3 b/man3/libnormalform_builtin_transformer.3
new file mode 120000
index 0000000..935c5c4
--- /dev/null
+++ b/man3/libnormalform_builtin_transformer.3
@@ -0,0 +1 @@
+enum_libnormalform_builtin_transformer.3 \ No newline at end of file
diff --git a/man3/libnormalform_clone.3 b/man3/libnormalform_clone.3
new file mode 100644
index 0000000..0906a44
--- /dev/null
+++ b/man3/libnormalform_clone.3
@@ -0,0 +1,104 @@
+.TH LIBNORMALFORM_CLONE 3 LIBNORMALFORM
+.SH NAME
+libnormalform_clone \- Create a deep clone
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_clone(LIBNORMALFORM_SENTENCE *\fIx\fP);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_clone ()
+function creates a deep clone of
+.IR x ,
+letting the application use the same
+sentence in concurrently from two threads.
+.PP
+Before calling the
+.BR libnormalform_clone ()
+function, application provided objects in
+.I x
+must be configured for cloning:
+.I .copy_for_clone
+in each
+.IR "struct libnormalform_variable" ,
+.IR "struct libnormalform_function" ,
+.IR "struct libnormalform_map" ,
+and
+.IR "struct libnormalform_transformer" ,
+shall either be set to the copy of the
+object to use in the clone of
+.IR x ,
+or to
+.I NULL
+if the object can safely be used by the
+clone of
+.IR x .
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_clone ()
+function returns a deep clone of
+.IR x ;
+otherwise, the function returns
+.I NULL
+and sets
+.I errno
+to indicate the error.
+
+.SH ERRORS
+The
+.BR libnormalform_clone ()
+function fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.PP
+The
+.BR libnormalform_clone ()
+function also fails without setting
+.I errno
+if
+.I x
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_clone ()
+T} Thread safety MT-Safe race:\fIx\fP
+T{
+.BR libnormalform_clone ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_clone ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH SEE ALSO
+.BR libnormalform (7),
+.BR libnormalform_ref (3),
+.BR libnormalform_free (3)
diff --git a/man3/libnormalform_empty.3 b/man3/libnormalform_empty.3
new file mode 120000
index 0000000..899f515
--- /dev/null
+++ b/man3/libnormalform_empty.3
@@ -0,0 +1 @@
+libnormalform_any.3 \ No newline at end of file
diff --git a/man3/libnormalform_evaluate.3 b/man3/libnormalform_evaluate.3
new file mode 100644
index 0000000..12675ee
--- /dev/null
+++ b/man3/libnormalform_evaluate.3
@@ -0,0 +1,78 @@
+.TH LIBNORMALFORM_EVALUATE 3 LIBNORMALFORM
+.SH NAME
+libnormalform_evaluate \- Determine value of a formula
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+int libnormalform_evaluate(LIBNORMALFORM_SENTENCE *\fIformula\fP);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_evaluate ()
+function determines the value of
+.IR formula .
+.PP
+Before calling the
+.BR libnormalform_evaluate ()
+function, the application must configure application
+defined parts of the formula. That is, any
+.IR "struct libnormalform_variable" ,
+.IR "struct libnormalform_function" ,
+.IR "struct libnormalform_map" ,
+and
+.IR "struct libnormalform_transformer"
+must be set configuared accord to the specifications
+specified for the function it was used in.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_evaluate ()
+function returns 1 if the
+.I formula
+is true for configured input, 0 if the
+.I formula
+is false for configured input;
+otherwise, the function returns
+.IR -1 .
+
+.SH ERRORS
+The
+.BR libnormalform_evaluate ()
+function fails if an application function fails.
+The
+.BR libnormalform_evaluate ()
+function does not modify
+.IR errno ,
+but lets application functions modify
+.IR errno .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_evaluate ()
+T} Thread safety MT-Safe race:\fIsentence\fP
+T{
+.BR libnormalform_evaluate ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_evaluate ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_existentially.3 b/man3/libnormalform_existentially.3
new file mode 120000
index 0000000..899f515
--- /dev/null
+++ b/man3/libnormalform_existentially.3
@@ -0,0 +1 @@
+libnormalform_any.3 \ No newline at end of file
diff --git a/man3/libnormalform_exists.3 b/man3/libnormalform_exists.3
new file mode 120000
index 0000000..899f515
--- /dev/null
+++ b/man3/libnormalform_exists.3
@@ -0,0 +1 @@
+libnormalform_any.3 \ No newline at end of file
diff --git a/man3/libnormalform_false.3 b/man3/libnormalform_false.3
new file mode 100644
index 0000000..83dd97a
--- /dev/null
+++ b/man3/libnormalform_false.3
@@ -0,0 +1,70 @@
+.TH LIBNORMALFORM_FALSE 3 LIBNORMALFORM
+.SH NAME
+libnormalform_false \- Contradiction
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_false(void);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_false ()
+function creates a contradictory sentence:
+a sentence that is always false, regardless
+of the its containing formula's input.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_false ()
+function returns an object representing
+the sentence; otherwise, the function returns
+.I NULL
+and sets
+.I errno
+to indicate the error.
+
+.SH ERRORS
+The
+.BR libnormalform_false ()
+function fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_false ()
+T} Thread safety MT-Safe
+T{
+.BR libnormalform_false ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_false ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_free.3 b/man3/libnormalform_free.3
new file mode 100644
index 0000000..7846dc5
--- /dev/null
+++ b/man3/libnormalform_free.3
@@ -0,0 +1,73 @@
+.TH LIBNORMALFORM_FREE 3 LIBNORMALFORM
+.SH NAME
+libnormalform_free \- Release a reference
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+void libnormalform_free(/* LIBNORMALFORM_SENTENCE | struct libnormalform_term */ *\fIobj\fP);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_free ()
+function can operate on both the type
+.I LIBNORMALFORM_SENTENCE *
+and the type
+.IR "struct libnormalform_term *" .
+The function recursively deallocates
+.IR obj ,
+however sence
+.I LIBNORMALFORM_SENTENCE *
+is reference counted,
+.IR obj ,
+if it is a
+.IR "LIBNORMALFORM_SENTENCE *" ,
+and any
+.IR "LIBNORMALFORM_SENTENCE *"
+stored in side it, will have it's reference
+count decreased by one, and the object is
+only deallocated (recursively) once the the
+reference count reaches 0.
+.PP
+No action is taken if
+.I obj
+is
+.IR NULL .
+
+.SH RETURN VALUE
+None.
+
+.SH ERRORS
+None.
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_free ()
+T} Thread safety MT-Safe race:\fIobj\fP
+T{
+.BR libnormalform_free ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_free ()
+T} Async-cancel safety AC-Unsafe heap
+.TE
+
+.SH SEE ALSO
+.BR libnormalform (7),
+.BR libnormalform_ref (3),
+.BR libnormalform_free (3)
diff --git a/man3/libnormalform_from_string.3 b/man3/libnormalform_from_string.3
new file mode 100644
index 0000000..f0bfc98
--- /dev/null
+++ b/man3/libnormalform_from_string.3
@@ -0,0 +1,265 @@
+.TH LIBNORMALFORM_FROM_STRING 3 LIBNORMALFORM
+.SH NAME
+libnormalform_from_string \- Deserialise a sentence from a string
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+struct libnormalform_representation_spec {
+ void *\fIuser_data\fP;
+ struct libnormalform_variable *(*\fIget_variable\fP)(char *, char **, void *);
+ struct libnormalform_function *(*\fIget_function\fP)(char *, char **, void *);
+ struct libnormalform_map *(*\fIget_map\fP)(char *, char **, void *);
+ struct libnormalform_transformer *(*\fIget_transformer\fP)(char *, char **, void *);
+};
+
+LIBNORMALFORM_SENTENCE *libnormalform_from_string(/* optionally const */ char *\fIs\fP,
+ /* at least as const as \fIs\fP */ char **\fIend_out\fP,
+ const struct libnormalform_representation_spec *\fIspec\fP);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_from_string ()
+function parse
+\fIs\fP
+and returns an equivalent sentence.
+.P
+If
+.I end_out
+is
+.RI non- NULL ,
+the position in
+.I s
+after the end of the representation is stored in
+.IR *end_out
+upon successful terminate (unspecified on failure),
+otherwise the function will validate that it
+only contains whitespace after the end of the
+representation.
+.PP
+.I s
+will not be modified by the
+.BR libnormalform_from_string ()
+function, however it will let user provided
+functions modify
+.IR s ,
+therefore
+.I s
+may be read-only if, and only if, the user provided
+functions do not modify
+.IR s .
+.PP
+.IR spec->get_variable ,
+.IR spec->get_function ,
+.IR spec->get_map ,
+and
+.IR spec->get_transformer ,
+may each be either
+.I NULL
+or a function pointers returns an object,
+according to their return type, described in
+the sentence. The functions shall return
+.I NULL
+on and only on failure. When these functions
+are called by the
+.BR libnormalform_from_string ()
+function, the first argument will be the beginning
+of the string they shall parse — these strings will
+not be properly terminated, — the second argument
+will be pointer that the end (the position immediately
+after the last byte) of the parsed string shall be
+stored (on success), and the third argument will be
+.I spec->user_data
+which is only used by the application for
+application-defined purposes.
+.I spec->user_data
+may be
+.IR NULL .
+.PP
+Neither
+.I s
+nor
+.I spec
+may be
+.IR NULL .
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_from_string ()
+sentence object equivalent to the sentence
+described by
+.IR s ;
+otherwise, the function returns
+.I NULL
+and sets
+.I errno
+to indicate the error.
+
+.SH ERRORS
+The
+.BR libnormalform_from_string ()
+function fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.TP
+.I EINVAL
+The representation is invalid.
+.TP
+.I EINVAL
+.I end_out
+is
+.I NULL
+but there are non-whitespace characters in
+.I s
+after the detected end of the representation.
+.TP
+.I EDOM
+The described sentence contains an empty clause
+for a connective that does not support empty
+clauses.
+.TP
+.I EDOM
+The described sentence contains a transformation
+somewhere over a qualifer.
+.TP
+.I ENOENT
+The described sentence contains a boolean variable but
+.I spec->get_variable
+was
+.IR NULL .
+.TP
+.I ENOENT
+The described sentence contains a boolean function but
+.I spec->get_function
+was
+.IR NULL .
+.TP
+.I ENOENT
+The described sentence contains (a domain of interest
+for a) qualifier but
+.I spec->get_map
+was
+.IR NULL .
+.TP
+.I ENOENT
+The described sentence contains a transformation
+(a input transformation function) but
+.I spec->get_transformer
+was
+.IR NULL .
+.PP
+The
+.BR libnormalform_from_string ()
+function will also fail if
+.IR spec->get_variable ,
+.IR spec->get_function ,
+.IR spec->get_map ,
+or
+.IR spec->get_transformer
+fails, and will retain
+.I errno
+as set by the function that failed, or leave
+.I errno
+unmodified if the failing function did not
+modify
+.IR errno .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_from_string ()
+T} Thread safety MT-Safe
+T{
+.BR libnormalform_from_string ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_from_string ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH EXTENDED DESCRIPTION
+The representation shall be on the whitespace-insensitive form:
+.PP
+.RS
+.nf
+\fIconstant\fP ::= "\fBTRUE\fP" | "\fBFALSE\fP";
+\fIconnective1\fP ::= "\fBNOT\fP";
+\fIconnective2\fP ::= "\fBAND\fP" | "\fBOR\fP" | "\fBXOR\fP" | "\fBIF\fP" | "\fBIMPLY\fP" |
+ "\fBNAND\fP" | "\fBNOR\fP" | "\fBXNOR\fP" | "\fBNIF\fP" | "\fBNIMPLY\fP";
+\fIqualifier0\fP ::= "\fBEMPTY\fP" | "\fBNONEMPTY\fP" | "\fBSINGLETON\fP";
+\fIqualifier1\fP ::= "\fBEXISTS\fP" | "\fBNEXISTS\fP" | "\fBUNIQUE\fP"
+ "\fBEXISTENTIALLY\fP" | "\fBUNIVERSALLY\fP" | "\fBUNIQUELY\fP";
+\fIqualifier2\fP ::= "\fBALL\fP" | "\fBANY\fP" | "\fBONE\fP";
+\fIunary\fP ::= \fIconnective1\fP [\fIreference-point\fP] "\fB(\fP" \fIsentence\fP "\fB)\fP";
+\fIvariadic\fP ::= \fIconnective2\fP [\fIreference-point\fP] "\fB(\fP" [\fIsentence-list\fP] "\fB)\fP";
+\fIsentence-list\fP ::= \fIsentence\fP ["\fB,\fP" \fIsentence-list\fP];
+\fIqualified0\fP ::= \fIqualifier0\fP [\fIreference-point\fP] "\fB(\fP" \fImap\fP "\fB)\fP";
+\fIqualified1\fP ::= \fIqualifier1\fP [\fIreference-point\fP] "\fB(\fP" \fImap\fP "\fB,\fP" \fIsentence\fP "\fB)\fP";
+\fIqualified2\fP ::= \fIqualifier2\fP [\fIreference-point\fP] "\fB(\fP" \fImap\fP "\fB,\fP" \fIsentence\fP "\fB,\fP" \fIsentence\fP "\fB)\fP";
+\fIatom\fP ::= \fIatom-var\fP | \fIatom-fun\fP;
+\fIatom-var\fP ::= "\fBVARIABLE\fP" [\fIreference-point\fP] "\fB(\fP" \fIvariable\fP "\fB)\fP";
+\fIatom-fun\fP ::= "\fBFUNCTION\fP" [\fIreference-point\fP] "\fB(\fP" \fIfunction\fP "\fB)\fP";
+\fItransformation\fP ::= "\fBTRANSFORMATION\fP" [\fIreference-point\fP] "\fB(\fP" \fItransformer\fP "\fB,\fP" \fIsentence\fP "\fB)\fP";
+\fIreference-point\fP ::= "\fB@\fP" \fIdecimal-number\fP;
+\fIreference\fP ::= "\fBREF(\fP" \fIdecimal-number\fP "\fB)\fP";
+\fIone-to-nine\fP ::= "\fB1\fP" | "\fB2\fP" | "\fB3\fP" | "\fB4\fP" | "\fB5\fP" | "\fB6\fP" | "\fB7\fP" | "\fB8\fP" | "\fB9\fP";
+\fIzero-to-nine\fP ::= "\fB0\fP" | \fIone-to-nine\fP;
+\fIdecimal-number\fP ::= "\fB0\fP" | \fIpositive-decimal\fP;
+\fIpositive-decimal\fP ::= \fIone-to-nine\fP [\fIdigits\fP];
+\fIdigits\fP ::= \fIzero-to-nine\fP [\fIdigits\fP];
+\fIsentence\fP ::= \fIconstant\fP | \fIunary\fP | \fIvariadic\fP | \fIqualified0\fP | \fIqualified1\fP |
+ \fIqualified2\fP |\fIatom\fP | \fItransformation\fP | \fIreference\fP;
+.fi
+.RE
+.PP
+where
+.I sentence
+is the root, and where
+.I map
+is parsed by
+.IR *spec->get_map ,
+.I variable
+is parsed by
+.IR *spec->get_variable ,
+.I function
+is parsed by
+.IR spec->get_function ,
+and
+.I transformer
+is parsed by
+.IR *spec->get_transformer .
+References must start at 0 and increment by one,
+in left-to-right order, every time a reference point
+is specified, and forward-references are not allowed
+(this includes reference to containing sentence (whose
+reference ID is lower because it is written earlier)).
+
+.SH NOTES
+The function will not attempt to deduplicate identical
+subsentences, but it will use any explicit deduplication.
+
+.SH SEE ALSO
+.BR libnormalform (7),
+.BR libnormalform_from_string (3)
diff --git a/man3/libnormalform_function.3 b/man3/libnormalform_function.3
new file mode 100644
index 0000000..d89c0e9
--- /dev/null
+++ b/man3/libnormalform_function.3
@@ -0,0 +1,152 @@
+.TH LIBNORMALFORM_FUNCTION 3 LIBNORMALFORM
+.SH NAME
+libnormalform_function \- Function with boolean codomain
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+struct libnormalform_function {
+ int (*\fIevaluate\fP)(void *user_data, void *input);
+ void *\fIuser_data\fP;
+ const char *\fIidentifier\fP;
+ struct libnormalform_function *\fIcopy_for_clone\fP;
+ struct libnormalform_function *\fIrelaxation\fP;
+ int \fIrequires_relaxation\fP;
+};
+
+LIBNORMALFORM_SENTENCE *libnormalform_function(struct libnormalform_function *\fIfunction\fP);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_function ()
+function creates a sentence object out
+of an application-managed function with
+a boolean output.
+.PP
+.I function->evaluate
+is used only be the
+.BR libnormalform_evaluate (3)
+function to determine the
+sentence's value for that specific
+call to the
+.BR libnormalform_evaluate (3)
+function.
+.I function->user_data is passed to
+.I *function->evaluate
+as its first argument, and the function
+input is passed as its second argument.
+The function is expected to return
+.I 1
+if the function is true for the input,
+.I 0
+if the function is false for the input,
+and
+.I -1
+on failure; on failure the function may
+optionally set
+.IR errno .
+.I function->user_data
+is only used by the application for
+application-defined purposes.
+.I function->user_data
+may, unlike
+.IR function->evalute ,
+be
+.IR NULL ;
+however
+.I function->evalute
+and
+.I function->user_data
+need not be set before the
+.BR libnormalform_evaluate (3)
+function is called.
+.PP
+See
+.BR libnormalform_to_string (3)
+for the purpose of
+.IR function->identifier ,
+it need not be set before the
+.BR libnormalform_to_string (3)
+function is called.
+.PP
+See
+.BR libnormalform_clone (3)
+for the purpose of
+.IR function->copy_for_clone ,
+it need not be set before the
+.BR libnormalform_clone (3)
+function is called.
+.PP
+See
+.BR libnormalform_express (3)
+for the purpose of
+.I function->relaxation
+and
+.IR function->requires_relaxation ,
+they need not be set before any of the
+.BR libnormalform_express (3),
+.BR libnormalform_dnf (3),
+and
+.BR libnormalform_cnf (3)
+functions are called.
+.PP
+.I function
+must not be
+.IR NULL .
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_function ()
+function returns an sentence object of
+the function; otherwise, the function
+returns
+.I NULL
+and sets
+.I errno
+to indicate the error.
+
+.SH ERRORS
+The
+.BR libnormalform_function ()
+function fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_function ()
+T} Thread safety MT-Safe
+T{
+.BR libnormalform_function ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_function ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH SEE ALSO
+.BR libnormalform (7),
+.BR libnormalform_variable (3)
diff --git a/man3/libnormalform_if.3 b/man3/libnormalform_if.3
new file mode 100644
index 0000000..86fde19
--- /dev/null
+++ b/man3/libnormalform_if.3
@@ -0,0 +1,233 @@
+.TH LIBNORMALFORM_IF 3 LIBNORMALFORM
+.SH NAME
+libnormalform_if \- Converse implication
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_if(LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_ifl(LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vif(LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_if_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_ifl_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vif_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_if2(LIBNORMALFORM_SENTENCE *\fIp\fP, LIBNORMALFORM_SENTENCE *\fIq\fP);
+#define LIBNORMALFORM_IF(...) /* ... */
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_if ()
+function creates a sentence that is logically
+equivalent to the converse implication of the
+arguments, that is, a clause that is only false
+when the first term is false despite all other
+terms being true.
+.PP
+The value of the
+.I xs
+parameter shall be a null-pointer terminated list
+of subsentences.
+.PP
+The
+.BR libnormalform_ifl ()
+function is a variant of
+.BR libnormalform_if ()
+which uses variadic arguments instead of an array.
+.PP
+The
+.BR libnormalform_vif ()
+function is a variant of
+.BR libnormalform_ifl ()
+which takes an
+.I va_list
+in place of variadic arguments.
+.PP
+The
+.BR libnormalform_if_checked (),
+.BR libnormalform_ifl_checked (),
+and
+.BR libnormalform_vif_checked ()
+functions are variants of the
+.BR libnormalform_if (),
+.BR libnormalform_ifl (),
+and
+.BR libnormalform_vif ()
+functions respectively which assumes
+that it is given
+.I n
+subsentances, and checks that all are
+.RI non- NULL .
+However, these functions still require
+the list of subsentences to be terminated
+using a null-pointer.
+.PP
+.I "libnormalform_if2(p, q)"
+is equivalent to
+.IR "libnormalform_ifl_checked(2, p, q, NULL)" .
+.PP
+The
+.BR LIBNORMALFORM_IF
+macro is a wrapper for the
+.BR libnormalform_if_checked ()
+but is more similar to
+.BR libnormalform_ifl ().
+Unlike
+.BR libnormalform_ifl (),
+the argument list
+.I must not
+be terminated by a null-pointer, instead
+the macro automatically as the null-pointer.
+The macro will count the number of arguments
+it is given, therefore it will fail it the
+argument list is has an extra null-pointer.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+These functions adopt the ownership of any
+.I LIBNORMALFORM_SENTENCE *
+passed into it. Therefore, the user shall
+not attempt to deallocate input sentences.
+This holds even on failure: if the function
+fails, input sentences are deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_if ()
+function and its variants return an object
+representing the sentence; otherwise, the
+functions return
+.I NULL
+and set
+.I errno
+to indicate the error.
+
+.SH ERRORS
+These functions fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.TP
+.I EDOM
+The function was not given any subsentences.
+.PP
+The
+.BR libnormalform_if_checked (),
+.BR libnormalform_ifl_checked (),
+and
+.BR libnormalform_vif_checked ()
+functions will also fail without setting
+.I errno
+if any of the first
+.I n
+.IR "LIBNORMALFORM_SENTENCE *" 's
+are
+.IR NULL .
+Likewise, the
+.BR libnormalform_if2 ()
+function will fail without setting
+.I errno
+if
+.I p
+or
+.I q
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_if (),
+.br
+.BR libnormalform_if_checked ()
+T} Thread safety MT-Safe race:\fIxs\fP and elements in \fIxs\fP
+T{
+.BR libnormalform_ifl (),
+.br
+.BR libnormalform_ifl_checked (),
+.br
+.BR libnormalform_if2 (),
+.br
+.BR LIBNORMALFORM_IF ()
+T} Thread safety MT-Safe race:parameters
+T{
+.BR libnormalform_vif (),
+.br
+.BR libnormalform_vif_checked ()
+T} Thread safety MT-Safe race:parameters and arguments in \fIargs\fP
+T{
+.BR libnormalform_if (),
+.br
+.BR libnormalform_ifl (),
+.br
+.BR libnormalform_vif (),
+.br
+.BR libnormalform_if_checked (),
+.br
+.BR libnormalform_ifl_checked (),
+.br
+.BR libnormalform_vif_checked (),
+.br
+.BR libnormalform_vif2 (),
+.br
+.BR LIBNORMALFORM_IF ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_if (),
+.br
+.BR libnormalform_ifl (),
+.br
+.BR libnormalform_vif (),
+.br
+.BR libnormalform_if_checked (),
+.br
+.BR libnormalform_ifl_checked (),
+.br
+.BR libnormalform_vif_checked (),
+.br
+.BR libnormalform_vif2 (),
+.br
+.BR LIBNORMALFORM_IF ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH NOTES
+The connective is non-commutative and left-associative. It's truthtable is (1101).
+.PP
+The
+.BR LIBNORMALFORM_IF ()
+macro requires ISO C23 support.
+.PP
+The
+.BR libnormalform_if ()
+is primary function, the other functions are
+just wrappers for the
+.BR libnormalform_if ()
+function.
+.PP
+Side-effects in the arguments of the macro
+.BR LIBNORMALFORM_IF ()
+are guaranteed to be applied exactly once.
+The side-effects in each macro are applied
+in no particular order.
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_if2.3 b/man3/libnormalform_if2.3
new file mode 120000
index 0000000..5bc98a1
--- /dev/null
+++ b/man3/libnormalform_if2.3
@@ -0,0 +1 @@
+libnormalform_if_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_if_checked.3 b/man3/libnormalform_if_checked.3
new file mode 120000
index 0000000..f5174b0
--- /dev/null
+++ b/man3/libnormalform_if_checked.3
@@ -0,0 +1 @@
+libnormalform_if.3 \ No newline at end of file
diff --git a/man3/libnormalform_ifl.3 b/man3/libnormalform_ifl.3
new file mode 120000
index 0000000..f5174b0
--- /dev/null
+++ b/man3/libnormalform_ifl.3
@@ -0,0 +1 @@
+libnormalform_if.3 \ No newline at end of file
diff --git a/man3/libnormalform_ifl_checked.3 b/man3/libnormalform_ifl_checked.3
new file mode 120000
index 0000000..5bc98a1
--- /dev/null
+++ b/man3/libnormalform_ifl_checked.3
@@ -0,0 +1 @@
+libnormalform_if_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_imply.3 b/man3/libnormalform_imply.3
new file mode 100644
index 0000000..b6e0284
--- /dev/null
+++ b/man3/libnormalform_imply.3
@@ -0,0 +1,236 @@
+.TH LIBNORMALFORM_IMPLY 3 LIBNORMALFORM
+.SH NAME
+libnormalform_imply \- Material implication
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_imply(LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_implyl(LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vimply(LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_imply_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_implyl_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vimply_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_imply2(LIBNORMALFORM_SENTENCE *\fIp\fP, LIBNORMALFORM_SENTENCE *\fIq\fP);
+#define LIBNORMALFORM_IMPLY(...) /* ... */
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_imply ()
+function creates a sentence that is logically
+equivalent to the material implication of the
+arguments, that is, a clause that is only false
+when the last term is false despite all other
+terms being true.
+.PP
+The value of the
+.I xs
+parameter shall be a null-pointer terminated list
+of subsentences.
+.PP
+The
+.BR libnormalform_implyl ()
+function is a variant of
+.BR libnormalform_imply ()
+which uses variadic arguments instead of an array.
+.PP
+The
+.BR libnormalform_vimply ()
+function is a variant of
+.BR libnormalform_implyl ()
+which takes an
+.I va_list
+in place of variadic arguments.
+.PP
+The
+.BR libnormalform_imply_checked (),
+.BR libnormalform_implyl_checked (),
+and
+.BR libnormalform_vimply_checked ()
+functions are variants of the
+.BR libnormalform_imply (),
+.BR libnormalform_implyl (),
+and
+.BR libnormalform_vimply ()
+functions respectively which assumes
+that it is given
+.I n
+subsentances, and checks that all are
+.RI non- NULL .
+However, these functions still require
+the list of subsentences to be terminated
+using a null-pointer.
+.PP
+.I "libnormalform_imply2(p, q)"
+is equivalent to
+.IR "libnormalform_implyl_checked(2, p, q, NULL)" .
+.PP
+The
+.BR LIBNORMALFORM_IMPLY
+macro is a wrapper for the
+.BR libnormalform_imply_checked ()
+but is more similar to
+.BR libnormalform_implyl ().
+Unlike
+.BR libnormalform_implyl (),
+the argument list
+.I must not
+be terminated by a null-pointer, instead
+the macro automatically as the null-pointer.
+The macro will count the number of arguments
+it is given, therefore it will fail it the
+argument list is has an extra null-pointer.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+These functions adopt the ownership of any
+.I LIBNORMALFORM_SENTENCE *
+passed into it. Therefore, the user shall
+not attempt to deallocate input sentences.
+This holds even on failure: if the function
+fails, input sentences are deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_imply ()
+function and its variants return an object
+representing the sentence; otherwise, the
+functions return
+.I NULL
+and set
+.I errno
+to indicate the error.
+
+.SH ERRORS
+These functions fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.PP
+The
+.BR libnormalform_imply_checked (),
+.BR libnormalform_implyl_checked (),
+and
+.BR libnormalform_vimply_checked ()
+functions will also fail without setting
+.I errno
+if any of the first
+.I n
+.IR "LIBNORMALFORM_SENTENCE *" 's
+are
+.IR NULL .
+Likewise, the
+.BR libnormalform_imply2 ()
+function will fail without setting
+.I errno
+if
+.I p
+or
+.I q
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_imply (),
+.br
+.BR libnormalform_imply_checked ()
+T} Thread safety MT-Safe race:\fIxs\fP and elements in \fIxs\fP
+T{
+.BR libnormalform_implyl (),
+.br
+.BR libnormalform_implyl_checked (),
+.br
+.BR libnormalform_imply2 (),
+.br
+.BR LIBNORMALFORM_IMPLY ()
+T} Thread safety MT-Safe race:parameters
+T{
+.BR libnormalform_vimply (),
+.br
+.BR libnormalform_vimply_checked ()
+T} Thread safety MT-Safe race:parameters and arguments in \fIargs\fP
+T{
+.BR libnormalform_imply (),
+.br
+.BR libnormalform_implyl (),
+.br
+.BR libnormalform_vimply (),
+.br
+.BR libnormalform_imply_checked (),
+.br
+.BR libnormalform_implyl_checked (),
+.br
+.BR libnormalform_vimply_checked (),
+.br
+.BR libnormalform_vimply2 (),
+.br
+.BR LIBNORMALFORM_IMPLY ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_imply (),
+.br
+.BR libnormalform_implyl (),
+.br
+.BR libnormalform_vimply (),
+.br
+.BR libnormalform_imply_checked (),
+.br
+.BR libnormalform_implyl_checked (),
+.br
+.BR libnormalform_vimply_checked (),
+.br
+.BR libnormalform_vimply2 (),
+.br
+.BR LIBNORMALFORM_IMPLY ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH NOTES
+If there are no subsentences, the resulting sentence is a tautology.
+.PP
+The connective is non-commutative and right-associative. It's truthtable is (1011).
+.PP
+The
+.BR LIBNORMALFORM_IMPLY ()
+macro requires ISO C23 support.
+.PP
+The
+.BR libnormalform_imply ()
+is primary function, the other functions are
+just wrappers for the
+.BR libnormalform_imply ()
+function, however
+.BR libnormalform_imply ()
+itself uses the
+.BR libnormalform_if ()
+function if it has subsentences.
+.PP
+Side-effects in the arguments of the macro
+.BR LIBNORMALFORM_IMPLY ()
+are guaranteed to be applied exactly once.
+The side-effects in each macro are applied
+in no particular order.
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_imply2.3 b/man3/libnormalform_imply2.3
new file mode 120000
index 0000000..d9d72bd
--- /dev/null
+++ b/man3/libnormalform_imply2.3
@@ -0,0 +1 @@
+libnormalform_imply_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_imply_checked.3 b/man3/libnormalform_imply_checked.3
new file mode 120000
index 0000000..8956d98
--- /dev/null
+++ b/man3/libnormalform_imply_checked.3
@@ -0,0 +1 @@
+libnormalform_imply.3 \ No newline at end of file
diff --git a/man3/libnormalform_implyl.3 b/man3/libnormalform_implyl.3
new file mode 120000
index 0000000..8956d98
--- /dev/null
+++ b/man3/libnormalform_implyl.3
@@ -0,0 +1 @@
+libnormalform_imply.3 \ No newline at end of file
diff --git a/man3/libnormalform_implyl_checked.3 b/man3/libnormalform_implyl_checked.3
new file mode 120000
index 0000000..d9d72bd
--- /dev/null
+++ b/man3/libnormalform_implyl_checked.3
@@ -0,0 +1 @@
+libnormalform_imply_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_map.3 b/man3/libnormalform_map.3
new file mode 120000
index 0000000..907aac0
--- /dev/null
+++ b/man3/libnormalform_map.3
@@ -0,0 +1 @@
+struct_libnormalform_map.3 \ No newline at end of file
diff --git a/man3/libnormalform_mapping.3 b/man3/libnormalform_mapping.3
new file mode 120000
index 0000000..7609d21
--- /dev/null
+++ b/man3/libnormalform_mapping.3
@@ -0,0 +1 @@
+struct_libnormalform_mapping.3 \ No newline at end of file
diff --git a/man3/libnormalform_nand.3 b/man3/libnormalform_nand.3
new file mode 100644
index 0000000..a3604ae
--- /dev/null
+++ b/man3/libnormalform_nand.3
@@ -0,0 +1,250 @@
+.TH LIBNORMALFORM_NAND 3 LIBNORMALFORM
+.SH NAME
+libnormalform_nand \- Alternative denial
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_nand(LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nandl(LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vnand(LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nand_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nandl_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vnand_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nand2(LIBNORMALFORM_SENTENCE *\fIp\fP, LIBNORMALFORM_SENTENCE *\fIq\fP);
+#define LIBNORMALFORM_NAND(...) /* ... */
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_nand ()
+function creates a sentence where each subsentence
+is connected with a NAND (alternative denial) operator.
+In the case that exactly two subsentences are given,
+this creates a clause that is true when and only when
+at least one is false. There is no generally meaningful
+interpretation if a NAND-clause containing more than
+two terms.
+.PP
+The value of the
+.I xs
+parameter shall be a null-pointer terminated list
+of subsentences.
+.PP
+The
+.BR libnormalform_nandl ()
+function is a variant of
+.BR libnormalform_nand ()
+which uses variadic arguments instead of an array.
+.PP
+The
+.BR libnormalform_vnand ()
+function is a variant of
+.BR libnormalform_nandl ()
+which takes an
+.I va_list
+in place of variadic arguments.
+.PP
+The
+.BR libnormalform_nand_checked (),
+.BR libnormalform_nandl_checked (),
+and
+.BR libnormalform_vnand_checked ()
+functions are variants of the
+.BR libnormalform_nand (),
+.BR libnormalform_nandl (),
+and
+.BR libnormalform_vnand ()
+functions respectively which assumes
+that it is given
+.I n
+subsentances, and checks that all are
+.RI non- NULL .
+However, these functions still require
+the list of subsentences to be terminated
+using a null-pointer.
+.PP
+.I "libnormalform_nand2(p, q)"
+is equivalent to
+.IR "libnormalform_nandl_checked(2, p, q, NULL)" .
+.PP
+The
+.BR LIBNORMALFORM_NAND
+macro is a wrapper for the
+.BR libnormalform_nand_checked ()
+but is more similar to
+.BR libnormalform_nandl ().
+Unlike
+.BR libnormalform_nandl (),
+the argument list
+.I must not
+be terminated by a null-pointer, instead
+the macro automatically as the null-pointer.
+The macro will count the number of arguments
+it is given, therefore it will fail it the
+argument list is has an extra null-pointer.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+These functions adopt the ownership of any
+.I LIBNORMALFORM_SENTENCE *
+passed into it. Therefore, the user shall
+not attempt to deallocate input sentences.
+This holds even on failure: if the function
+fails, input sentences are deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_nand ()
+function and its variants return an object
+representing the sentence; otherwise, the
+functions return
+.I NULL
+and set
+.I errno
+to indicate the error.
+
+.SH ERRORS
+These functions fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.TP
+.I EDOM
+The function was not given any subsentences.
+.PP
+The
+.BR libnormalform_nand_checked (),
+.BR libnormalform_nandl_checked (),
+and
+.BR libnormalform_vnand_checked ()
+functions will also fail without setting
+.I errno
+if any of the first
+.I n
+.IR "LIBNORMALFORM_SENTENCE *" 's
+are
+.IR NULL .
+Likewise, the
+.BR libnormalform_nand2 ()
+function will fail without setting
+.I errno
+if
+.I p
+or
+.I q
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_nand (),
+.br
+.BR libnormalform_nand_checked ()
+T} Thread safety MT-Safe race:\fIxs\fP and elements in \fIxs\fP
+T{
+.BR libnormalform_nandl (),
+.br
+.BR libnormalform_nandl_checked (),
+.br
+.BR libnormalform_nand2 (),
+.br
+.BR LIBNORMALFORM_NAND ()
+T} Thread safety MT-Safe race:parameters
+T{
+.BR libnormalform_vnand (),
+.br
+.BR libnormalform_vnand_checked ()
+T} Thread safety MT-Safe race:parameters and arguments in \fIargs\fP
+T{
+.BR libnormalform_nand (),
+.br
+.BR libnormalform_nandl (),
+.br
+.BR libnormalform_vnand (),
+.br
+.BR libnormalform_nand_checked (),
+.br
+.BR libnormalform_nandl_checked (),
+.br
+.BR libnormalform_vnand_checked (),
+.br
+.BR libnormalform_vnand2 (),
+.br
+.BR LIBNORMALFORM_NAND ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_nand (),
+.br
+.BR libnormalform_nandl (),
+.br
+.BR libnormalform_vnand (),
+.br
+.BR libnormalform_nand_checked (),
+.br
+.BR libnormalform_nandl_checked (),
+.br
+.BR libnormalform_vnand_checked (),
+.br
+.BR libnormalform_vnand2 (),
+.br
+.BR LIBNORMALFORM_NAND ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH NOTES
+The connective is commutative and left-associative. It's truthtable is (1110).
+.PP
+The
+.BR LIBNORMALFORM_NAND ()
+macro requires ISO C23 support.
+.PP
+The
+.BR libnormalform_nand ()
+is primary function, the other functions are
+just wrappers for the
+.BR libnormalform_nand ()
+function.
+.PP
+These functions creates a clause where each term
+is connected with the NAND connective. Unlike what
+the name Alternative denial imply, this does
+.I not
+create a sentence that is true when at most one
+subsentences is true. Nor does it unlike what the
+name Negated AND imply, this does
+.I not
+create a sentence that is true when at least
+one subsentence is false. There is unfortunately
+no generally meaningful interpretation: adding
+false term on the right always create a tautology,
+while adding a true term on the right inverts the
+original clause.
+.PP
+Side-effects in the arguments of the macro
+.BR LIBNORMALFORM_NAND ()
+are guaranteed to be applied exactly once.
+The side-effects in each macro are applied
+in no particular order.
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_nand2.3 b/man3/libnormalform_nand2.3
new file mode 120000
index 0000000..0a1c901
--- /dev/null
+++ b/man3/libnormalform_nand2.3
@@ -0,0 +1 @@
+libnormalform_nand_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_nand_checked.3 b/man3/libnormalform_nand_checked.3
new file mode 120000
index 0000000..e25f19a
--- /dev/null
+++ b/man3/libnormalform_nand_checked.3
@@ -0,0 +1 @@
+libnormalform_nand.3 \ No newline at end of file
diff --git a/man3/libnormalform_nandl.3 b/man3/libnormalform_nandl.3
new file mode 120000
index 0000000..e25f19a
--- /dev/null
+++ b/man3/libnormalform_nandl.3
@@ -0,0 +1 @@
+libnormalform_nand.3 \ No newline at end of file
diff --git a/man3/libnormalform_nandl_checked.3 b/man3/libnormalform_nandl_checked.3
new file mode 120000
index 0000000..0a1c901
--- /dev/null
+++ b/man3/libnormalform_nandl_checked.3
@@ -0,0 +1 @@
+libnormalform_nand_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_nexists.3 b/man3/libnormalform_nexists.3
new file mode 120000
index 0000000..eb792d0
--- /dev/null
+++ b/man3/libnormalform_nexists.3
@@ -0,0 +1 @@
+libnormalform_exists.3 \ No newline at end of file
diff --git a/man3/libnormalform_nif.3 b/man3/libnormalform_nif.3
new file mode 100644
index 0000000..174b9d4
--- /dev/null
+++ b/man3/libnormalform_nif.3
@@ -0,0 +1,239 @@
+.TH LIBNORMALFORM_NIF 3 LIBNORMALFORM
+.SH NAME
+libnormalform_nif \- Converse abjunction
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_nif(LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nifl(LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vnif(LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nif_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nifl_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vnif_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nif2(LIBNORMALFORM_SENTENCE *\fIp\fP, LIBNORMALFORM_SENTENCE *\fIq\fP);
+#define LIBNORMALFORM_NIF(...) /* ... */
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_nif ()
+function creates a sentence that is logically
+equivalent to the converse abjunction of the
+arguments.
+.PP
+The value of the
+.I xs
+parameter shall be a null-pointer terminated list
+of subsentences.
+.PP
+The
+.BR libnormalform_nifl ()
+function is a variant of
+.BR libnormalform_nif ()
+which uses variadic arguments instead of an array.
+.PP
+The
+.BR libnormalform_vnif ()
+function is a variant of
+.BR libnormalform_nifl ()
+which takes an
+.I va_list
+in place of variadic arguments.
+.PP
+The
+.BR libnormalform_nif_checked (),
+.BR libnormalform_nifl_checked (),
+and
+.BR libnormalform_vnif_checked ()
+functions are variants of the
+.BR libnormalform_nif (),
+.BR libnormalform_nifl (),
+and
+.BR libnormalform_vnif ()
+functions respectively which assumes
+that it is given
+.I n
+subsentances, and checks that all are
+.RI non- NULL .
+However, these functions still require
+the list of subsentences to be terminated
+using a null-pointer.
+.PP
+.I "libnormalform_nif2(p, q)"
+is equivalent to
+.IR "libnormalform_nifl_checked(2, p, q, NULL)" .
+.PP
+The
+.BR LIBNORMALFORM_NIF
+macro is a wrapper for the
+.BR libnormalform_nif_checked ()
+but is more similar to
+.BR libnormalform_nifl ().
+Unlike
+.BR libnormalform_nifl (),
+the argument list
+.I must not
+be terminated by a null-pointer, instead
+the macro automatically as the null-pointer.
+The macro will count the number of arguments
+it is given, therefore it will fail it the
+argument list is has an extra null-pointer.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+These functions adopt the ownership of any
+.I LIBNORMALFORM_SENTENCE *
+passed into it. Therefore, the user shall
+not attempt to deallocate input sentences.
+This holds even on failure: if the function
+fails, input sentences are deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_nif ()
+function and its variants return an object
+representing the sentence; otherwise, the
+functions return
+.I NULL
+and set
+.I errno
+to indicate the error.
+
+.SH ERRORS
+These functions fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.PP
+The
+.BR libnormalform_nif_checked (),
+.BR libnormalform_nifl_checked (),
+and
+.BR libnormalform_vnif_checked ()
+functions will also fail without setting
+.I errno
+if any of the first
+.I n
+.IR "LIBNORMALFORM_SENTENCE *" 's
+are
+.IR NULL .
+Likewise, the
+.BR libnormalform_nif2 ()
+function will fail without setting
+.I errno
+if
+.I p
+or
+.I q
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_nif (),
+.br
+.BR libnormalform_nif_checked ()
+T} Thread safety MT-Safe race:\fIxs\fP and elements in \fIxs\fP
+T{
+.BR libnormalform_nifl (),
+.br
+.BR libnormalform_nifl_checked (),
+.br
+.BR libnormalform_nif2 (),
+.br
+.BR LIBNORMALFORM_NIF ()
+T} Thread safety MT-Safe race:parameters
+T{
+.BR libnormalform_vnif (),
+.br
+.BR libnormalform_vnif_checked ()
+T} Thread safety MT-Safe race:parameters and arguments in \fIargs\fP
+T{
+.BR libnormalform_nif (),
+.br
+.BR libnormalform_nifl (),
+.br
+.BR libnormalform_vnif (),
+.br
+.BR libnormalform_nif_checked (),
+.br
+.BR libnormalform_nifl_checked (),
+.br
+.BR libnormalform_vnif_checked (),
+.br
+.BR libnormalform_vnif2 (),
+.br
+.BR LIBNORMALFORM_NIF ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_nif (),
+.br
+.BR libnormalform_nifl (),
+.br
+.BR libnormalform_vnif (),
+.br
+.BR libnormalform_nif_checked (),
+.br
+.BR libnormalform_nifl_checked (),
+.br
+.BR libnormalform_vnif_checked (),
+.br
+.BR libnormalform_vnif2 (),
+.br
+.BR LIBNORMALFORM_NIF ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH NOTES
+If there are no subsentences, the resulting sentence is a contradiction.
+.PP
+The connective is non-commutative and left-associative. It's truthtable is (0010).
+.PP
+The
+.BR LIBNORMALFORM_NIF ()
+macro requires ISO C23 support.
+.PP
+The
+.BR libnormalform_nif ()
+is primary function, the other functions are
+just wrappers for the
+.BR libnormalform_nif ()
+function.
+.PP
+These functions creates a clause where each term is
+connected with the NIF connective. There is
+unfortunately no generally meaningful interpretation:
+adding a false term on the left does not change the
+result but adding a true term on the left inverts the
+result only if all terms are true, whereas adding false
+term on the right creates a contradiction, while adding
+a true term on the right inverts the original clause.
+.PP
+Side-effects in the arguments of the macro
+.BR LIBNORMALFORM_NIF ()
+are guaranteed to be applied exactly once.
+The side-effects in each macro are applied
+in no particular order.
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_nif2.3 b/man3/libnormalform_nif2.3
new file mode 120000
index 0000000..5949db4
--- /dev/null
+++ b/man3/libnormalform_nif2.3
@@ -0,0 +1 @@
+libnormalform_nif_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_nif_checked.3 b/man3/libnormalform_nif_checked.3
new file mode 120000
index 0000000..d269483
--- /dev/null
+++ b/man3/libnormalform_nif_checked.3
@@ -0,0 +1 @@
+libnormalform_nif.3 \ No newline at end of file
diff --git a/man3/libnormalform_nifl.3 b/man3/libnormalform_nifl.3
new file mode 120000
index 0000000..d269483
--- /dev/null
+++ b/man3/libnormalform_nifl.3
@@ -0,0 +1 @@
+libnormalform_nif.3 \ No newline at end of file
diff --git a/man3/libnormalform_nifl_checked.3 b/man3/libnormalform_nifl_checked.3
new file mode 120000
index 0000000..5949db4
--- /dev/null
+++ b/man3/libnormalform_nifl_checked.3
@@ -0,0 +1 @@
+libnormalform_nif_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_nimply.3 b/man3/libnormalform_nimply.3
new file mode 100644
index 0000000..ca7a0e9
--- /dev/null
+++ b/man3/libnormalform_nimply.3
@@ -0,0 +1,241 @@
+.TH LIBNORMALFORM_NIMPLY 3 LIBNORMALFORM
+.SH NAME
+libnormalform_nimply \- Material abjunction
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_nimply(LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nimplyl(LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vnimply(LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nimply_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nimplyl_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vnimply_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nimply2(LIBNORMALFORM_SENTENCE *\fIp\fP, LIBNORMALFORM_SENTENCE *\fIq\fP);
+#define LIBNORMALFORM_NIMPLY(...) /* ... */
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_nimply ()
+function creates a sentence that is logically
+equivalent to the material abjunction of the
+arguments.
+.PP
+The value of the
+.I xs
+parameter shall be a null-pointer terminated list
+of subsentences.
+.PP
+The
+.BR libnormalform_nimplyl ()
+function is a variant of
+.BR libnormalform_nimply ()
+which uses variadic arguments instead of an array.
+.PP
+The
+.BR libnormalform_vnimply ()
+function is a variant of
+.BR libnormalform_nimplyl ()
+which takes an
+.I va_list
+in place of variadic arguments.
+.PP
+The
+.BR libnormalform_nimply_checked (),
+.BR libnormalform_nimplyl_checked (),
+and
+.BR libnormalform_vnimply_checked ()
+functions are variants of the
+.BR libnormalform_nimply (),
+.BR libnormalform_nimplyl (),
+and
+.BR libnormalform_vnimply ()
+functions respectively which assumes
+that it is given
+.I n
+subsentances, and checks that all are
+.RI non- NULL .
+However, these functions still require
+the list of subsentences to be terminated
+using a null-pointer.
+.PP
+.I "libnormalform_nimply2(p, q)"
+is equivalent to
+.IR "libnormalform_nimplyl_checked(2, p, q, NULL)" .
+.PP
+The
+.BR LIBNORMALFORM_NIMPLY
+macro is a wrapper for the
+.BR libnormalform_nimply_checked ()
+but is more similar to
+.BR libnormalform_nimplyl ().
+Unlike
+.BR libnormalform_nimplyl (),
+the argument list
+.I must not
+be terminated by a null-pointer, instead
+the macro automatically as the null-pointer.
+The macro will count the number of arguments
+it is given, therefore it will fail it the
+argument list is has an extra null-pointer.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+These functions adopt the ownership of any
+.I LIBNORMALFORM_SENTENCE *
+passed into it. Therefore, the user shall
+not attempt to deallocate input sentences.
+This holds even on failure: if the function
+fails, input sentences are deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_nimply ()
+function and its variants return an object
+representing the sentence; otherwise, the
+functions return
+.I NULL
+and set
+.I errno
+to indicate the error.
+
+.SH ERRORS
+These functions fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.TP
+.I EDOM
+The function was not given any subsentences.
+.PP
+The
+.BR libnormalform_nimply_checked (),
+.BR libnormalform_nimplyl_checked (),
+and
+.BR libnormalform_vnimply_checked ()
+functions will also fail without setting
+.I errno
+if any of the first
+.I n
+.IR "LIBNORMALFORM_SENTENCE *" 's
+are
+.IR NULL .
+Likewise, the
+.BR libnormalform_nimply2 ()
+function will fail without setting
+.I errno
+if
+.I p
+or
+.I q
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_nimply (),
+.br
+.BR libnormalform_nimply_checked ()
+T} Thread safety MT-Safe race:\fIxs\fP and elements in \fIxs\fP
+T{
+.BR libnormalform_nimplyl (),
+.br
+.BR libnormalform_nimplyl_checked (),
+.br
+.BR libnormalform_nimply2 (),
+.br
+.BR LIBNORMALFORM_NIMPLY ()
+T} Thread safety MT-Safe race:parameters
+T{
+.BR libnormalform_vnimply (),
+.br
+.BR libnormalform_vnimply_checked ()
+T} Thread safety MT-Safe race:parameters and arguments in \fIargs\fP
+T{
+.BR libnormalform_nimply (),
+.br
+.BR libnormalform_nimplyl (),
+.br
+.BR libnormalform_vnimply (),
+.br
+.BR libnormalform_nimply_checked (),
+.br
+.BR libnormalform_nimplyl_checked (),
+.br
+.BR libnormalform_vnimply_checked (),
+.br
+.BR libnormalform_vnimply2 (),
+.br
+.BR LIBNORMALFORM_NIMPLY ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_nimply (),
+.br
+.BR libnormalform_nimplyl (),
+.br
+.BR libnormalform_vnimply (),
+.br
+.BR libnormalform_nimply_checked (),
+.br
+.BR libnormalform_nimplyl_checked (),
+.br
+.BR libnormalform_vnimply_checked (),
+.br
+.BR libnormalform_vnimply2 (),
+.br
+.BR LIBNORMALFORM_NIMPLY ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH NOTES
+The connective is non-commutative and right-associative. It's truthtable is (0100).
+.PP
+The
+.BR LIBNORMALFORM_NIMPLY ()
+macro requires ISO C23 support.
+.PP
+The
+.BR libnormalform_nimply ()
+is primary function, the other functions are
+just wrappers for the
+.BR libnormalform_nimply ()
+function.
+.PP
+These functions creates a clause where each term is
+connected with the NIMPLY connective. There is
+unfortunately no generally meaningful interpretation:
+adding false term on the left creates a contradiction,
+while adding a true term on the left inverts the
+original clause, whereas adding a false term on the
+right does not change the result but adding a true
+term on the right inverts the result only if all terms
+are true.
+.PP
+Side-effects in the arguments of the macro
+.BR LIBNORMALFORM_NIMPLY ()
+are guaranteed to be applied exactly once.
+The side-effects in each macro are applied
+in no particular order.
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_nimply2.3 b/man3/libnormalform_nimply2.3
new file mode 120000
index 0000000..adb482f
--- /dev/null
+++ b/man3/libnormalform_nimply2.3
@@ -0,0 +1 @@
+libnormalform_nimply_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_nimply_checked.3 b/man3/libnormalform_nimply_checked.3
new file mode 120000
index 0000000..47711fc
--- /dev/null
+++ b/man3/libnormalform_nimply_checked.3
@@ -0,0 +1 @@
+libnormalform_nimply.3 \ No newline at end of file
diff --git a/man3/libnormalform_nimplyl.3 b/man3/libnormalform_nimplyl.3
new file mode 120000
index 0000000..47711fc
--- /dev/null
+++ b/man3/libnormalform_nimplyl.3
@@ -0,0 +1 @@
+libnormalform_nimply.3 \ No newline at end of file
diff --git a/man3/libnormalform_nimplyl_checked.3 b/man3/libnormalform_nimplyl_checked.3
new file mode 120000
index 0000000..adb482f
--- /dev/null
+++ b/man3/libnormalform_nimplyl_checked.3
@@ -0,0 +1 @@
+libnormalform_nimply_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_nonempty.3 b/man3/libnormalform_nonempty.3
new file mode 120000
index 0000000..899f515
--- /dev/null
+++ b/man3/libnormalform_nonempty.3
@@ -0,0 +1 @@
+libnormalform_any.3 \ No newline at end of file
diff --git a/man3/libnormalform_nor.3 b/man3/libnormalform_nor.3
new file mode 100644
index 0000000..164e8c5
--- /dev/null
+++ b/man3/libnormalform_nor.3
@@ -0,0 +1,245 @@
+.TH LIBNORMALFORM_NOR 3 LIBNORMALFORM
+.SH NAME
+libnormalform_nor \- Alternative denial
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_nor(LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_norl(LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vnor(LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nor_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_norl_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vnor_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_nor2(LIBNORMALFORM_SENTENCE *\fIp\fP, LIBNORMALFORM_SENTENCE *\fIq\fP);
+#define LIBNORMALFORM_NOR(...) /* ... */
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_nor ()
+function creates a sentence where each subsentence
+is connected with a NOR (alternative denial) operator.
+In the case that exactly two subsentences are given,
+this creates a clause that is true when and only when
+at least one is false. There is no generally meaningful
+interpretation if a NOR-clause containing more than
+two terms.
+.PP
+The value of the
+.I xs
+parameter shall be a null-pointer terminated list
+of subsentences.
+.PP
+The
+.BR libnormalform_norl ()
+function is a variant of
+.BR libnormalform_nor ()
+which uses variadic arguments instead of an array.
+.PP
+The
+.BR libnormalform_vnor ()
+function is a variant of
+.BR libnormalform_norl ()
+which takes an
+.I va_list
+in place of variadic arguments.
+.PP
+The
+.BR libnormalform_nor_checked (),
+.BR libnormalform_norl_checked (),
+and
+.BR libnormalform_vnor_checked ()
+functions are variants of the
+.BR libnormalform_nor (),
+.BR libnormalform_norl (),
+and
+.BR libnormalform_vnor ()
+functions respectively which assumes
+that it is given
+.I n
+subsentances, and checks that all are
+.RI non- NULL .
+However, these functions still require
+the list of subsentences to be terminated
+using a null-pointer.
+.PP
+.I "libnormalform_nor2(p, q)"
+is equivalent to
+.IR "libnormalform_norl_checked(2, p, q, NULL)" .
+.PP
+The
+.BR LIBNORMALFORM_NOR
+macro is a wrapper for the
+.BR libnormalform_nor_checked ()
+but is more similar to
+.BR libnormalform_norl ().
+Unlike
+.BR libnormalform_norl (),
+the argument list
+.I must not
+be terminated by a null-pointer, instead
+the macro automatically as the null-pointer.
+The macro will count the number of arguments
+it is given, therefore it will fail it the
+argument list is has an extra null-pointer.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+These functions adopt the ownership of any
+.I LIBNORMALFORM_SENTENCE *
+passed into it. Therefore, the user shall
+not attempt to deallocate input sentences.
+This holds even on failure: if the function
+fails, input sentences are deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_nor ()
+function and its variants return an object
+representing the sentence; otherwise, the
+functions return
+.I NULL
+and set
+.I errno
+to indicate the error.
+
+.SH ERRORS
+These functions fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.TP
+.I EDOM
+The function was not given any subsentences.
+.PP
+The
+.BR libnormalform_nor_checked (),
+.BR libnormalform_norl_checked (),
+and
+.BR libnormalform_vnor_checked ()
+functions will also fail without setting
+.I errno
+if any of the first
+.I n
+.IR "LIBNORMALFORM_SENTENCE *" 's
+are
+.IR NULL .
+Likewise, the
+.BR libnormalform_nor2 ()
+function will fail without setting
+.I errno
+if
+.I p
+or
+.I q
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_nor (),
+.br
+.BR libnormalform_nor_checked ()
+T} Thread safety MT-Safe race:\fIxs\fP and elements in \fIxs\fP
+T{
+.BR libnormalform_norl (),
+.br
+.BR libnormalform_norl_checked (),
+.br
+.BR libnormalform_nor2 (),
+.br
+.BR LIBNORMALFORM_NOR ()
+T} Thread safety MT-Safe race:parameters
+T{
+.BR libnormalform_vnor (),
+.br
+.BR libnormalform_vnor_checked ()
+T} Thread safety MT-Safe race:parameters and arguments in \fIargs\fP
+T{
+.BR libnormalform_nor (),
+.br
+.BR libnormalform_norl (),
+.br
+.BR libnormalform_vnor (),
+.br
+.BR libnormalform_nor_checked (),
+.br
+.BR libnormalform_norl_checked (),
+.br
+.BR libnormalform_vnor_checked (),
+.br
+.BR libnormalform_vnor2 (),
+.br
+.BR LIBNORMALFORM_NOR ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_nor (),
+.br
+.BR libnormalform_norl (),
+.br
+.BR libnormalform_vnor (),
+.br
+.BR libnormalform_nor_checked (),
+.br
+.BR libnormalform_norl_checked (),
+.br
+.BR libnormalform_vnor_checked (),
+.br
+.BR libnormalform_vnor2 (),
+.br
+.BR LIBNORMALFORM_NOR ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH NOTES
+The connective is commutative and left-associative. It's truthtable is (1000).
+.PP
+The
+.BR LIBNORMALFORM_NOR ()
+macro requires ISO C23 support.
+.PP
+The
+.BR libnormalform_nor ()
+is primary function, the other functions are
+just wrappers for the
+.BR libnormalform_nor ()
+function.
+.PP
+These functions creates a clause where each term is
+connected with the NOR connective. Unlike what the
+names Joint denial and Negated OR imply, this does
+.I not
+create a sentence that is true when all subsentences
+are false. There is unfortunately no generally
+meaningful interpretation: adding true term on the
+right always create a contradiction, while adding a
+false term on the right inverts the original clause.
+.PP
+Side-effects in the arguments of the macro
+.BR LIBNORMALFORM_NOR ()
+are guaranteed to be applied exactly once.
+The side-effects in each macro are applied
+in no particular order.
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_nor2.3 b/man3/libnormalform_nor2.3
new file mode 120000
index 0000000..acea879
--- /dev/null
+++ b/man3/libnormalform_nor2.3
@@ -0,0 +1 @@
+libnormalform_nor_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_nor_checked.3 b/man3/libnormalform_nor_checked.3
new file mode 120000
index 0000000..dd76dbe
--- /dev/null
+++ b/man3/libnormalform_nor_checked.3
@@ -0,0 +1 @@
+libnormalform_nor.3 \ No newline at end of file
diff --git a/man3/libnormalform_norl.3 b/man3/libnormalform_norl.3
new file mode 120000
index 0000000..dd76dbe
--- /dev/null
+++ b/man3/libnormalform_norl.3
@@ -0,0 +1 @@
+libnormalform_nor.3 \ No newline at end of file
diff --git a/man3/libnormalform_norl_checked.3 b/man3/libnormalform_norl_checked.3
new file mode 120000
index 0000000..acea879
--- /dev/null
+++ b/man3/libnormalform_norl_checked.3
@@ -0,0 +1 @@
+libnormalform_nor_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_not.3 b/man3/libnormalform_not.3
new file mode 100644
index 0000000..0ebe548
--- /dev/null
+++ b/man3/libnormalform_not.3
@@ -0,0 +1,92 @@
+.TH LIBNORMALFORM_NOT 3 LIBNORMALFORM
+.SH NAME
+libnormalform_not \- Negation
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_not(LIBNORMALFORM_SENTENCE *\fIx\fP);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_not ()
+function creates a sentence whose value is
+always the inverse of the value the sentence
+.I x
+takes.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+The
+.BR libnormalform_not ()
+function adopt the ownership of
+.IR x .
+Therefore, the user shall not attempt to
+deallocate
+.IR x .
+This holds even on failure: if the function
+fails,
+.I x
+is deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_not ()
+function returns an object representing
+the sentence; otherwise, the function returns
+.I NULL
+and sets
+.I errno
+to indicate the error.
+
+.SH ERRORS
+The
+.BR libnormalform_not ()
+function fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.PP
+The
+.BR libnormalform_not ()
+function also fails without setting
+.I errno
+if
+.I x
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_not ()
+T} Thread safety MT-Safe race:\fIx\fP
+T{
+.BR libnormalform_not ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_not ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_one.3 b/man3/libnormalform_one.3
new file mode 100644
index 0000000..bf79161
--- /dev/null
+++ b/man3/libnormalform_one.3
@@ -0,0 +1,253 @@
+.TH LIBNORMALFORM_ONE 3 LIBNORMALFORM
+.SH NAME
+libnormalform_one \- Unique existential qualifier
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+struct libnormalform_mapping {
+ void *\fIkey\fP;
+ void *\fIvalue\fP;
+};
+
+struct libnormalform_map {
+ struct libnormalform_mapping *\fImappings\fP;
+ size_t \fInmappings\fP;
+ void *\fIuser_data\fP;
+ const char *\fIidentifier\fP;
+ struct libnormalform_map *\fIcopy_for_clone\fP;
+};
+
+LIBNORMALFORM_SENTENCE *
+libnormalform_one(struct libnormalform_map *\fId\fP, LIBNORMALFORM_SENTENCE *\fIk\fP, LIBNORMALFORM_SENTENCE *\fIv\fP);
+
+LIBNORMALFORM_SENTENCE *
+libnormalform_unique(struct libnormalform_map *\fId\fP, LIBNORMALFORM_SENTENCE *\fIk\fP);
+
+LIBNORMALFORM_SENTENCE *
+libnormalform_uniquely(struct libnormalform_map *\fId\fP, LIBNORMALFORM_SENTENCE *\fIv\fP);
+
+LIBNORMALFORM_SENTENCE *
+libnormalform_singleton(struct libnormalform_map *\fId\fP);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_one ()
+function creates a sentence that is true
+when and only when the sentence
+.I v
+is true for the
+.I .value
+for exactly one element in
+.I d
+for which
+.I k
+is also true for the
+.I .key
+of the element.
+.PP
+The
+.BR libnormalform_unique ()
+function creates a sentence that is true
+when and only when the sentence
+.I k
+is true for the
+.I .key
+of exactly one element in
+.IR d .
+.PP
+The
+.BR libnormalform_uniquely ()
+function creates a sentence that is true
+when and only when the sentence
+.I v
+is true for the
+.I .value
+of exactly one element in
+.IR d .
+.PP
+The
+.BR libnormalform_singleton ()
+function creates a sentence that is true
+when and only when
+.IR d
+contains exactly one element.
+.PP
+.I d->mappings
+and
+.I d->nmappings
+is used only be the
+.BR libnormalform_evaluate (3)
+function and must be set before
+.BR libnormalform_evaluate (3)
+is called, but need not be set
+earlier.
+.I d->nmappings
+shall be set to number of elements in
+the qualifers domain of interest, and
+.I d->mappings
+shall be set to the list of elements
+in the domain. Each element shall have its
+.I .key
+set to the value the antecedent formula
+.RI ( k )
+is tested on, and
+.I .value
+set to the value the predicate formula
+.RI ( v )
+is tested on; these fields may be
+.IR NULL ,
+and are ultimately evaluated via
+arguments passed to the
+.BR libnormalform_function (3)
+function but may undergo transformation
+via arguments passed to the
+.BR libnormalform_transformation (3)
+function on the way.
+.PP
+The values
+.I d->mappings
+and
+.I d->nmappings
+may be set differently every time the
+.BR libnormalform_evaluate (3)
+is called.
+.PP
+Although unused, the
+.BR libnormalform_singleton ()
+function requires that
+.I d->mappings
+is properly set up (although the values
+in it can all be
+.IR NULL )
+before the
+.BR libnormalform_evaluate (3)
+function is called.
+.PP
+See
+.BR libnormalform_to_string (3)
+for the purpose of
+.IR d->identifier ,
+it need not be set before the
+.BR libnormalform_to_string (3)
+function is called.
+.PP
+See
+.BR libnormalform_clone (3)
+for the purpose of
+.IR d->copy_for_clone ,
+it need not be set before the
+.BR libnormalform_clone (3)
+function is called.
+.PP
+The application can set
+.I d->user_data
+set freely, and can opt to leave it
+unset. It is never used or reference
+by the library, but it could be used
+by the application to identify the
+domain.
+.PP
+.I d
+must not be
+.IR NULL .
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+These functions adopt the ownership of any
+.I LIBNORMALFORM_SENTENCE *
+passed into it. Therefore, the user shall
+not attempt to deallocate input sentences.
+This holds even on failure: if the function
+fails, input sentences are deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_one (),
+.BR libnormalform_unique (),
+.BR libnormalform_uniquely (),
+and
+.BR libnormalform_singleton ()
+functions return an object representing
+the sentence; otherwise, the functions
+return
+.I NULL
+and set
+.I errno
+to indicate the error.
+
+.SH ERRORS
+The
+.BR libnormalform_one (),
+.BR libnormalform_unique (),
+.BR libnormalform_uniquely (),
+and
+.BR libnormalform_singleton ()
+functions fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.PP
+These functions will also fail without setting
+.I errno
+if
+.I k
+or
+.I v
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_one (),
+.br
+.BR libnormalform_unique (),
+.br
+.BR libnormalform_uniquely ()
+T} Thread safety MT-Safe race:\fIk\fP,\fIv\fP
+T{
+.BR libnormalform_singleton ()
+T} Thread safety MT-Safe
+T{
+.BR libnormalform_one (),
+.br
+.BR libnormalform_unique (),
+.br
+.BR libnormalform_uniquely (),
+.br
+.BR libnormalform_singleton ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_one (),
+.br
+.BR libnormalform_unique (),
+.br
+.BR libnormalform_uniquely (),
+.br
+.BR libnormalform_singleton ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH SEE ALSO
+.BR libnormalform (7),
+.BR libnormalform_function (3)
diff --git a/man3/libnormalform_or.3 b/man3/libnormalform_or.3
new file mode 100644
index 0000000..9d57ee8
--- /dev/null
+++ b/man3/libnormalform_or.3
@@ -0,0 +1,233 @@
+.TH LIBNORMALFORM_OR 3 LIBNORMALFORM
+.SH NAME
+libnormalform_or \- Inclusive disjunction
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_or(LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_orl(LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vor(LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_or_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_orl_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vor_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_or2(LIBNORMALFORM_SENTENCE *\fIp\fP, LIBNORMALFORM_SENTENCE *\fIq\fP);
+#define LIBNORMALFORM_OR(...) /* ... */
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_or ()
+function creates a sentence that is logically
+equivalent to the inclusive disjunction of the
+arguments, that is, a sentence that is true when
+and only when at least one subsentence is true.
+.PP
+The value of the
+.I xs
+parameter shall be a null-pointer terminated list
+of subsentences.
+.PP
+The
+.BR libnormalform_orl ()
+function is a variant of
+.BR libnormalform_or ()
+which uses variadic arguments instead of an array.
+.PP
+The
+.BR libnormalform_vor ()
+function is a variant of
+.BR libnormalform_orl ()
+which takes an
+.I va_list
+in place of variadic arguments.
+.PP
+The
+.BR libnormalform_or_checked (),
+.BR libnormalform_orl_checked (),
+and
+.BR libnormalform_vor_checked ()
+functions are variants of the
+.BR libnormalform_or (),
+.BR libnormalform_orl (),
+and
+.BR libnormalform_vor ()
+functions respectively which assumes
+that it is given
+.I n
+subsentances, and checks that all are
+.RI non- NULL .
+However, these functions still require
+the list of subsentences to be terminated
+using a null-pointer.
+.PP
+.I "libnormalform_or2(p, q)"
+is equivalent to
+.IR "libnormalform_orl_checked(2, p, q, NULL)" .
+.PP
+The
+.BR LIBNORMALFORM_OR
+macro is a wrapper for the
+.BR libnormalform_or_checked ()
+but is more similar to
+.BR libnormalform_orl ().
+Unlike
+.BR libnormalform_orl (),
+the argument list
+.I must not
+be terminated by a null-pointer, instead
+the macro automatically as the null-pointer.
+The macro will count the number of arguments
+it is given, therefore it will fail it the
+argument list is has an extra null-pointer.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+These functions adopt the ownership of any
+.I LIBNORMALFORM_SENTENCE *
+passed into it. Therefore, the user shall
+not attempt to deallocate input sentences.
+This holds even on failure: if the function
+fails, input sentences are deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_or ()
+function and its variants return an object
+representing the sentence; otherwise, the
+functions return
+.I NULL
+and set
+.I errno
+to indicate the error.
+
+.SH ERRORS
+These functions fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.PP
+The
+.BR libnormalform_or_checked (),
+.BR libnormalform_orl_checked (),
+and
+.BR libnormalform_vor_checked ()
+functions will also fail without setting
+.I errno
+if any of the first
+.I n
+.IR "LIBNORMALFORM_SENTENCE *" 's
+are
+.IR NULL .
+Likewise, the
+.BR libnormalform_or2 ()
+function will fail without setting
+.I errno
+if
+.I p
+or
+.I q
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_or (),
+.br
+.BR libnormalform_or_checked ()
+T} Thread safety MT-Safe race:\fIxs\fP and elements in \fIxs\fP
+T{
+.BR libnormalform_orl (),
+.br
+.BR libnormalform_orl_checked (),
+.br
+.BR libnormalform_or2 (),
+.br
+.BR LIBNORMALFORM_OR ()
+T} Thread safety MT-Safe race:parameters
+T{
+.BR libnormalform_vor (),
+.br
+.BR libnormalform_vor_checked ()
+T} Thread safety MT-Safe race:parameters and arguments in \fIargs\fP
+T{
+.BR libnormalform_or (),
+.br
+.BR libnormalform_orl (),
+.br
+.BR libnormalform_vor (),
+.br
+.BR libnormalform_or_checked (),
+.br
+.BR libnormalform_orl_checked (),
+.br
+.BR libnormalform_vor_checked (),
+.br
+.BR libnormalform_vor2 (),
+.br
+.BR LIBNORMALFORM_OR ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_or (),
+.br
+.BR libnormalform_orl (),
+.br
+.BR libnormalform_vor (),
+.br
+.BR libnormalform_or_checked (),
+.br
+.BR libnormalform_orl_checked (),
+.br
+.BR libnormalform_vor_checked (),
+.br
+.BR libnormalform_vor2 (),
+.br
+.BR LIBNORMALFORM_OR ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH NOTES
+If there are no subsentences, the resulting sentence is a contradiction.
+.PP
+The connective is commutative and associative. It's truthtable is (0111).
+.PP
+The
+.BR LIBNORMALFORM_OR ()
+macro requires ISO C23 support.
+.PP
+Using
+.BR libnormalform_or2 (),
+has greatest performance, however
+.BR libnormalform_or ()
+is better at simplifying the sentence.
+The other functions are just wrappers for the
+.BR libnormalform_or ()
+function.
+.PP
+Side-effects in the arguments of the macro
+.BR LIBNORMALFORM_OR ()
+are guaranteed to be applied exactly once.
+The side-effects in each macro are applied
+in no particular order.
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_or2.3 b/man3/libnormalform_or2.3
new file mode 120000
index 0000000..3d2cdc4
--- /dev/null
+++ b/man3/libnormalform_or2.3
@@ -0,0 +1 @@
+libnormalform_or_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_or_checked.3 b/man3/libnormalform_or_checked.3
new file mode 120000
index 0000000..25bea64
--- /dev/null
+++ b/man3/libnormalform_or_checked.3
@@ -0,0 +1 @@
+libnormalform_or.3 \ No newline at end of file
diff --git a/man3/libnormalform_orl.3 b/man3/libnormalform_orl.3
new file mode 120000
index 0000000..25bea64
--- /dev/null
+++ b/man3/libnormalform_orl.3
@@ -0,0 +1 @@
+libnormalform_or.3 \ No newline at end of file
diff --git a/man3/libnormalform_orl_checked.3 b/man3/libnormalform_orl_checked.3
new file mode 120000
index 0000000..3d2cdc4
--- /dev/null
+++ b/man3/libnormalform_orl_checked.3
@@ -0,0 +1 @@
+libnormalform_or_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_ref.3 b/man3/libnormalform_ref.3
new file mode 100644
index 0000000..5592e48
--- /dev/null
+++ b/man3/libnormalform_ref.3
@@ -0,0 +1,111 @@
+.TH LIBNORMALFORM_REF 3 LIBNORMALFORM
+.SH NAME
+libnormalform_ref \- Acquire new reference
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_ref(LIBNORMALFORM_SENTENCE *\fIx\fP);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_ref ()
+function increases the reference count of
+.I x
+by one and returns
+.I x
+(it is advisable to treat the return pointer
+as unique but that it must be used in the
+same thread as the input pointer),
+letting the application input the sentence
+object to multiple sentences or multiple
+times in the same sentence.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_ref ()
+function returns
+.IR x ;
+otherwise, the function returns
+.I NULL
+and sets
+.I errno
+to indicate the error.
+
+.SH ERRORS
+The
+.BR libnormalform_ref ()
+function fails if:
+.TP
+.I ENOMEM
+The reference count of
+.I x
+was already maximised (at
+.IR SIZE_MAX );
+this would imply that something is wrong in the
+application, and it might as well abort.
+.PP
+The
+.BR libnormalform_ref ()
+function also fails without setting
+.I errno
+if
+.I x
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_ref ()
+T} Thread safety MT-Safe race:\fIx\fP
+T{
+.BR libnormalform_ref ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_ref ()
+T} Async-cancel safety AC-Unsafe heap
+.TE
+
+.SH APPLICATION USAGE
+The
+.B LIBNORMALFORM_SENTENCE
+type is not thread-safe. If you want to use an
+instance of it from two or more threads concurrently,
+you need to use the
+.BR libnormalform_clone (3)
+function to create a deep clone of the instance.
+Additionally applications shall assume that any
+.B LIBNORMALFORM_SENTENCE
+constructed using an instance of this type contains
+that instance and cannot be used concurrently, from
+another thread, with that instance or any other
+instance created with it, appart from instances
+created with the
+.BR libnormalform_clone (3)
+function.
+
+.SH SEE ALSO
+.BR libnormalform (7),
+.BR libnormalform_clone (3),
+.BR libnormalform_free (3)
diff --git a/man3/libnormalform_representation_spec.3 b/man3/libnormalform_representation_spec.3
new file mode 120000
index 0000000..a996c52
--- /dev/null
+++ b/man3/libnormalform_representation_spec.3
@@ -0,0 +1 @@
+struct_libnormalform_representation_spec.3 \ No newline at end of file
diff --git a/man3/libnormalform_sentence.3 b/man3/libnormalform_sentence.3
new file mode 120000
index 0000000..3f5af8c
--- /dev/null
+++ b/man3/libnormalform_sentence.3
@@ -0,0 +1 @@
+struct_libnormalform_sentence.3 \ No newline at end of file
diff --git a/man3/libnormalform_singleton.3 b/man3/libnormalform_singleton.3
new file mode 120000
index 0000000..5e3df78
--- /dev/null
+++ b/man3/libnormalform_singleton.3
@@ -0,0 +1 @@
+libnormalform_one.3 \ No newline at end of file
diff --git a/man3/libnormalform_to_string.3 b/man3/libnormalform_to_string.3
new file mode 100644
index 0000000..7008990
--- /dev/null
+++ b/man3/libnormalform_to_string.3
@@ -0,0 +1,105 @@
+.TH LIBNORMALFORM_TO_STRING 3 LIBNORMALFORM
+.SH NAME
+libnormalform_to_string \- Serialise into a string
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+char *libnormalform_to_string(LIBNORMALFORM_SENTENCE *\fIx\fP);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_to_string ()
+function creates a string representation if
+.I x
+designed for machine parsing, but can also be
+read by sufficiently literate humans.
+.PP
+Before calling the
+.BR libnormalform_to_string ()
+function, application provided objects in
+.I x
+must be configured for serialisation:
+.I .identifier
+in each
+.IR "struct libnormalform_variable" ,
+.IR "struct libnormalform_function" ,
+.IR "struct libnormalform_map" ,
+and
+.IR "struct libnormalform_transformer" ,
+shall either be set to the string representation,
+of the object, that can be parsed by the application
+without it being terminated by a null byte.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR free (3)
+function.
+.PP
+.I x
+must not be
+.IR NULL .
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_to_string ()
+function returns a null-byte terminated
+non-empty, ASCII string representation of
+.IR x ;
+otherwise, the function returns
+.I NULL
+and sets
+.I errno
+to indicate the error.
+
+.SH ERRORS
+The
+.BR libnormalform_to_string ()
+function fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+serialise the sentence object.
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_to_string ()
+T} Thread safety MT-Safe race:\fIx\fP
+T{
+.BR libnormalform_to_string ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_to_string ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH NOTES
+When a
+.I LIBNORMALFORM_SENTENCE
+is created, it is optimised (this includes eliminiation
+of redundant information and reordering) and reduced to
+into fewer types of connetives (it's reducted into negation
+normal form, except with XOR allowed, but not necessarily
+to any canonical form) during construction, so the
+.BR libnormalform_to_string ()
+function will not necessarily reproduce the sentence
+as it was specified when it was constructed.
+
+.SH SEE ALSO
+.BR libnormalform (7),
+.BR libnormalform_from_string (3)
diff --git a/man3/libnormalform_transformation.3 b/man3/libnormalform_transformation.3
new file mode 100644
index 0000000..7bb129e
--- /dev/null
+++ b/man3/libnormalform_transformation.3
@@ -0,0 +1,245 @@
+.TH LIBNORMALFORM_TRANSFORMATION 3 LIBNORMALFORM
+.SH PROLOGUE
+This document describes the function
+.BR libnormalform_transformation ,
+refer to
+.BR struct_libnormalform_transformation (3)
+for the type
+.IR "struct libnormalform_transformation" .
+
+.SH NAME
+libnormalform_transformation \- Function morphism
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+enum libnormalform_builtin_transformer {
+ \fILIBNORMALFORM_NOT_BUILT_IN\fP = 0,
+ \fILIBNORMALFORM_DOMAIN_VIEW\fP,
+ \fILIBNORMALFORM_IMAGE_VIEW\fP
+};
+
+struct libnormalform_transformer {
+ void *(*\fItransform\fP)(void *user_data, void *input);
+ void (*\fIdeallocate\fP)(void *user_data, void *output);
+ void *\fIuser_data\fP;
+ const char *\fIidentifier\fP;
+ struct libnormalform_transformer *\fIcopy_for_clone\fP;
+ int \fIrequires_elimination\fP;
+ enum libnormalform_builtin_transformer \fIbuiltin\fP;
+};
+
+LIBNORMALFORM_SENTENCE *libnormalform_transformation(struct libnormalform_transformer *\fIfunction\fP,
+ LIBNORMALFORM_SENTENCE *\fIsentence\fP);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_transformation ()
+function creates a sentence output
+the transformation with the application-defined
+.I function
+over a
+.IR sentence.
+The pointer
+.I function
+is application-managed, and must exists while
+the returned sentece exists.
+.PP
+.I function->transform
+is used only be the
+.BR libnormalform_evaluate (3)
+function to modify input to other
+functions (both
+.I struct libnormalform_function
+and
+.IR "struct libnormalform_transformer" ).
+.I function->user_data is passed to
+.I *function->transform
+as its first argument, and the function
+input is passed as its second argument.
+The function is expected to return a
+.RI non- NULL
+pointer upon successful completion and
+.I NULL
+on failure; on failure the function may
+optionally set
+.IR errno .
+If
+.I function->deallocate
+is
+.IR non -NULL ,
+but unless
+.I *function->transform
+returns
+.IR NULL ,
+the library will call
+.I *function->deallocate
+when the pointer returned by
+.I *function->transform
+is no longer needed.
+.I function->user_data is passed to
+.I *function->deallocate
+as its first argument, and the returned
+pointer is passed as its second argument.
+.I function->user_data
+is only used by the application for
+application-defined purposes.
+.I function->user_data
+and
+.I function->deallocate
+may, unlike
+.IR function->transform ,
+be
+.IR NULL ;
+however
+.IR function->transform ,
+.IR function->deallocate ,
+and
+.I function->user_data
+need not be set before the
+.BR libnormalform_evaluate (3)
+function is called.
+.PP
+See
+.BR libnormalform_to_string (3)
+for the purpose of
+.IR function->identifier ,
+it need not be set before the
+.BR libnormalform_to_string (3)
+function is called.
+.PP
+See
+.BR libnormalform_clone (3)
+for the purpose of
+.IR function->copy_for_clone ,
+it need not be set before the
+.BR libnormalform_clone (3)
+function is called.
+.PP
+See
+.BR libnormalform_express (3)
+for the purpose of
+.IR function->requires_elimination ,
+it need not be set before any of the
+.BR libnormalform_express (3),
+.BR libnormalform_dnf (3),
+and
+.BR libnormalform_cnf (3)
+functions are called.
+.PP
+See
+.BR libnormalform_express (3)
+for the purpose of
+.IR function->builtin ,
+the
+.BR libnormalform_transformation ()
+function always sets it to
+.IR LIBNORMALFORM_NOT_BUILT_IN .
+.PP
+.I function
+must not be
+.IR NULL .
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+The
+.BR libnormalform_transformation ()
+function adopt the ownership of
+.IR sentence .
+Therefore, the user shall not attempt to
+deallocate
+.IR sentence .
+This holds even on failure: if the function
+fails,
+.I sentence
+is deallocated.
+.PP
+.I *function->transform
+may be called multiple types for the same
+input even if it is only specified in a sentence
+once, therefore calling it multiple times must
+not have undesirable side effects. The function
+shall return equivalent output given equivalent
+input. Additionally for any functions F, G,
+T(F # G) must be equivalent to T(F) # T(G) for
+any operator #, where T is
+.IR *function->transform .
+Transformations over constants and variables
+are removed as these do not take any input.
+Transformations over qualifiers are illegal.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_transformation ()
+function returns an sentence object of
+the transformation; otherwise, the function
+returns
+.I NULL
+and sets
+.I errno
+to indicate the error.
+.PP
+The
+.BR libnormalform_transformation ()
+function also fails without setting
+.I errno
+if
+.I sentence
+is
+.IR NULL .
+
+.SH ERRORS
+The
+.BR libnormalform_transformation ()
+function fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.TP
+.I EDOM
+.I sentence
+contains a qualifier.
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_transformation ()
+T} Thread safety MT-Safe race:\fIsentence\fP
+T{
+.BR libnormalform_transformation ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_transformation ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH NOTES
+Sentences created with the
+.BR libnormalform_empty (),
+.BR libnormalform_nonempty (),
+and
+.BR libnormalform_singleton ()
+functions count as qualifiers and
+cannot be used in a transformation.
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_transformer.3 b/man3/libnormalform_transformer.3
new file mode 120000
index 0000000..9bb1a97
--- /dev/null
+++ b/man3/libnormalform_transformer.3
@@ -0,0 +1 @@
+struct_libnormalform_transformer.3 \ No newline at end of file
diff --git a/man3/libnormalform_true.3 b/man3/libnormalform_true.3
new file mode 100644
index 0000000..a5da907
--- /dev/null
+++ b/man3/libnormalform_true.3
@@ -0,0 +1,70 @@
+.TH LIBNORMALFORM_TRUE 3 LIBNORMALFORM
+.SH NAME
+libnormalform_true \- Tautology
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_true(void);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_true ()
+function creates a tautological sentence:
+a sentence that is always true, regardless
+of the its containing formula's input.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_true ()
+function returns an object representing
+the sentence; otherwise, the function returns
+.I NULL
+and sets
+.I errno
+to indicate the error.
+
+.SH ERRORS
+The
+.BR libnormalform_true ()
+function fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_true ()
+T} Thread safety MT-Safe
+T{
+.BR libnormalform_true ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_true ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_unique.3 b/man3/libnormalform_unique.3
new file mode 120000
index 0000000..5e3df78
--- /dev/null
+++ b/man3/libnormalform_unique.3
@@ -0,0 +1 @@
+libnormalform_one.3 \ No newline at end of file
diff --git a/man3/libnormalform_uniquely.3 b/man3/libnormalform_uniquely.3
new file mode 120000
index 0000000..5e3df78
--- /dev/null
+++ b/man3/libnormalform_uniquely.3
@@ -0,0 +1 @@
+libnormalform_one.3 \ No newline at end of file
diff --git a/man3/libnormalform_universally.3 b/man3/libnormalform_universally.3
new file mode 120000
index 0000000..e479a8c
--- /dev/null
+++ b/man3/libnormalform_universally.3
@@ -0,0 +1 @@
+libnormalform_all.3 \ No newline at end of file
diff --git a/man3/libnormalform_value.3 b/man3/libnormalform_value.3
new file mode 120000
index 0000000..9602858
--- /dev/null
+++ b/man3/libnormalform_value.3
@@ -0,0 +1 @@
+enum_libnormalform_value.3 \ No newline at end of file
diff --git a/man3/libnormalform_vand.3 b/man3/libnormalform_vand.3
new file mode 120000
index 0000000..32c5aa9
--- /dev/null
+++ b/man3/libnormalform_vand.3
@@ -0,0 +1 @@
+libnormalform_andl.3 \ No newline at end of file
diff --git a/man3/libnormalform_vand_checked.3 b/man3/libnormalform_vand_checked.3
new file mode 120000
index 0000000..b4cbf43
--- /dev/null
+++ b/man3/libnormalform_vand_checked.3
@@ -0,0 +1 @@
+libnormalform_andl_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_variable.3 b/man3/libnormalform_variable.3
new file mode 100644
index 0000000..ad30a37
--- /dev/null
+++ b/man3/libnormalform_variable.3
@@ -0,0 +1,127 @@
+.TH LIBNORMALFORM_VARIABLE 3 LIBNORMALFORM
+.SH NAME
+libnormalform_variable \- Boolean variable
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+enum libnormalform_value {
+ \fILIBNORMALFORM_FALSE\fP = 0,
+ \fILIBNORMALFORM_TRUE\fP = 1
+};
+
+struct libnormalform_variable {
+ enum libnormalform_value \fIvalue\fP;
+ void *\fIuser_data\fP;
+ const char *\fIidentifier;
+ struct libnormalform_variable *\fIcopy_for_clone\fP;
+};
+
+LIBNORMALFORM_SENTENCE *libnormalform_variable(struct libnormalform_variable *\fIvariable\fP);
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_variable ()
+function creates a sentence object out
+of an application-managed variable.
+.PP
+.I variable->value
+is used only be the
+.BR libnormalform_evaluate (3)
+function and must be set to either
+.I LIBNORMALFORM_FALSE
+or
+.I LIBNORMALFORM_TRUE
+before the
+.BR libnormalform_evaluate (3)
+function is called, to let the
+function know what value the
+variable has for that specific
+call to the
+.BR libnormalform_evaluate (3)
+function.
+.PP
+See
+.BR libnormalform_to_string (3)
+for the purpose of
+.IR variable->identifier ,
+it need not be set before the
+.BR libnormalform_to_string (3)
+function is called.
+.PP
+See
+.BR libnormalform_clone (3)
+for the purpose of
+.IR variable->copy_for_clone ,
+it need not be set before the
+.BR libnormalform_clone (3)
+function is called.
+.PP
+The application can set
+.I variable->user_data
+set freely, and can opt to leave it
+unset. It is never used or reference
+by the library, but it could be used
+by the application to identify the
+variable.
+.PP
+.I variable
+must not be
+.IR NULL .
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_variable ()
+function returns an sentence object of
+the variable; otherwise, the function
+returns
+.I NULL
+and sets
+.I errno
+to indicate the error.
+
+.SH ERRORS
+The
+.BR libnormalform_variable ()
+function fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_variable ()
+T} Thread safety MT-Safe
+T{
+.BR libnormalform_variable ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_variable ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH SEE ALSO
+.BR libnormalform (7),
+.BR libnormalform_function (3)
diff --git a/man3/libnormalform_vif.3 b/man3/libnormalform_vif.3
new file mode 120000
index 0000000..8c9a9cd
--- /dev/null
+++ b/man3/libnormalform_vif.3
@@ -0,0 +1 @@
+libnormalform_ifl.3 \ No newline at end of file
diff --git a/man3/libnormalform_vif_checked.3 b/man3/libnormalform_vif_checked.3
new file mode 120000
index 0000000..6b5aa3c
--- /dev/null
+++ b/man3/libnormalform_vif_checked.3
@@ -0,0 +1 @@
+libnormalform_ifl_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_vimply.3 b/man3/libnormalform_vimply.3
new file mode 120000
index 0000000..b973027
--- /dev/null
+++ b/man3/libnormalform_vimply.3
@@ -0,0 +1 @@
+libnormalform_implyl.3 \ No newline at end of file
diff --git a/man3/libnormalform_vimply_checked.3 b/man3/libnormalform_vimply_checked.3
new file mode 120000
index 0000000..777fe30
--- /dev/null
+++ b/man3/libnormalform_vimply_checked.3
@@ -0,0 +1 @@
+libnormalform_implyl_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_vnand.3 b/man3/libnormalform_vnand.3
new file mode 120000
index 0000000..a6f43be
--- /dev/null
+++ b/man3/libnormalform_vnand.3
@@ -0,0 +1 @@
+libnormalform_nandl.3 \ No newline at end of file
diff --git a/man3/libnormalform_vnand_checked.3 b/man3/libnormalform_vnand_checked.3
new file mode 120000
index 0000000..c7005ad
--- /dev/null
+++ b/man3/libnormalform_vnand_checked.3
@@ -0,0 +1 @@
+libnormalform_nandl_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_vnif.3 b/man3/libnormalform_vnif.3
new file mode 120000
index 0000000..fecbc72
--- /dev/null
+++ b/man3/libnormalform_vnif.3
@@ -0,0 +1 @@
+libnormalform_nifl.3 \ No newline at end of file
diff --git a/man3/libnormalform_vnif_checked.3 b/man3/libnormalform_vnif_checked.3
new file mode 120000
index 0000000..52f1181
--- /dev/null
+++ b/man3/libnormalform_vnif_checked.3
@@ -0,0 +1 @@
+libnormalform_nifl_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_vnimply.3 b/man3/libnormalform_vnimply.3
new file mode 120000
index 0000000..c4fb4a5
--- /dev/null
+++ b/man3/libnormalform_vnimply.3
@@ -0,0 +1 @@
+libnormalform_nimplyl.3 \ No newline at end of file
diff --git a/man3/libnormalform_vnimply_checked.3 b/man3/libnormalform_vnimply_checked.3
new file mode 120000
index 0000000..f768f8c
--- /dev/null
+++ b/man3/libnormalform_vnimply_checked.3
@@ -0,0 +1 @@
+libnormalform_nimplyl_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_vnor.3 b/man3/libnormalform_vnor.3
new file mode 120000
index 0000000..7247725
--- /dev/null
+++ b/man3/libnormalform_vnor.3
@@ -0,0 +1 @@
+libnormalform_norl.3 \ No newline at end of file
diff --git a/man3/libnormalform_vnor_checked.3 b/man3/libnormalform_vnor_checked.3
new file mode 120000
index 0000000..b11849c
--- /dev/null
+++ b/man3/libnormalform_vnor_checked.3
@@ -0,0 +1 @@
+libnormalform_norl_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_vor.3 b/man3/libnormalform_vor.3
new file mode 120000
index 0000000..27a0be5
--- /dev/null
+++ b/man3/libnormalform_vor.3
@@ -0,0 +1 @@
+libnormalform_orl.3 \ No newline at end of file
diff --git a/man3/libnormalform_vor_checked.3 b/man3/libnormalform_vor_checked.3
new file mode 120000
index 0000000..da75167
--- /dev/null
+++ b/man3/libnormalform_vor_checked.3
@@ -0,0 +1 @@
+libnormalform_orl_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_vxnor.3 b/man3/libnormalform_vxnor.3
new file mode 120000
index 0000000..6f2ae2d
--- /dev/null
+++ b/man3/libnormalform_vxnor.3
@@ -0,0 +1 @@
+libnormalform_xnorl.3 \ No newline at end of file
diff --git a/man3/libnormalform_vxnor_checked.3 b/man3/libnormalform_vxnor_checked.3
new file mode 120000
index 0000000..2f6251f
--- /dev/null
+++ b/man3/libnormalform_vxnor_checked.3
@@ -0,0 +1 @@
+libnormalform_xnorl_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_vxor.3 b/man3/libnormalform_vxor.3
new file mode 120000
index 0000000..08ad00c
--- /dev/null
+++ b/man3/libnormalform_vxor.3
@@ -0,0 +1 @@
+libnormalform_xorl.3 \ No newline at end of file
diff --git a/man3/libnormalform_vxor_checked.3 b/man3/libnormalform_vxor_checked.3
new file mode 120000
index 0000000..89c3126
--- /dev/null
+++ b/man3/libnormalform_vxor_checked.3
@@ -0,0 +1 @@
+libnormalform_xorl_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_xnor.3 b/man3/libnormalform_xnor.3
new file mode 100644
index 0000000..56a3cab
--- /dev/null
+++ b/man3/libnormalform_xnor.3
@@ -0,0 +1,245 @@
+.TH LIBNORMALFORM_XNOR 3 LIBNORMALFORM
+.SH NAME
+libnormalform_xnor \- Logical equivalence
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_xnor(LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_xnorl(LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vxnor(LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_xnor_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_xnorl_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vxnor_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_xnor2(LIBNORMALFORM_SENTENCE *\fIp\fP, LIBNORMALFORM_SENTENCE *\fIq\fP);
+#define LIBNORMALFORM_XNOR(...) /* ... */
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_xnor ()
+function creates a sentence that is logically
+equivalent to the logical equivalecne of the
+arguments, that is, a sentence that is true
+exactly when the parity of the subsentences
+equal to whether the number of subsentences is odd.
+.PP
+The value of the
+.I xs
+parameter shall be a null-pointer terminated list
+of subsentences.
+.PP
+The
+.BR libnormalform_xnorl ()
+function is a variant of
+.BR libnormalform_xnor ()
+which uses variadic arguments instead of an array.
+.PP
+The
+.BR libnormalform_vxnor ()
+function is a variant of
+.BR libnormalform_xnorl ()
+which takes an
+.I va_list
+in place of variadic arguments.
+.PP
+The
+.BR libnormalform_xnor_checked (),
+.BR libnormalform_xnorl_checked (),
+and
+.BR libnormalform_vxnor_checked ()
+functions are variants of the
+.BR libnormalform_xnor (),
+.BR libnormalform_xnorl (),
+and
+.BR libnormalform_vxnor ()
+functions respectively which assumes
+that it is given
+.I n
+subsentances, and checks that all are
+.RI non- NULL .
+However, these functions still require
+the list of subsentences to be terminated
+using a null-pointer.
+.PP
+.I "libnormalform_xnor2(p, q)"
+is equivalent to
+.IR "libnormalform_xnorl_checked(2, p, q, NULL)" .
+.PP
+The
+.BR LIBNORMALFORM_XNOR
+macro is a wrapper for the
+.BR libnormalform_xnor_checked ()
+but is more similar to
+.BR libnormalform_xnorl ().
+Unlike
+.BR libnormalform_xnorl (),
+the argument list
+.I must not
+be terminated by a null-pointer, instead
+the macro automatically as the null-pointer.
+The macro will count the number of arguments
+it is given, therefore it will fail it the
+argument list is has an extra null-pointer.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+These functions adopt the ownership of any
+.I LIBNORMALFORM_SENTENCE *
+passed into it. Therefore, the user shall
+not attempt to deallocate input sentences.
+This holds even on failure: if the function
+fails, input sentences are deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_xnor ()
+function and its variants return an object
+representing the sentence; otherwise, the
+functions return
+.I NULL
+and set
+.I errno
+to indicate the error.
+
+.SH ERRORS
+These functions fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.PP
+The
+.BR libnormalform_xnor_checked (),
+.BR libnormalform_xnorl_checked (),
+and
+.BR libnormalform_vxnor_checked ()
+functions will also fail without setting
+.I errno
+if any of the first
+.I n
+.IR "LIBNORMALFORM_SENTENCE *" 's
+are
+.IR NULL .
+Likewise, the
+.BR libnormalform_xnor2 ()
+function will fail without setting
+.I errno
+if
+.I p
+or
+.I q
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_xnor (),
+.br
+.BR libnormalform_xnor_checked ()
+T} Thread safety MT-Safe race:\fIxs\fP and elements in \fIxs\fP
+T{
+.BR libnormalform_xnorl (),
+.br
+.BR libnormalform_xnorl_checked (),
+.br
+.BR libnormalform_xnor2 (),
+.br
+.BR LIBNORMALFORM_XNOR ()
+T} Thread safety MT-Safe race:parameters
+T{
+.BR libnormalform_vxnor (),
+.br
+.BR libnormalform_vxnor_checked ()
+T} Thread safety MT-Safe race:parameters and arguments in \fIargs\fP
+T{
+.BR libnormalform_xnor (),
+.br
+.BR libnormalform_xnorl (),
+.br
+.BR libnormalform_vxnor (),
+.br
+.BR libnormalform_xnor_checked (),
+.br
+.BR libnormalform_xnorl_checked (),
+.br
+.BR libnormalform_vxnor_checked (),
+.br
+.BR libnormalform_vxnor2 (),
+.br
+.BR LIBNORMALFORM_XNOR ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_xnor (),
+.br
+.BR libnormalform_xnorl (),
+.br
+.BR libnormalform_vxnor (),
+.br
+.BR libnormalform_xnor_checked (),
+.br
+.BR libnormalform_xnorl_checked (),
+.br
+.BR libnormalform_vxnor_checked (),
+.br
+.BR libnormalform_vxnor2 (),
+.br
+.BR LIBNORMALFORM_XNOR ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH NOTES
+If there are no subsentences, the resulting sentence is a tautology.
+.PP
+The connective is commutative and associative. It's truthtable is (1001).
+.PP
+The
+.BR LIBNORMALFORM_XNOR ()
+macro requires ISO C23 support.
+.PP
+Using
+.BR libnormalform_xnor2 (),
+has greatest performance, however
+.BR libnormalform_xnor ()
+is better at simplifying the sentence.
+The other functions are just wrappers for the
+.BR libnormalform_xnor ()
+function.
+.PP
+These functions creates a clause where each term
+is connected with the XNOR connective. Unlike what
+the name Logical equivalence, this does
+.I not
+create a sentence that is true when all subsentences
+have the same value (this is only the case when there
+are 2 or 0 subsentences). Rather, when the number
+of terms is odd, it is equivalent to the parity (XOR)
+of the terms, but when the number of terms is odd, it
+is the inverse of the parity.
+.PP
+Side-effects in the arguments of the macro
+.BR LIBNORMALFORM_XNOR ()
+are guaranteed to be applied exactly once.
+The side-effects in each macro are applied
+in no particular order.
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_xnor2.3 b/man3/libnormalform_xnor2.3
new file mode 120000
index 0000000..2c62e7a
--- /dev/null
+++ b/man3/libnormalform_xnor2.3
@@ -0,0 +1 @@
+libnormalform_xnor_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_xnor_checked.3 b/man3/libnormalform_xnor_checked.3
new file mode 120000
index 0000000..49b2b6c
--- /dev/null
+++ b/man3/libnormalform_xnor_checked.3
@@ -0,0 +1 @@
+libnormalform_xnor.3 \ No newline at end of file
diff --git a/man3/libnormalform_xnorl.3 b/man3/libnormalform_xnorl.3
new file mode 120000
index 0000000..49b2b6c
--- /dev/null
+++ b/man3/libnormalform_xnorl.3
@@ -0,0 +1 @@
+libnormalform_xnor.3 \ No newline at end of file
diff --git a/man3/libnormalform_xnorl_checked.3 b/man3/libnormalform_xnorl_checked.3
new file mode 120000
index 0000000..2c62e7a
--- /dev/null
+++ b/man3/libnormalform_xnorl_checked.3
@@ -0,0 +1 @@
+libnormalform_xnor_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_xor.3 b/man3/libnormalform_xor.3
new file mode 100644
index 0000000..70e9584
--- /dev/null
+++ b/man3/libnormalform_xor.3
@@ -0,0 +1,242 @@
+.TH LIBNORMALFORM_XOR 3 LIBNORMALFORM
+.SH NAME
+libnormalform_xor \- Exclusive disjunction
+
+.SH SYNOPSIS
+.nf
+#include <libnormalform.h>
+
+LIBNORMALFORM_SENTENCE *libnormalform_xor(LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_xorl(LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vxor(LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_xor_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE **\fIxs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_xorl_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, ... /*, NULL */);
+LIBNORMALFORM_SENTENCE *libnormalform_vxor_checked(size_t \fIn\fP, LIBNORMALFORM_SENTENCE *\fIa\fP, va_list \fPargs\fP);
+LIBNORMALFORM_SENTENCE *libnormalform_xor2(LIBNORMALFORM_SENTENCE *\fIp\fP, LIBNORMALFORM_SENTENCE *\fIq\fP);
+#define LIBNORMALFORM_XOR(...) /* ... */
+.fi
+.PP
+Link with
+.IR -lnormalform .
+
+.SH DESCRIPTION
+The
+.BR libnormalform_xor ()
+function creates a sentence that is logically
+equivalent to the exclusive disjunction of the
+arguments, that is, a sentence that is true when
+and only when an odd number of subsentence is true.
+.PP
+The value of the
+.I xs
+parameter shall be a null-pointer terminated list
+of subsentences.
+.PP
+The
+.BR libnormalform_xorl ()
+function is a variant of
+.BR libnormalform_xor ()
+which uses variadic arguments instead of an array.
+.PP
+The
+.BR libnormalform_vxor ()
+function is a variant of
+.BR libnormalform_xorl ()
+which takes an
+.I va_list
+in place of variadic arguments.
+.PP
+The
+.BR libnormalform_xor_checked (),
+.BR libnormalform_xorl_checked (),
+and
+.BR libnormalform_vxor_checked ()
+functions are variants of the
+.BR libnormalform_xor (),
+.BR libnormalform_xorl (),
+and
+.BR libnormalform_vxor ()
+functions respectively which assumes
+that it is given
+.I n
+subsentances, and checks that all are
+.RI non- NULL .
+However, these functions still require
+the list of subsentences to be terminated
+using a null-pointer.
+.PP
+.I "libnormalform_xor2(p, q)"
+is equivalent to
+.IR "libnormalform_xorl_checked(2, p, q, NULL)" .
+.PP
+The
+.BR LIBNORMALFORM_XOR
+macro is a wrapper for the
+.BR libnormalform_xor_checked ()
+but is more similar to
+.BR libnormalform_xorl ().
+Unlike
+.BR libnormalform_xorl (),
+the argument list
+.I must not
+be terminated by a null-pointer, instead
+the macro automatically as the null-pointer.
+The macro will count the number of arguments
+it is given, therefore it will fail it the
+argument list is has an extra null-pointer.
+.PP
+The returned pointer shall either be
+deallocated with the
+.BR libnormalform_free (3)
+function or be relinquished by being
+used as part of another sentence.
+.PP
+These functions adopt the ownership of any
+.I LIBNORMALFORM_SENTENCE *
+passed into it. Therefore, the user shall
+not attempt to deallocate input sentences.
+This holds even on failure: if the function
+fails, input sentences are deallocated.
+
+.SH RETURN VALUE
+Upon successful completion, the
+.BR libnormalform_xor ()
+function and its variants return an object
+representing the sentence; otherwise, the
+functions return
+.I NULL
+and set
+.I errno
+to indicate the error.
+
+.SH ERRORS
+These functions fails if:
+.TP
+.I ENOMEM
+Insufficient memory was available to
+create the sentence object.
+.PP
+The
+.BR libnormalform_xor_checked (),
+.BR libnormalform_xorl_checked (),
+and
+.BR libnormalform_vxor_checked ()
+functions will also fail without setting
+.I errno
+if any of the first
+.I n
+.IR "LIBNORMALFORM_SENTENCE *" 's
+are
+.IR NULL .
+Likewise, the
+.BR libnormalform_xor2 ()
+function will fail without setting
+.I errno
+if
+.I p
+or
+.I q
+is
+.IR NULL .
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this
+section, see
+.BR attributes (7)
+and
+.IR "info \(dq(libc)POSIX Safety Concepts\(dq" .
+.TS
+allbox;
+lb lb lb
+l l l.
+Interface Attribute Value
+T{
+.BR libnormalform_xor (),
+.br
+.BR libnormalform_xor_checked ()
+T} Thread safety MT-Safe race:\fIxs\fP and elements in \fIxs\fP
+T{
+.BR libnormalform_xorl (),
+.br
+.BR libnormalform_xorl_checked (),
+.br
+.BR libnormalform_xor2 (),
+.br
+.BR LIBNORMALFORM_XOR ()
+T} Thread safety MT-Safe race:parameters
+T{
+.BR libnormalform_vxor (),
+.br
+.BR libnormalform_vxor_checked ()
+T} Thread safety MT-Safe race:parameters and arguments in \fIargs\fP
+T{
+.BR libnormalform_xor (),
+.br
+.BR libnormalform_xorl (),
+.br
+.BR libnormalform_vxor (),
+.br
+.BR libnormalform_xor_checked (),
+.br
+.BR libnormalform_xorl_checked (),
+.br
+.BR libnormalform_vxor_checked (),
+.br
+.BR libnormalform_vxor2 (),
+.br
+.BR LIBNORMALFORM_XOR ()
+T} Async-signal safety AS-Unsafe heap
+T{
+.BR libnormalform_xor (),
+.br
+.BR libnormalform_xorl (),
+.br
+.BR libnormalform_vxor (),
+.br
+.BR libnormalform_xor_checked (),
+.br
+.BR libnormalform_xorl_checked (),
+.br
+.BR libnormalform_vxor_checked (),
+.br
+.BR libnormalform_vxor2 (),
+.br
+.BR LIBNORMALFORM_XOR ()
+T} Async-cancel safety AC-Safe mem, AC-Unsafe heap
+.TE
+
+.SH NOTES
+If there are no subsentences, the resulting sentence is a contradiction.
+.PP
+The connective is commutative and associative. It's truthtable is (0110).
+.PP
+The
+.BR LIBNORMALFORM_XOR ()
+macro requires ISO C23 support.
+.PP
+Using
+.BR libnormalform_xor2 (),
+has greatest performance, however
+.BR libnormalform_xor ()
+is better at simplifying the sentence.
+The other functions are just wrappers for the
+.BR libnormalform_xor ()
+function.
+.PP
+These functions creates a clause where each term
+is connected with the XOR connective. Unlike what
+the name Exclusive disjunction imply, this does
+.I not
+create a sentence that is true when exactly one
+subsentence is true. Rather this creates the parity
+of the terms: the sentece is when an odd number of
+subsentences are true.
+.PP
+Side-effects in the arguments of the macro
+.BR LIBNORMALFORM_XOR ()
+are guaranteed to be applied exactly once.
+The side-effects in each macro are applied
+in no particular order.
+
+.SH SEE ALSO
+.BR libnormalform (7)
diff --git a/man3/libnormalform_xor2.3 b/man3/libnormalform_xor2.3
new file mode 120000
index 0000000..cd0eb39
--- /dev/null
+++ b/man3/libnormalform_xor2.3
@@ -0,0 +1 @@
+libnormalform_xor_checked.3 \ No newline at end of file
diff --git a/man3/libnormalform_xor_checked.3 b/man3/libnormalform_xor_checked.3
new file mode 120000
index 0000000..7da4f32
--- /dev/null
+++ b/man3/libnormalform_xor_checked.3
@@ -0,0 +1 @@
+libnormalform_xor.3 \ No newline at end of file
diff --git a/man3/libnormalform_xorl.3 b/man3/libnormalform_xorl.3
new file mode 120000
index 0000000..7da4f32
--- /dev/null
+++ b/man3/libnormalform_xorl.3
@@ -0,0 +1 @@
+libnormalform_xor.3 \ No newline at end of file
diff --git a/man3/libnormalform_xorl_checked.3 b/man3/libnormalform_xorl_checked.3
new file mode 120000
index 0000000..cd0eb39
--- /dev/null
+++ b/man3/libnormalform_xorl_checked.3
@@ -0,0 +1 @@
+libnormalform_xor_checked.3 \ No newline at end of file
diff --git a/man3/struct_libnormalform_function.3 b/man3/struct_libnormalform_function.3
new file mode 120000
index 0000000..57241ab
--- /dev/null
+++ b/man3/struct_libnormalform_function.3
@@ -0,0 +1 @@
+libnormalform_function.3 \ No newline at end of file
diff --git a/man3/struct_libnormalform_map.3 b/man3/struct_libnormalform_map.3
new file mode 120000
index 0000000..899f515
--- /dev/null
+++ b/man3/struct_libnormalform_map.3
@@ -0,0 +1 @@
+libnormalform_any.3 \ No newline at end of file
diff --git a/man3/struct_libnormalform_mapping.3 b/man3/struct_libnormalform_mapping.3
new file mode 120000
index 0000000..907aac0
--- /dev/null
+++ b/man3/struct_libnormalform_mapping.3
@@ -0,0 +1 @@
+struct_libnormalform_map.3 \ No newline at end of file
diff --git a/man3/struct_libnormalform_representation_spec.3 b/man3/struct_libnormalform_representation_spec.3
new file mode 120000
index 0000000..19a7285
--- /dev/null
+++ b/man3/struct_libnormalform_representation_spec.3
@@ -0,0 +1 @@
+libnormalform_from_string.3 \ No newline at end of file
diff --git a/man3/struct_libnormalform_sentence.3 b/man3/struct_libnormalform_sentence.3
new file mode 120000
index 0000000..8d3cfbb
--- /dev/null
+++ b/man3/struct_libnormalform_sentence.3
@@ -0,0 +1 @@
+LIBNORMALFORM_SENTENCE.3 \ No newline at end of file
diff --git a/man3/struct_libnormalform_transformer.3 b/man3/struct_libnormalform_transformer.3
new file mode 120000
index 0000000..86848de
--- /dev/null
+++ b/man3/struct_libnormalform_transformer.3
@@ -0,0 +1 @@
+libnormalform_transformation.3 \ No newline at end of file
diff --git a/man3/struct_libnormalform_variable.3 b/man3/struct_libnormalform_variable.3
new file mode 120000
index 0000000..3bf0ee7
--- /dev/null
+++ b/man3/struct_libnormalform_variable.3
@@ -0,0 +1 @@
+libnormalform_variable.3 \ No newline at end of file