# (callable) Strip portions between `(*´ and `*)´ and collapse newlines in the argument.
# Backslash sequences in the argument are handled ⅌ `printf´.
# Single quotes must not appear in the argument or this will break.
-makeunreadable = $(shell LANG=C LC_ALL=C printf '%s\n' '$(subst $(newline),$(space),$1)' | $(SED) 's/^ *//;s/ *$$//;s/ *([*][^*]*[*]) *//g' | $(XARGS) -0 $(PRINTF) '%b\n')
+makeunreadable = $(shell LANG=C LC_ALL=C printf '%s\n' '$(subst $(newline),$(space),$1)' | $(SED) 's/^[ ]*//;s/[ ]*$$//;s/[ ]*([*][^*]*[*])[ ]*//g' | $(XARGS) -0 $(PRINTF) '%b\n')
define readablesedcmd
\\@^/[*]$$@,\\@^[\t]*[*]/$$@d; (*delete multiline comments*)
\\@^/[*][*]$$@s@^.*$$@@; (*delete start of documentation comments (leaving newline)*)
\\@^ [*][*]//*$$@s@^.*$$@@; (*delete end of documentation comments (leaving newline)*)
\\@^ [*][*]$$@s@$$@ @; (*add trailing space to empty documentation comment lines*)
-\\@^ [*][*] @!{\\@.@s@^@\t|`@;\\@.@s@$$@´@;}; (*format non·empty lines of code*)
-\\@^ [*][*] @{s@^ [*][*] [ \t]*@@;s@ :—@ :—@g;s@« @« @g;s@‹ @‹ @g;s@—: @—: @g;s@ »@ »@g;s@ ›@ ›@g;s@{<\\([^>]*\\)[.]h>}@{🔗`\\1`<./\\1>}@;}; (*drop prefix from documentation lines and format*)
+\\@^ [*][*] @!{ (*format non·empty lines of code*)
+ s@/[*]\\([^* ]*\\)[*]/@\\1@g; (*explicit formatting*)
+ \\@/[*][^ ]*[*]/@!{ (*autoformat lines without explicit formatting*)
+ s@^\0043ifndef \\([^ ]*\\)@\0043ifndef ⟨\\1⟩@; (*macro ifndef*)
+ s@^\0043define \\([^ ]*\\)@\0043define ⟨\\1⟩@; (*macro define*)
+ s@^\0043endif /[*] \\([^ ]*\\) [*]/@\0043endif /* ⟨\\1⟩ */@; (*macro define*)
+ \\@\t*[?:]@!s@^\\(\t\t*\\)\\([^ ]*\\);@\\1⟨\\2⟩;@; (*handle (presumed) enum members without assignment*)
+ \\@\t*[?:]@!s@^\\(\t\t*\\)\\([^ ]*\\) =@\\1⟨\\2⟩ =@; (*handle (presumed) enum members with assignment*)
+ \\@\t*[?:]@!s@^\\(\t\t*\\)\\([^= ]\\( *[^= ]\\)*\\) \\([^ ][^ ]*\\);@\\1⸤\\2⸥ ⟨\\4⟩;@; (*handle (presumed) struct members*)
+ s@^\\(constexpr \\)*\\([^\t= ]\\( *[^= ]\\)*\\) \\([^= ][^= ]*\\) =@\\1⸤\\2⸥ ⟨\\4⟩ =@; (*handle file‐scope assignments*)
+ s@^enum \\([^ ][^ ]*\\)@enum ⸤\\1⸥@; (*enum declarations*)
+ \\@^enum@s@: \\([^{]*[^{ ]\\)@: ⸤\\1⸥@; (*enum underlying values*)
+ s@^struct \\([^ ][^ ]*\\)@struct ⸤\\1⸥@; (*struct declarations*)
+ s@^typedef \\([^ ]\\( *[^ ]\\)*\\) \\([^ ][^ ]*\\);@typedef ⸤\\1⸥ ⸤\\3⸥;@; (*typedef definitions*)
+ \\@^[^\t ][^\t ]* [^ ][^ ]*(@s@, *@⸥, ⸤@g; (*format function arguments*)
+ s@^\\([^\t ][^ ]*\\) \\([^ ][^ ]*\\)(\\([^)][^)]*\\))@⸤\\1⸥ ⟨\\2⟩(⸤\\3⸥)@; (*format functions*)
+ s@\\(//.*\\)$$@⟦\\1⟧@; (*format comments*)
+ };
+ \\@.@s@^@\t|`@; (*format beginning of line*)
+ \\@.@s@$$@´@; (*format end of line*)
+};
+\\@^ [*][*] @{ (*format documentation*)
+ s@^ [*][*] [ \t]*@@; (*drop documentation leader*)
+ s@ :—@ :—@g; (*fixup spacing for :—*)
+ s@« @« @g; (*fixup spacing for «*)
+ s@‹ @‹ @g; (*fixup spacing for ‹*)
+ s@—: @—: @g; (*fixup spacing for —:*)
+ s@ »@ »@g; (*fixup spacing for »*)
+ s@ ›@ ›@g; (*fixup spacing for ›*)
+ s@{<\\([^>]*\\)[.]h>}@{🔗`\\1`<./\\1>}@g; (*header file linking*)
+};
endef
sedcmd := $(call makeunreadable,$(readablesedcmd))
-define readablestylesheet
-@charset "UTF-8";
-article{ Margin: Auto; Width: Min-Content; Max-Width: 100% }
-article::after{ Display: Block; Width: 31REM; Max-Width: 100%; Min-Width: 100%; Content: "" }
-blockquote>pre{ Margin: Auto; Width: 71CH; Max-Width: 100%; White-Space: Pre-Wrap }
-blockquote>pre+pre{ Margin-Top: 1LH }
-endef
-stylesheet := $(call makeunreadable,$(readablestylesheet))
-
# The first argument should be shell commands producing Les·M·L; the second should be the title of the page.
-processlesml = { $(PRINTF) '%s\n' '<?xml version="1.0"?>' '<html xmlns="http://www.w3.org/1999/xhtml"><head><title>$2</title><style>$(stylesheet)</style></head><body>'; { $(PRINTF) '%s\n%s' '<?xml version="1.0"?>' '<script xmlns="http://www.w3.org/1999/xhtml" type="text/lesml"><![CDATA['; $1; $(PRINTF) '\n%s\n' ']]></script>'; } | xsltproc $(LESML)/parser.xslt - | $(SED) '1{/^<?xml/d;}'; $(PRINTF) '%s\n' '</body></html>' ; }
+processlesml = { $(PRINTF) '%s\n%s' '<?xml version="1.0"?>' '<script xmlns="http://www.w3.org/1999/xhtml" type="text/lesml"><![CDATA['; $1; $(PRINTF) '\n%s\n' ']]></script>'; } | xsltproc --stringparam PROJECT_NAME '$(PROJECT_NAME)' --stringparam TITLE '$2' xslt/documentation.xslt -
-$(DOCUMENTATION_FILES) : $(DOCDIR)/%.xhtml : %.h $(LESML)/parser.xslt
+$(DOCUMENTATION_FILES) : $(DOCDIR)/%.xhtml : %.h $(LESML)/parser.xslt xslt/documentation.xslt
@if $(TEST) '!' -d $(DOCDIR); then $(MKDIR) -p $(DOCDIR); fi
@$(PRINTF) '%s\n' 'Building documentation for <$<>…' >&2
- @$(call processlesml,$(PRINTF) '%s\n\n' '#!lesml@en$$' '⁌ Documentation for `<$<>´'; $(SED) '$(sedcmd)' <'$<'; $(PRINTF) '\n\n%s' '⁂' 'A part of {🔗$(PROJECT_NAME) Documentation<./index.xhtml>}.',Documentation for <$<> | $(PROJECT_NAME) Documentation) >|'$@'
+ @$(call processlesml,$(PRINTF) '%s\n\n' '#!lesml@en$$' '⁌ Documentation for `<$<>´'; $(SED) '$(sedcmd)' <'$<'; $(PRINTF) '\n\n%s' '⁂' 'A part of {🔗$(PROJECT_NAME) Documentation<./index.xhtml>}.',Documentation for <$<>) >|'$@'
-$(DOCDIR)/README.xhtml : README $(LESML)/parser.xslt
+$(DOCDIR)/README.xhtml : README $(LESML)/parser.xslt xslt/documentation.xslt
@$(PRINTF) '%s\n' 'Building documentation README…' >&2
- @$(call processlesml,$(CAT) README; $(PRINTF) '\n\n%s' '⁂' 'A part of {🔗$(PROJECT_NAME) Documentation<./index.xhtml>}.',$(PROJECT_NAME) Readme | $(PROJECT_NAME) Documentation) >|'$@'
+ @$(call processlesml,$(CAT) README; $(PRINTF) '\n\n%s' '⁂' 'A part of {🔗$(PROJECT_NAME) Documentation<./index.xhtml>}.',$(PROJECT_NAME) Readme) >|'$@'
-$(DOCDIR)/index.xhtml : FORCE $(LESML)/parser.xslt
+$(DOCDIR)/index.xhtml : FORCE $(LESML)/parser.xslt xslt/documentation.xslt
@$(PRINTF) '%s\n' 'Building documentation index…' >&2
- @$(call processlesml,$(PRINTF) '%s\n\n' '#!lesml@en$$' '⁌ $(PROJECT_NAME) Documentation' '• {🔗$(PROJECT_NAME) Readme<./README.xhtml>}'$(foreach header,$(HEADER_FILES), '• {🔗Documentation for `$(header)´<./$(patsubst %.h,./%.xhtml,$(header))>}'),$(PROJECT_NAME) Documentation) >|'$@'
+ @$(call processlesml,$(PRINTF) '%s\n\n' '#!lesml@en$$' '⁌ $(PROJECT_NAME) Documentation' '• {🔗$(PROJECT_NAME) Readme<./README.xhtml>}'$(foreach header,$(HEADER_FILES), '• {🔗Documentation for `$(header)´<./$(patsubst %.h,./%.xhtml,$(header))>}'),) >|'$@'
$(LESML)/parser.xslt : %/parser.xslt : FORCE
$(GIT) submodule update --init '$*'
** § Types
**////////////////////////////////////////////////////////////////////
/**
- ** ❦ `enum cgirls_mtype´
+ ** ❦ `enum ⸤cgirls_mtype⸥´
**
- ** The `cgirls_mtype´ enumeration is used to indicate recognized
+ ** The `⸤cgirls_mtype⸥´ enumeration is used to indicate recognized
** mediatype extensions.
**/
enum cgirls_mtype : unsigned char {
/**
- ** The value `cgirls_mtype_any´ indicates no mediatype preference.
+ ** The value `⟨cgirls_mtype_any⟩´ indicates no mediatype preference.
**/
cgirls_mtype_any = 0,
/**
- ** The value `cgirls_mtype_txt´ indicates a preference for
+ ** The value `⟨cgirls_mtype_txt⟩´ indicates a preference for
** `text/plain´ content.
**/
cgirls_mtype_txt = 1,
/**
- ** The value `cgirls_mtype_htm´ indicates a preference for
+ ** The value `⟨cgirls_mtype_htm⟩´ indicates a preference for
** `text/html´ content.
**/
cgirls_mtype_htm = 2,
/**
- ** The value `cgirls_mtype_xml´ indicates a preference for
+ ** The value `⟨cgirls_mtype_xml⟩´ indicates a preference for
** `application/xml´ content, ideally with an `<?xml-stylesheet?>´
** processing instruction.
**/
cgirls_mtype_xml = 3,
/**
- ** The value `cgirls_mtype_rdf´ indicates a preference for
+ ** The value `⟨cgirls_mtype_rdf⟩´ indicates a preference for
** `application/rdf+xml´ content.
**/
cgirls_mtype_rdf = 4,
typedef enum cgirls_mtype cgirls_mtype;
/**
- ** ❦ `enum cgirls_vb´
+ ** ❦ `enum ⸤cgirls_vb⸥´
**
- ** The `cgirls_vb´ enumeration is used to indicate recognized verbs
+ ** The `⸤cgirls_vb⸥´ enumeration is used to indicate recognized verbs
** for requests.
**/
enum cgirls_vb : unsigned char {
/**
- ** The value `cgirls_vb_unknown´ indicates an unknown or unspecified
+ ** The value `⟨cgirls_vb_unknown⟩´ indicates an unknown or unspecified
** verb.
**/
cgirls_vb_unknown = 0,
/**
- ** The value `cgirls_vb_index´ indicates a request for an index of
+ ** The value `⟨cgirls_vb_index⟩´ indicates a request for an index of
** projects.
**/
cgirls_vb_index = 1,
/**
- ** The value `cgirls_vb_branches´ indicates a request for an index of
- ** branches in a given project. The value `cgirls_vb_tags´ indicates a
- ** request for an index of tags.
+ ** The value `⟨cgirls_vb_branches⟩´ indicates a request for an index
+ ** of branches in a given project. The value `⟨cgirls_vb_tags⟩´
+ ** indicates a request for an index of tags.
**/
// cgirls_vb_branches = ??,
// cgirls_vb_tags = ??,
/**
- ** The value `cgirls_vb_show´ indicates a request for an object in a
- ** human‐readable manner. The value `cgirls_vb_raw´ indicates a
+ ** The value `⟨cgirls_vb_show⟩´ indicates a request for an object in a
+ ** human‐readable manner. The value `⟨cgirls_vb_raw⟩´ indicates a
** request for the raw contents of an object. The value
- ** `cgirls_vb_blame´ indicates a request for a blame of a commit.
+ ** `⟨cgirls_vb_blame⟩´ indicates a request for a blame of a commit.
**/
cgirls_vb_show = 2,
// cgirls_vb_raw = ??,
// cgirls_vb_blame = ??,
/**
- ** The value `cgirls_vb_index´ indicates a request for a diff between
- ** two commits.
+ ** The value `⟨cgirls_vb_index⟩´ indicates a request for a diff
+ ** between two commits.
**/
// cgirls_vb_diff = ??,
/**
- ** The values `cgirls_vb_log´, `cgirls_vb_shortlog´, `cgirls_vb_atom´,
- ** and `cgirls_vb_patch´ indicate requests for logs of a number of
- ** commits in various formats.
+ ** The values `⟨cgirls_vb_log⟩´, `⟨cgirls_vb_shortlog⟩´,
+ ** `⟨cgirls_vb_atom⟩´, and `⟨cgirls_vb_patch⟩´ indicate requests for
+ ** logs of a number of commits in various formats.
**/
// cgirls_vb_log = ??,
// cgirls_vb_shortlog = ??,
**
** Verbs can be categorized into a few distinct classes :—
**
- ** • Verbs which do not require a project :— `cgirls_vb_index´.
+ ** • Verbs which do not require a project :— `⟨cgirls_vb_index⟩´.
**
** • Verbs which require a project, but not a revspec :—
- ** `cgirls_vb_branches´, `cgirls_vb_tags´.
+ ** `⟨cgirls_vb_branches⟩´, `⟨cgirls_vb_tags⟩´.
**
** • Verbs which request information about a single object :—
- ** `cgirls_vb_show´, `cgirls_vb_raw´, `cgirls_vb_blame´.
+ ** `⟨cgirls_vb_show⟩´, `⟨cgirls_vb_raw⟩´, `⟨cgirls_vb_blame⟩´.
**
- ** • Verbs which compare two commits :— `cgirls_vb_diff´.
+ ** • Verbs which compare two commits :— `⟨cgirls_vb_diff⟩´.
**
** • Verbs which produce information about an open‐ended number of
- ** commits :— `cgirls_vb_log´, `cgirls_vb_shortlog´,
- ** `cgirls_vb_atom´, `cgirls_vb_patch´.
+ ** commits :— `⟨cgirls_vb_log⟩´, `⟨cgirls_vb_shortlog⟩´,
+ ** `⟨cgirls_vb_atom⟩´, `⟨cgirls_vb_patch⟩´.
**/
};
typedef enum cgirls_vb cgirls_vb;
/**
- ** ❦ `struct cgirls_req_status´
+ ** ❦ `struct ⸤cgirls_req_status⸥´
**
- ** The struct `cgirls_req_status´ wraps a status code and message for
- ** a response.
+ ** The struct `⸤cgirls_req_status⸥´ wraps a status code and message
+ ** for a response.
**
- ** The `.message´ is only significant if `.code´ is not `200´.
+ ** The `⟨.message⟩´ is only significant if `⟨.code⟩´ is not `200´.
**/
typedef struct cgirls_req_status cgirls_req_status;
struct cgirls_req_status {
};
/**
- ** ❦ `struct cgirls_req´
+ ** ❦ `struct ⸤cgirls_req⸥´
**
- ** The struct `cgirls_req´ represents a request.
+ ** The struct `⸤cgirls_req⸥´ represents a request.
**
** Requests must have a verb, may specify a mediatype extension, and
- ** might also reference a project, revspec, and subpath.
+ ** might also reference a project, revspec, and subpath. The value of
+ ** `⟨.subpath⟩´, if not `⟨nullptr⟩´, must be a `⟨nullptr⟩´‐terminated
+ ** array of strings.
**
** All requests have a status, which is used to express request
- ** validity. If `.status.code´ is not `200´, the request is invalid
- ** and a response with the associated code and message is recommended.
+ ** validity. If `⟨.status⟩⟨.code⟩´ is not `200´, the request is
+ ** invalid and a response with the associated code and message is
+ ** recommended.
**/
typedef struct cgirls_req cgirls_req;
struct cgirls_req {
** § Functions
**////////////////////////////////////////////////////////////////////
/**
- ** ❦ `cgirls_req cgirls_path·to·req(char const*const)´
+ ** ❦ `⸤cgirls_req⸥ ⟨cgirls_path·to·req⟩(⸤char const*const⸥)´
**
- ** The `cgirls_path·to·req´ function takes a path string (such as one
- ** provided by the C·G·I `PATH_INFO´ environment variable) and returns
- ** a `cgirls_req´ which represents its semantics.
+ ** The `⟨cgirls_path·to·req⟩´ function takes a path string (such as
+ ** one provided by the C·G·I `⟨PATH_INFO⟩´ environment variable) and
+ ** returns a `⸤cgirls_req⸥´ which represents its semantics.
**
** This resulting struct contains a lot of dynamically‐allocated data,
- ** so it ☞︎must☜︎ be freed with `cgirls_req·free´ after use.
+ ** so it ☞︎must☜︎ be freed with `⟨cgirls_req·free⟩´ after use.
**
** Maximally, the path string is processed according to the following
** form :—
** extension). Not all components necessarily need to be specified,
** and not all possible values are valid or meaningful.
**
- ** In case of an error, `.status.code´ on the returned `cgirls_req´
- ** will be some·thing other than `200´.
+ ** In case of an error, `⟨.status⟩⟨.code⟩´ on the returned
+ ** `⸤cgirls_req⸥´ will be some·thing other than `200´.
**/
cgirls_req cgirls_path·to·req(char const*const);
/**
- ** ❦ `void cgirls_req·free(cgirls_req)´
+ ** ❦ `⸤void⸥ ⟨cgirls_req·free⟩(⸤cgirls_req⸥)´
**
- ** The `cgirls_req·free´ function frees up any dynamically‐allocated
- ** memory in the provided `cgirls_req´, assuming that it was created
- ** with `cgirls_path·to·req´ or similar.
+ ** The `⟨cgirls_req·free⟩´ function frees up any dynamically‐allocated
+ ** memory in the provided `⸤cgirls_req⸥´, assuming that it was created
+ ** with `⟨cgirls_path·to·req⟩´ or similar.
**/
void cgirls_req·free(cgirls_req);
/**
- ** ❦ `char* cgirls_req·to·path(cgirls_req)´
+ ** ❦ `⸤char*⸥ ⟨cgirls_req·to·path⟩(⸤cgirls_req⸥)´
**
- ** The `cgirls_req·to·path´ function does the reverse of
- ** `cgirls_path·to·req´: It takes in a `cgirls_req´ structure and
+ ** The `⟨cgirls_req·to·path⟩´ function does the reverse of
+ ** `⟨cgirls_path·to·req⟩´: It takes in a `⸤cgirls_req⸥´ struct and
** returns the canonical path string which represents it.
**
- ** All possible `cgirls_req´s have a canonical string representation;
- ** `cgirls_req·to·path´ will only return `nullptr´ if it
+ ** All possible `⸤cgirls_req⸥´s have a canonical string
+ ** representation; `⟨cgirls_req·to·path⟩´ will only return `⟨nullptr⟩´
+ ** if it fails to allocate memory while constructing the resulting
+ ** string. Return values are dynamically allocated and must be
+ ** manually freed with `⟨free⟩´.
**
- ** It is worth noting that, if the `.project´ is the null pointer, the
- ** canonical path string will always be the empty string.
+ ** It is worth noting that, if the `⟨.project⟩´ is the null pointer,
+ ** the canonical path string will always be the empty string.
**/
char* cgirls_req·to·path(cgirls_req);
--- /dev/null
+<?xml version="1.0"?>
+<!--
+SPDX-FileCopyrightText: 2025 Lady <https://www.ladys.computer/about/#lady>
+SPDX-License-Identifier: MPL-2.0
+-->
+<!--
+⁌ C·Girls ∷ documentation.xslt
+
+© 2025 Lady [@ Ladys Computer]
+
+This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
+If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+-->
+<!DOCTYPE transform [
+ <!ENTITY xhtml 'http://www.w3.org/1999/xhtml'>
+]>
+<transform
+ xmlns="http://www.w3.org/1999/XSL/Transform"
+ xmlns:exsl="http://exslt.org/common"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ extension-element-prefixes="exsl"
+ version="1.0"
+>
+ <param name="PROJECT_NAME"/>
+ <param name="TITLE"/>
+ <include href="../LesML/parser.xslt"/>
+ <template match="/">
+ <variable name="result-fragment">
+ <apply-templates/>
+ </variable>
+ <variable name="result" select="exsl:node-set($result-fragment)/*"/>
+ <element name="html" namespace="&xhtml;">
+ <attribute name="lang">
+ <text>en</text>
+ </attribute>
+ <attribute name="xml:lang">
+ <text>en</text>
+ </attribute>
+ <element name="head" namespace="&xhtml;">
+ <element name="title" namespace="&xhtml;">
+ <if test="$TITLE != ''">
+ <value-of select="$TITLE"/>
+ <text> | </text>
+ </if>
+ <value-of select="$PROJECT_NAME"/>
+ <text> Documentation</text>
+ </element>
+ <element name="style" namespace="&xhtml;">
+ <text><![CDATA[@charset "UTF-8";
+@namespace "http://www.w3.org/1999/xhtml";
+article{ Box-Sizing: Border-Box; Margin: Auto; Padding-Inline: 2REM; Inline-Size: Min-Content; Max-Inline-Size: 100%; Line-Height: 1.2 }
+article::after{ Display: Block; Inline-Size: 31REM; Max-Inline-Size: 100%; Min-Inline-Size: 100%; Content: "" }
+blockquote>pre{ Margin: Auto; Inline-Size: 71CH; Max-Inline-Size: 100%; White-Space: Pre-Wrap }
+blockquote>pre+pre{ Margin-Top: 1LH }
+h1,h2,h3{ Margin-Inline: -1REM; Border-Block-End: Thin Solid; Padding-Block: .25EM; Padding-Inline: 1REM; Font-Weight: Inherit }
+h1{ Font-Size: XX-Large }
+h2{ Font-Size: X-Large }
+h3{ Font-Size: Large }
+hr{ Margin-Inline: -1REM }
+pre{ Line-Height: 1.8 }
+code small{ Color: RGB(From CurrentColor R G B / .5); Font-Size: Inherit }
+code u{ Text-Decoration-Style: Wavy; Text-Decoration-Skip-Ink: None; Text-Decoration-Color: RGB(From CurrentColor R G B / .5); Text-Decoration-Thickness: 1PX; Text-Underline-Position: Under }
+]]></text>
+ </element>
+ </element>
+ <element name="body" namespace="&xhtml;">
+ <element name="article" namespace="&xhtml;">
+ <apply-templates select="exsl:node-set($result)//html:div[@class='body']"/>
+ </element>
+ </element>
+ </element>
+ </template>
+ <template match="html:code/html:i[not(@lang)]">
+ <element name="html:var">
+ <apply-templates select="@*|node()"/>
+ </element>
+ </template>
+ <template match="@*|node()" priority="-1">
+ <copy>
+ <apply-templates select="@*|node()"/>
+ </copy>
+ </template>
+</transform>