-# SPDX-FileCopyrightText: 2023, 2024 Lady <https://www.ladys.computer/about/#lady>
+# SPDX-FileCopyrightText: 2023, 2024, 2025 Lady <https://www.ladys.computer/about/#lady>
# SPDX-License-Identifier: MPL-2.0
SHELL = /bin/sh
EXTRAFINDDATARULES :=
FINDDATARULES := -name '.' $(foreach ext,$(DATAEXT), -o -name '$(subst ','"'"',[!.]*.$(ext))')$(if $(EXTRAFINDDATARULES), -a '(' $(EXTRAFINDDATARULES) ')',)
+# A semicolon‐separated list of regular expressions which paths should be required to match when finding files.
+FINDFILTERONLY :=
+
+# A semicolon‐separated list of regular expressions for paths which should be filtered out when finding files.
+FINDFILTEROUT :=
+
+# A semicolon‐separated list of regular expressions for paths which paths should be required to match when finding includes.
+#
+# This is generally only useful when `SRCDIR´ and `INCLUDEDIR´ point to the same location.
+# In that situation, this variable can be used to select certain files as includes, leaving the others to be recognized as sources instead.
+#
+# Otherwise, appropriately constructing `FINDFILTERONLY´ to look at the base directory of the files it finds should be sufficient.
+FINDINCLUDEFILTERONLY :=
+
+# A semicolon‐separated list of regular expressions for paths which should be filtered out in addition to those in `FINDFILTEROUT´ when finding includes.
+#
+# This is generally only useful when `SRCDIR´ and `INCLUDEDIR´ point to the same location.
+# In that situation, this variable can be used to exclude certain files from being recognized as includes, which will make them recognized as sources instead.
+#
+# Otherwise, appropriately constructing `FINDFILTEROUT´ to look at the base directory of the files it finds should be sufficient.
+FINDINCLUDEFILTEROUT :=
+
+# If not empty, the regular expression provided by `FINDFILTERONLY´ is an extended regular expression.
+FINDFILTERONLYEXTENDED :=
+
+# If not empty, the regular expression provided by `FINDFILTEROUT´ is an extended regular expression.
+#
+# By default, this matches `FINDFILTERONLYEXTENDED´
+FINDFILTEROUTEXTENDED := $(FINDFILTERONLYEXTENDED)
+
+# If not empty, the regular expression provided by `FINDFILTEROUT´ is an extended regular expression.
+#
+# By default, this matches `FINDFILTERONLYEXTENDED´
+FINDINCLUDEFILTERONLYEXTENDED := $(FINDFILTERONLYEXTENDED)
+
+# If not empty, the regular expression provided by `FINDINCLUDEFILTEROUT´ is an extended regular expression.
+#
+# By default, this matches `FINDFILTEROUTEXTENDED´
+FINDINCLUDEFILTEROUTEXTENDED := $(and $(FINDFILTERONLYEXTENDED),$(FINDFILTEROUTEXTENDED),1)
+
# The list of magic files to use when determining media types.
#
# Some are provided as part of this repository, but you can add more if you need different media type detection.
# If `$(notbuilding)´ is non·empty, this variable produces no result to avoid unnecessary work.
#
# ☡ This variable creates at least one subshell every time it is computed.
-override diffprereqs = $(if $(notbuilding),,$(and $(subst $(shell $(CAT) $(call quote,$(BUILDDIR)/lastprereqs/$1) 2>>/dev/null || :),,$2),$(shell $(call ensuredirectory,$(BUILDDIR)/lastprereqs) && $(PRINTF) '%s\n' $(call quote,$2) >|$(BUILDDIR)/lastprereqs/$1),)$2 $(BUILDDIR)/lastprereqs/$1)
+override diffprereqs = $(if $(notbuilding),,$(and $(or $(wildcard $(BUILDDIR)/lastprereqs/$1),$(shell $(TOUCH) $(call quote,$(BUILDDIR)/lastprereqs/$1)),1),$(subst $(shell $(CAT) $(call quote,$(BUILDDIR)/lastprereqs/$1) 2>>/dev/null || :),,$2),$(shell $(call ensuredirectory,$(BUILDDIR)/lastprereqs) && $(PRINTF) '%s\n' $(call quote,$2) >|$(call quote,$(BUILDDIR)/lastprereqs/$1)),)$2 $(BUILDDIR)/lastprereqs/$1)
# ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
override sedesc = $(subst /,[/],$(subst $$,\$$,$(subst *,\*,$(subst .,\.,$(subst [,\[,$(subst ^,\^,$(subst \,\\,$1)))))))
# (overridable) Collect all of the applicable includes from the includes directory.
-sourceincludes := $(if $(and $(INCLUDEDIR),$(wildcard $(INCLUDEDIR))),$(patsubst ./%,%,$(shell $(FIND) $(foreach dir,$(INCLUDEDIR),$(call quote,$(dir))) '(' $(FINDINCLUDERULES) ')' -a -type f -a -print)),)
+sourceincludes := $(foreach dir,$(INCLUDEDIR),$(and $(dir),$(wildcard $(dir)),$(patsubst ./%,%,$(shell $(FIND) $(call quote,$(dir)) '(' $(FINDINCLUDERULES) ')' -a -type f -a -print$(and $(FINDFILTERONLY),$(space)| $(GREP)$(and $(FINDFILTERONLYEXTENDED),$(space)-E) $(foreach filter,$(shell $(PRINTF) '%s\n' $(call quote,$(FINDFILTERONLY)) | $(TR) ' ;' '; '),-e $(call quote,$(subst ;, ,$(filter)))))$(and $(FINDINCLUDEFILTERONLY),$(space)| $(GREP)$(and $(FINDINCLUDEFILTERONLYEXTENDED),$(space)-E) $(foreach filter,$(shell $(PRINTF) '%s\n' $(call quote,$(FINDINCLUDEFILTERONLY)) | $(TR) ' ;' '; '),-e $(call quote,$(subst ;, ,$(filter)))))$(and $(FINDFILTEROUT),$(space)| $(GREP)$(and $(FINDFILTEROUTEXTENDED),$(space)-E) -v $(foreach filter,$(shell $(PRINTF) '%s\n' $(call quote,$(FINDFILTEROUT)) | $(TR) ' ;' '; '),-e $(call quote,$(subst ;, ,$(filter)))))$(and $(FINDINCLUDEFILTEROUT),$(space)| $(GREP)$(and $(FINDINCLUDEFILTEROUTEXTENDED),$(space)-E) -v $(foreach filter,$(shell $(PRINTF) '%s\n' $(call quote,$(FINDINCLUDEFILTEROUT)) | $(TR) ' ;' '; '),-e $(call quote,$(subst ;, ,$(filter)))))))))
# (overridable) Collect all of the applicable source files from the source directory, removing any which are also includes.
-sourcefiles := $(if $(and $(SRCDIR),$(wildcard $(SRCDIR))),$(filter-out $(sourceincludes),$(patsubst ./%,%,$(shell $(FIND) $(foreach dir,$(SRCDIR),$(call quote,$(dir))) '(' $(FINDRULES) ')' -a -type f -a -print))))
+sourcefiles := $(filter-out $(sourceincludes),$(foreach dir,$(SRCDIR),$(and $(dir),$(wildcard $(dir)),$(patsubst ./%,%,$(shell $(FIND) $(call quote,$(dir)) '(' $(FINDRULES) ')' -a -type f -a -print$(and $(FINDFILTERONLY),$(space)| $(GREP)$(and $(FINDFILTERONLYEXTENDED),$(space)-E) $(foreach filter,$(shell $(PRINTF) '%s\n' $(call quote,$(FINDFILTERONLY)) | $(TR) ' ;' '; '),-e $(call quote,$(subst ;, ,$(filter)))))$(and $(FINDFILTEROUT),$(space)| $(GREP)$(and $(FINDFILTEROUTEXTENDED),$(space)-E) -v $(foreach filter,$(shell $(PRINTF) '%s\n' $(call quote,$(FINDFILTEROUT)) | $(TR) ' ;' '; '),-e $(call quote,$(subst ;, ,$(filter))))))))))
# Figure out the file type of each source file and source include.
ifneq ($(wildcard $(BUILDDIR)/magic.mgc),)
# • When the metadata of ⹐source files they depend on⹑ change.
#
# This is to reduce the number of needless regenerations of files with no substantial change.
-$(call compiled,$(compilablefiles)) : $(BUILDDIR)/results/% : $$(call parsed,$$(call uncompiled,$$@)) $$(call parsed,$$(call dependencies,$$(call uncompiled,$$@))) $(BUILDDIR)/transform.catalog $(TRANSFORMLIBS) $$(call metadata,$$(call dependencies,$$(call uncompiled,$$@)))
+$(call compiled,$(compilablefiles)) : $(BUILDDIR)/results/% : $$(call parsed,$$(call uncompiled,$$@)) $$(call parsed,$$(call dependencies,$$(call uncompiled,$$@))) $(BUILDDIR)/transform.catalog $(THISDIR)/lib/catalog2transform.xslt $(TRANSFORMLIBS) $$(call metadata,$$(call dependencies,$$(call uncompiled,$$@)))
$(call inform,$(PRINTF) '%s\n' $(call quote,Compiling </$*>…) >&2)
$(silent)$(call ensuredirectory,$(dir $@))
$(silent)$(XSLTPROC) --nonet --novalid --nomkdir --nowrite --stringparam METADATA 'metadata' --stringparam BUILDTIME $$($(DATE) -u '+%Y-%m-%dT%H:%M:%SZ') --stringparam IDENTIFIER $(call quote,$(call localuri,$(call uncompiled,$@)))$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) $(call quote,$(BUILDDIR)/transform.xslt) $(call quote,$<) >|$(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/%
+$(call built,$(compilablefiles)) : $(BUILDDIR)/public/% : $(BUILDDIR)/results/% $(THISDIR)/lib/archive2extractor.xslt
$(call inform,$(PRINTF) '%s\n' $(call quote,Building </$*>…) >&2)
$(silent)$(call ensuredirectory,$(dir $@))
$(silent)$(RM) -f -R $(call quote,$@)
# ─ ¶ Non‐Recipe Variable Definitions ─────────────────────────────────
# Non·empty if this is a two‐step build.
-override twostep := $(if $(DATADIR),$(shell if $(TEST) -d $(call quote,$(DATADIR)); then $(PRINTF) '%s\n' '1'; fi),)
+override twostep := $(if $(DATADIR),$(call not,$(shell for dir in $(foreach dir,$(DATADIR),$(call quote,$(dir))); do if $(TEST) '!' -d "$$dir"; then $(PRINTF) '%s\n' '0'; fi; done)),)
# Pair each source magic file with its location in the build directory.
override magicpair := $(foreach magicfile,$(MAGIC),$(magicfile)|$(BUILDDIR)/magic/$(call namehash,$(magicfile)))