]> Lady’s Gitweb - Shushe/blobdiff - GNUmakefile
Force removal of existing directories
[Shushe] / GNUmakefile
index da2912d85817f78e5b60bd6e681d753a4fc3f52f..0156970c9b352fa5c7e62430e7ac6beec527f627 100644 (file)
@@ -22,15 +22,15 @@ override define makefileinfo
 ║│ • cksum                                                    │║
 ║│ • cp                                                       │║
 ║│ • date                                                     │║
-║│ • echo                                                     │║
 ║│ • file                                                     │║
 ║│ • find                                                     │║
 ║│ • grep                                                     │║
 ║│ • git (optional)                                           │║
 ║│ • ln                                                       │║
-║│ • mkdir (requires support for `-p´)                        │║
+║│ • ls                                                       │║
+║│ • mkdir                                                    │║
 ║│ • mv                                                       │║
-║│ • od (requires support for `-t x1´)                        │║
+║│ • od                                                       │║
 ║│ • pax (only when generating archives)                      │║
 ║│ • printf                                                   │║
 ║│ • rm                                                       │║
@@ -39,10 +39,10 @@ override define makefileinfo
 ║│ • stat                                                     │║
 ║│ • test                                                     │║
 ║│ • touch                                                    │║
-║│ • tr (requires support for `-d´)                           │║
-║│ • uuencode (requires support for `-m´ and `-r´)            │║
-║│ • uudecode (requires support for `-m´ and `-r´)            │║
-║│ • xargs (requires support for `-0´)                        │║
+║│ • tr                                                       │║
+║│ • uuencode                                                 │║
+║│ • uudecode                                                 │║
+║│ • xargs                                                    │║
 ║│ • xmlcatalog (provided by libxml2)                         │║
 ║│ • xmllint (provided by libxml2)                            │║
 ║│ • xsltproc (provided by libxslt)                           │║
