summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Master/texmf-dist/doc/latex/zref-check/CHANGELOG.md8
-rw-r--r--Master/texmf-dist/doc/latex/zref-check/DEPENDS.txt3
-rw-r--r--Master/texmf-dist/doc/latex/zref-check/README.md17
-rw-r--r--Master/texmf-dist/doc/latex/zref-check/zref-check-code.pdfbin0 -> 702150 bytes
-rw-r--r--Master/texmf-dist/doc/latex/zref-check/zref-check-code.tex87
-rw-r--r--Master/texmf-dist/doc/latex/zref-check/zref-check.pdfbin0 -> 454988 bytes
-rw-r--r--Master/texmf-dist/doc/latex/zref-check/zref-check.tex89
-rw-r--r--Master/texmf-dist/source/latex/zref-check/zref-check.dtx2218
-rw-r--r--Master/texmf-dist/source/latex/zref-check/zref-check.ins98
-rw-r--r--Master/texmf-dist/tex/latex/zref-check/zref-check.sty962
-rwxr-xr-xMaster/tlpkg/bin/tlpkg-ctan-check2
-rw-r--r--Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc1
-rw-r--r--Master/tlpkg/tlpsrc/zref-check.tlpsrc0
13 files changed, 3484 insertions, 1 deletions
diff --git a/Master/texmf-dist/doc/latex/zref-check/CHANGELOG.md b/Master/texmf-dist/doc/latex/zref-check/CHANGELOG.md
new file mode 100644
index 00000000000..debf07cafcb
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/zref-check/CHANGELOG.md
@@ -0,0 +1,8 @@
+# Changelog
+
+## [Unreleased](https://github.com/gusbrs/zref-check/compare/v0.1.0...HEAD)
+
+## [v0.1.0](https://github.com/gusbrs/zref-check/releases/tag/v0.1.0) (2021-08-04)
+
+### Added
+- Initial release.
diff --git a/Master/texmf-dist/doc/latex/zref-check/DEPENDS.txt b/Master/texmf-dist/doc/latex/zref-check/DEPENDS.txt
new file mode 100644
index 00000000000..bd9b1e21c48
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/zref-check/DEPENDS.txt
@@ -0,0 +1,3 @@
+hard zref
+hard oberdiek
+soft hyperref
diff --git a/Master/texmf-dist/doc/latex/zref-check/README.md b/Master/texmf-dist/doc/latex/zref-check/README.md
new file mode 100644
index 00000000000..c5726af278e
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/zref-check/README.md
@@ -0,0 +1,17 @@
+# zref-check
+
+**Flexible LaTeX cross-references with contextual checks based on zref**
+
+`zref-check` provides an user interface for making LaTeX cross-references
+flexibly, while allowing to have them checked for consistency with the
+document structure as typeset. Statements such as “above”, “on the next
+page”, “previously”, “as will be discussed”, “on the previous chapter” and so
+on can be given to `\zcheck` in free-form, and a set of “checks” can be
+specified to be run against a given `label`, which will result in a warning at
+compilation time if any of these checks fail. `\zctarget` and the `zcregion`
+environment are also defined as a means to easily set label targets to
+arbitrary places in the text which can be referred to by `\zcheck`.
+
+The released version of this package is available from CTAN.
+
+For more details, check the Documentation.
diff --git a/Master/texmf-dist/doc/latex/zref-check/zref-check-code.pdf b/Master/texmf-dist/doc/latex/zref-check/zref-check-code.pdf
new file mode 100644
index 00000000000..52682fbc5e5
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/zref-check/zref-check-code.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/zref-check/zref-check-code.tex b/Master/texmf-dist/doc/latex/zref-check/zref-check-code.tex
new file mode 100644
index 00000000000..d9ee1c58d0a
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/zref-check/zref-check-code.tex
@@ -0,0 +1,87 @@
+% \iffalse meta-comment
+%
+% File: zref-check-code.tex
+%
+% This file is part of the LaTeX package "zref-check".
+%
+% Copyright (C) 2021 Gustavo Barros
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file:
+%
+% https://www.latex-project.org/lppl.txt
+%
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+%
+% This work is "maintained" (as per LPPL maintenance status) by
+% Gustavo Barros.
+%
+% This work consists of the files zref-check.dtx,
+% zref-check.ins,
+% zref-check.tex,
+% zref-check-code.tex,
+% and the derived files zref-check.sty and
+% zref-check.pdf,
+% zref-check-code.pdf.
+%
+% The released version of this package is available from CTAN.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the package can be found at
+%
+% https://github.com/gusbrs/zref-check
+%
+% for those people who are interested.
+%
+% -----------------------------------------------------------------------
+%
+% \fi
+
+\documentclass{l3doc}
+
+% Have \GetFileInfo pick up date and version data
+\usepackage{zref-check}
+
+\NewDocumentCommand\opt{m}{\texttt{#1}}
+
+% Have the Index at 'section' level rather than 'part'. Otherwise it is just
+% the same definition from 'l3doc.cls'.
+\IndexPrologue{%
+ \section*{Index}
+ \markboth{Index}{Index}
+ \addcontentsline{toc}{section}{Index}
+ The italic numbers denote the pages where the corresponding entry is
+ described, numbers underlined point to the definition, all others indicate
+ the places where it is used.%
+}
+
+\begin{document}
+
+\GetFileInfo{zref-check.sty}
+
+\title{%
+ The \pkg{zref-check} package implementation%
+ \thanks{This file describes \fileversion, last revised \filedate.}%
+}
+
+\author{%
+ Gustavo Barros%
+ \thanks{\url{https://github.com/gusbrs/zref-check}}%
+}
+
+\date{\filedate}
+
+\maketitle
+
+\tableofcontents
+
+\DisableDocumentation
+
+\DocInput{zref-check.dtx}
+
+\end{document}
diff --git a/Master/texmf-dist/doc/latex/zref-check/zref-check.pdf b/Master/texmf-dist/doc/latex/zref-check/zref-check.pdf
new file mode 100644
index 00000000000..ffdf3330371
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/zref-check/zref-check.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/zref-check/zref-check.tex b/Master/texmf-dist/doc/latex/zref-check/zref-check.tex
new file mode 100644
index 00000000000..0edf9557f85
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/zref-check/zref-check.tex
@@ -0,0 +1,89 @@
+% \iffalse meta-comment
+%
+% File: zref-check.tex
+%
+% This file is part of the LaTeX package "zref-check".
+%
+% Copyright (C) 2021 Gustavo Barros
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file:
+%
+% https://www.latex-project.org/lppl.txt
+%
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+%
+% This work is "maintained" (as per LPPL maintenance status) by
+% Gustavo Barros.
+%
+% This work consists of the files zref-check.dtx,
+% zref-check.ins,
+% zref-check.tex,
+% zref-check-code.tex,
+% and the derived files zref-check.sty and
+% zref-check.pdf,
+% zref-check-code.pdf.
+%
+% The released version of this package is available from CTAN.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the package can be found at
+%
+% https://github.com/gusbrs/zref-check
+%
+% for those people who are interested.
+%
+% -----------------------------------------------------------------------
+%
+% \fi
+
+\documentclass{l3doc}
+
+% Have \GetFileInfo pick up date and version data
+\usepackage{zref-check}
+
+\NewDocumentCommand\opt{m}{\texttt{#1}}
+
+\begin{document}
+
+\GetFileInfo{zref-check.sty}
+
+\title{%
+ The \pkg{zref-check} package%
+ \thanks{This file describes \fileversion, last revised \filedate.}%
+}
+
+\author{%
+ Gustavo Barros%
+ \thanks{\url{https://github.com/gusbrs/zref-check}}%
+}
+
+\date{\filedate}
+
+\maketitle
+
+\begin{abstract}
+ \pkg{zref-check} provides an user interface for making \LaTeX{}
+ cross-references flexibly, while allowing to have them checked for
+ consistency with the document structure as typeset. Statements such as
+ ``above'', ``on the next page'', ``previously'', ``as will be discussed'',
+ ``on the previous chapter'' and so on can be given to \cs{zcheck} in
+ free-form, and a set of ``checks'' can be specified to be run against a
+ given \texttt{label}, which will result in a warning at compilation time if
+ any of these checks fail. \cs{zctarget} and the \texttt{zcregion}
+ environment are also defined as a means to easily set label targets to
+ arbitrary places in the text which can be referred to by \cs{zcheck}.
+\end{abstract}
+
+\tableofcontents
+
+\DisableImplementation
+
+\DocInput{zref-check.dtx}
+
+\end{document}
diff --git a/Master/texmf-dist/source/latex/zref-check/zref-check.dtx b/Master/texmf-dist/source/latex/zref-check/zref-check.dtx
new file mode 100644
index 00000000000..3ef8af66d81
--- /dev/null
+++ b/Master/texmf-dist/source/latex/zref-check/zref-check.dtx
@@ -0,0 +1,2218 @@
+% \iffalse meta-comment
+%
+% File: zref-check.dtx
+%
+% This file is part of the LaTeX package "zref-check".
+%
+% Copyright (C) 2021 Gustavo Barros
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file:
+%
+% https://www.latex-project.org/lppl.txt
+%
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+%
+% This work is "maintained" (as per LPPL maintenance status) by
+% Gustavo Barros.
+%
+% This work consists of the files zref-check.dtx,
+% zref-check.ins,
+% zref-check.tex,
+% zref-check-code.tex,
+% and the derived files zref-check.sty and
+% zref-check.pdf,
+% zref-check-code.pdf.
+%
+% The released version of this package is available from CTAN.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the package can be found at
+%
+% https://github.com/gusbrs/zref-check
+%
+% for those people who are interested.
+%
+% -----------------------------------------------------------------------
+%
+% \fi
+%
+% \iffalse
+%<*driver>
+\documentclass{l3doc}
+% Have \GetFileInfo pick up date and version data
+\usepackage{zref-check}
+\NewDocumentCommand\opt{m}{\texttt{#1}}
+\MakeShortVerb{\|}
+\begin{document}
+ \DocInput{zref-check.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+%
+% \begin{documentation}
+%
+% \section{Introduction}
+%
+% The \pkg{zref-check} package provides an user interface for making \LaTeX{}
+% cross-references exploiting document contextual information to enrich the
+% way the reference can be rendered, but at the same time ensuring the means
+% that these cross-references can be done consistently with the document
+% structure.
+%
+% The usual \LaTeX{} cross-reference is done by referring to a \texttt{label},
+% associated with one or another document structural element, and this
+% reference will typeset for you some content based on the information which
+% is stored in that label. \cs{zcheck}, the main user command of
+% \pkg{zref-check}, has a somewhat different concept. Instead of trying to
+% provide the text to be typeset based on the contextual information,
+% \cs{zcheck} lets the user supply an arbitrary text and specify one or more
+% checks to be done on the label(s) being referred to. If any of the checks
+% fail, a warning is issued upon compilation, so that the user can go back to
+% that cross-reference and correct it as needed, without having to rely on
+% burdensome and error prone manual proof-reading.
+%
+% This grants a much increased flexibility for the cross-reference text, which
+% means in practice that the writing style, the variety of expressions you may
+% use for similar situations, does not need to be sacrificed for the
+% convenience. \cs{zcheck}'s cross-references do not need to ``feel''
+% automated to be consistently checked. Localization is also not an issue,
+% since the cross-reference text is provided directly by the user. Separating
+% ``typesetting'' from ``checking'' also means there is a lot of document
+% context we can leverage for this purpose (see Section~\ref{sec:checks}).
+%
+% A standard \LaTeX{} cross-reference is made to refer to specific numbered
+% document elements -- chapters, sections, figures, tables, equations, etc.
+% The cross-reference will normally produce that number (which is the
+% element's ``id'') and, eventually, its ``type'' (the counter). We may also
+% refer to the page that element occurs and even its ``title'' (in which case,
+% atypically, we may even get to refer to an unnumbered section, provided we
+% also implicitly supply by some means the ``id'').
+%
+% For references to these usual specific document elements, \pkg{zref-check}
+% caters for a particular kind of cross-reference which is common:
+% \emph{relational} statements based on them. \cs{zcheck} can typeset and
+% meaningfully check cross-references such as ``above'', ``on the next page'',
+% ``on the facing page'', ``on the previous section'', ``later on this
+% chapter'' and so on. After all, if your reference is being made on page 2
+% and refers to something on the same page, ``on this page'' reads much better
+% than ``on page~2''. If you are writing chapter~4, ``on the previous
+% chapter'' sounds nicer than ``on chapter~3''.
+%
+% However, there is yet another kind of ``looser'' cross-reference we
+% routinely do in our documents. Expressions such as ``previously'', ``as
+% mentioned before'', ``as will be discussed'', and so on, are a powerful
+% discursive instrument, which enriches the text, by offering hints to the
+% arguments' threads, without necessarily pressing them too hard onto the
+% reader. So, we might not want to say ``on footnote 57, pag.~34'', but
+% prefer ``previously'', not ``on Section 3.4'', but rather ``below'', or
+% ``later on''. Besides, we also may refer to certain passages in the text in
+% this way, rather than to numbered document elements. And this kind of
+% reference is not only hard to check and find, but also to fix. After all,
+% if you are making one such reference, you are taking that statement as a
+% premisse at the current point in the text. So, if that reference is
+% missing, or relocated, you may need to bring in the support to the premisse
+% for your argument to close, rather than just ``adjust the reference text''.
+% \pkg{zref-check} also provides support for this kind of cross-reference,
+% allowing for them to be consistently verified.
+%
+%
+%
+% \section{Loading the package}
+% \label{sec:loading-package}
+%
+% As usual:
+%
+% \begin{syntax}
+% \cs{usepackage}\oarg{options}|{zref-check}|
+% \end{syntax}
+%
+%
+%
+% \section{Dependencies}
+%
+% \pkg{zref} is required, of course, but in particular, its modules
+% \pkg{zref-user} and \pkg{zref-abspage} are loaded by default. \pkg{ifdraft}
+% (from the \pkg{oberdiek} bundle) is also loaded by default. A \LaTeX{}
+% kernel later than 2021-06-01 is required, since we rely on the new hook
+% system from \pkg{ltcmdhooks} for the sectioning checks. If \pkg{hyperref}
+% is loaded and option \pkg{hyperref} is given, \pkg{zref-check} makes use of
+% it, but it does not load the package for you.
+%
+%
+% \section{User interface}
+% \label{sec:user-interface}
+%
+% \begin{function}{\zcheck}
+% \begin{syntax}
+% \cs{zcheck}\oarg{options}\marg{labels}\oarg{checks}\marg{text}
+% \end{syntax}
+% Typesets \marg{text}, as given, while performing the comma separated list
+% of \oarg{checks} on each of the comma separated list of \marg{labels}.
+% When \pkg{hyperref} support is enabled, \marg{text} will be made a
+% hyperlink to \emph{the first} label in \marg{labels}. The starred version
+% of the command does the same as the plain one, just does not form a link.
+% The \oarg{options} are (mostly) the same as those of the package, and can
+% be given to local effect.
+% \end{function}
+%
+% \begin{function}{\zctarget}
+% \begin{syntax}
+% \cs{zctarget}\marg{label}\marg{text}
+% \end{syntax}
+% Typesets \marg{text}, as given, and places a pair of \texttt{zlabel}s, one
+% at the start of \marg{text}, using \marg{label} as label name, another one
+% (internal) at the end of \marg{text}.
+% \end{function}
+%
+%
+% \begin{function}{zcregion}
+% \begin{syntax}
+% |\begin{zcregion}|\marg{label}
+% | ...|
+% |\end{zcregion}|
+% \end{syntax}
+% An environment that does the same as \cs{zctarget}, for cases of longer
+% stretches of text.
+% \end{function}
+%
+%
+% \begin{function}{\zrefchecksetup}
+% \begin{syntax}
+% \cs{zrefchecksetup}\marg{options}
+% \end{syntax}
+% Sets \pkg{zref-check}'s options (see Section~\ref{sec:options}).
+% \end{function}
+%
+%
+% \section{Checks}
+% \label{sec:checks}
+%
+% \pkg{zref-check} provides several ``checks'' to be used with \cs{zcheck}.
+% The checks may be combined in a \cs{zcheck} call, e.g.\ \opt{[close,
+% after]}, or \opt{[thischap, before]}. In this case, each check in
+% \oarg{checks} is performed against each of the \marg{labels}. This is done
+% independently for each check, which means, in practice, that the checks bear
+% a logical \texttt{AND} relation to the others. Whether the combination is
+% meaningful, is up to the user. As is the correspondence between the
+% \oarg{checks} and the \marg{text>} in \cs{zcheck}.
+%
+% The use of checks which perform ``within the page'' comparisons -- namely
+% \opt{above} and \opt{below} and, through them, \opt{before} and \opt{after}
+% -- comes with some caveats you should be acquainted with.
+% Section~\ref{sec:within-page-checks} discusses their limitations and expands
+% on the expected workflow for their use to ensure reliable results.
+%
+% Note that the naming convention of the checks adopts the perspective of
+% \cs{zcheck}. That is, the name of the check describes the position of the
+% label being referred to, relative to the \cs{zcheck} call being made. For
+% example, the \opt{before} check should issue no message if
+% \cs{ztarget}|{mylabel}{...}| occurs before
+% \cs{zcheck}|{mylabel}[before]{...}|.
+%
+% The available checks are the following:
+%
+% \begin{description}[leftmargin=0pt, itemindent=0pt, align=right,
+% labelsep=1em, font=\MacroFont]
+%
+% \item[thispage] \meta{label} occurs on the same page as \cs{zcheck}.
+%
+% \item[prevpage] \meta{label} occurs on the previous page relative to
+% \cs{zcheck}.
+%
+% \item[nextpage] \meta{label} occurs on the next page relative to
+% \cs{zcheck}.
+%
+% \item[facing] On a \texttt{twoside} document, both \meta{label} and
+% \cs{zcheck} fall onto a double spread, each on one of the two facing
+% pages.
+%
+% \item[above] \meta{label} and \cs{zcheck} are both on the same page, and
+% \meta{label} occurs ``above'' \cs{zcheck}.
+%
+% \item[below] \meta{label} and \cs{zcheck} are both on the same page, and
+% \meta{label} occurs ``below'' \cs{zcheck}.
+%
+% \item[pagesbefore] \meta{label} occurs on any page before the one of
+% \cs{zcheck}.
+%
+% \item[ppbefore] Convenience alias for \opt{pagesbefore}.
+%
+% \item[pagesafter] \meta{label} occurs on any page after the one of
+% \cs{zcheck}.
+%
+% \item[ppafter] Convenience alias for \opt{pagesafter}.
+%
+% \item[before] Either \opt{above} or \opt{pagesbefore}.
+%
+% \item[after] Either \opt{below} or \opt{pagesafter}.
+%
+% \item[thischap] \meta{label} occurs on the same chapter as \cs{zcheck}.
+%
+% \item[prevchap] \meta{label} occurs on the previous chapter relative to the
+% one of \cs{zcheck}.
+%
+% \item[nextchap] \meta{label} occurs on the next chapter relative to the one
+% of \cs{zcheck}.
+%
+% \item[chapsbefore] \meta{label} occurs on any chapter before the one of
+% \cs{zcheck}.
+%
+% \item[chapsafter] \meta{label} occurs on any chapter after the one of
+% \cs{zcheck}.
+%
+% \item[thissec] \meta{label} occurs on the same section as \cs{zcheck}.
+%
+% \item[prevsec] \meta{label} occurs on the previous section (of the same
+% chapter) relative to the one of \cs{zcheck}.
+%
+% \item[nextsec] \meta{label} occurs on the next section (of the same chapter)
+% relative to the one of \cs{zcheck}.
+%
+% \item[secsbefore] \meta{label} occurs on any section (of the same chapter)
+% before the one of \cs{zcheck}.
+%
+% \item[secsafter] \meta{label} occurs on any section (of the same chapter)
+% after the one of \cs{zcheck}.
+%
+% \item[close] \meta{label} occurs within a page range from \opt{closerange}
+% pages before the one of \cs{zcheck} to \opt{closerange} pages after it
+% (about the \opt{closerange} option, see Section~\ref{sec:options}).
+%
+% \item[far] Not \opt{close}.
+%
+% \end{description}
+%
+%
+%
+% \section{Options}
+% \label{sec:options}
+%
+% Options are a standard \texttt{key=value} comma separated list, and can be
+% set globally either as \cs{usepackage}\oarg{options} at load-time (see
+% Section~\ref{sec:loading-package}), or by means of \cs{zrefchecksetup} (see
+% Section~\ref{sec:user-interface}) in the preamble. Most options can also be
+% used with local effects, through the optional argument \oarg{options} of
+% \cs{zcheck}.
+%
+% \DescribeOption{hyperref}
+% Controls the use of \pkg{hyperref} by \pkg{zref-check} and takes values
+% \opt{auto}, \opt{true}, \opt{false}. The default value, \opt{auto}, makes
+% \pkg{zref-check} use \pkg{hyperref} if it is loaded, meaning \cs{zcheck} can
+% be hyperlinked to the \emph{first label} in \marg{labels}. \opt{true} does
+% the same thing, but warns if \pkg{hyperref} is not loaded (\pkg{hyperref} is
+% never loaded for you). In either of these cases, if \pkg{hyperref} is
+% loaded, module \pkg{zref-hyperref} is also loaded by \pkg{zref-check}.
+% \opt{false} means not to use \pkg{hyperref} regardless of its availability.
+% This is a preamble only option, but \cs{zcheck} provides granular control of
+% hyperlinking by means of its starred version.
+%
+%
+% \DescribeOption{msglevel}
+% Sets the level of messages issued by \cs{zcheck} failed checks and takes
+% values \opt{warn}, \opt{info}, \opt{none}, \opt{obeydraft}, \opt{obeyfinal}.
+% The default value, \opt{warn}, issues messages both to the terminal and to
+% the log file, \opt{info} issues messages to the log file only, \opt{none}
+% suppresses all messages. \opt{obeydraft} corresponds to \opt{info} if
+% option \opt{draft} is passed to \cs{documentclass}, and to \opt{warn}
+% otherwise. \opt{obeyfinal} corresponds to \opt{warn} if option \opt{final}
+% is (explicitly) passed to \cs{documentclass} and \opt{info} otherwise.
+% \opt{ignore} is provided as convenience alias for \opt{msglevel=none} for
+% local use only. This option only affects the messages issued by the checks
+% in \cs{zcheck}, not other messages or warnings of the package. In
+% particular, it does not affect warnings issued for undefined labels, which
+% just use \cs{zref@refused} and thus are the same as standard \LaTeX{} ones
+% for this purpose.
+%
+%
+% \DescribeOption{onpage}
+% Allows to control the messaging style for ``within page checks'', and takes
+% values \opt{labelseq}, \opt{msg}, \opt{obeydraft}, \opt{obeyfinal}. The
+% default, \opt{labelseq}, uses the labels' shipout sequence, as retrieved
+% from the \file{.aux} file, to infer relative position within the page.
+% \opt{msg} also uses the same method for checking relative position, but
+% issues a (different) message \emph{even if the check passes}, to provide a
+% simple workflow for robust checking of ``false negatives'', considering the
+% label sequence is not fool proof (for details and workflow recommendations,
+% see Section~\ref{sec:within-page-checks}). \opt{msg} also issues its
+% messages at the same level defined in \opt{msglevel}. \opt{obeydraft}
+% corresponds to \opt{labelseq} if option \opt{draft} is passed to
+% \cs{documentclass} and to \opt{msg} otherwise. \opt{obeyfinal} corresponds
+% to \opt{msg} if option \opt{final} is (explicitly) passed to
+% \cs{documentclass}, and to \opt{labelseq} otherwise.
+%
+%
+% \DescribeOption{closerange}
+% Defines the width of the range of pages, relative to the reference, that are
+% considered ``close'' by the \opt{close} check. Takes a positive integer as
+% value, with default 5.
+%
+%
+% \DescribeOption{labelcmd}
+% Defines the command used to set the user labels in \cs{zctarget} and
+% \texttt{zcregion}. Takes a control sequence \emph{name} as value, and the
+% default sets labels with the minimal required properties, those of the
+% \texttt{zrefcheck} property list. This is a preamble only option. The
+% specified control sequence must receive one mandatory argument (the
+% \marg{label}) and must generate a \texttt{zref label} with at least the
+% properties in the \texttt{zrefcheck} property list. The intended use case
+% is that of the user creating a convenience macro which calls both \cs{label}
+% and \cs{zlabel}, as suggested in Section~\ref{sec:labels}, so that the same
+% labels are accessible either from the standard reference system or from
+% \pkg{zref}. For example:
+%
+% \begin{verbatim}
+% \NewDocumentCommand\mybothlabels{m}{\label{#1}\zlabel{#1}}
+% \zrefchecksetup{labelcmd=mybothlabels}
+% \end{verbatim}
+%
+% Note that the value of the underlying counter used for labels in
+% \cs{zctarget} and \texttt{zcregion} -- what you'd get with a plain \cs{ref}
+% here -- is not really meaningful. But you get to use
+% \cs{pageref}\marg{label}, or \pkg{hyperref}'s
+% \cs{hyperref}\oarg{label}\marg{text} on the labels used in \cs{zctarget} and
+% \texttt{zcregion} with this procedure.
+%
+%
+% \section{Labels}
+% \label{sec:labels}
+%
+% \pkg{zref-check} depends on \pkg{zref}, as the name entails, which means it
+% is able to work with \pkg{zref} labels, in general created by \cs{zlabel},
+% but also with \cs{zctarget} and the \texttt{zcregion} environment provided
+% by this package. This has some advantages, particularly the data
+% flexibility of \pkg{zref}, and the absence of the ubiquitous ``load-order''
+% and compatibility problems which are well known to afflict \LaTeX{} packages
+% of this area of functionality. On the other hand, the reliance on
+% \pkg{zref} labels may be seen as an inconvenience, since users of the
+% standard cross-reference infrastructure may need to add extra labels for
+% this. That's true. But \pkg{zref-check} is not meant to replace the
+% existing functionality of the kernel or of the traditional packages in this
+% area (to my knowledge, it only intersects directly with \pkg{varioref} and,
+% even so, it is quite different in scope). Indeed, it is easy to see the use
+% in tandem with standard references, for example:
+%
+% \begin{verbatim}
+% ... Figure~\ref{fig:figure-1}, \zcheck*{fig:figure-1}[nextpage]{on
+% the next page}.
+% \end{verbatim}
+%
+% Besides, \pkg{zref} does not share the label name-space with the standard
+% labels, so that you can call both \cs{label} and \cs{zlabel} with the same
+% label name (manually, or through a convenience macro), to ease the label set
+% administration. The example above presumes that was the case.
+%
+% All user commands of \pkg{zref-check} have their \marg{label} arguments
+% protected for \pkg{babel} active characters using \pkg{zref}'s
+% \cs{zref@wrapper@babel}, so that we should have equivalent support in that
+% regard, as \pkg{zref} itself does. However, \pkg{zref-check} sets labels
+% which either start with \texttt{zrefcheck@} or end with \texttt{@zrefcheck},
+% for internal use. Label names with either of those are considered reserved
+% by the package.
+%
+%
+% \section{Limitations}
+%
+% There are three qualitatively different kinds of checks being used by
+% \cs{zcheck}, according to the source and reliability of the information they
+% mobilize: page number checks, within page checks, and sectioning checks.
+%
+%
+% \subsection{Page number checks}
+%
+% Page number checks -- \opt{thispage}, \opt{prevpage}, \opt{nextpage},
+% \opt{pagesbefore}, \opt{pagesafter}, \opt{facing} -- use the
+% \texttt{abspage} property provided by the \pkg{zref-abspage} module. This
+% is a solid piece of information, on which we can rely upon. However,
+% despite that, page number checks may still become ill-defined, if the
+% \marg{text} argument in \cs{zcheck}, when typeset, crosses page boundaries,
+% starting in one page, and finishing in another. The same can happen with
+% the text in \cs{zctarget} and the \texttt{zcregion} environment.
+%
+% This is why the user commands of this package set always a pair or labels
+% around \meta{text}. So, when checking \cs{zcheck} against a regular
+% \texttt{zlabel} both the start and the end of the \meta{text} are checked
+% against the label, and the check fails if either of them fails. When
+% checking \cs{zcheck} against a \cs{zctarget} or a \texttt{zcregion}, both
+% beginnings and ends are checked against each other two by two, and if any of
+% them fails, the check fails. In other words, if a page number checks
+% passes, we know that the entire \meta{text} arguments pass it.
+%
+% This is a corner case (albeit relevant) which must be taken care of, and it
+% is possible to do so robustly. Hence, we can expect reliable results in
+% these tests.
+%
+%
+% \subsection{Within page checks}
+% \label{sec:within-page-checks}
+%
+% When both label and reference fall on the same page things become much
+% trickier. This is basically the case of the checks \opt{above} and
+% \opt{below} (and, through them, \opt{before} and \opt{after}). There is no
+% equally reliable information (that I know of) as we have for the page number
+% checks for this, especially when floats come into play. Which, of course,
+% is the interesting case to handle.
+%
+% To infer relative position of label and reference on the same page,
+% \pkg{zref-check} uses the labels' shipout sequence, which is retrieved at
+% load-time from the order in which the labels occur in the \file{.aux} file.
+% Indeed, \pkg{zref} writes labels to the \file{.aux} file at shipout (and,
+% hence, in shipout order), and needs to do so, because a number of its
+% properties are only available at that point.
+%
+% However, even if this method will buy us a correct check for a regular float
+% on a regular page (which, to be fair, is a good result), it is not difficult
+% do conceive situations in which this sequence may not be meaningful, or even
+% correct, for the case. A number of cases which may do so are: two column
+% documents, text wrapping, scaling, overlays, etc. (I don't know if those
+% make the method fail, I just don't know if they don't). Therefore, the
+% \texttt{labelseq} should be taken as a \emph{proxy} and not fully reliable,
+% meaning that the user should be watchful of its results.
+%
+% For this reason, \pkg{zref-check} provides an easy way to do so, by allowing
+% specific control of the messaging style of the checks which do within page
+% comparisons though the option \opt{onpage}. The concern is not really with
+% false positives (getting a warning when it was not due), but with false
+% negatives (not getting a warning when it was due). Hence, setting
+% \opt{onpage} to \opt{msg} at a final typesetting stage (or just set it to
+% \opt{obeydraft} or \opt{obeyfinal} if that's part of your workflow) provides
+% a way to easily identify all cases of such checks (failing or passing), and
+% double-check them. In case the test is passing though, the message is
+% different from that of a failing check, to quickly convey why you are
+% getting the message. This option can also be set at the local level, if the
+% page in question is known to be problematic, or just atypical.
+%
+%
+% \subsection{Sectioning checks}
+%
+% The information used by sectioning checks is provided by means of dedicated
+% counters for chapters and sections, similarly as standard counters for them,
+% but which are stepped and reset regardless of whether these sectioning
+% commands are numbered or not (that is, starred or not). And this for two
+% reasons. First, we don't need the absolute counter value to be able to make
+% the kind of relative statement we want to do here. Second, this allows us
+% to have these checks work for numbered and unnumbered sectioning commands
+% without having to worry about how those are used within the document.
+%
+% The caveat is that the package does this by hooking into \cs{chapter} and
+% \cs{section}, which poses two restrictions for the proper working of these
+% checks. First, we are using the new hook system for this, as provided by
+% \pkg{ltcmdhooks}, which means a \LaTeX{} kernel later than 2021-06-01 is
+% required. Second, since we are hooking into \cs{chapter} and \cs{section},
+% these checks presume these commands are being used by the document class for
+% this purpose (either directly, or internally as, for example, KOMA-Script's
+% \cs{addchap} and \cs{addsec} do). If that's not the case, additional setup
+% may be needed for these checks to work as expected.
+%
+%
+% \end{documentation}
+%
+%
+% \begin{implementation}
+%
+% \section{Initial setup}
+%
+% Start the \pkg{DocStrip} guards.
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+%
+% Identify the internal prefix (\LaTeX3 \pkg{DocStrip} convention).
+% \begin{macrocode}
+%<@@=zrefcheck>
+% \end{macrocode}
+%
+%
+% For the \texttt{chapter} and \texttt{section} checks, \pkg{zref-check} uses
+% the new hook system in \pkg{ltcmdhooks}, which was released with the
+% 2021/06/01 \LaTeX{} kernel.
+% \begin{macrocode}
+\providecommand\IfFormatAtLeastTF{\@ifl@t@r\fmtversion}
+\IfFormatAtLeastTF{2021-06-01}
+ {}
+ {%
+ \PackageError{zref-check}{LaTeX kernel too old}
+ {%
+ 'zref-check' requires a LaTeX kernel newer than 2021-06-01.%
+ \MessageBreak Loading will abort!%
+ }%
+ \endinput
+ }%
+% \end{macrocode}
+%
+% Identify the package.
+% \begin{macrocode}
+\ProvidesExplPackage {zref-check} {2021-08-04} {0.1.0}
+ {Flexible cross-references with contextual checks based on zref}
+% \end{macrocode}
+%
+% \section{Dependencies}
+%
+% \begin{macrocode}
+\RequirePackage { zref-user }
+\RequirePackage { zref-abspage }
+\RequirePackage { ifdraft }
+% \end{macrocode}
+%
+%
+% \section{\pkg{zref} setup}
+%
+% \begin{variable}{\g_@@_abschap_int, \g_@@_abssec_int}
+% Provide absolute counters for section and chapter, and respective
+% \pkg{zref} properties, so that we can make checks about relation of
+% chapters/sections regardless of internal counters, since we don't get
+% those for the unnumbered (starred) ones. About the proper place to make
+% the hooks for this purpose, see
+% \url{https://tex.stackexchange.com/q/605533/105447} (thanks Ulrike
+% Fischer).
+% \begin{macrocode}
+\int_new:N \g_@@_abschap_int
+\int_new:N \g_@@_abssec_int
+% \end{macrocode}
+% \end{variable}
+%
+%
+% If the documentclass does not define \cs{chapter} the only thing that
+% happens is that the chapter counter is never incremented, and the section
+% one never reset.
+% \begin{macrocode}
+\AddToHook { cmd / chapter / before }
+ {
+ \int_gincr:N \g_@@_abschap_int
+ \int_zero:N \g_@@_abssec_int
+ }
+\zref@newprop { abschap } [0] { \int_use:N \g_@@_abschap_int }
+\zref@addprop \ZREF@mainlist { abschap }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\AddToHook { cmd / section / before }
+ { \int_gincr:N \g_@@_abssec_int }
+\zref@newprop { abssec } [0] { \int_use:N \g_@@_abssec_int }
+\zref@addprop \ZREF@mainlist { abssec }
+% \end{macrocode}
+%
+%
+% This is the list of properties to be used by \pkg{zref-check}, that is, the
+% list of properties the references and targets store. This is the minimum
+% set required, more properties may be added according to options.
+% \begin{macrocode}
+\zref@newlist { zrefcheck }
+\zref@addprops { zrefcheck }
+ {
+ abspage ,
+ abschap ,
+ abssec ,
+ page
+ }
+% \end{macrocode}
+%
+%
+% \section{Plumbing}
+%
+% \subsection{Messages}
+%
+% \begin{macro}{\@@_message:nnnn, \@@_message:nnnx}
+% \begin{macrocode}
+\cs_new:Npn \@@_message:nnnn #1#2#3#4
+ {
+ \use:c { msg_ \l_@@_msglevel_tl :nnnnn }
+ { zref-check } {#1} {#2} {#3} {#4}
+ }
+\cs_generate_variant:Nn \@@_message:nnnn { nnnx }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+\msg_new:nnn { zref-check } { check-failed }
+ {
+ Failed~check~'#1'~for~label~'#2' \iow_newline:
+ on~page~#3~on~input~line~\msg_line_number:.
+ }
+\msg_new:nnn { zref-check } { double-check }
+ {
+ Double-check~'#1'~for~label~'#2' \iow_newline:
+ on~page~#3~on~input~line~\msg_line_number:.
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\msg_new:nnn { zref-check } { check-missing }
+ { Check~'#1'~not~defined~on~input~line~\msg_line_number:. }
+\msg_new:nnn { zref-check } { property-undefined }
+ { Property~'#1'~not~defined~on~input~line~\msg_line_number:. }
+\msg_new:nnn { zref-check } { property-not-in-label }
+ { Label~'#1'~has~no~property~'#2'~on~input~line~\msg_line_number:. }
+\msg_new:nnn { zref-check } { property-not-integer }
+ {
+ Property~'#1'~for~label~'#2'~not~an~integer \iow_newline:
+ on~input~line~\msg_line_number:.
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\msg_new:nnn { zref-check } { hyperref-preamble-only }
+ {
+ Option~'hyperref'~only~available~in~the~preamble. \iow_newline:
+ Use~the~starred~version~of~'\noexpand\zcheck'~instead.
+ }
+\msg_new:nnn { zref-check } { missing-hyperref }
+ { Missing~'hyperref'~package. \iow_newline: Setting~'hyperref=false'. }
+\msg_new:nnn { zref-check } { ignore-document-only }
+ {
+ Option~'ignore'~only~available~in~the~document. \iow_newline:
+ Use~option~'msglevel'~instead.
+ }
+\msg_new:nnn { zref-check } { option-preamble-only }
+ {
+ Option~'#1'~only~available~in~the~preamble \iow_newline:
+ on~input~line~\msg_line_number:.
+ }
+\msg_new:nnn { zref-check } { closerange-not-positive-integer }
+ {
+ Option~'closerange'~not~a~positive~integer \iow_newline:
+ on~input~line~\msg_line_number:.~Using~default~value.
+ }
+\msg_new:nnn { zref-check } { labelcmd-undefined }
+ {
+ Control~sequence~named~'#1'~used~in~option~'labelcmd'~is~not~defined.~
+ Using~default~value.
+ }
+% \end{macrocode}
+%
+%
+% \subsection{Integer testing}
+%
+% \begin{macro}{\@@_is_integer:n, \@@_int_to_roman:w}
+% From \url{https://tex.stackexchange.com/a/244405} (thanks Enrico Gregorio,
+% aka `egreg'), also see \url{https://tex.stackexchange.com/a/19769}.
+% Following the \texttt{l3styleguide}, I made a copy of
+% \cs{__int_to_roman:w}, since it is an internal function from the
+% \texttt{int} module, but we still get a warning from \texttt{l3build doc},
+% complaining about it. And we're using \cs{tl_if_empty:oTF} instead of
+% \cs{tl_if_blank:oTF} as in egreg's answer, since \cs{romannumeral} is
+% defined so that ``the expansion is empty if the number is zero or
+% negative'', not ``blank''. A couple of comments about this technique: the
+% underlying \cs{romannumeral} ignores space tokens and explicit signs
+% (\texttt{+} and \texttt{-}) in the expansion and hence it can only be used
+% to test positive integers; also the technique cannot distinguish whether
+% it received an empty argument or if ``the expansion was empty'' as a
+% result of receiving number as argument, so this must also be controlled
+% for since, in our use case, this may happen.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_int_to_roman:w \__int_to_roman:w
+\prg_new_conditional:Npnn \@@_is_integer:n #1 { p, T , F , TF }
+ {
+ \tl_if_empty:oTF {#1}
+ { \prg_return_false: }
+ {
+ \tl_if_empty:oTF { \@@_int_to_roman:w -0#1 }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_is_integer_rgx:n}
+% A possible alternative to \cs{@@_is_integer:n} is to use a straightforward
+% regexp match (see \url{https://tex.stackexchange.com/a/427559}). It does
+% not suffer from the mentioned caveats from the \cs{__int_to_roman:w}
+% technique, however, while \cs{@@_is_integer:n} is expandable,
+% \cs{@@_is_integer_rgx:n} is not. Also, \cs{@@_is_integer_rgx:n} is
+% probably slower.
+% \begin{macrocode}
+\prg_new_protected_conditional:Npnn \@@_is_integer_rgx:n #1 { TF }
+ {
+ \regex_match:nnTF { \A\d+\Z } {#1}
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Options}
+%
+%
+% \subsubsection*{\opt{hyperref} option}
+%
+% \begin{variable}{\l_@@_use_hyperref_bool, \l_@@_warn_hyperref_bool}
+% \begin{macrocode}
+\bool_new:N \l_@@_use_hyperref_bool
+\bool_new:N \l_@@_warn_hyperref_bool
+\keys_define:nn { zref-check }
+ {
+ hyperref .choice: ,
+ hyperref / auto .code:n =
+ {
+ \bool_set_true:N \l_@@_use_hyperref_bool
+ \bool_set_false:N \l_@@_warn_hyperref_bool
+ } ,
+ hyperref / true .code:n =
+ {
+ \bool_set_true:N \l_@@_use_hyperref_bool
+ \bool_set_true:N \l_@@_warn_hyperref_bool
+ } ,
+ hyperref / false .code:n =
+ {
+ \bool_set_false:N \l_@@_use_hyperref_bool
+ \bool_set_false:N \l_@@_warn_hyperref_bool
+ } ,
+ hyperref .initial:n = auto ,
+ hyperref .default:n = auto
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macrocode}
+\AtBeginDocument
+ {
+ \@ifpackageloaded { hyperref }
+ {
+ \bool_if:NT \l_@@_use_hyperref_bool
+ {
+ \RequirePackage { zref-hyperref }
+ \zref@addprop { zrefcheck } { anchor }
+ }
+ }
+ {
+ \bool_if:NT \l_@@_warn_hyperref_bool
+ { \msg_warning:nn { zref-check } { missing-hyperref } }
+ \bool_set_false:N \l_@@_use_hyperref_bool
+ }
+ \keys_define:nn { zref-check }
+ {
+ hyperref .code:n =
+ { \msg_warning:nn { zref-check } { hyperref-preamble-only } }
+ }
+ }
+% \end{macrocode}
+%
+%
+% \subsubsection*{\opt{msglevel} option}
+%
+% \begin{variable}{\l_@@_msglevel_tl}
+% \begin{macrocode}
+\tl_new:N \l_@@_msglevel_tl
+\keys_define:nn { zref-check }
+ {
+ msglevel .choice: ,
+ msglevel / warn .code:n =
+ { \tl_set:Nn \l_@@_msglevel_tl { warning } } ,
+ msglevel / info .code:n =
+ { \tl_set:Nn \l_@@_msglevel_tl { info } } ,
+ msglevel / none .code:n =
+ { \tl_set:Nn \l_@@_msglevel_tl { none } } ,
+ msglevel / obeydraft .code:n =
+ {
+ \ifdraft
+ { \tl_set:Nn \l_@@_msglevel_tl { info } }
+ { \tl_set:Nn \l_@@_msglevel_tl { warning } }
+ } ,
+ msglevel / obeyfinal .code:n =
+ {
+ \ifoptionfinal
+ { \tl_set:Nn \l_@@_msglevel_tl { warning } }
+ { \tl_set:Nn \l_@@_msglevel_tl { info } }
+ } ,
+ msglevel .value_required:n = true ,
+ msglevel .initial:n = warn ,
+% \end{macrocode}
+% \opt{ignore} is a convenience alias for \opt{msglevel=none}, but only for
+% use in the document body.
+% \begin{macrocode}
+ ignore .code:n =
+ { \msg_warning:nn { zref-check } { ignore-document-only } } ,
+ ignore .value_forbidden:n = true
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macrocode}
+\AtBeginDocument
+ {
+ \keys_define:nn { zref-check }
+ { ignore .meta:n = { msglevel = none } }
+ }
+% \end{macrocode}
+%
+%
+% \subsubsection*{\opt{onpage} option}
+%
+% \begin{variable}{\l_@@_msgonpage_bool}
+% \begin{macrocode}
+\bool_new:N \l_@@_msgonpage_bool
+\keys_define:nn { zref-check }
+ {
+ onpage .choice: ,
+ onpage / labelseq .code:n =
+ {
+ \bool_set_false:N \l_@@_msgonpage_bool
+ } ,
+ onpage / msg .code:n =
+ {
+ \bool_set_true:N \l_@@_msgonpage_bool
+ } ,
+ onpage / obeydraft .code:n =
+ {
+ \ifdraft
+ { \bool_set_false:N \l_@@_msgonpage_bool }
+ { \bool_set_true:N \l_@@_msgonpage_bool }
+ } ,
+ onpage / obeyfinal .code:n =
+ {
+ \ifoptionfinal
+ { \bool_set_true:N \l_@@_msgonpage_bool }
+ { \bool_set_false:N \l_@@_msgonpage_bool }
+ } ,
+ onpage .value_required:n = true ,
+ onpage .initial:n = labelseq
+ }
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \subsubsection*{\opt{closerange} option}
+%
+% \begin{variable}{\l_@@_close_range_int}
+% \begin{macrocode}
+\int_new:N \l_@@_close_range_int
+\keys_define:nn { zref-check }
+ {
+ closerange .code:n =
+ {
+ \@@_is_integer_rgx:nTF {#1}
+ { \int_set:Nn \l_@@_close_range_int { \int_eval:n {#1} } }
+ {
+ \msg_warning:nn { zref-check } { closerange-not-positive-integer }
+ \int_set:Nn \l_@@_close_range_int { 5 }
+ }
+ } ,
+ closerange .value_required:n = true ,
+ closerange .initial:n = 5
+ }
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \subsubsection*{\opt{labelcmd} option}
+%
+% \begin{variable}{\l_@@_target_label_tl}
+% I'd love to receive the macro itself rather than it's name, but this would
+% bring unwarranted complications:
+% \url{https://tex.stackexchange.com/a/489570}.
+% \begin{macrocode}
+\tl_new:N \l_@@_target_label_tl
+\bool_new:N \l_@@_target_label_bool
+\keys_define:nn { zref-check }
+ {
+ labelcmd .code:n =
+ {
+ \tl_set:Nn \l_@@_target_label_tl {#1}
+ \bool_set_true:N \l_@@_target_label_bool
+ } ,
+ labelcmd .value_required:n = true ,
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_target_label:n}
+% Default definition of the function for user label setting in \cs{zctarget}
+% and \texttt{zcregion}. It may be redefined at \texttt{begindocument}
+% according to option \opt{labelcmd}.
+% \begin{macrocode}
+\cs_new:Npn \@@_target_label:n #1
+ { \zref@labelbylist {#1} { zrefcheck } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+\AtBeginDocument
+ {
+ \bool_if:NT \l_@@_target_label_bool
+ {
+ \tl_if_blank:VT \l_@@_target_label_tl
+ { \tl_clear:N \l_@@_target_label_tl }
+ \cs_if_exist:cTF { \l_@@_target_label_tl }
+ {
+ \cs_set:Npx \@@_target_label:n #1
+ {
+ \exp_not:o
+ { \cs:w \l_@@_target_label_tl \cs_end: }
+ {#1}
+ }
+ }
+ {
+ \exp_args:NnnV \msg_warning:nnn { zref-check }
+ { labelcmd-undefined } { \l_@@_target_label_tl }
+ }
+ }
+ \keys_define:nn { zref-check }
+ {
+ labelcmd .code:n =
+ {
+ \msg_warning:nnn { zref-check }
+ { option-preamble-only } { labelcmd }
+ }
+ }
+ }
+% \end{macrocode}
+%
+%
+% \subsubsection*{Package options}
+%
+% Process load-time package options
+% (\url{https://tex.stackexchange.com/a/15840}).
+% \begin{macrocode}
+\RequirePackage { l3keys2e }
+\ProcessKeysOptions { zref-check }
+% \end{macrocode}
+%
+%
+% \begin{macro}[int]{\zrefchecksetup}
+% Provide \cs{zrefchecksetup}.
+% \begin{macrocode}
+\NewDocumentCommand \zrefchecksetup { m }
+ { \keys_set:nn { zref-check } {#1} }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Position on page}
+%
+% Method for determining relative position within the page: the sequence in
+% which the labels get shipped out, inferred from the sequence in which the
+% labels occur in the \file{.aux} file.
+%
+% Some relevant info about the sequence of things:
+% \url{https://tex.stackexchange.com/a/120978} and \texttt{texdoc lthooks},
+% section ``Hooks provided by |\begin{document}|''.
+%
+%
+% One first attempt at this was to use \cs{zref@newlabel}, which is the macro
+% in which \pkg{zref} stores the label information in the aux file. When the
+% \file{.aux} file is read at the beginning of the compilation, this macro is
+% expanded for each of the labels. So, by redefining this macro we can feed a
+% variable (a L3 sequence), and then do what it usually does, which is to
+% define each label with the internal macro \cs{@newl@bel}, when the
+% \file{.aux} file is read.
+%
+% Patching this macro for this is not possible. First, \cs{zref@newlabel} is
+% one of those ``commands that look ahead'' mentioned in \pkg{ltcmdhooks}
+% documentation. Indeed, \cs{@newl@bel} receives 3 arguments, and
+% \cs{zref@newlabel} just passes the first, the following two will be scanned
+% ahead. Second, the \pkg{ltcmdhooks} hooks are not actually available when
+% the \file{.aux} file is read, they come only after |\begin{document}|.
+% Hence, redefinition would be the only alternative. My attempts at this
+% ended up registered at \url{https://tex.stackexchange.com/a/604744}. But
+% the best result in these lines was:
+%
+% \begin{verbatim}
+% \ZREF@Robust\edef\zref@newlabel#1{
+% \noexpand\seq_gput_right:Nn \noexpand\g__zrefcheck_auxfile_lblseq_seq {#1}
+% \noexpand\@newl@bel{\ZREF@RefPrefix}{#1}
+% }
+% \end{verbatim}
+%
+%
+% However, better than the above is to just read it from the \file{.aux} file
+% directly, which relieves us from hacking into any internals. That's what
+% David Carlisle's answer at \url{https://tex.stackexchange.com/a/147705}
+% does. This answer has actually been converted into the package
+% \pkg{listlbls} by Norbert Melzer, but it is made to work with regular
+% labels, not with \pkg{zref}'s. And it also does not really expose the
+% information in a retrievable way (as far as I can tell). So, the below is
+% adapted from Carlisle's answer's technique (a poor man's version of it...).
+%
+% There is some subtlety here as to whether this approach makes it safe for us
+% to read the labels at this point without \cs{zref@wrapper@babel}. The
+% common wisdom is that babel's shorthands are only active after
+% |\begin{document}| (e.g., \url{https://tex.stackexchange.com/a/98897}).
+% Alas, it is more complicated than that. Babel's documentation says (in
+% section 9.5 Shorthands): ``To prevent problems with the loading of other
+% packages after babel we reset the catcode of the character to the original
+% one at the end of the package and of each language file (except with
+% KeepShorthandsActive). It is re-activate[d] again at |\begin{document}|.
+% We also need to make sure that the shorthands are active during the
+% processing of the \file{.aux} file. Otherwise some citations may give
+% unexpected results in the printout when a shorthand was used in the optional
+% argument of |\bibitem| for example.'' This is done with
+% |\if@filesw \immediate\write\@mainaux{...}|. In other words, the
+% catcode change is written in the \file{.aux} file itself! Indeed, if you
+% inspect the file, you'll find them there. Besides, there is still the
+% ominous ``except with KeepShorthandsActive''.
+%
+% However, the \emph{method} we're using here is not quite the same as the
+% usual run of the \file{.aux} file, because we're actively discarding the
+% lines for which the first token is not equal to \cs{zref@newlabel}. I have
+% tested the famous sensitive case for this: \pkg{babel} \opt{french} and
+% labels with colons. And things worked as expected. Well, \emph{if}
+% \opt{KeepShorthandsActive} is enabled \emph{with \opt{french}} and we load
+% the package \emph{after babel} things do break, but not quite because of the
+% colons in the labels. Even \pkg{siunitx} breaks in the same
+% conditions\dots{}
+%
+% For reference: About what are valid characters for use in labels:
+% \url{https://tex.stackexchange.com/a/18312}. About some problems with
+% active colons: \url{https://tex.stackexchange.com/a/89470}. About the
+% difference between L3 strings and token lists, see
+% \url{https://tex.stackexchange.com/a/446381}, in particular Joseph Wright's
+% comment: ``Strings are for data that will never be typeset, for example file
+% names, identifiers, etc.: if the material may be used in typesetting, it
+% should be a token list.'' See also moewe's (CW) answer in the same lines.
+% Which suggests using L3 strings for the reference labels might be a good
+% catch all approach, and possibly more robust. David Carlisle's comment
+% about \pkg{inputenc} and how the strings work is a caveat (see
+% \url{https://tex.stackexchange.com/q/446123#comment1516961_446381}, thanks
+% David Carlisle). Still\dots{} let's stick to tradition as long as it works,
+% \pkg{zref} already does a great job in this regard anyway.
+%
+%
+% \begin{variable}{\g_@@_auxfile_lblseq_prop}
+% \begin{macrocode}
+\prop_new:N \g_@@_auxfile_lblseq_prop
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macrocode}
+\tl_set:Nn \g_tmpa_tl { \c_sys_jobname_str .aux }
+\file_if_exist:nT { \g_tmpa_tl }
+ {
+% \end{macrocode}
+% Retrieve the information from the \file{.aux} file, and store it in a
+% property list, so that the sequence can be retrieved in key-value fashion.
+% \begin{macrocode}
+ \ior_open:Nn \g_tmpa_ior { \g_tmpa_tl }
+ \group_begin:
+ \int_zero:N \l_tmpa_int
+ \tl_clear:N \l_tmpa_tl
+ \tl_clear:N \l_tmpb_tl
+ \bool_set_false:N \l_tmpa_bool
+ \ior_map_variable:NNn \g_tmpa_ior \l_tmpa_tl
+ {
+ \tl_map_variable:NNn \l_tmpa_tl \l_tmpb_tl
+ {
+ \tl_if_eq:NnTF \l_tmpb_tl { \zref@newlabel }
+ {
+% \end{macrocode}
+% Found a \cs{zref@label}, signal it.
+% \begin{macrocode}
+ \bool_set_true:N \l_tmpa_bool
+ }
+ {
+ \bool_if:NTF \l_tmpa_bool
+ {
+ \bool_set_false:N \l_tmpa_bool
+ \int_incr:N \l_tmpa_int
+ \prop_gput:Nxx \g_@@_auxfile_lblseq_prop
+ { \l_tmpb_tl } { \int_use:N \l_tmpa_int }
+ }
+ {
+% \end{macrocode}
+% If there is not a match of the first token with \cs{zref@newlabel}, break
+% the loop and discard the rest of the line, to ensure no babel calls to
+% \cs{catcode} in the \file{.aux} file get expanded. This also breaks the
+% loop and discards the rest of the \cs{zref@newlabel} lines after we got the
+% label we wanted, since we reset \cs{l_tmpa_bool} in the \texttt{T} branch.
+% \begin{macrocode}
+ \tl_map_break:
+ }
+ }
+ }
+ }
+ \group_end:
+ \ior_close:N \g_tmpa_ior
+ }
+% \end{macrocode}
+%
+%
+%
+% The alternate method I had considered (more than that...) for this was using
+% yx coordinates supplied by \pkg{zref}'s \pkg{savepos} module. However, this
+% approach brought in a number of complexities, including the need to patch
+% either \cs{zref@label} or \cs{ZREF@label}. In addition, the technique was
+% at the bottom fundamentally flawed. Ulrike Fischer was very much right when
+% she said that ``structure and position are two different beasts''
+% (\url{https://github.com/ho-tex/zref/issues/12#issuecomment-880022576}). It
+% is true that the checks based on it behaved decently, in normal
+% circumstances, and except for outrageous label placement by the user, it
+% would return the expected results. We don't really need exact coordinates
+% to decide ``above/below''. Besides, it would do an exact job for the
+% dedicated target macros of this package. However, I could not conceive a
+% situation where the \texttt{yx} criterion would perform clearly better than
+% the \texttt{labelseq} one. And, if that's the case, and considering the
+% complications it brings, this check was a slippery slope. All in all, I've
+% decided to drop it.
+%
+%
+%
+% \subsection{Counter}
+%
+% We need a dedicated counter for the labels generated by the checks and
+% targets. The value of the counter is not relevant, we just need it to be
+% able to set proper anchors with \cs{refstepcounter}. And, since I couldn't
+% find a \cs{refstepcounter} equivalent in L3, we use a standard 2e counter
+% here. I'm also using the technique to ensure the counter is never reset
+% that is used by \file{zref-abspage.sty} and \cs{zref@require@unique}.
+% Indeed, the requirements are the same, we need numbers ensured to be
+% \emph{unique} in the counter.
+%
+% \begin{macrocode}
+\begingroup
+ \let \@addtoreset \ltx@gobbletwo
+ \newcounter { zrefcheck }
+\endgroup
+\setcounter { zrefcheck } { 0 }
+% \end{macrocode}
+%
+%
+%
+% \subsection{Label formats}
+%
+% \begin{macro}{\@@_check_lblfmt:n}
+% \begin{syntax}
+% \cs{@@_check_lblfmt:n} \Arg{check id int}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new:Npn \@@_check_lblfmt:n #1 { zrefcheck@ \int_use:N #1 }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_end_lblfmt:n}
+% \begin{syntax}
+% \cs{@@_end_lblfmt:n} \Arg{label}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new:Npn \@@_end_lblfmt:n #1 { #1 @zrefcheck }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Property values}
+%
+%
+% \begin{macro}[int]{\zrefcheck_get_astl:nnn}
+% A convenience function to retrieve property values from labels. Uses
+% \cs{g_@@_auxfile_lblseq_prop} for \texttt{lblseq}, and calls
+% \cs{zref@extractdefault} for everything else.
+%
+% We cannot use the ``return value'' of \cs{@@_get_astl:nnn} or
+% \cs{@@_get_asint:nnn} directly, because we need to use the retrieved
+% property values as arguments in the checks, however we use here a number
+% of non-expandable operations. Hence, we receive a local \texttt{tl/int}
+% variable as third argument and set that, so that it is available (and
+% expandable) at the place of use. For this reason, we do not group here,
+% because we are passing a local variable around, but it is expected this
+% function will be called within a group.
+%
+% We're returning \cs{c_empty_tl} in case of failure to find the intended
+% property value (explicitly in \cs{zref@extractdefault}, but that is also
+% what \cs{tl_clear:N} does).
+%
+% \begin{syntax}
+% \cs{zrefcheck_get_astl:nnn} \Arg{label} \Arg{prop} \Arg{tl var}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new:Npn \zrefcheck_get_astl:nnn #1#2#3
+ {
+ \tl_clear:N #3
+ \tl_if_eq:nnTF {#2} { lblseq }
+ {
+ \prop_get:NnNF \g_@@_auxfile_lblseq_prop {#1} #3
+ {
+ \msg_warning:nnnn { zref-check }
+ { property-not-in-label } {#1} {#2}
+ }
+ }
+ {
+% \end{macrocode}
+% There are three things we need to check to ensure the information we are
+% trying to retrieve here exists: the existence of \Arg{label}, the existence
+% of \Arg{prop}, and whether the particular label being queried actually
+% contains the property. If that's all in place, the value is passed to the
+% checks, and it's their responsibility to verify the consistency of this
+% value.
+%
+% The existence of the label is an user facing issue, and a warning for this
+% is placed in \cs{@@_zcheck:nnnnn} (and done with \cs{zref@refused}). We do
+% check here though for definition with \cs{zref@ifrefundefined} and silently
+% do nothing if it is undefined, to reduce irrelevant warnings in a fresh
+% compilation round. The other two are more ``internal'' problems, either
+% some problem with the checks, or with the configuration of \pkg{zref} for
+% their consumption.
+% \begin{macrocode}
+ \zref@ifrefundefined {#1}
+ {}
+ {
+ \zref@ifpropundefined {#2}
+ { \msg_warning:nnnn { zref-check } { property-undefined } {#2} }
+ {
+ \zref@ifrefcontainsprop {#1} {#2}
+ {
+ \tl_set:Nx #3
+ { \zref@extractdefault {#1} {#2} { \c_empty_tl } }
+ }
+ {
+ \msg_warning:nnnn
+ { zref-check } { property-not-in-label } {#1} {#2}
+ }
+ }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{variable}{\l_@@_integer_bool}
+% \cs{zrefcheck_get_asint:nnn} is a very convenient wrapper around the more
+% general \cs{zrefcheck_get_astl:nnn}, since almost always we'll be wanting
+% to compare numbers in the checks. However, it is quite hard for it to
+% ensure an integer is \emph{always} returned in the case of errors. And
+% those do occur, even in a well structured document (e.g., in a first round
+% of compilation). To complicate things, the L3 integer predicates are
+% \emph{very} sensitive to receiving any other kind of data, and they
+% \emph{scream}. To handle this \cs{zrefcheck_get_asint:nnn} uses
+% \cs{l_@@_integer_bool} to signal if an integer could not be returned. To
+% use this function always set \cs{l_@@_integer_bool} to true first, then
+% call it as much as you need. If any of these calls got is returning
+% anything which is not an integer, \cs{l_@@_integer_bool} will have been
+% set to false, and you should check that this hasn't happened before
+% actually comparing the integers (\cs{bool_lazy_and:nnTF} is your friend).
+% \begin{macrocode}
+\bool_new:N \l_@@_integer_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_propval_tl}
+% \begin{macrocode}
+\tl_new:N \l_@@_propval_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[int]{\zrefcheck_get_asint:nnn}
+% \begin{syntax}
+% \cs{zrefcheck_get_asint:nnn} \Arg{label} \Arg{prop} \Arg{int var}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new:Npn \zrefcheck_get_asint:nnn #1#2#3
+ {
+ \zrefcheck_get_astl:nnn {#1} {#2} { \l_@@_propval_tl }
+ \@@_is_integer:nTF { \l_@@_propval_tl }
+ {
+% \end{macrocode}
+% Make it an integer data type.
+% \begin{macrocode}
+ \int_set:Nn #3 { \int_eval:n { \l_@@_propval_tl } }
+ }
+ {
+ \bool_set_false:N \l_@@_integer_bool
+ \zref@ifrefundefined {#1}
+% \end{macrocode}
+% Keep silent if ref is undefined to reduce irrelevant warnings in a fresh
+% compilation round. Again, this is also not the point to check for undefined
+% references, that's a task for \cs{@@_zcheck:nnnnn}.
+% \begin{macrocode}
+ { }
+ {
+ \msg_warning:nnnn { zref-check }
+ { property-not-integer } {#2} {#1}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+%
+% \section{User interface}
+%
+%
+% \subsection{\cs{zcheck}}
+%
+% \begin{macro}[int]{\zcheck}
+% The \marg{text} argument of \cs{zcheck} should not be long, since
+% \cs{hyperlink} cannot receive a long argument. Besides, there is no
+% reason for it to be. Note, also, that hyperlinks crossing page boundaries
+% have some known issues: \url{https://tex.stackexchange.com/a/182769},
+% \url{https://tex.stackexchange.com/a/54607},
+% \url{https://tex.stackexchange.com/a/179907}.
+%
+% \begin{syntax}
+% \cs{zcheck}\meta{*}\oarg{options}\marg{labels}\oarg{checks}\marg{text}
+% \end{syntax}
+%
+% \begin{macrocode}
+\NewDocumentCommand \zcheck
+ { s O { } > { \SplitList { , } } m > { \SplitList { , } } O { } m }
+ { \zref@wrapper@babel \@@_zcheck:nnnnn {#3} {#1} {#2} {#4} {#5} }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{variable}
+% {
+% \g_@@_id_int ,
+% \l_@@_checkbeg_tl ,
+% \l_@@_checkend_tl ,
+% \l_@@_link_label_tl ,
+% \l_@@_link_anchor_tl ,
+% \l_@@_link_star_tl
+% }
+% \begin{macrocode}
+\int_new:N \g_@@_id_int
+\tl_new:N \l_@@_checkbeg_tl
+\tl_new:N \l_@@_checkend_tl
+\tl_new:N \l_@@_link_label_tl
+\tl_new:N \l_@@_link_anchor_tl
+\bool_new:N \l_@@_link_star_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_zcheck:nnnnn}
+% An intermediate internal function, which does the actual heavy lifting,
+% and places \Arg{labels} as first argument, so that it can be protected by
+% \cs{zref@wrapper@babel} in \cs{zcheck}. This is the same procedure as the
+% one used in the definition of \cs{zref} in \file{zref-user.sty} for
+% protection of \pkg{babel} active characters.
+%
+% \begin{syntax}
+% \cs{@@_zcheck:nnnnn} \Arg{labels} \Arg{*} \Arg{options} \Arg{checks} \Arg{text}
+% \end{syntax}
+%
+% \begin{macrocode}
+\cs_new:Npn \@@_zcheck:nnnnn #1#2#3#4#5
+ {
+ \group_begin:
+% \end{macrocode}
+% Process local options.
+% \begin{macrocode}
+ \keys_set:nn { zref-check } {#3}
+% \end{macrocode}
+% Names of the labels for this zrefcheck call.
+% \begin{macrocode}
+ \int_gincr:N \g_@@_id_int
+ \tl_set:Nx \l_@@_checkbeg_tl
+ { \@@_check_lblfmt:n { \g_@@_id_int } }
+ \tl_set:Nx \l_@@_checkend_tl
+ { \@@_end_lblfmt:n { \l_@@_checkbeg_tl } }
+% \end{macrocode}
+% Set checkbeg label.
+% \begin{macrocode}
+ \zref@labelbylist { \l_@@_checkbeg_tl } { zrefcheck }
+% \end{macrocode}
+% Typeset \marg{text}, with hyperlink when appropriate. Even though the first
+% argument can receive a list of labels, there is no meaningful way to set
+% links to multiple targets. Hence, only the first one is considered for
+% hyperlinking.
+% \begin{macrocode}
+ \tl_set:Nn \l_@@_link_label_tl { \tl_head:n {#1} }
+ \bool_set:Nn \l_@@_link_star_tl {#2}
+ \zref@ifrefundefined { \l_@@_link_label_tl }
+% \end{macrocode}
+% If the reference is undefined, just typeset.
+% \begin{macrocode}
+ {#5}
+ {
+ \bool_if:nTF
+ {
+ \l_@@_use_hyperref_bool &&
+ ! \l_@@_link_star_tl
+ }
+ {
+ \exp_args:Nx \zrefcheck_get_astl:nnn
+ { \l_@@_link_label_tl }
+ { anchor } { \l_@@_link_anchor_tl }
+ \hyperlink { \l_@@_link_anchor_tl } {#5}
+ }
+ {#5}
+ }
+% \end{macrocode}
+% Set checkend label.
+% \begin{macrocode}
+ \zref@labelbylist { \l_@@_checkend_tl } { zrefcheck }
+% \end{macrocode}
+% Check if \meta{labels} are defined.
+% \begin{macrocode}
+ \tl_map_function:nN {#1} \zref@refused
+% \end{macrocode}
+% Run the checks.
+% \begin{macrocode}
+ \@@_run_checks:nnV {#4} {#1} { \l_@@_checkbeg_tl }
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Targets}
+%
+% \begin{macro}[int]{\zctarget}
+% \begin{syntax}
+% \cs{zctarget}\marg{label}\marg{text}
+% \end{syntax}
+% \begin{macrocode}
+\NewDocumentCommand \zctarget { m +m }
+ {
+% \end{macrocode}
+% Group contents of \cs{zctarget} to avoid leaking the effects of
+% \cs{refstepcounter} over \cs{@currentlabel}. The same care is not needed
+% for \texttt{zcregion}, since the environment is already grouped.
+% \begin{macrocode}
+ \group_begin:
+ \refstepcounter { zrefcheck }
+ \zref@wrapper@babel \@@_target_label:n {#1}
+ #2
+ \zref@wrapper@babel
+ \zref@labelbylist { \@@_end_lblfmt:n {#1} } { zrefcheck }
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{zcregion}
+% \begin{syntax}
+% |\begin{zcregion}|\marg{label}
+% | ...|
+% |\end{zcregion}|
+% \end{syntax}
+% \begin{macrocode}
+\NewDocumentEnvironment {zcregion} { m }
+ {
+ \refstepcounter { zrefcheck }
+ \zref@wrapper@babel \@@_target_label:n {#1}
+ }
+ {
+ \zref@wrapper@babel
+ \zref@labelbylist { \@@_end_lblfmt:n {#1} } { zrefcheck }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \section{Checks}
+%
+% What is needed define a \pkg{zref-check} check?
+%
+% First, a conditional function defined with:
+%
+% \cs{prg_new_conditional:Npnn} \cs{@@_check_\meta{check}:nn} |#1#2 { F }|
+%
+% \noindent where \meta{check} is the name of the check, the first argument is
+% the \Arg{label} and the second the \Arg{reference}. The existence of the
+% check is verified by the existence of the function with this name-scheme
+% (and signatures). As usual, this function must return either
+% \cs{prg_return_true:} or \cs{prg_return_false:}. Of course, you can define
+% other variants if you need them internally, it is just that what the package
+% does expect and verifies is the existence of the \texttt{:nnF} variant.
+%
+% Note that the naming convention of the checks adopts the perspective of the
+% \meta{reference}. That is, the ``before'' check should return true if the
+% \meta{label} occurs before the ``reference''.
+%
+% The check conditionals are expected to retrieve \pkg{zref}'s label
+% information with \cs{zrefcheck_get_astl:nnn} or
+% \cs{zrefcheck_get_asint:nnn}. Also, technically speaking, the
+% \meta{reference} argument is also a label, actually a pair of them, as set
+% by \cs{zcheck}. For the ``labels'', any \pkg{zref} property in \pkg{zref}'s
+% main list is available, the ``references'' store the properties in the
+% \texttt{zrefcheck} list. Besides those, there is also the \texttt{lblseq}
+% (fake) property (for either ``labels'' or ``references''), stored in
+% \cs{g_@@_auxfile_lblseq_prop}.
+%
+% Second, the required properties of labels and references must be duly
+% registered for \pkg{zref}. This can be done with \cs{zref@newprop},
+% \cs{zref@addprop} and friends, as usual.
+%
+%
+% \subsection{Running}
+%
+% \begin{macro}{\@@_run_checks:nnn, \@@_run_checks:nnV}
+% \begin{syntax}
+% \cs{@@_run_checks:nnn} \Arg{checks} \Arg{labels} \Arg{reference}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new:Npn \@@_run_checks:nnn #1#2#3
+ {
+ \group_begin:
+ \tl_map_inline:nn {#2}
+ {
+ \tl_map_inline:nn {#1}
+ { \@@_do_check:nnn {####1} {##1} {#3} }
+ }
+ \group_end:
+ }
+\cs_generate_variant:Nn \@@_run_checks:nnn { nnV }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{variable}
+% {
+% \l_@@_passedcheck_bool ,
+% \l_@@_onpage_bool ,
+% \c_@@_onpage_checks_seq
+% }
+% \begin{macrocode}
+\bool_new:N \l_@@_passedcheck_bool
+\bool_new:N \l_@@_onpage_bool
+\seq_new:N \c_@@_onpage_checks_seq
+\seq_set_from_clist:Nn \c_@@_onpage_checks_seq
+ { above , below , before , after }
+% \end{macrocode}
+% \end{variable}
+%
+%
+% Variant not provided by \pkg{expl3}.
+% \begin{macrocode}
+\cs_generate_variant:Nn \exp_args:Nnno { Nnoo }
+% \end{macrocode}
+%
+% \begin{macro}{\@@_do_check:nnn}
+% \begin{syntax}
+% \cs{@@_do_check:nnn} \Arg{check} \Arg{label beg} \Arg{reference beg}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new:Npn \@@_do_check:nnn #1#2#3
+ {
+ \group_begin:
+% \end{macrocode}
+% \meta{label beg} may be defined or not, it is arbitrary user input. Whether
+% this is the case is checked in \cs{@@_zcheck:nnnnn}, and due warning already
+% ensues. And there is no point in checking ``relative position'' of an
+% undefined label. Hence, in the absence of |#2|, we do nothing at all here.
+% \begin{macrocode}
+ \zref@ifrefundefined {#2}
+ {}
+ {
+ \tl_if_empty:nF {#1}
+ {
+ \bool_set_true:N \l_@@_passedcheck_bool
+ \bool_set_false:N \l_@@_onpage_bool
+ \cs_if_exist:cTF { @@_check_ #1 :nnF }
+ {
+% \end{macrocode}
+% ``label beg'' vs ``reference beg''.
+% \begin{macrocode}
+ \use:c { @@_check_ #1 :nnF }
+ {#2} {#3}
+ { \bool_set_false:N \l_@@_passedcheck_bool }
+% \end{macrocode}
+% ``label beg'' vs ``reference end''.
+% \begin{macrocode}
+ \exp_args:Nnno \use:c { @@_check_ #1 :nnF }
+ {#2} { \@@_end_lblfmt:n {#3} }
+ { \bool_set_false:N \l_@@_passedcheck_bool }
+% \end{macrocode}
+% ``label end'' \emph{may} have been created by the target commands.
+% \begin{macrocode}
+ \zref@ifrefundefined { \@@_end_lblfmt:n {#2} }
+ {}
+ {
+% \end{macrocode}
+% ``label end'' vs ``reference beg''.
+% \begin{macrocode}
+ \exp_args:Nno \use:c { @@_check_ #1 :nnF }
+ { \@@_end_lblfmt:n {#2} } {#3}
+ { \bool_set_false:N \l_@@_passedcheck_bool }
+% \end{macrocode}
+% ``label end'' vs ``reference end''.
+% \begin{macrocode}
+ \exp_args:Nnoo \use:c { @@_check_ #1 :nnF }
+ { \@@_end_lblfmt:n {#2} }
+ { \@@_end_lblfmt:n {#3} }
+ { \bool_set_false:N \l_@@_passedcheck_bool }
+ }
+% \end{macrocode}
+% Handle option \opt{onpage=msg}. This is only granted for tests which
+% perform ``within this page'' checks (\opt{above}, \opt{below}, \opt{before},
+% \opt{after}) \emph{and} if any of the two by two checks uses a ``within this
+% page'' comparison. If both conditions are met, signal.
+% \begin{macrocode}
+ \seq_if_in:NnT \c_@@_onpage_checks_seq {#1}
+ {
+ \@@_check_thispage:nnT
+ {#2} {#3}
+ { \bool_set_true:N \l_@@_onpage_bool }
+ \@@_check_thispage:nnT
+ {#2} { \@@_end_lblfmt:n {#3} }
+ { \bool_set_true:N \l_@@_onpage_bool }
+ \zref@ifrefundefined { \@@_end_lblfmt:n {#2} }
+ {}
+ {
+ \@@_check_thispage:nnT
+ { \@@_end_lblfmt:n {#2} } {#3}
+ { \bool_set_true:N \l_@@_onpage_bool }
+ \@@_check_thispage:nnT
+ { \@@_end_lblfmt:n {#2} }
+ { \@@_end_lblfmt:n {#3} }
+ { \bool_set_true:N \l_@@_onpage_bool }
+ }
+ }
+ \bool_if:NTF \l_@@_passedcheck_bool
+ {
+ \bool_if:nT
+ {
+ \l_@@_msgonpage_bool &&
+ \l_@@_onpage_bool
+ }
+ {
+ \@@_message:nnnx { double-check } {#1} {#2}
+ { \zref@extractdefault {#3} {page} {'unknown'} }
+ }
+ }
+ {
+ \@@_message:nnnx { check-failed } {#1} {#2}
+ { \zref@extractdefault {#3} {page} {'unknown'} }
+ }
+ }
+ { \msg_warning:nnn { zref-check } { check-missing } {#1} }
+ }
+ }
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Conditionals}
+%
+% \begin{variable}
+% {
+% \l_@@_lbl_int ,
+% \l_@@_ref_int ,
+% \l_@@_lbl_b_int ,
+% \l_@@_ref_b_int
+% }
+% More readable scratch variables for the tests.
+% \begin{macrocode}
+\int_new:N \l_@@_lbl_int
+\int_new:N \l_@@_ref_int
+\int_new:N \l_@@_lbl_b_int
+\int_new:N \l_@@_ref_b_int
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \subsubsection{This page}
+%
+% \begin{macro}{\@@_check_thispage:nn}
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_check_thispage:nn #1#2 { T , F , TF }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l_@@_ref_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } = { \l_@@_ref_int } &&
+% \end{macrocode}
+% `0' is the default value of \texttt{abspage}, but this value should not
+% happen normally for this property, since even the first page, after it gets
+% shipped out, will receive value `1'. So, if we do find `0' here, better
+% signal something is wrong. This comment extends to all page number checks.
+% \begin{macrocode}
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{On page}
+%
+% \begin{macro}{\@@_check_above:nn, \@@_check_below:nn}
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_check_above:nn #1#2 { F , TF }
+ {
+ \group_begin:
+ \@@_check_thispage:nnTF {#1} {#2}
+ {
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { lblseq } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { lblseq } { \l_@@_ref_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } < { \l_@@_ref_int } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \@@_check_below:nn #1#2 { F , TF }
+ {
+ \@@_check_thispage:nnTF {#1} {#2}
+ {
+ \@@_check_above:nnTF {#1} {#2}
+ { \prg_return_false: }
+ { \prg_return_true: }
+ }
+ { \prg_return_false: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Before / After}
+%
+% \begin{macro}{\@@_check_before:nn, \@@_check_after:nn}
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_check_before:nn #1#2 { F }
+ {
+ \@@_check_pagesbefore:nnTF {#1} {#2}
+ { \prg_return_true: }
+ {
+ \@@_check_above:nnTF {#1} {#2}
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ }
+\prg_new_conditional:Npnn \@@_check_after:nn #1#2 { F }
+ {
+ \@@_check_pagesafter:nnTF {#1} {#2}
+ { \prg_return_true: }
+ {
+ \@@_check_below:nnTF {#1} {#2}
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Pages}
+%
+% \begin{macro}
+% {
+% \@@_check_nextpage:nn ,
+% \@@_check_prevpage:nn ,
+% \@@_check_pagesbefore:nn ,
+% \@@_check_ppbefore:nn ,
+% \@@_check_pagesafter:nn ,
+% \@@_check_ppafter:nn ,
+% \@@_check_facing:nn
+% }
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_check_nextpage:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l_@@_ref_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } = { \l_@@_ref_int + 1 } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \@@_check_prevpage:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l_@@_ref_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } = { \l_@@_ref_int - 1 } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \@@_check_pagesbefore:nn #1#2 { F , TF }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l_@@_ref_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } < { \l_@@_ref_int } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\cs_new_eq:NN \@@_check_ppbefore:nnF \@@_check_pagesbefore:nnF
+\prg_new_conditional:Npnn \@@_check_pagesafter:nn #1#2 { F , TF }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l_@@_ref_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } > { \l_@@_ref_int } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\cs_new_eq:NN \@@_check_ppafter:nnF \@@_check_pagesafter:nnF
+\prg_new_conditional:Npnn \@@_check_facing:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l_@@_ref_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+% \end{macrocode}
+% There exists no ``facing'' page if the document is not twoside.
+% \begin{macrocode}
+ \legacy_if_p:n { @twoside } &&
+% \end{macrocode}
+% Now we test ``facing''.
+% \begin{macrocode}
+ (
+ (
+ \int_if_odd_p:n { \l_@@_ref_int } &&
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } = { \l_@@_ref_int - 1 }
+ ) ||
+ (
+ \int_if_even_p:n { \l_@@_ref_int } &&
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } = { \l_@@_ref_int + 1 }
+ )
+ ) &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Close / Far}
+%
+% \begin{macro}{\@@_check_close:nn, \@@_check_far:nn}
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_check_close:nn #1#2 { F , TF }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l_@@_ref_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \int_abs:n { \l_@@_lbl_int - \l_@@_ref_int } }
+ <
+ { \l_@@_close_range_int + 1 } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \@@_check_far:nn #1#2 { F }
+ {
+ \@@_check_close:nnTF {#1} {#2}
+ { \prg_return_false: }
+ { \prg_return_true: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Chapter}
+%
+% \begin{macro}
+% {
+% \@@_check_thischap:nn ,
+% \@@_check_nextchap:nn ,
+% \@@_check_prevchap:nn ,
+% \@@_check_chapsafter:nn ,
+% \@@_check_chapsbefore:nn
+% }
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_check_thischap:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l_@@_ref_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } = { \l_@@_ref_int } &&
+% \end{macrocode}
+% `0' is the default value of \texttt{abschap} property, and means here no
+% \cs{chapter} has yet been issued, therefore it cannot be ``this chapter'',
+% nor ``the next chapter'', nor ``the previous chapter'', it is just ``no
+% chapter''. Note, however, that a statement about a ``future'' chapter does
+% not require the ``current'' one to exist. This comment extends to all
+% chapter checks.
+% \begin{macrocode}
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \@@_check_nextchap:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l_@@_ref_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } = { \l_@@_ref_int + 1 } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \@@_check_prevchap:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l_@@_ref_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } = { \l_@@_ref_int - 1 } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \@@_check_chapsafter:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l_@@_ref_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } > { \l_@@_ref_int } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \@@_check_chapsbefore:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l_@@_ref_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } < { \l_@@_ref_int } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Section}
+%
+% \begin{macro}
+% {
+% \@@_check_thissec:nn ,
+% \@@_check_nextsec:nn ,
+% \@@_check_prevsec:nn ,
+% \@@_check_secsafter:nn ,
+% \@@_check_secsbefore:nn
+% }
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_check_thissec:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abssec } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abssec } { \l_@@_ref_int }
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l_@@_lbl_b_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l_@@_ref_b_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_b_int } = { \l_@@_ref_b_int } &&
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } = { \l_@@_ref_int } &&
+% \end{macrocode}
+% `0' is the default value of \texttt{abssec} property, and means here no
+% \cs{section} has yet been issued since its counter has been reset, which
+% occurs at the beginning of the document and at every chapter. Hence, as is
+% the case for chapters, `0' is just ``not a section''. The same observation
+% about the need of the ``current'' section to exist to be able to refer to a
+% ``future'' one also holds. This comment extends to all section checks.
+% \begin{macrocode}
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \@@_check_nextsec:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abssec } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abssec } { \l_@@_ref_int }
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l_@@_lbl_b_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l_@@_ref_b_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_b_int } = { \l_@@_ref_b_int } &&
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } = { \l_@@_ref_int + 1 } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \@@_check_prevsec:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abssec } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abssec } { \l_@@_ref_int }
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l_@@_lbl_b_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l_@@_ref_b_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_b_int } = { \l_@@_ref_b_int } &&
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } = { \l_@@_ref_int - 1 } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \@@_check_secsafter:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abssec } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abssec } { \l_@@_ref_int }
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l_@@_lbl_b_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l_@@_ref_b_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_b_int } = { \l_@@_ref_b_int } &&
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } > { \l_@@_ref_int } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \@@_check_secsbefore:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l_@@_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abssec } { \l_@@_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abssec } { \l_@@_ref_int }
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l_@@_lbl_b_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l_@@_ref_b_int }
+ \bool_lazy_and:nnTF
+ { \l_@@_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l_@@_lbl_b_int } = { \l_@@_ref_b_int } &&
+ \int_compare_p:nNn
+ { \l_@@_lbl_int } < { \l_@@_ref_int } &&
+ ! \int_compare_p:nNn { \l_@@_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l_@@_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \PrintIndex
+%
+% \end{implementation}
+%
diff --git a/Master/texmf-dist/source/latex/zref-check/zref-check.ins b/Master/texmf-dist/source/latex/zref-check/zref-check.ins
new file mode 100644
index 00000000000..4a18782a2d1
--- /dev/null
+++ b/Master/texmf-dist/source/latex/zref-check/zref-check.ins
@@ -0,0 +1,98 @@
+% \iffalse meta-comment
+%
+% File: zref-check.ins
+%
+% This file is part of the LaTeX package "zref-check".
+%
+% Copyright (C) 2021 Gustavo Barros
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file:
+%
+% https://www.latex-project.org/lppl.txt
+%
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+%
+% This work is "maintained" (as per LPPL maintenance status) by
+% Gustavo Barros.
+%
+% This work consists of the files zref-check.dtx,
+% zref-check.ins,
+% zref-check.tex,
+% zref-check-code.tex,
+% and the derived files zref-check.sty and
+% zref-check.pdf,
+% zref-check-code.pdf.
+%
+% The released version of this package is available from CTAN.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the package can be found at
+%
+% https://github.com/gusbrs/zref-check
+%
+% for those people who are interested.
+%
+% -----------------------------------------------------------------------
+%
+% \fi
+
+\input l3docstrip.tex
+
+\keepsilent
+
+\askforoverwritefalse
+
+\preamble
+
+This file was generated from file(s) of the LaTeX package "zref-check".
+
+Copyright (C) 2021 Gustavo Barros
+
+It may be distributed and/or modified under the conditions of the
+LaTeX Project Public License (LPPL), either version 1.3c of this
+license or (at your option) any later version. The latest version
+of this license is in the file:
+
+ https://www.latex-project.org/lppl.txt
+
+and version 1.3 or later is part of all distributions of LaTeX
+version 2005/12/01 or later.
+
+
+This work is "maintained" (as per LPPL maintenance status) by
+ Gustavo Barros.
+
+This work consists of the files zref-check.dtx,
+ zref-check.ins,
+ zref-check.tex,
+ zref-check-code.tex,
+ and the derived files zref-check.sty and
+ zref-check.pdf,
+ zref-check-code.pdf.
+
+The released version of this package is available from CTAN.
+
+-----------------------------------------------------------------------
+
+The development version of the package can be found at
+
+ https://github.com/gusbrs/zref-check
+
+for those people who are interested.
+
+-----------------------------------------------------------------------
+
+\endpreamble
+
+\postamble
+\endpostamble
+
+\generate{\file{zref-check.sty}{\from{zref-check.dtx}{package}}}
+
+\endbatchfile
diff --git a/Master/texmf-dist/tex/latex/zref-check/zref-check.sty b/Master/texmf-dist/tex/latex/zref-check/zref-check.sty
new file mode 100644
index 00000000000..72e8a2f8784
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/zref-check/zref-check.sty
@@ -0,0 +1,962 @@
+%%
+%% This is file `zref-check.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% zref-check.dtx (with options: `package')
+%%
+%% This file was generated from file(s) of the LaTeX package "zref-check".
+%%
+%% Copyright (C) 2021 Gustavo Barros
+%%
+%% It may be distributed and/or modified under the conditions of the
+%% LaTeX Project Public License (LPPL), either version 1.3c of this
+%% license or (at your option) any later version. The latest version
+%% of this license is in the file:
+%%
+%% https://www.latex-project.org/lppl.txt
+%%
+%% and version 1.3 or later is part of all distributions of LaTeX
+%% version 2005/12/01 or later.
+%%
+%%
+%% This work is "maintained" (as per LPPL maintenance status) by
+%% Gustavo Barros.
+%%
+%% This work consists of the files zref-check.dtx,
+%% zref-check.ins,
+%% zref-check.tex,
+%% zref-check-code.tex,
+%% and the derived files zref-check.sty and
+%% zref-check.pdf,
+%% zref-check-code.pdf.
+%%
+%% The released version of this package is available from CTAN.
+%%
+%% -----------------------------------------------------------------------
+%%
+%% The development version of the package can be found at
+%%
+%% https://github.com/gusbrs/zref-check
+%%
+%% for those people who are interested.
+%%
+%% -----------------------------------------------------------------------
+%%
+\providecommand\IfFormatAtLeastTF{\@ifl@t@r\fmtversion}
+\IfFormatAtLeastTF{2021-06-01}
+ {}
+ {%
+ \PackageError{zref-check}{LaTeX kernel too old}
+ {%
+ 'zref-check' requires a LaTeX kernel newer than 2021-06-01.%
+ \MessageBreak Loading will abort!%
+ }%
+ \endinput
+ }%
+\ProvidesExplPackage {zref-check} {2021-08-04} {0.1.0}
+ {Flexible cross-references with contextual checks based on zref}
+\RequirePackage { zref-user }
+\RequirePackage { zref-abspage }
+\RequirePackage { ifdraft }
+\int_new:N \g__zrefcheck_abschap_int
+\int_new:N \g__zrefcheck_abssec_int
+\AddToHook { cmd / chapter / before }
+ {
+ \int_gincr:N \g__zrefcheck_abschap_int
+ \int_zero:N \g__zrefcheck_abssec_int
+ }
+\zref@newprop { abschap } [0] { \int_use:N \g__zrefcheck_abschap_int }
+\zref@addprop \ZREF@mainlist { abschap }
+\AddToHook { cmd / section / before }
+ { \int_gincr:N \g__zrefcheck_abssec_int }
+\zref@newprop { abssec } [0] { \int_use:N \g__zrefcheck_abssec_int }
+\zref@addprop \ZREF@mainlist { abssec }
+\zref@newlist { zrefcheck }
+\zref@addprops { zrefcheck }
+ {
+ abspage ,
+ abschap ,
+ abssec ,
+ page
+ }
+\cs_new:Npn \__zrefcheck_message:nnnn #1#2#3#4
+ {
+ \use:c { msg_ \l__zrefcheck_msglevel_tl :nnnnn }
+ { zref-check } {#1} {#2} {#3} {#4}
+ }
+\cs_generate_variant:Nn \__zrefcheck_message:nnnn { nnnx }
+\msg_new:nnn { zref-check } { check-failed }
+ {
+ Failed~check~'#1'~for~label~'#2' \iow_newline:
+ on~page~#3~on~input~line~\msg_line_number:.
+ }
+\msg_new:nnn { zref-check } { double-check }
+ {
+ Double-check~'#1'~for~label~'#2' \iow_newline:
+ on~page~#3~on~input~line~\msg_line_number:.
+ }
+\msg_new:nnn { zref-check } { check-missing }
+ { Check~'#1'~not~defined~on~input~line~\msg_line_number:. }
+\msg_new:nnn { zref-check } { property-undefined }
+ { Property~'#1'~not~defined~on~input~line~\msg_line_number:. }
+\msg_new:nnn { zref-check } { property-not-in-label }
+ { Label~'#1'~has~no~property~'#2'~on~input~line~\msg_line_number:. }
+\msg_new:nnn { zref-check } { property-not-integer }
+ {
+ Property~'#1'~for~label~'#2'~not~an~integer \iow_newline:
+ on~input~line~\msg_line_number:.
+ }
+\msg_new:nnn { zref-check } { hyperref-preamble-only }
+ {
+ Option~'hyperref'~only~available~in~the~preamble. \iow_newline:
+ Use~the~starred~version~of~'\noexpand\zcheck'~instead.
+ }
+\msg_new:nnn { zref-check } { missing-hyperref }
+ { Missing~'hyperref'~package. \iow_newline: Setting~'hyperref=false'. }
+\msg_new:nnn { zref-check } { ignore-document-only }
+ {
+ Option~'ignore'~only~available~in~the~document. \iow_newline:
+ Use~option~'msglevel'~instead.
+ }
+\msg_new:nnn { zref-check } { option-preamble-only }
+ {
+ Option~'#1'~only~available~in~the~preamble \iow_newline:
+ on~input~line~\msg_line_number:.
+ }
+\msg_new:nnn { zref-check } { closerange-not-positive-integer }
+ {
+ Option~'closerange'~not~a~positive~integer \iow_newline:
+ on~input~line~\msg_line_number:.~Using~default~value.
+ }
+\msg_new:nnn { zref-check } { labelcmd-undefined }
+ {
+ Control~sequence~named~'#1'~used~in~option~'labelcmd'~is~not~defined.~
+ Using~default~value.
+ }
+\cs_new_eq:NN \__zrefcheck_int_to_roman:w \__int_to_roman:w
+\prg_new_conditional:Npnn \__zrefcheck_is_integer:n #1 { p, T , F , TF }
+ {
+ \tl_if_empty:oTF {#1}
+ { \prg_return_false: }
+ {
+ \tl_if_empty:oTF { \__zrefcheck_int_to_roman:w -0#1 }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ }
+\prg_new_protected_conditional:Npnn \__zrefcheck_is_integer_rgx:n #1 { TF }
+ {
+ \regex_match:nnTF { \A\d+\Z } {#1}
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+\bool_new:N \l__zrefcheck_use_hyperref_bool
+\bool_new:N \l__zrefcheck_warn_hyperref_bool
+\keys_define:nn { zref-check }
+ {
+ hyperref .choice: ,
+ hyperref / auto .code:n =
+ {
+ \bool_set_true:N \l__zrefcheck_use_hyperref_bool
+ \bool_set_false:N \l__zrefcheck_warn_hyperref_bool
+ } ,
+ hyperref / true .code:n =
+ {
+ \bool_set_true:N \l__zrefcheck_use_hyperref_bool
+ \bool_set_true:N \l__zrefcheck_warn_hyperref_bool
+ } ,
+ hyperref / false .code:n =
+ {
+ \bool_set_false:N \l__zrefcheck_use_hyperref_bool
+ \bool_set_false:N \l__zrefcheck_warn_hyperref_bool
+ } ,
+ hyperref .initial:n = auto ,
+ hyperref .default:n = auto
+ }
+\AtBeginDocument
+ {
+ \@ifpackageloaded { hyperref }
+ {
+ \bool_if:NT \l__zrefcheck_use_hyperref_bool
+ {
+ \RequirePackage { zref-hyperref }
+ \zref@addprop { zrefcheck } { anchor }
+ }
+ }
+ {
+ \bool_if:NT \l__zrefcheck_warn_hyperref_bool
+ { \msg_warning:nn { zref-check } { missing-hyperref } }
+ \bool_set_false:N \l__zrefcheck_use_hyperref_bool
+ }
+ \keys_define:nn { zref-check }
+ {
+ hyperref .code:n =
+ { \msg_warning:nn { zref-check } { hyperref-preamble-only } }
+ }
+ }
+\tl_new:N \l__zrefcheck_msglevel_tl
+\keys_define:nn { zref-check }
+ {
+ msglevel .choice: ,
+ msglevel / warn .code:n =
+ { \tl_set:Nn \l__zrefcheck_msglevel_tl { warning } } ,
+ msglevel / info .code:n =
+ { \tl_set:Nn \l__zrefcheck_msglevel_tl { info } } ,
+ msglevel / none .code:n =
+ { \tl_set:Nn \l__zrefcheck_msglevel_tl { none } } ,
+ msglevel / obeydraft .code:n =
+ {
+ \ifdraft
+ { \tl_set:Nn \l__zrefcheck_msglevel_tl { info } }
+ { \tl_set:Nn \l__zrefcheck_msglevel_tl { warning } }
+ } ,
+ msglevel / obeyfinal .code:n =
+ {
+ \ifoptionfinal
+ { \tl_set:Nn \l__zrefcheck_msglevel_tl { warning } }
+ { \tl_set:Nn \l__zrefcheck_msglevel_tl { info } }
+ } ,
+ msglevel .value_required:n = true ,
+ msglevel .initial:n = warn ,
+ ignore .code:n =
+ { \msg_warning:nn { zref-check } { ignore-document-only } } ,
+ ignore .value_forbidden:n = true
+ }
+\AtBeginDocument
+ {
+ \keys_define:nn { zref-check }
+ { ignore .meta:n = { msglevel = none } }
+ }
+\bool_new:N \l__zrefcheck_msgonpage_bool
+\keys_define:nn { zref-check }
+ {
+ onpage .choice: ,
+ onpage / labelseq .code:n =
+ {
+ \bool_set_false:N \l__zrefcheck_msgonpage_bool
+ } ,
+ onpage / msg .code:n =
+ {
+ \bool_set_true:N \l__zrefcheck_msgonpage_bool
+ } ,
+ onpage / obeydraft .code:n =
+ {
+ \ifdraft
+ { \bool_set_false:N \l__zrefcheck_msgonpage_bool }
+ { \bool_set_true:N \l__zrefcheck_msgonpage_bool }
+ } ,
+ onpage / obeyfinal .code:n =
+ {
+ \ifoptionfinal
+ { \bool_set_true:N \l__zrefcheck_msgonpage_bool }
+ { \bool_set_false:N \l__zrefcheck_msgonpage_bool }
+ } ,
+ onpage .value_required:n = true ,
+ onpage .initial:n = labelseq
+ }
+\int_new:N \l__zrefcheck_close_range_int
+\keys_define:nn { zref-check }
+ {
+ closerange .code:n =
+ {
+ \__zrefcheck_is_integer_rgx:nTF {#1}
+ { \int_set:Nn \l__zrefcheck_close_range_int { \int_eval:n {#1} } }
+ {
+ \msg_warning:nn { zref-check } { closerange-not-positive-integer }
+ \int_set:Nn \l__zrefcheck_close_range_int { 5 }
+ }
+ } ,
+ closerange .value_required:n = true ,
+ closerange .initial:n = 5
+ }
+\tl_new:N \l__zrefcheck_target_label_tl
+\bool_new:N \l__zrefcheck_target_label_bool
+\keys_define:nn { zref-check }
+ {
+ labelcmd .code:n =
+ {
+ \tl_set:Nn \l__zrefcheck_target_label_tl {#1}
+ \bool_set_true:N \l__zrefcheck_target_label_bool
+ } ,
+ labelcmd .value_required:n = true ,
+ }
+\cs_new:Npn \__zrefcheck_target_label:n #1
+ { \zref@labelbylist {#1} { zrefcheck } }
+\AtBeginDocument
+ {
+ \bool_if:NT \l__zrefcheck_target_label_bool
+ {
+ \tl_if_blank:VT \l__zrefcheck_target_label_tl
+ { \tl_clear:N \l__zrefcheck_target_label_tl }
+ \cs_if_exist:cTF { \l__zrefcheck_target_label_tl }
+ {
+ \cs_set:Npx \__zrefcheck_target_label:n #1
+ {
+ \exp_not:o
+ { \cs:w \l__zrefcheck_target_label_tl \cs_end: }
+ {#1}
+ }
+ }
+ {
+ \exp_args:NnnV \msg_warning:nnn { zref-check }
+ { labelcmd-undefined } { \l__zrefcheck_target_label_tl }
+ }
+ }
+ \keys_define:nn { zref-check }
+ {
+ labelcmd .code:n =
+ {
+ \msg_warning:nnn { zref-check }
+ { option-preamble-only } { labelcmd }
+ }
+ }
+ }
+\RequirePackage { l3keys2e }
+\ProcessKeysOptions { zref-check }
+\NewDocumentCommand \zrefchecksetup { m }
+ { \keys_set:nn { zref-check } {#1} }
+\prop_new:N \g__zrefcheck_auxfile_lblseq_prop
+\tl_set:Nn \g_tmpa_tl { \c_sys_jobname_str .aux }
+\file_if_exist:nT { \g_tmpa_tl }
+ {
+ \ior_open:Nn \g_tmpa_ior { \g_tmpa_tl }
+ \group_begin:
+ \int_zero:N \l_tmpa_int
+ \tl_clear:N \l_tmpa_tl
+ \tl_clear:N \l_tmpb_tl
+ \bool_set_false:N \l_tmpa_bool
+ \ior_map_variable:NNn \g_tmpa_ior \l_tmpa_tl
+ {
+ \tl_map_variable:NNn \l_tmpa_tl \l_tmpb_tl
+ {
+ \tl_if_eq:NnTF \l_tmpb_tl { \zref@newlabel }
+ {
+ \bool_set_true:N \l_tmpa_bool
+ }
+ {
+ \bool_if:NTF \l_tmpa_bool
+ {
+ \bool_set_false:N \l_tmpa_bool
+ \int_incr:N \l_tmpa_int
+ \prop_gput:Nxx \g__zrefcheck_auxfile_lblseq_prop
+ { \l_tmpb_tl } { \int_use:N \l_tmpa_int }
+ }
+ {
+ \tl_map_break:
+ }
+ }
+ }
+ }
+ \group_end:
+ \ior_close:N \g_tmpa_ior
+ }
+\begingroup
+ \let \@addtoreset \ltx@gobbletwo
+ \newcounter { zrefcheck }
+\endgroup
+\setcounter { zrefcheck } { 0 }
+\cs_new:Npn \__zrefcheck_check_lblfmt:n #1 { zrefcheck@ \int_use:N #1 }
+\cs_new:Npn \__zrefcheck_end_lblfmt:n #1 { #1 @zrefcheck }
+\cs_new:Npn \zrefcheck_get_astl:nnn #1#2#3
+ {
+ \tl_clear:N #3
+ \tl_if_eq:nnTF {#2} { lblseq }
+ {
+ \prop_get:NnNF \g__zrefcheck_auxfile_lblseq_prop {#1} #3
+ {
+ \msg_warning:nnnn { zref-check }
+ { property-not-in-label } {#1} {#2}
+ }
+ }
+ {
+ \zref@ifrefundefined {#1}
+ {}
+ {
+ \zref@ifpropundefined {#2}
+ { \msg_warning:nnnn { zref-check } { property-undefined } {#2} }
+ {
+ \zref@ifrefcontainsprop {#1} {#2}
+ {
+ \tl_set:Nx #3
+ { \zref@extractdefault {#1} {#2} { \c_empty_tl } }
+ }
+ {
+ \msg_warning:nnnn
+ { zref-check } { property-not-in-label } {#1} {#2}
+ }
+ }
+ }
+ }
+ }
+\bool_new:N \l__zrefcheck_integer_bool
+\tl_new:N \l__zrefcheck_propval_tl
+\cs_new:Npn \zrefcheck_get_asint:nnn #1#2#3
+ {
+ \zrefcheck_get_astl:nnn {#1} {#2} { \l__zrefcheck_propval_tl }
+ \__zrefcheck_is_integer:nTF { \l__zrefcheck_propval_tl }
+ {
+ \int_set:Nn #3 { \int_eval:n { \l__zrefcheck_propval_tl } }
+ }
+ {
+ \bool_set_false:N \l__zrefcheck_integer_bool
+ \zref@ifrefundefined {#1}
+ { }
+ {
+ \msg_warning:nnnn { zref-check }
+ { property-not-integer } {#2} {#1}
+ }
+ }
+ }
+\NewDocumentCommand \zcheck
+ { s O { } > { \SplitList { , } } m > { \SplitList { , } } O { } m }
+ { \zref@wrapper@babel \__zrefcheck_zcheck:nnnnn {#3} {#1} {#2} {#4} {#5} }
+\int_new:N \g__zrefcheck_id_int
+\tl_new:N \l__zrefcheck_checkbeg_tl
+\tl_new:N \l__zrefcheck_checkend_tl
+\tl_new:N \l__zrefcheck_link_label_tl
+\tl_new:N \l__zrefcheck_link_anchor_tl
+\bool_new:N \l__zrefcheck_link_star_tl
+\cs_new:Npn \__zrefcheck_zcheck:nnnnn #1#2#3#4#5
+ {
+ \group_begin:
+ \keys_set:nn { zref-check } {#3}
+ \int_gincr:N \g__zrefcheck_id_int
+ \tl_set:Nx \l__zrefcheck_checkbeg_tl
+ { \__zrefcheck_check_lblfmt:n { \g__zrefcheck_id_int } }
+ \tl_set:Nx \l__zrefcheck_checkend_tl
+ { \__zrefcheck_end_lblfmt:n { \l__zrefcheck_checkbeg_tl } }
+ \zref@labelbylist { \l__zrefcheck_checkbeg_tl } { zrefcheck }
+ \tl_set:Nn \l__zrefcheck_link_label_tl { \tl_head:n {#1} }
+ \bool_set:Nn \l__zrefcheck_link_star_tl {#2}
+ \zref@ifrefundefined { \l__zrefcheck_link_label_tl }
+ {#5}
+ {
+ \bool_if:nTF
+ {
+ \l__zrefcheck_use_hyperref_bool &&
+ ! \l__zrefcheck_link_star_tl
+ }
+ {
+ \exp_args:Nx \zrefcheck_get_astl:nnn
+ { \l__zrefcheck_link_label_tl }
+ { anchor } { \l__zrefcheck_link_anchor_tl }
+ \hyperlink { \l__zrefcheck_link_anchor_tl } {#5}
+ }
+ {#5}
+ }
+ \zref@labelbylist { \l__zrefcheck_checkend_tl } { zrefcheck }
+ \tl_map_function:nN {#1} \zref@refused
+ \__zrefcheck_run_checks:nnV {#4} {#1} { \l__zrefcheck_checkbeg_tl }
+ \group_end:
+ }
+\NewDocumentCommand \zctarget { m +m }
+ {
+ \group_begin:
+ \refstepcounter { zrefcheck }
+ \zref@wrapper@babel \__zrefcheck_target_label:n {#1}
+ #2
+ \zref@wrapper@babel
+ \zref@labelbylist { \__zrefcheck_end_lblfmt:n {#1} } { zrefcheck }
+ \group_end:
+ }
+\NewDocumentEnvironment {zcregion} { m }
+ {
+ \refstepcounter { zrefcheck }
+ \zref@wrapper@babel \__zrefcheck_target_label:n {#1}
+ }
+ {
+ \zref@wrapper@babel
+ \zref@labelbylist { \__zrefcheck_end_lblfmt:n {#1} } { zrefcheck }
+ }
+\cs_new:Npn \__zrefcheck_run_checks:nnn #1#2#3
+ {
+ \group_begin:
+ \tl_map_inline:nn {#2}
+ {
+ \tl_map_inline:nn {#1}
+ { \__zrefcheck_do_check:nnn {####1} {##1} {#3} }
+ }
+ \group_end:
+ }
+\cs_generate_variant:Nn \__zrefcheck_run_checks:nnn { nnV }
+\bool_new:N \l__zrefcheck_passedcheck_bool
+\bool_new:N \l__zrefcheck_onpage_bool
+\seq_new:N \c__zrefcheck_onpage_checks_seq
+\seq_set_from_clist:Nn \c__zrefcheck_onpage_checks_seq
+ { above , below , before , after }
+\cs_generate_variant:Nn \exp_args:Nnno { Nnoo }
+\cs_new:Npn \__zrefcheck_do_check:nnn #1#2#3
+ {
+ \group_begin:
+ \zref@ifrefundefined {#2}
+ {}
+ {
+ \tl_if_empty:nF {#1}
+ {
+ \bool_set_true:N \l__zrefcheck_passedcheck_bool
+ \bool_set_false:N \l__zrefcheck_onpage_bool
+ \cs_if_exist:cTF { __zrefcheck_check_ #1 :nnF }
+ {
+ \use:c { __zrefcheck_check_ #1 :nnF }
+ {#2} {#3}
+ { \bool_set_false:N \l__zrefcheck_passedcheck_bool }
+ \exp_args:Nnno \use:c { __zrefcheck_check_ #1 :nnF }
+ {#2} { \__zrefcheck_end_lblfmt:n {#3} }
+ { \bool_set_false:N \l__zrefcheck_passedcheck_bool }
+ \zref@ifrefundefined { \__zrefcheck_end_lblfmt:n {#2} }
+ {}
+ {
+ \exp_args:Nno \use:c { __zrefcheck_check_ #1 :nnF }
+ { \__zrefcheck_end_lblfmt:n {#2} } {#3}
+ { \bool_set_false:N \l__zrefcheck_passedcheck_bool }
+ \exp_args:Nnoo \use:c { __zrefcheck_check_ #1 :nnF }
+ { \__zrefcheck_end_lblfmt:n {#2} }
+ { \__zrefcheck_end_lblfmt:n {#3} }
+ { \bool_set_false:N \l__zrefcheck_passedcheck_bool }
+ }
+ \seq_if_in:NnT \c__zrefcheck_onpage_checks_seq {#1}
+ {
+ \__zrefcheck_check_thispage:nnT
+ {#2} {#3}
+ { \bool_set_true:N \l__zrefcheck_onpage_bool }
+ \__zrefcheck_check_thispage:nnT
+ {#2} { \__zrefcheck_end_lblfmt:n {#3} }
+ { \bool_set_true:N \l__zrefcheck_onpage_bool }
+ \zref@ifrefundefined { \__zrefcheck_end_lblfmt:n {#2} }
+ {}
+ {
+ \__zrefcheck_check_thispage:nnT
+ { \__zrefcheck_end_lblfmt:n {#2} } {#3}
+ { \bool_set_true:N \l__zrefcheck_onpage_bool }
+ \__zrefcheck_check_thispage:nnT
+ { \__zrefcheck_end_lblfmt:n {#2} }
+ { \__zrefcheck_end_lblfmt:n {#3} }
+ { \bool_set_true:N \l__zrefcheck_onpage_bool }
+ }
+ }
+ \bool_if:NTF \l__zrefcheck_passedcheck_bool
+ {
+ \bool_if:nT
+ {
+ \l__zrefcheck_msgonpage_bool &&
+ \l__zrefcheck_onpage_bool
+ }
+ {
+ \__zrefcheck_message:nnnx { double-check } {#1} {#2}
+ { \zref@extractdefault {#3} {page} {'unknown'} }
+ }
+ }
+ {
+ \__zrefcheck_message:nnnx { check-failed } {#1} {#2}
+ { \zref@extractdefault {#3} {page} {'unknown'} }
+ }
+ }
+ { \msg_warning:nnn { zref-check } { check-missing } {#1} }
+ }
+ }
+ \group_end:
+ }
+\int_new:N \l__zrefcheck_lbl_int
+\int_new:N \l__zrefcheck_ref_int
+\int_new:N \l__zrefcheck_lbl_b_int
+\int_new:N \l__zrefcheck_ref_b_int
+\prg_new_conditional:Npnn \__zrefcheck_check_thispage:nn #1#2 { T , F , TF }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l__zrefcheck_ref_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } = { \l__zrefcheck_ref_int } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_above:nn #1#2 { F , TF }
+ {
+ \group_begin:
+ \__zrefcheck_check_thispage:nnTF {#1} {#2}
+ {
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { lblseq } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { lblseq } { \l__zrefcheck_ref_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } < { \l__zrefcheck_ref_int } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_below:nn #1#2 { F , TF }
+ {
+ \__zrefcheck_check_thispage:nnTF {#1} {#2}
+ {
+ \__zrefcheck_check_above:nnTF {#1} {#2}
+ { \prg_return_false: }
+ { \prg_return_true: }
+ }
+ { \prg_return_false: }
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_before:nn #1#2 { F }
+ {
+ \__zrefcheck_check_pagesbefore:nnTF {#1} {#2}
+ { \prg_return_true: }
+ {
+ \__zrefcheck_check_above:nnTF {#1} {#2}
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_after:nn #1#2 { F }
+ {
+ \__zrefcheck_check_pagesafter:nnTF {#1} {#2}
+ { \prg_return_true: }
+ {
+ \__zrefcheck_check_below:nnTF {#1} {#2}
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_nextpage:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l__zrefcheck_ref_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } = { \l__zrefcheck_ref_int + 1 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_prevpage:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l__zrefcheck_ref_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } = { \l__zrefcheck_ref_int - 1 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_pagesbefore:nn #1#2 { F , TF }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l__zrefcheck_ref_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } < { \l__zrefcheck_ref_int } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\cs_new_eq:NN \__zrefcheck_check_ppbefore:nnF \__zrefcheck_check_pagesbefore:nnF
+\prg_new_conditional:Npnn \__zrefcheck_check_pagesafter:nn #1#2 { F , TF }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l__zrefcheck_ref_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } > { \l__zrefcheck_ref_int } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\cs_new_eq:NN \__zrefcheck_check_ppafter:nnF \__zrefcheck_check_pagesafter:nnF
+\prg_new_conditional:Npnn \__zrefcheck_check_facing:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l__zrefcheck_ref_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \legacy_if_p:n { @twoside } &&
+ (
+ (
+ \int_if_odd_p:n { \l__zrefcheck_ref_int } &&
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } = { \l__zrefcheck_ref_int - 1 }
+ ) ||
+ (
+ \int_if_even_p:n { \l__zrefcheck_ref_int } &&
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } = { \l__zrefcheck_ref_int + 1 }
+ )
+ ) &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_close:nn #1#2 { F , TF }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abspage } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abspage } { \l__zrefcheck_ref_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \int_abs:n { \l__zrefcheck_lbl_int - \l__zrefcheck_ref_int } }
+ <
+ { \l__zrefcheck_close_range_int + 1 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_far:nn #1#2 { F }
+ {
+ \__zrefcheck_check_close:nnTF {#1} {#2}
+ { \prg_return_false: }
+ { \prg_return_true: }
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_thischap:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l__zrefcheck_ref_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } = { \l__zrefcheck_ref_int } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_nextchap:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l__zrefcheck_ref_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } = { \l__zrefcheck_ref_int + 1 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_prevchap:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l__zrefcheck_ref_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } = { \l__zrefcheck_ref_int - 1 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_chapsafter:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l__zrefcheck_ref_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } > { \l__zrefcheck_ref_int } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_chapsbefore:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l__zrefcheck_ref_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } < { \l__zrefcheck_ref_int } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_thissec:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abssec } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abssec } { \l__zrefcheck_ref_int }
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l__zrefcheck_lbl_b_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l__zrefcheck_ref_b_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_b_int } = { \l__zrefcheck_ref_b_int } &&
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } = { \l__zrefcheck_ref_int } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_nextsec:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abssec } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abssec } { \l__zrefcheck_ref_int }
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l__zrefcheck_lbl_b_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l__zrefcheck_ref_b_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_b_int } = { \l__zrefcheck_ref_b_int } &&
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } = { \l__zrefcheck_ref_int + 1 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_prevsec:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abssec } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abssec } { \l__zrefcheck_ref_int }
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l__zrefcheck_lbl_b_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l__zrefcheck_ref_b_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_b_int } = { \l__zrefcheck_ref_b_int } &&
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } = { \l__zrefcheck_ref_int - 1 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_secsafter:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abssec } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abssec } { \l__zrefcheck_ref_int }
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l__zrefcheck_lbl_b_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l__zrefcheck_ref_b_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_b_int } = { \l__zrefcheck_ref_b_int } &&
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } > { \l__zrefcheck_ref_int } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+\prg_new_conditional:Npnn \__zrefcheck_check_secsbefore:nn #1#2 { F }
+ {
+ \group_begin:
+ \bool_set_true:N \l__zrefcheck_integer_bool
+ \zrefcheck_get_asint:nnn {#1} { abssec } { \l__zrefcheck_lbl_int }
+ \zrefcheck_get_asint:nnn {#2} { abssec } { \l__zrefcheck_ref_int }
+ \zrefcheck_get_asint:nnn {#1} { abschap } { \l__zrefcheck_lbl_b_int }
+ \zrefcheck_get_asint:nnn {#2} { abschap } { \l__zrefcheck_ref_b_int }
+ \bool_lazy_and:nnTF
+ { \l__zrefcheck_integer_bool }
+ {
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_b_int } = { \l__zrefcheck_ref_b_int } &&
+ \int_compare_p:nNn
+ { \l__zrefcheck_lbl_int } < { \l__zrefcheck_ref_int } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_lbl_int } = { 0 } &&
+ ! \int_compare_p:nNn { \l__zrefcheck_ref_int } = { 0 }
+ }
+ { \group_insert_after:N \prg_return_true: }
+ { \group_insert_after:N \prg_return_false: }
+ \group_end:
+ }
+%%
+%%
+%% End of file `zref-check.sty'.
diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check
index 47af32ab8a3..d6c2606024c 100755
--- a/Master/tlpkg/bin/tlpkg-ctan-check
+++ b/Master/tlpkg/bin/tlpkg-ctan-check
@@ -859,7 +859,7 @@ my @TLP_working = qw(
yinit-otf york-thesis youngtab yplan yquant ytableau
zapfchan zapfding zbmath-review-template zebra-goodies zed-csp
zhlineskip zhlipsum zhnumber zhmetrics zhmetrics-uptex zhspacing
- ziffer zlmtt zootaxa-bst zref
+ ziffer zlmtt zootaxa-bst zref zref-check
zwgetfdate zwpagelayout
zxjafbfont zxjafont zxjatype zztex
);
diff --git a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
index c35040a2494..9fa4ab08355 100644
--- a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
+++ b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
@@ -1387,5 +1387,6 @@ depend zebra-goodies
depend zed-csp
depend ziffer
depend zref
+depend zref-check
depend zwgetfdate
depend zwpagelayout
diff --git a/Master/tlpkg/tlpsrc/zref-check.tlpsrc b/Master/tlpkg/tlpsrc/zref-check.tlpsrc
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Master/tlpkg/tlpsrc/zref-check.tlpsrc