From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001
From: Norbert Preining <norbert@preining.info>
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
+%</dtx>
+%<*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}
+%</test>
+%<*dtx>
+\fi
+%</dtx>
+%    \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
+%<driver> \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}
+%</driver>
+%    \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]{%
+%<etex> \edef#2{\detokenize{#3}}%
+%<*!etex>
+  \toks@{#3}%
+  \edef#2{\the\toks@}%
+  \@onelevel@sanitize#2%
+%</!etex>
+  \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}
+%</package>
+%<*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}
+%</test>
+%<*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>
+%<*!etex>
+  \toks@{#3}%
+  \edef#2{\the\toks@}%
+  \@onelevel@sanitize#2%
+  \edef#2{\expandafter\qst@mmtmp\expandafter
+    \@gobbletwo\expandafter#1#2\iffalse#1\fi}%
+%</!etex>
+}
+%    \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}
+%</package>
+%<test>\stop
+%    \end{macrocode}
+% \Finale
-- 
cgit v1.2.3