@@ -68,6 +68,10 @@ override define makefileinfo
 ║│ • `make list´: List all recognized source files and their  │║
 ║│   classification (including media type and dependencies).  │║
 ║│                                                            │║
+║│ • `make listout´: List out the destinations of all         │║
+║│   resulting files (relative to `DESTDIR´), e·g for         │║
+║│   processing by another script.                            │║
+║│                                                            │║
 ║│ • `make uninstall´: Remove installed files, but not        │║
 ║│   `BUILDDIR´.                                              │║
 ║│                                                            │║
@@ -99,12 +103,12 @@ CAT := cat
 CKSUM := cksum
 CP := cp
 DATE := date
-ECHO := echo
 FILE := file
 FIND := find
 GIT := git
 GREP := grep
 LN := ln
+LS := ls
 MKDIR := mkdir
 MV := mv
 OD := od
@@ -169,7 +173,7 @@ THISDIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
 # By default, `find´ will ignore files which begin with a period and those which are likely to cause problems for `make´.
 EXTRAFINDRULES :=
 EXTRAFINDINCLUDERULES :=
-FINDRULES := ! '(' '(' -name '[.-]*' -o -name '*[][*?:|$$%\#\\; ]*' -o -name '*[)]' ')' -a -prune ')'$(if $(EXTRAFINDRULES), -a $(EXTRAFINDRULES),)
+FINDRULES := ! '(' '(' -name '[.-]*' -o -name '*[][*?:|$$%\#\\; ]*' -o -name '*"{*' -o -name '*}"*' -o -name '*[)]' ')' -a -prune ')'$(if $(EXTRAFINDRULES), -a $(EXTRAFINDRULES),)
 FINDINCLUDERULES := $(FINDRULES)$(if $(EXTRAFINDINCLUDERULES), -a $(EXTRAFINDINCLUDERULES),)
 
 # The list of magic files to use when determining media types.
@@ -215,6 +219,9 @@ endif
 #
 # • ‹ urn:fdc:ladys.computer:20231231:Shu1She4:mode:archive ›:
 #   Generates archive files from parse results.
+#
+# • ‹ urn:fdc:ladys.computer:20231231:Shu1She4:mode:paged ›:
+#   Generates paginated files from parse results.
 MODE := urn:fdc:ladys.computer:20231231:Shu1She4:mode:default
 
 # Set to a non·empty value to print all commands as they run.
@@ -253,21 +260,35 @@ override silent := $(if $(VERBOSE),,@)
 # This is messy; there is no portable way of using `stat´.
 #
 # ☡ This variable creates a subshell every time it is computed.
-override modtime = $(shell if $(STAT) --version 2> /dev/null | $(GREP) -q GNU; then $(DATE) -d "@$$(TZ= $(STAT) -c '%Y' $(call quote,$1))" '+%Y-%m-%dT%H:%M:%SZ'; else TZ= $(STAT) -f '%Sm' -t '%Y-%m-%dT%H:%M:%SZ' $(call quote,$1); fi)
+override modtime = $(shell if $(STAT) --version 2> /dev/null | $(GREP) -q GNU; then $(DATE) -u -d "@$$(TZ= $(STAT) -c '%Y' $(call quote,$1))" '+%Y-%m-%dT%H:%M:%SZ'; else TZ= $(STAT) -f '%Sm' -t '%Y-%m-%dT%H:%M:%SZ' $(call quote,$1); fi)
 
 # ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
 
 # (callable) Check to see if the given directory exists and create it if not.
 override ensuredirectory = if $(TEST) ! -d $(call quote,$1); then $(MKDIR) -p $(call quote,$1); fi
 
+# Quote standard input in such a way that piping it to xargs will result in it being processed as a single argument.
+#
+# If standard input ends in a newline, it is stripped; all other newlines are preserved.
+override xargsquote = $(SED) $(call quote,s/'/'"'"'/g;s/^/'/;s/$$/'/;$$!s/$$/\\/)
+
+# Quote standard input in such a way that piping it to xargs will result in each line being processed as a single argument.
+override xargsmultiquote = $(SED) $(call quote,s/'/'"'"'/g;s/^/'/;s/$$/'/)
+
 # (callable) Test if the provided xpath expression matches the provided document.
 override xpath = $(XMLLINT) --xpath $(call quote,$1) $(call quote,$2) > /dev/null 2> /dev/null
 
 # (callable) Extract the value of the text nodes in the provided X·M·L document and print them to `stdout´.
 override extracttext = $(PRINTF) '%s' '<transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0"><output method="text" encoding="UTF-8"/></transform>' | $(XSLTPROC) --nonet --novalid - $(call quote,$1)
 
+# (callable) List the files in the provided directory which are associated with the provided filename, one per line.
+override associatedfiles = $(LS) -1 $(call quote,$1) | $(SED) '/.*"{.*}".*/!d;s/^\(.*\)"{.*}"\(.*\)$$/\1\2|&/' | $(GREP) -F -e $(call quote,$2|) | $(SED) 's/^.*|//'
+
+# (callable) Remove files associated with the provided file.
+override removeassociatedfiles = ASSOCIATED="$$($(call associatedfiles,$(dir $1),$(notdir $1)) | $(TR) '\n' ' ')"; if $(TEST) -n "$$ASSOCIATED"; then cd $(call quote,$(dir $1)) && $(PRINTF) '%s\n' "$$ASSOCIATED" | $(SED) 's/ \{2,\}/ /g;s/^ //;s/ $$//' | $(TR) ' ' '\n' | $(xargsmultiquote) | $(XARGS) -E '' $(RM); fi
+
 # (callable) Process the provided transformation result and output the result to the provided location, given the provided relative path.
-override processresultto = if $(call xpath,/*[local-name()="raw-text" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(RM) -f $(call quote,$2); $(call extracttext,$1) > $(call quote,$2); elif $(call xpath,/*[local-name()="base64-binary" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(RM) -f $(call quote,$2); $(call extracttext,$1) | $(TR) -d '\t\n\f\r ' | $(UUDECODE) -m -r > $(call quote,$2); elif $(call xpath,/*[local-name()="archive" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(RM) -f $(call quote,$2); $(MAKE) -f $(call quote,$(abspath $(THISDIR)/GNUmakefile)) $(call quote,$2) NAME=$(call quote,$3) SRC=$(call quote,$1) BUILDDIR=$(call quote,$(BUILDDIR)/archive/$3) DESTDIR=$(call quote,$(patsubst %/,%,$(dir $2))) MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:archive'; else $(RM) -f $(call quote,$2); $(XMLLINT) --nsclean $(call quote,$1) > $(call quote,$2); fi
+override processresultto = if $(call xpath,/*[local-name()="raw-text" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(call extracttext,$1) > $(call quote,$2); $(call removeassociatedfiles,$2); elif $(call xpath,/*[local-name()="base64-binary" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then { $(PRINTF) '%s\n' 'begin-base64 644 -'; $(call extracttext,$1) | $(TR) -d '\t\n\f\r '; $(PRINTF) '\n%s\n' '===='; } | $(UUDECODE) -o /dev/stdout > $(call quote,$2); $(call removeassociatedfiles,$2); elif $(call xpath,/*[local-name()="archive" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(MAKE) -f $(call quote,$(abspath $(THISDIR)/GNUmakefile)) $(call quote,$2) NAME=$(call quote,$3) SRC=$(call quote,$1) BUILDDIR=$(call quote,$(BUILDDIR)/archive/$3) DESTDIR=$(call quote,$(patsubst %/,%,$(dir $2))) MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:archive'; $(call removeassociatedfiles,$2); elif $(call xpath,//*[local-name()="page" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(MAKE) -f $(call quote,$(abspath $(THISDIR)/GNUmakefile)) $(call quote,$2) NAME=$(call quote,$3) SRC=$(call quote,$1) BUILDDIR=$(call quote,$(BUILDDIR)/paged/$3) DESTDIR=$(call quote,$(patsubst %/,%,$(dir $2))) MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:paged'; else $(XMLLINT) --nsclean $(call quote,$1) > $(call quote,$2); $(call removeassociatedfiles,$2);  fi
 
 # ━ § BEGIN DEFAULT MAKE·FILE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
@@ -288,7 +309,7 @@ override diffprereqs = $(if $(subst $(shell $(CAT) $(call quote,$(BUILDDIR)/last
 override sedesc = $(subst /,[/],$(subst $$,\$$,$(subst *,\*,$(subst .,\.,$(subst [,\[,$(subst ^,\^,$(subst \,\\,$1)))))))
 
 # The command to use for percent‐decoding.
-override perdeccmd := $(SED) 's/|/%7C/g;s/[\]/%5C/g;s/%[0-9A-Fa-f]\{2\}/|&|/g' | $(TR) '|' '\n' | $(SED) '/^%[0-9A-Fa-f]\{2\}$$/!s/%/|%25|/' | $(TR) '|' '\n' | $(AWK) '$$0!~/%/{printf "%s",$$0}/%/{d="0123456789ABCDEF";v=substr(toupper($$0),2,2);printf "\\%04o",(index(d,substr(v,1,1))-1)*16+index(d,substr(v,2,1))-1}' | $(XARGS) -0 $(PRINTF) '%b'
+override perdeccmd := $(SED) 's/|/%7C/g;s/[\]/%5C/g;s/%[0123456789ABCDEFabcdef]\{2\}/|&|/g' | $(TR) '|' '\n' | $(SED) '/^%[0123456789ABCDEFabcdef]\{2\}$$/!s/%/|%25|/' | $(TR) '|' '\n' | $(AWK) '$$0!~/%/{printf "%s",$$0}/%/{d="0123456789ABCDEF";v=substr(toupper($$0),2,2);printf "\\%04o",(index(d,substr(v,1,1))-1)*16+index(d,substr(v,2,1))-1}' | $(xargsquote) | $(XARGS) -E '' $(PRINTF) '%b'
 
 # (callable) Percent‐decode the given strings.
 #
@@ -303,7 +324,7 @@ override perdec = $(shell $(PRINTF) '%s\0450A' $(foreach encoded,$1,$(call quote
 # It is assumed that the given strings do not contain newlines.
 #
 # ☡ This variable creates a subshell every time it is computed.
-override perenc = $(shell $(PRINTF) '%s\n' $(foreach unencoded,$1,$(call quote,$(unencoded))) | $(OD) -t x1 | $(SED) 's/^[0-9]*//;s/0[Aa]/%&/g;s/2[146-9A-Ea-e]/%&/g;s/3[0-9AaBbDd]/%&/g;s/40/%&/g;s/[46][1-9A-Fa-f]/%&/g;s/[57][0-9Aa]/%&/g;s/5[Ff]/%&/g;s/7[Ee]/%&/g;s/[ ][0-9A-Fa-f]\{2\}/%25&/g' | $(TR) -d ' \n' | $(TR) 'abcdef' 'ABCDEF' | $(perdeccmd))
+override perenc = $(shell $(PRINTF) '%s\n' $(foreach unencoded,$1,$(call quote,$(unencoded))) | $(OD) -t x1 | $(SED) 's/^[0123456789]*//;s/0[Aa]/%&/g;s/2[146789ABCDEabcde]/%&/g;s/3[0123456789AaBbDd]/%&/g;s/40/%&/g;s/[46][123456789ABCDEFabcdef]/%&/g;s/[57][0123456789Aa]/%&/g;s/5[Ff]/%&/g;s/7[Ee]/%&/g;s/[ ][0123456789ABCDEFabcdef]\{2\}/%25&/g' | $(TR) -d ' \n' | $(TR) 'abcdef' 'ABCDEF' | $(perdeccmd))
 
 # (callable) Percent‐encode each component in the given paths.
 #
@@ -355,7 +376,7 @@ override includepath = $(firstword $(foreach directory,$(INCLUDEDIR),$(if $(filt
 # (callable) Get base64 data u·r·i’s for the given files.
 #
 # ☡ This variable creates a subshell every time it is computed.
-override datauri = $(foreach file,$1,data:$(call typeoffile,$(file));base64,$(shell $(UUENCODE) -m -r $(call quote,$(file)) _ | tr -d ' \n'))
+override datauri = $(foreach file,$1,data:$(call typeoffile,$(file));base64,$(shell $(UUENCODE) -m $(call quote,$(file)) _ | $(SED) '2,$$!d;$$d' | $(TR) -d ' \n'))
 
 # Pair each source file and include with its local u·r·i.
 override sourcelocalpair := $(foreach file,$(sourcefiles) $(sourceincludes),$(file)|about:shushe?$(if $(filter $(file),$(sourceincludes)),include=$(call pathenc,$(call includepath,$(file))),source=$(call pathenc,$(call sourcepath,$(file)))))
@@ -451,14 +472,14 @@ endif
 override id = $(XMLLINT) --xpath '/*/*[local-name()="id" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"]/text()[1]' $(call quote,$1) 2> /dev/null || $(PRINTF) '%s\n' $(call quote,about:shushe?$(or $2,unknown)=$(call pathenc,$(basename $(notdir $1))))
 
 # (callable) Sanitize and wrap the provided plaintext file in X·M·L, printing to `stdout´.
-override wrapplaintext = $(TR) '\000\013\014' '\032\011\012' < $(call quote,$1) | $(SED) "$$($(PRINTF) '%b' 's/]]>/]]]]><!\\[CDATA\\[>/g\ns/\0357\0277\0276/�/g\ns/\0357\0277\0277/�/g\n$$!s/\\r$$//g\ns/\\r/\\n/g\n$$!s/\0302\0205$$//g\ns/\0302\0205/\\n/g;s/\0342\0200\0250/\\n/g;s/[\0001-\0010]/�/g;s/[\0016-\0037]/�/g')" | $(XARGS) -0 -J %% $(PRINTF) '%b%s%s\n' '<?xml version=\042\061.0\042?>\n<script xmlns=\042http://www.w3.org/1999/xhtml\042 type=\042$(call typeoffile,$1)\042><![CDATA[' %% ']]></script>'
+override wrapplaintext = { $(PRINTF) '%s\n%s' '<?xml version="1.0"?>' '<script xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$1)"><![CDATA['; $(TR) '\000\013\014' '\032\011\012' < $(call quote,$1) | $(SED) "$$($(PRINTF) '%b' 's/]]>/]]]]><!\\[CDATA\\[>/g\ns/\0357\0277\0276/�/g\ns/\0357\0277\0277/�/g\n$$!s/\\r$$//g\ns/\\r/\\n/g\n$$!s/\0302\0205$$//g\ns/\0302\0205/\\n/g\ns/\0342\0200\0250/\\n/g\ns/[\0001\0002\0003\0004\0005\0006\0007\0010]/�/g\ns/[\0016\0017\0020\0021\0022\0023\0024\0025\0026\0027\0031\0032\0033\0034\0035\0036\0037]/�/g')"; $(PRINTF) '%s\n' ']]></script>'; }
 
 # (callable) Check if the provided X·M·L file is X·M·L 1.1, and if so, coerce to X·M·L 1.0 as best as possible, printing the result (or the original file contents) to `stdout´.
 #
 # The X·M·L declaration will be dropped and character escapes for C0 control codes will be replaced with a literal `U+0091 PRIVATE USE ONE´, which is invalid in X·M·L 1.1, but valid X·M·L 1.0 (making the replacement obvious).
 #
 # This isn’t a perfect substitution (it makes some assumptions about the format of the underlying X·M·L), but it should be workable for most sensible, welformed files.
-override serializexml = $(SED) "$$($(PRINTF) '%b' '/<?xml[ \t]\\{1,\\}version=[\0042\0047]1.1/,$${ s/<?xml[^>]*?>/<!--<?xml version=\00421.1\0042?>-->/\n s/&\0043x0*[1-8BCEFbcef];/\0302\0221/g\n s/&\0043x0*1[0-9A-Fa-f];/\0302\0221/g\n s/&\00430*[1-8];/\0302\0221/g\n s/&\00430*1[124-9];/\0302\0221/g\n s/&\00430*2[0-9];/\0302\0221/g\n s/&\00430*3[01];/\0302\0221/g\n}')" < $(call quote,$1) | $(SED) "$$(PRINTF '%b' ':a\n/^\\n*$$/{ $$d\n N\n ba\n}')"
+override serializexml = $(SED) "$$($(PRINTF) '%b' '/<?xml[ \t]\\{1,\\}version=[\0042\0047]1.1/,$${ s/<?xml[^>]*?>/<!--<?xml version=\00421.1\0042?>-->/\n s/&\0043x0*[12345678BCEFbcef];/\0302\0221/g\n s/&\0043x0*1[0123456789ABCDEFabcdef];/\0302\0221/g\n s/&\00430*[12345678];/\0302\0221/g\n s/&\00430*1[12456789];/\0302\0221/g\n s/&\00430*2[0123456789];/\0302\0221/g\n s/&\00430*3[01];/\0302\0221/g\n}')" < $(call quote,$1) | $(SED) "$$($(PRINTF) '%b' ':a\n/^\\n*$$/{ $$d\n N\n ba\n}')"
 
 # ─ ¶ Phony Targets ───────────────────────────────────────────────────
 
@@ -467,7 +488,7 @@ all : $(call built,$(recursivefiles) $(installablefiles)) ;
 
 # Destroy buildfiles.
 clean :
-       $(if $(BUILDDIR),$(silent)$(RM) -rf $(call quote,$(BUILDDIR)/),)
+       $(if $(BUILDDIR),$(silent)$(RM) -f -R $(call quote,$(BUILDDIR)/),)
 
 # Destroy build directory and installed files.
 gone : clean uninstall ;
@@ -483,6 +504,10 @@ install : $(call installed,$(recursivefiles) $(installablefiles)) ;
 list :
        @$(PRINTF) '%b' $(call quote,$(foreach file,$(sort $(sourcefiles)) $(sort $(sourceincludes)),\0033[1m$(file)\0033[22m|$(call typeoffile,$(file))|[\0033[3m$(if $(filter $(file),$(xmlfiles)),xml,$(if $(filter $(file),$(plaintextfiles)),text,asset))$(if $(filter $(file),$(sourceincludes)),|include,)\0033[23m]$(if $(call dependencies,$(file))$(call recursives,$(file)), $(strip $(foreach recursive,$(call recursives,$(file)),\0033[93;41m•|Recursive|Dependency|\0033[39;49m|$(recursive)) $(foreach dependency,$(call dependencies,$(file)),\0033[2m•|Dependency|\0033[22m|$(dependency))))$(if $(filter $(file),$(sourcefiles)), →|<\0033[4m/$(call destination,$(file))\0033[24m>,) )) | $(TR) ' |' '\n '
 
+# Lists out the destinations of all resulting files (relative to `DESTDIR´).
+listout :
+       @$(PRINTF) '⛩️📰 书社 Output: %s\n' $(call quote,$(foreach file,$(sort $(sourcefiles)),$(call destination,$(file))))
+
 # Destroy installed files.
 uninstall :
        $(foreach file,$(installablefiles),$(if $(wildcard $(call installed,$(file))),$(silent)$(PRINTF) '%s\n' $(call quote,Removing </$(patsubst $(DESTDIR)/%,%,$(call installed,$(file)))>…)$(newline)$(silent)$(RM) -f $(call quote,$(call installed,$(file)))$(newline),))
@@ -503,7 +528,7 @@ FORCE : ;
 .SUFFIXES : ;
 
 # Phony rules; always consider these out·of·date.
-.PHONY : FORCE all default clean gone info install list uninstall $(call built,$(recursivefiles)) ;
+.PHONY : FORCE all default clean gone info install list listout uninstall $(call built,$(recursivefiles)) ;
 
 ifneq ($(typeupdates)$(wildcard $(BUILDDIR)/dependencies)$(wildcard $(BUILDDIR)/destinations),)
 # Reload this make·file if the dependency graph or output destinations have changed.
@@ -518,7 +543,7 @@ $(THISDIR)/GNUmakefile :: $(BUILDDIR)/dependencies $(BUILDDIR)/destinations
 ifeq ($(typeupdates),)
        @if $(TEST) ! -f $(call quote,$(BUILDDIR)/.update-types); then $(PRINTF) '%b\n' '\0033[1mDependency graph and output destinations updated. Restarting…\0033[22m'; fi
 else
-       $(silent)$(RM) $(BUILDDIR)/.update-types
+       $(silent)$(RM) $(call quote,$(BUILDDIR)/.update-types)
        @$(PRINTF) '%b\n' '\0033[1mDependency graph and output destinations updated. Restarting…\0033[22m'
 endif
 endif
@@ -549,18 +574,18 @@ $(call magicfile,$(MAGIC)) : $(BUILDDIR)/magic/% : $$(call magicsource,$$@)
 # It must be updated if any of the files in the magic directory change.
 $(BUILDDIR)/magic.mgc : $(call diffprereqs,magic,$(sort $(call magicfile,$(MAGIC))))
        $(foreach outdated,$(filter-out $^,$(wildcard $(BUILDDIR)/magic/*)),$(silent)$(RM) $(call quote,$(outdated))$(newline))
-       @$(ECHO) "Compiling new magic…"
+       @$(PRINTF) '%s\n' 'Compiling new magic…'
        $(silent)$(call ensuredirectory,$(dir $@))
        $(silent)cd $(call quote,$(BUILDDIR)) && $(FILE) -C -m $(call quote,$(realpath $(BUILDDIR)/magic))
        $(silent)$(TOUCH) $(call quote,$(BUILDDIR)/.update-types)
 
 # Generate the main parser.
 $(BUILDDIR)/parser.catalog : $(call diffprereqs,parsers,$(sort $(PARSERS)))
-       @$(ECHO) "Generating catalog of parsers…"
+       @$(PRINTF) '%s\n' 'Generating catalog of parsers…'
        $(silent)$(XMLCATALOG) --create --noout $(call quote,$@)
-       $(foreach parser,$(PARSERS),$(silent)( $(call id,$(parser)) ) | $(XARGS) -I %% $(XMLCATALOG) --add uri %% $(call quote,$(call fileuri,$(parser))) --noout $(call quote,$@)$(newline))
+       $(foreach parser,$(PARSERS),$(silent){ $(call id,$(parser)); $(PRINTF) '%s\n' $(call quote,$(call fileuri,$(parser))) '--noout' $(call quote,$@); } | $(xargsmultiquote) | $(XARGS) -E '' $(XMLCATALOG) --add uri$(newline))
 $(BUILDDIR)/parser.xslt : $(BUILDDIR)/parser.catalog $(THISDIR)/lib/catalog2parser.xslt
-       @$(ECHO) "Generating main parser…"
+       @$(PRINTF) '%s\n' 'Generating main parser…'
        $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2parser.xslt) $(call quote,$<)
        $(silent)$(TOUCH) $(call quote,$(BUILDDIR)/.update-types)
 
@@ -571,19 +596,20 @@ $(BUILDDIR)/parser.xslt : $(BUILDDIR)/parser.catalog $(THISDIR)/lib/catalog2pars
 $(call parsed,$(sourcefiles) $(sourceincludes)) : % : $$(call unparsed,$$@) $(BUILDDIR)/parser.xslt $(typeupdates)
        @$(PRINTF) '%s\n' $(call quote,Processing `$<´…)
        $(silent)$(call ensuredirectory,$(dir $@))
-       $(silent)$(if $(filter $<,$(assetfiles)),$(PRINTF) '%s\n' $(call quote,<object xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$<)" data="$(call datauri,$<)"/>) > $(call quote,$@),$(if $(filter $<,$(plaintextfiles)),$(call wrapplaintext,$<),$(call serializexml,$<)) | $(XSLTPROC) --nonet --novalid -o $(call quote,$@) --stringparam BUILDTIME $$(TZ= $(DATE) '+%Y-%m-%dT%H:%M:%SZ') --stringparam IDENTIFIER $(call quote,$(call localuri,$<)) --stringparam SRCTIME '$(call modtime,$<)' --stringparam CKSUM $$($(CKSUM) $(call quote,$<) | $(SED) 's/[ ].*//')$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) $(call quote,$(BUILDDIR)/parser.xslt) -)
+       $(silent)$(if $(filter $<,$(assetfiles)),$(PRINTF) '%s\n' $(call quote,<object xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$<)" data="$(call datauri,$<)"/>) > $(call quote,$@),$(if $(filter $<,$(plaintextfiles)),$(call wrapplaintext,$<),$(call serializexml,$<)) | $(XSLTPROC) --nonet --novalid -o $(call quote,$@) --stringparam BUILDTIME $$($(DATE) -u '+%Y-%m-%dT%H:%M:%SZ') --stringparam IDENTIFIER $(call quote,$(call localuri,$<)) --stringparam SRCTIME '$(call modtime,$<)' --stringparam CKSUM $$($(CKSUM) $(call quote,$<) | $(SED) 's/[ ].*//')$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) $(call quote,$(BUILDDIR)/parser.xslt) -)
 
 # Generate a catalog of all parsed files, for use when processing includes.
 #
 # This does not depend on actually transforming the files.
 $(BUILDDIR)/catalog : $(call diffprereqs,sources,$(sort $(sourcefiles) $(sourceincludes))) $(typeupdates)
-       @$(ECHO) "Generating catalog of parsed files…"
+       @$(PRINTF) '%s\n' 'Generating catalog of parsed files…'
        $(silent)$(XMLCATALOG) --create --noout $(call quote,$@)
        $(foreach source,$(sourcefiles) $(sourceincludes),$(silent)$(XMLCATALOG) --add uri $(call quote,$(call localuri,$(source))) $(call quote,$(call fileuri,$(call parsed,$(source)))#$(if $(filter $(source),$(assetfiles)),asset,xml)) --noout $(call quote,$@)$(newline))
 
 # Build a list of dependencies for each parsed file.
 $(BUILDDIR)/dependencies : $(BUILDDIR)/catalog $(call parsed,$(plaintextfiles) $(xmlfiles)) $(THISDIR)/lib/catalog2dependencies.xslt
-       @$(ECHO) "Identifying dependencies…"
+       @$(PRINTF) '%s\n' 'Identifying dependencies…'
+       $(silent)$(TOUCH) $(call quote,$@)
        $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2dependencies.xslt) $(call quote,$<)
 
 # Generate a catalog of destinations for files.
@@ -591,39 +617,44 @@ $(BUILDDIR)/dependencies : $(BUILDDIR)/catalog $(call parsed,$(plaintextfiles) $
 # This depends on parsing non·asset source files, but not assets or includes.
 # It does not require knowing the dependencies.
 $(BUILDDIR)/destinations : $(BUILDDIR)/catalog $(call parsed,$(filter-out $(assetfiles),$(sourcefiles))) $(THISDIR)/lib/catalog2destinations.xslt
-       @$(ECHO) "Identifying output destinations…"
+       @$(PRINTF) '%s\n' 'Identifying output destinations…'
+       $(silent)$(TOUCH) $(call quote,$@)
        $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2destinations.xslt) $(call quote,$<)
 
 # Generate the main transform.
 $(BUILDDIR)/transform.catalog : $(call diffprereqs,transforms,$(sort $(TRANSFORMS)))
-       @$(ECHO) "Generating catalog of transforms…"
+       @$(PRINTF) '%s\n' 'Generating catalog of transforms…'
        $(silent)$(XMLCATALOG) --create --noout $(call quote,$@)
-       $(foreach transform,$(TRANSFORMS),$(silent)( $(call id,$(transform)) ) | $(XARGS) -I %% $(XMLCATALOG) --add uri %% $(call quote,$(call fileuri,$(transform))) --noout $(call quote,$@)$(newline))
+       $(foreach transform,$(TRANSFORMS),$(silent){ $(call id,$(transform)); $(PRINTF) '%s\n' $(call quote,$(call fileuri,$(transform))) '--noout' $(call quote,$@); } | $(xargsmultiquote) | $(XARGS) -E '' $(XMLCATALOG) --add uri$(newline))
 $(BUILDDIR)/transform.xslt : $(BUILDDIR)/transform.catalog $(THISDIR)/lib/catalog2transform.xslt
-       @$(ECHO) "Generating main transform…"
+       @$(PRINTF) '%s\n' 'Generating main transform…'
        $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2transform.xslt) $(call quote,$<)
 
 # Compile the result files using the dependencies as necessary.
 $(call compiled,$(compilablefiles)) : $(BUILDDIR)/results/% : $$(call parsed,$$(call uncompiled,$$@)) $(BUILDDIR)/transform.xslt $$(call parsed,$$(call dependencies,$$(call uncompiled,$$@)))
        @$(PRINTF) '%s\n' $(call quote,Compiling </$*>…)
        $(silent)$(call ensuredirectory,$(dir $@))
-       $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) --stringparam CATALOG 'catalog' --stringparam BUILDTIME $$(TZ= $(DATE) '+%Y-%m-%dT%H:%M:%SZ') --stringparam SRCTIME '$(call modtime,$(call uncompiled,$@))' --stringparam IDENTIFIER $(call quote,$(call localuri,$(call uncompiled,$@))) --stringparam PATH $(call quote,/$*) --stringparam CKSUM $$($(CKSUM) $(call quote,$(call uncompiled,$@)) | $(SED) 's/[ ].*//')$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) $(call quote,$(BUILDDIR)/transform.xslt) $(call quote,$<)
+       $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) --stringparam CATALOG 'catalog' --stringparam BUILDTIME $$($(DATE) -u '+%Y-%m-%dT%H:%M:%SZ') --stringparam SRCTIME '$(call modtime,$(call uncompiled,$@))' --stringparam IDENTIFIER $(call quote,$(call localuri,$(call uncompiled,$@))) --stringparam PATH $(call quote,/$*) --stringparam CKSUM $$($(CKSUM) $(call quote,$(call uncompiled,$@)) | $(SED) 's/[ ].*//')$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) $(call quote,$(BUILDDIR)/transform.xslt) $(call quote,$<)
 
 # Create the final files from the compiled results (or error in the case of recursive ones).
 $(call built,$(compilablefiles)) : $(BUILDDIR)/public/% : $(BUILDDIR)/results/%
        @$(PRINTF) '%s\n' $(call quote,Building </$*>…)
        $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)$(RM) -f -R $(call quote,$@)
        $(silent)$(call processresultto,$<,$@,$*)
 $(call built,$(filter $(assetfiles),$(sourcefiles))) : $(BUILDDIR)/public/% : $$(call unbuilt,$$@)
        @$(PRINTF) '%s\n' $(call quote,Building </$*>…)
        $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)$(RM) -f -R $(call quote,$@)
        $(silent)$(CP) $(call quote,$<) $(call quote,$@)
 
 # Install compiled files (or error in the case of recursive ones).
 $(call installed,$(recursivefiles) $(installablefiles)) : $(DESTDIR)/% : $(BUILDDIR)/public/%
        @$(PRINTF) '%s\n' $(call quote,Installing </$*>…)
        $(silent)$(call ensuredirectory,$(dir $@))
-       $(silent)$(CP) $(call quote,$<) $(call quote,$@)
+       $(silent)$(RM) -f -R $(call quote,$@)
+       $(silent)$(CP) -R $(call quote,$<) $(call quote,$@)
+       $(silent)for associated in $$($(call associatedfiles,$(dir $<),$(notdir $<))); do $(PRINTF) '%s\n' "$$associated" | $(SED) 's/^\(.*\)"{\(.*\)}"\(.*\)$$/\1\2\3/' | $(xargsquote) | $(XARGS) -E '' $(PRINTF) '%s%s\n' $(call quote,$(dir $@)) | $(xargsquote) | $(XARGS) -E '' $(CP) $(call quote,$(dir $<))"$$associated"; done
 
 # ━ § BEGIN ARCHIVE MAKE·FILE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
@@ -669,15 +700,72 @@ $(foreach file,$(archivefiles),$(BUILDDIR)/extracted/$(file)) : $(BUILDDIR)/inde
 $(foreach file,$(archivefiles),$(BUILDDIR)/files/$(file)) : $(BUILDDIR)/files/% : $(BUILDDIR)/extracted/%
        @$(PRINTF) '%s\n' $(call quote,Building </$(NAME)/$*>…)
        $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)$(RM) -f -R $(call quote,$@)
        $(silent)$(call processresultto,$<,$@,$*)
 
 # Archive all components in the file to the destination.
 #
 # This is a match‐anything target, with the assumption that this make·file is being called recursively from the default mode.
-$(DESTDIR)/% : $(foreach file,$(archivefiles),$(BUILDDIR)/files/$(file))
+$(DESTDIR)/% : $(SRC) $(foreach file,$(archivefiles),$(BUILDDIR)/files/$(file))
        @$(PRINTF) '%s\n' $(call quote,Archiving </$(NAME)>…)
        $(silent)$(call ensuredirectory,$(dir $@))
-       $(silent)cd $(call quote,$(BUILDDIR)/files); $(PRINTF) '%s\n' $(foreach file,$(archivefiles),$(call quote,$(file))) | $(PAX) -w > $(call quote,$(abspath $@))
+       $(silent)$(RM) -f -R $(call quote,$@)
+       $(silent)cd $(call quote,$(BUILDDIR)/files); if $(call xpath,/*/@*[local-name()="expanded" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$(abspath $<)); then $(MKDIR) -p $(call quote,$(abspath $@)); $(PRINTF) '%s\n' $(foreach file,$(archivefiles),$(call quote,$(file))) | $(PAX) -r -w $(call quote,$(abspath $@)); else $(PRINTF) '%s\n' $(foreach file,$(archivefiles),$(call quote,$(file))) | $(PAX) -w -x ustar > $(call quote,$(abspath $@)); fi
+
+# ━ § BEGIN PAGED MAKE·FILE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+else ifeq ($(MODE),urn:fdc:ladys.computer:20231231:Shu1She4:mode:paged)
+
+# ─ ¶ Non‐Recipe Variable Definitions ─────────────────────────────────
+
+# Get the list of pages.
+ifneq ($(wildcard $(BUILDDIR)/index),)
+override pagefiles := $(patsubst ./pages/%,%,$(shell $(CAT) $(call quote,$(BUILDDIR)/index)))
+endif
+
+# ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
+
+# ─ ¶ Phony Targets ───────────────────────────────────────────────────
+
+# ─ ¶ Special Targets ─────────────────────────────────────────────────
+
+# Reload this make·file if the pages have changed.
+$(THISDIR)/GNUmakefile : $(BUILDDIR)/index
+       $(silent)$(TOUCH) $(THISDIR)/GNUmakefile
+       @$(PRINTF) '%b\n' $(call quote,\0033[1mPages for </$(NAME)> updated. Restarting…\0033[22m)
+
+# ─ ¶ Build Targets ───────────────────────────────────────────────────
+
+# Build the extractor transform for extracting the pages of the paged source file.
+$(BUILDDIR)/extractor.xslt : $(SRC) $(THISDIR)/lib/paged2extractor.xslt
+       $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) --stringparam NAME $(call quote,$(call notdir,$<)) $(call quote,$(THISDIR)/lib/paged2extractor.xslt) $(call quote,$<)
+
+# Use the extractor transform to extract the paged source file out into its pages.
+#
+# This target sleeps for 1 second to ensure the resulting index will always be newer than this make·file.
+$(BUILDDIR)/index : $(BUILDDIR)/extractor.xslt $(SRC)
+       @$(PRINTF) '%s\n' $(call quote,Extracting pages for </$(NAME)>…)
+       $(silent)$(SLEEP) 1
+       $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) --writesubtree $(call quote,$(dir $@)) $(call quote,$<) $(call quote,$(SRC))
+
+# All other pages are extracted alongside the base.
+$(foreach file,$(pagefiles),$(BUILDDIR)/pages/$(file)) : $(BUILDDIR)/index ;
+
+# Process each page into its final form.
+$(foreach file,$(pagefiles),$(BUILDDIR)/public/$(file)) : $(BUILDDIR)/public/% : $(BUILDDIR)/pages/%
+       @$(PRINTF) '%s\n' $(call quote,Building page `$(subst }",,$(subst "{,,$*))´ of </$(NAME)>…)
+       $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)$(call processresultto,$<,$@,$*)
+
+# Archive all components in the file to the destination.
+#
+# This is a match‐anything target, with the assumption that this make·file is being called recursively from the default mode.
+$(DESTDIR)/% : $(foreach file,$(pagefiles),$(BUILDDIR)/public/$(file))
+       @$(PRINTF) '%s\n' $(call quote,Collecting pages for </$(NAME)>…)
+       $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)$(call removeassociatedfiles,$@)
+       $(silent)cp $(foreach file,$(pagefiles),$(call quote,$(BUILDDIR)/public/$(file))) $(DESTDIR)
 
 # ━ § END DEFINED MAKE·FILE MODES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
This page took 0.034007 seconds and 4 git commands to generate.