From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- macros/latex/contrib/qstest/makematch.dtx | 598 ++++++++++++++++++++++++++++++ 1 file changed, 598 insertions(+) create mode 100644 macros/latex/contrib/qstest/makematch.dtx (limited to 'macros/latex/contrib/qstest/makematch.dtx') diff --git a/macros/latex/contrib/qstest/makematch.dtx b/macros/latex/contrib/qstest/makematch.dtx new file mode 100644 index 0000000000..b66ec1a70d --- /dev/null +++ b/macros/latex/contrib/qstest/makematch.dtx @@ -0,0 +1,598 @@ +% \iffalse +%% +%% Copyright (C) 2006, 2007 QuinScape GmbH +%% http://www.quinscape.de +% +% This file may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% \fi +% \CheckSum{354} +% \section{Using \texttt{makematch}} +% +% The basic idea of \texttt{makematch} is to compile patterns and +% targets (and/or lists of them) and match the former to the latter. +% This functionality is used extensively in QuinScape's +% \href{file:qstest}{\texttt{qstest}} package for unit testing. We'll +% use that package for documenting usage of \texttt{makematch}; the +% following construct is skips the tests when \texttt{makematch.dtx} is +% used as a standalone file. +% \begin{macrocode} +%<*dtx> +\iffalse +% +%<*test> +\RequirePackage{makematch,qstest} +\IncludeTests{*} +% \end{macrocode} +% +% \texttt{makematch} requires an e\TeX-based \LaTeX\ which should be +% standard for current \TeX\ distributions. +% +% \hypertarget{patterns}{% +% \subsection{Match patterns and targets} +% } This +% package has the notion of match patterns and targets. Patterns and +% targets get sanitized at the time they are specified; this means +% that nothing gets expanded, but replaced by a textual representation +% consisting of spaces (with catcode~10) and other characters +% (catcode~12). Control words are usually followed by a single space +% when getting sanitized. +% +% Patterns and targets are actually generalized to pattern and target +% lists by this package: you can, when specifying either, instead give +% a list by using an optional argument for specifying a list separator +% (the lists used in \texttt{qstest} are comma-separated). +% +% Target lists are unordered: the order of targets in them is +% irrelevant. Leading spaces in front of each target get stripped, +% all others are retained. +% +% Pattern lists similarly consist of a list of patterns, with leading +% spaces stripped from each pattern. In contrast to target lists, the +% order of pattern lists is significant, with later patterns +% overriding earlier ones. Also in contrast to target lists, empty +% patterns are removed. +% +% There are two special characters inside of a pattern: the first is +% the wildcard |*| which matches any number of consecutive characters +% (including the empty string) in a target. Wildcards can occur +% anywhere and more than once in a pattern. +% +% The second special character in a pattern is only recognized at the +% beginning of a pattern, and only if that pattern is part of a +% pattern list (namely, when a list separator is +% specified).\footnote{And if |!| is not the list separator of the +% list.} If a pattern is preceded by |!| then the following +% pattern, if it matches, causes any previous match from the pattern +% list to be disregarded. +% +% So for example, the pattern list |{*,!foo}| matches any target list +% that does not contain the match target |foo|. +% +% An empty target list |{}| is considered to contain the empty string. +% Thus the pattern |*| matches every target list, including empty +% ones, while the pattern list |{}| does not match any keyword list, +% including empty ones. +% +% \subsection{The Interface} +% +% \DescribeMacro{\MakeMatcher} takes two mandatory arguments. The +% first is a macro name. This macro will become the new matcher. The +% second argument of \cmd{\MakeMatcher} is the pattern to match. An +% optional argument before the mandatory ones can be used for +% specifying a list separator in which case the first mandatory +% argument becomes a pattern list (only in this case are leading |!| +% characters before list elements interpreted specially). +% \begin{macrocode} +\begin{qstest}{\MakeMatcher}{\MakeMatcher} + \MakeMatcher\stylefiles{*.sty} + \MakeMatcher\headbang{!*} + \MakeMatcher[,]\truestylefiles{*.sty,!.thumbnails/*,!*/.thumbnails/*} +% \end{macrocode} +% The matcher constructed in that manner is called with three +% arguments. The first argument is a control sequence name containing +% a match target (or target list) prepared using +% \cmd{\MakeMatchTarget} (see below). +% +% Alternatively, the first argument can be a brace-enclosed list (note +% that you'll need \emph{two} nested levels of braces, one for +% enclosing the argument, one for specifying that this is a list) +% which will then get passed to \cmd{\MakeMatchTarget} (see below) for +% processing before use. The inner level of braces inside of the +% first argument may be preceded by a bracketed optional argument +% specifying the list separator for this list. +% +% The second argument of the matcher is executed if the pattern list +% for which the matcher has been built matches the keyword list. The +% third is executed if it doesn't. List separators of pattern and +% keyword list are completely independent from each other. Ok, we +% expect the following to result just in calls of \cmd{\true} (a call +% of \cmd{\false} is turned into a failed expectation): +% \begin{macrocode} + \begin{qstest}{\Makematcher literal}{\MakeMatcher} + \begin{ExpectCallSequence}{\true{}\false{}`% + .#1{\Expect*{\CalledName#1}{true}}+'} + \stylefiles{{xxx/.thumbnails/blubb.sty}}{\true}{\false} + \truestylefiles{{xxx/.thumbnails/blubb.sty}}{\false}{\true} + \headbang{{xxx/.thumbnails/blubb.sty}}{\false}{\true} + \stylefiles{[ ]{x.sty.gz .thumbnails/x.sty !x}}{\true}{\false} + \truestylefiles{[ ]{x.sty.gz .thumbnails/x.sty !x}}{\false}{\true} + \headbang{[ ]{x.sty.gz .thumbnails/x.sty !x}}{\true}{\false} + \end{ExpectCallSequence} + \end{qstest} +% \end{macrocode} +% +% So how do we create a sanitized keyword list in a control sequence? +% +% \DescribeMacro{\MakeMatchTarget} is called with two mandatory +% arguments, the first being a control sequence name where the keyword +% list in the second argument will get stored in a sanitized form: it +% is converted without expansion to characters of either ``special'' +% or ``space'' category (catcodes 12 and~10, respectively), and any +% leading spaces at the beginning of an element is removed. Without +% an optional bracketed argument, not more than sanitization and +% leading space stripping is done. If an optional bracketed argument +% before the mandatory arguments is specified, it defines the list +% separator: this has to be a single sanitized character token (either +% a space or a character of category ``other'') that is used as the +% list separator for the input (the finished list will actually always +% use the macro |\,| as a list separator). +% \begin{macrocode} + \begin{qstest}{\Makematcher with \MakeMatchTarget}% + {\MakeMatcher,\MakeMatchTarget} + \MakeMatchTarget\single{xxx/.thumbnails/blubb.sty} + \MakeMatchTarget[ ]\multiple{x.sty.gz .thumbnails/x.sty !x} + \begin{ExpectCallSequence}{\true{}\false{}`% + .#1{\Expect*{\CalledName#1}{true}}+'} + \stylefiles{\single}{\true}{\false} + \truestylefiles\single{\false}{\true} + \headbang\single{\false}{\true} + \stylefiles{\multiple}{\true}{\false} + \truestylefiles\multiple{\false}{\true} + \headbang\multiple{\true}{\false} + \end{ExpectCallSequence} + \end{qstest} +% \end{macrocode} +% \DescribeMacro{\MatchedTarget} This will after a match process +% contain the target matched by the last matching pattern (if several +% targets in a match target list match, only the first of those is +% considered and recorded), regardless of whether the corresponding +% pattern was negated with |!|. +% +% \DescribeMacro{\RemoveMatched} After a successful match, you can +% call \cmd{\RemoveMatched} with one argument: the control sequence +% name where the list was kept, and the match will get removed from +% the list. If every list element is removed, the list will be +% identical to \cmd{\@empty}. +% \begin{macrocode} + \begin{qstest}{\MatchedTarget} + {\MakeMatcher,\MakeMatchTarget,\MatchedTarget} + \MakeMatchTarget\single{xxx/.thumbnails/blubb.sty} + \MakeMatchTarget[ ]\multiple{x.sty.gz .thumbnails/x.sty !x} + \begin{ExpectCallSequence}{\true{}\false{}`% + .#1{\Expect*{\CalledName#1}{true}}+'} + \stylefiles{\single}{\true}{\false} + \Expect*{\single}{xxx/.thumbnails/blubb.sty} + \Expect*{\meaning\MatchedTarget}*{\meaning\single} + \RemoveMatched\single + \Expect*{\meaning\single}{macro:->} + \truestylefiles\single{\false}{\true} + \headbang\single{\false}{\true} + \stylefiles{\multiple}{\true}{\false} + \Expect*{\MatchedTarget}{.thumbnails/x.sty} + \RemoveMatched\multiple + \Expect\expandafter{\multiple}{x.sty.gz\,!x} + \truestylefiles\multiple{\false}{\true} + \Expect*{\meaning\MatchedTarget}{undefined} + \headbang\multiple{\true}{\false} + \Expect*{\MatchedTarget}{!x} + \RemoveMatched\multiple + \Expect*{\multiple}{x.sty.gz} + \end{ExpectCallSequence} + \end{qstest} +\end{qstest} +% \end{macrocode} +% +% \subsection{Notes on sanitization} +% Note that sanitization to printable characters has several +% consequences: it means that the control sequence \cmd{\,} will turn +% into the string |\| followed by the end of the keyword. Note also +% that single-character control sequences with a nonletter name are +% not followed by a space in sanitization. This means that +% sanitization depends on the current catcodes. Most particularly, +% sanitizing the input |\@abc12| will turn into |\@abc 12| when |@| is +% of catcode letter, but to |\@abc12| when |@| is a nonletter. +% +% So sanitization cannot hide all effects of catcode differences. It +% is still essential since otherwise braces would cause rather severe +% complications during matching. +% +% Another curiosity of sanitization is that explicit macro parameter +% characters (usually |#|) get duplicated while being sanitized. +% +% So this is the end of the documentation section, so we end our test +% file setup by complementing the beginning: +% \begin{macrocode} +% +%<*dtx> +\fi +% +% \end{macrocode} +% +% \StopEventually{} +% \section{The driver file} +% An explicit driver file generated by docstrip will typeset the +% implementation. Running the |.dtx| file through, in contrast, will +% only typeset the user level documentation. +% \begin{macrocode} +%<*driver> +\documentclass{ltxdoc} +\usepackage{makematch} +\usepackage{ifpdf} +\usepackage{hyperref} +\OnlyDescription +% \AlsoImplementation +\begin{document} +\GetFileInfo{makematch.sty} +\date{\filedate} +\title{\texttt{\filename}\\\fileinfo\\version \fileversion} +\author{David Kastrup\thanks{\href{mailto:dak@gnu.org}% + {David.Kastrup@QuinScape.de}, \href{http://quinscape.de}{QuinScape + GmbH}}} +\maketitle +\DocInput{makematch.dtx} +\end{document} +% +% \end{macrocode} +% \section{The installer file} +% +% There is no separate installer file for this package as it is part +% of the \texttt{qstest} bundle and uses its +% \href{file:qstest#installer}{installer}. +% +% \section{The Implementation} +% \subsection{Front matter} +% Some data and version magic from SVN keyword expansion. +% \begin{macrocode} +%<*package> +\NeedsTeXFormat{LaTeX2e} +\def\next$#1: #2.dtx #3 #4-#5-#6 #7${% + \ProvidesPackage{#2}[#4/#5/#6 1.#3 Pattern matching with + wildcards] +} +\next +$Id: makematch.dtx 7925 2007-02-23 14:22:19Z dkastrup $ +% \end{macrocode} +% \subsection{Pattern matching} +% \begin{macro}{\MakeMatcher} +% This is the principal magic for doing pattern matching. The +% control sequence name given in |#1| becomes a pattern matching +% engine for the pattern list specified in |#2|. If this control +% sequence is executed at a later point of time, it matches the +% compiled pattern list to the keyword list contained in the +% sanitized macro specified in its first argument (if the first +% argument itself starts with an additional opening brace, it is +% considered to be a keyword list that yet needs to be sanitized). +% +% Macros in |#2| are not expanded, and everything but spaces is +% converted to catcode~12 characters. At the start of a pattern or +% a keyword, spaces get ignored. Spaces inside of patterns or +% keywords should work as expected, however. +% \begin{macrocode} +\newcommand\MakeMatcher[3][\relax]{% +% \edef#2{\detokenize{#3}}% +%<*!etex> + \toks@{#3}% + \edef#2{\the\toks@}% + \@onelevel@sanitize#2% +% + \def\qst@mmtmp##1##2#1{\qst@parseonecase{##1}{##2}}% + \let\qst@comma= #1\relax + \edef#2##1{\noexpand\qst@setup##1% + \expandafter\qst@parsestart\expandafter\@firstoftwo +% \end{macrocode} +% The following |{#1\m@ne}| sequence causes \cmd{\qst@parsestart} to +% end parsing. +% \begin{macrocode} + #2#1{#1\m@ne}\noexpand\qst@finish}} +% \end{macrocode} +% \end{macro} +% We define two shorthands for matchers that match always and never, +% respectively: +% \begin{macro}{\qst@matchalways} +% \begin{macrocode} +\long\def\qst@matchalways#1#2#3{#2} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\qst@matchnever} +% \begin{macrocode} +\long\def\qst@matchnever#1#2#3{#3} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\qst@setup} +% Gets one argument, namely a macro containing the match list, or +% otherwise a list enclosed with a level of braces, optionally +% preceded by the list separator to be used in brackets. This is +% stored in \cmd{\qst@matchlist}. Furthermore, \cmd{\qst@finish} is +% set to the default value indicating a non-match. +% \begin{macrocode} +\def\qst@setup{\let\MatchedTarget\@undefined + \let\qst@finish\@secondoftwo + \futurelet\qst@matchlist\qst@setupii} +\def\qst@setupii{\ifcase + \ifcat\noexpand\qst@matchlist\bgroup\@ne\fi + \ifx\qst@matchlist[\tw@\fi %] + \m@ne + \or + \expandafter\MakeMatchTarget\expandafter\qst@matchlist + \or + \expandafter\qst@setupiii + \else \expandafter\@gobble + \fi} +\def\qst@setupiii[#1]{\MakeMatchTarget[{#1}]\qst@matchlist} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\qst@parsestart} +% This tests at the start of a new word whether we are finished or +% whether there is an inverted condition. Note that this will +% remove spaces before a word. |#1| indicates the polarity, |#2|~is +% always a single token, no braces possible. +% \begin{macrocode} +\def\qst@parsestart#1#2{% + \ifcase + \ifx\qst@comma#2\@ne\fi + \ifx\qst@comma\relax + \else\ifx!#2#1\tw@\@ne\fi + \fi + \thr@@ + \or + \expandafter\qst@parsestart + \expandafter\@firstoftwo + \or + \expandafter\qst@parsestart + \expandafter\@secondoftwo + \or + \expandafter\qst@mmtmp + \expandafter#1% + \expandafter#2% + \fi +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\qst@afterfi} +% This is just a helper macro cleaning up a following |\fi|. +% \begin{macrocode} +\def\qst@afterfi#1#2\fi{\fi#1} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\qst@parseonecase} +% We process one pattern here. A pattern ends with |,| and we have +% passed in |#1| the command to execute in case the pattern +% matches. +% \begin{macrocode} +\def\qst@parseonecase#1#2{% + \noexpand\qst@checkname {\qst@parsewild#2*\,23456789*}% + \noexpand#1\qst@parsestart\@firstoftwo} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\qst@parsewild} +% This is the parsing macro for wildcards and stuff. |#1|~is +% material before the next |*| character or the end of the sequence, +% |#2|~is either empty (indicating the end of the word to match) or +% material coming after a wildcard and terminated by |*|, +% |#3|~contains the next unused parameter number, and |#4| contains +% following parameter numbers. If we emitted a wildcard code, we +% jump into \cmd{\qst@skipwild} in order to skip additional +% wildcards. +% \begin{macrocode} +\def\qst@parsewild#1*#2\,#3#4*{% + #1% + \ifx\,#2\,% + \else + #####3% + \qst@afterfi{\qst@skipwild#2\,#4*}% + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\qst@skipwild} +% This caters for the case where successive wildcards are +% encountered. This is the case if |#1| is empty, meaning that the +% string started with |*|, but |#2| is non-empty, indicating that we +% are not at the terminal |*|. +% \begin{macrocode} +\def\qst@skipwild#1*#2\,{% + #1% + \ifcase + \ifx *#1*\ifx\,#2\,\else \@ne \fi \fi + \tw@ + \or + \expandafter\qst@skipwild + \or + \expandafter\qst@parsewild\expandafter*% + \fi#2\,} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\qst@checkname} +% This is called with a compiled form of a test pattern in~|#1| and +% a single token that will get assigned to \cmd{\qst@finish} in case +% that we got a match of the pattern with any of the comma-separated +% keywords in \cmd{\MatchList}. +% +% Here is how \cmd{\qst@checkname} works: both test pattern and +% option list are placed between commas (actually \cmd{\,}) so that +% a match of the test pattern on the list implies a full match. The +% test pattern happens to match itself when just interpreted as an +% unexpanded pattern string, and this pattern string does not +% contain commas in itself. We append the pattern string as an +% artificial last element in the option list. Since the trailing +% comma placed at the end of the match pattern can't match inside of +% an option, options are consumed only completely. If the pattern +% matched a string containing a comma, it actually did so across +% more than a single option. In that case, we remove everything up +% to the first comma and try again. +% +% We define \cmd{\qst@mmtmp} as a macro that matches starting at an +% arbitrary comma (throwing away everything preceding), then +% retaining the matched string (note that |#1| in the replacement +% text will faithfully reproduce what was matched by |#1| in the +% argument string, also note the difference between |#1| and |##1|), +% appending a separator of \cmd{\@nil} in order to delimit the +% matched sequence. +% \begin{macrocode} +\def\qst@checkname#1{% + \def\qst@mmtmp##1\,#1\,{#1\,\@nil}% + \expandafter\expandafter\expandafter\qst@checknameii + \expandafter\qst@mmtmp + \expandafter\,\qst@matchlist\,#1\,\@nil} +% \end{macrocode} +% \begin{macro}{\qst@checknameii} +% So we now do the check. If |#3| is |\@nil|, the sentinel has been +% consumed and we did not match anything. If this is not the case, +% we split the matched material at the first comma into |#1| +% and~|#2|. If |#2| is empty, no comma is contained in the match, +% so we matched a complete option. Otherwise, if |#2| is non-empty, +% the match contained a comma and was across several options +% (possibly breaking into the sentinel without consuming it). Ugh. +% We remove the first option that was conflated in the match, and +% restart the match process. +% +% Note that |#3| has its origin from behind a comma, so at its +% position there are no leading spaces that could get lost by it +% being an undelimited argument. +% \begin{macrocode} +\def\qst@checknameii#1\,#2\@nil#3{% + \ifcase + \ifx\@nil#3\@ne\fi + \ifx\@nil#2\@nil \tw@\fi + \m@ne + \or + \expandafter\qst@checknamenomatch + \or + \expandafter\qst@checknamematch + \fi \expandafter\qst@checknameii\qst@mmtmp#1\,#2#3} +% \end{macrocode} +% \begin{macro}{\qst@checknamenomatch} +% This removes remaining garbage and the code corresponding to the +% polarity of the test since the test is not taken. +% \begin{macrocode} +\def\qst@checknamenomatch#1\@nil#2{} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\qst@checknamematch} +% We had a match, something which did not include a comma and at the +% same time left the sentinel at the end of the word list intact. +% So clean up and take over the right polarity. +% \begin{macrocode} +\def\qst@checknamematch#1\qst@mmtmp#2\,#3\@nil{% + \def\MatchedTarget{#2}% + \let\qst@finish} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% Now for removing patterns: |\romannumeral\z@| expands to +% nothing, but we use it as a an \cmd{\expandafter}-Propagator. +% \begin{macro}{\RemoveMatched} +% \begin{macrocode} +\def\RemoveMatched#1{\ifx#1\MatchedTarget + \let#1\@empty + \else + \expandafter\def\expandafter\qst@mmtmp + \expandafter##\expandafter1\expandafter\,\MatchedTarget\,{##1\,}% + \expandafter\def\expandafter#1\expandafter{% + \romannumeral\expandafter\expandafter\expandafter\z@ + \expandafter\qst@remmat + \romannumeral\expandafter\expandafter\expandafter\z@ + \expandafter\qst@mmtmp\expandafter\,#1\,\@nil}% + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\qst@remmat} +% This is just a helper macro removing \cmd{\,} from around the +% list. +% \begin{macrocode} +\def\qst@remmat\,#1\,\@nil{#1} +% \end{macrocode} +% \end{macro} +% +% Ok, let's test this thing for some patterns. +% \begin{macrocode} +% +%<*test> +\makeatletter +\begin{qstest}{\MakeMatcher internals}{\MakeMatcher,internal} + \MakeMatcher\sometest{} + \Expect*{\meaning\sometest}{macro:#1->\qst@setup#1\qst@finish} + \MakeMatcher[,]\sometest{ a, bc*, !woozle**, !*#*woz***.*x, !!*ab} + \Expect*{\meaning\sometest}{macro:#1->% + \qst@setup#1% + \qst@checkname{a}\@firstoftwo + \qst@checkname{bc##2}\@firstoftwo + \qst@checkname{woozle##2}\@secondoftwo + \qst@checkname{##2####3woz##4.##5x}\@secondoftwo + \qst@checkname{##2ab}\@firstoftwo + \qst@finish} + \MakeMatcher[ ]\another{ a bc* ! woozle** ! *#*woz***.*x ! ! *ab} + \Expect*{\meaning\another}*{\meaning\sometest} +\end{qstest} +% +%<*package> +% \end{macrocode} +% +% \begin{macro}{\MakeMatchTarget} +% This gets two obligatory arguments, a control sequence name and +% the keyword list. This list is sanitized and prepared for +% matching. The list sanitized in this manner is stored in the +% control sequence in~|#2|, the first obligatory argument. The +% gobbledygook before and after the detokenized content is there to +% get started nicely into the loop with \cmd{\qst@mmtmp} and get out +% again without having to employ expensive tests. The purpose of +% \cmd{\qst@mmtmp} is to remove leading spaces from list elements +% and replace the list separator (which defaults to `|,|' but can be +% specified with an optional argument to \cmd{\MakeMatchTarget}) +% with the sentinel separator |\,| which can't otherwise occur in a +% sanitized list. There are several special values for the list +% separator that make sense: +% \begin{description} +% \item[\textvisiblespace] A space character (catcode 10). List +% entries are separated by spaces. +% \item[$\textrm{other}_{12}$] A character of catcode~12 that is +% going to be used as a list separator. Don't use anything other +% than sanitized characters, or the effects will be as with the +% following: +% \item[\texttt{\string\relax}] The default, does not do any list +% replacement. +% \end{description} +% Don't ever pass anything other than a single token (possibly +% brace-enclosed) in this manner, or things will go really wrong. +% \begin{macrocode} +\newcommand\MakeMatchTarget[3][\relax]{% + \def\qst@mmtmp##1#1##2{##1\noexpand\,\qst@mmtmp##2}% +%<*etex> + \edef#2{\expandafter\qst@mmtmp\expandafter + \@gobbletwo\expandafter#1\detokenize{#3}\iffalse#1\fi}% +% +%<*!etex> + \toks@{#3}% + \edef#2{\the\toks@}% + \@onelevel@sanitize#2% + \edef#2{\expandafter\qst@mmtmp\expandafter + \@gobbletwo\expandafter#1#2\iffalse#1\fi}% +% +} +% \end{macrocode} +% \end{macro} +% \subsection{The End} +% The test can be ended either in the driver file, or in a standalone +% testfile. \cmd{\stop} is \LaTeX's way of ending the processing of +% an input file before any document processing or setup has been done. +% \begin{macrocode} +% +%\stop +% \end{macrocode} +% \Finale -- cgit v1.2.3